diff --git a/include/bal_errors.h b/include/bal_errors.h index 20573d7..9cafce6 100644 --- a/include/bal_errors.h +++ b/include/bal_errors.h @@ -13,7 +13,8 @@ typedef enum BAL_SUCCESS = 0, BAL_ERROR_INVALID_ARGUMENT = -1, BAL_ERROR_ALLOCATION_FAILED = -2, - BAL_ERROR_ENGINE_STATE_INVALID = -3, + BAL_ERROR_MEMORY_ALIGNMENT = -3, + BAL_ERROR_ENGINE_STATE_INVALID = -4, // IR Errors. // diff --git a/include/bal_memory.h b/include/bal_memory.h index d51c831..acecf1d 100644 --- a/include/bal_memory.h +++ b/include/bal_memory.h @@ -11,6 +11,8 @@ #define BALLISTIC_MEMORY_H #include "bal_attributes.h" +#include "bal_types.h" +#include "bal_errors.h" #include #include @@ -38,6 +40,30 @@ typedef void (*bal_free_function_t)(void *allocator, void *pointer, size_t size); +/*! + * @brief Translate a Guest Virtual Address to a Host Virtual Address. + * + * @details + * Ballistic calls this when it needs to fetch instructions. The implementer + * must return a pointer to the host memory corresponding to the requested + * guest address. + * + * @param[in] context The oapque pointer provided in @ref + * bal_memory_interface_t. + * @param[in] guest_address The guest address to translate. + * @param[out] max_readable_size The implementer MUST write the number of + * contiguous bytes valid to read from the + * returned pointer. This prevents Ballistic from + * reading off the end of a mapped page or buffer. + * + * @return A pointer to the host memory containing the data at @p guest_address. + * @return NULL if the address is unmapped or invalid. + */ +typedef const uint8_t *(*bal_translate_function_t)( + void *context, + bal_guest_address_t guest_address, + size_t *max_readable_size); + typedef struct { /*! @@ -58,15 +84,54 @@ typedef struct } bal_allocator_t; +typedef struct +{ + void *context; + bal_translate_function_t translate; +} bal_memory_interface_t; + /*! * @brief Populates an allocator struct with the default implementation. * - * @param[out] allocator The strict to populate. Must not be NULL. + * @param[out] allocator The struct to populate. Must not be NULL. * * @warn Only supports Windows and POSIX systems. */ -BAL_COLD void get_default_allocator(bal_allocator_t *out_allocator); +BAL_COLD void bal_get_default_allocator(bal_allocator_t *out_allocator); +/*! + * @brief Initializes a translation interface that uses a flat, contiguous + * memory buffer. + * + * @params[in] allocator The allocator used to allocate the internal interface + * structure. + * @params[out] interface The interface struct to populate. + * @params[in] buffer Pointer to the pre-allocated host memory containing + * the guest code. + * @params[in] size The size of the buffer in bytes. + * + * @return BAL_SUCCESS on success. + * @return BAL_ERROR_INVALID_ARGUMENT if arguments are NULL. + * @return BAL_ERROR_MEMORY_ALIGNMENT if buffer is not align to 4 bytes. + * + * @warning The caller retains ownership of buffer. It must remain valid for + * the lifetime of the interface. + */ +BAL_COLD bal_error_t +bal_memory_init_flat(bal_allocator_t *BAL_RESTRICT allocator, + bal_memory_interface_t *BAL_RESTRICT interface, + void *BAL_RESTRICT buffer, + size_t size); + +/*! + * @brief Frees the interface's internal state. + * + * @details + * This does not free the buffer passed during initialization, as Ballistic + * does not own it. + */ +BAL_COLD void bal_memory_destroy_flat(bal_allocator_t *allocator, + bal_memory_interface_t *interface); #endif /* BALLISTIC_MEMORY_H */ /*** end of file ***/ diff --git a/include/bal_types.h b/include/bal_types.h index 5afce85..29a2042 100644 --- a/include/bal_types.h +++ b/include/bal_types.h @@ -8,7 +8,9 @@ #include + typedef uint64_t bal_instruction_t; +typedef uint64_t bal_guest_address_t; typedef uint16_t bal_instruction_count_t; typedef uint16_t bal_ssa_id_t; typedef uint8_t bal_bit_width_t; diff --git a/src/bal_memory.c b/src/bal_memory.c index 9f02604..0a21d85 100644 --- a/src/bal_memory.c +++ b/src/bal_memory.c @@ -1,22 +1,78 @@ #include "bal_memory.h" -#include "bal_platform.h" #include #include -void *default_allocate(void *, size_t, size_t); -void default_free(void *, void *, size_t); +static void *default_allocate(void *, size_t, size_t); +static void default_free(void *, void *, size_t); +BAL_HOT static const uint8_t *_bal_translate_flat(void *, + bal_guest_address_t, + size_t *); + +typedef struct +{ + uint8_t *host_base; + size_t size; +} flat_translation_interface_t; void -get_default_allocator (bal_allocator_t *out_allocator) +bal_get_default_allocator (bal_allocator_t *out_allocator) { out_allocator->allocator = NULL; out_allocator->allocate = default_allocate; out_allocator->free = default_free; } +bal_error_t +bal_memory_init_flat (bal_allocator_t *BAL_RESTRICT allocator, + bal_memory_interface_t *BAL_RESTRICT interface, + void *BAL_RESTRICT buffer, + size_t size) +{ + if (NULL == allocator || NULL == interface || NULL == buffer || 0 == size) + { + return BAL_ERROR_INVALID_ARGUMENT; + } + + if (((uintptr_t)buffer & 3U) != 0) + { + // Buffer is not 4 byte aligned. + // + return BAL_ERROR_MEMORY_ALIGNMENT; + } + + size_t memory_alignment = 4U; + flat_translation_interface_t *flat_interface + = (flat_translation_interface_t *)allocator->allocate( + allocator, memory_alignment, sizeof(flat_translation_interface_t)); + + flat_interface->host_base = (uint8_t *)buffer; + flat_interface->size = size; + interface->context = flat_interface; + interface->translate = _bal_translate_flat; + return BAL_SUCCESS; +} + +void +bal_memory_destroy_flat (bal_allocator_t *allocator, + bal_memory_interface_t *interface) +{ + if (NULL == allocator || NULL == interface) + { + return; + } + + if (NULL == interface->context) + { + return; + } + + allocator->free( + allocator, interface->context, sizeof(flat_translation_interface_t)); +} + #if BAL_PLATFORM_POSIX -void * +static void * default_allocate (void *allocator, size_t alignment, size_t size) { if (0 == size) @@ -25,11 +81,10 @@ default_allocate (void *allocator, size_t alignment, size_t size) } void *memory = aligned_alloc(alignment, size); - return memory; } -void +static void default_free (void *allocator, void *pointer, size_t size) { free(pointer); @@ -41,7 +96,7 @@ default_free (void *allocator, void *pointer, size_t size) #include -void * +static void * default_allocate (void *allocator, size_t alignment, size_t size) { if (0 == size) @@ -50,16 +105,42 @@ default_allocate (void *allocator, size_t alignment, size_t size) } void *memory = _aligned_malloc(alignment, size); - return memory; } -void +static void default_free (void *allocator, void *pointer, size_t size) { _aligned_free(pointer); -} +} #endif /* BAL_PLATFORM_WINDOWS */ +static const uint8_t * +_bal_translate_flat (void *BAL_RESTRICT interface, + bal_guest_address_t guest_address, + size_t *BAL_RESTRICT max_readable_size) +{ + if (BAL_UNLIKELY(NULL == interface || 0 == guest_address + || NULL == max_readable_size)) + { + return NULL; + } + + flat_translation_interface_t *BAL_RESTRICT context + = (flat_translation_interface_t *)((bal_memory_interface_t *)interface) + ->context; + + // Is address out of bounds. + // + if (guest_address >= context->size) + { + return NULL; + } + + *max_readable_size = context->size - guest_address; + const uint8_t *host_address = context->host_base + guest_address; + return host_address; +} + /*** end of file ***/