mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2024-12-23 05:35:32 +00:00
implement host-controlled memory mapping for #261
This commit is contained in:
parent
c6b6ba5daa
commit
6d21ebabea
|
@ -48,6 +48,8 @@ typedef void (*uc_args_uc_u64_t)(struct uc_struct *, uint64_t addr);
|
||||||
|
|
||||||
typedef MemoryRegion* (*uc_args_uc_ram_size_t)(struct uc_struct*, ram_addr_t begin, size_t size, uint32_t perms);
|
typedef MemoryRegion* (*uc_args_uc_ram_size_t)(struct uc_struct*, ram_addr_t begin, size_t size, uint32_t perms);
|
||||||
|
|
||||||
|
typedef MemoryRegion* (*uc_args_uc_ram_size_ptr_t)(struct uc_struct*, ram_addr_t begin, size_t size, void *ptr);
|
||||||
|
|
||||||
typedef void (*uc_mem_unmap_t)(struct uc_struct*, MemoryRegion *mr);
|
typedef void (*uc_mem_unmap_t)(struct uc_struct*, MemoryRegion *mr);
|
||||||
|
|
||||||
typedef void (*uc_readonly_mem_t)(MemoryRegion *mr, bool readonly);
|
typedef void (*uc_readonly_mem_t)(MemoryRegion *mr, bool readonly);
|
||||||
|
@ -97,6 +99,7 @@ struct uc_struct {
|
||||||
uc_args_tcg_enable_t tcg_enabled;
|
uc_args_tcg_enable_t tcg_enabled;
|
||||||
uc_args_uc_long_t tcg_exec_init;
|
uc_args_uc_long_t tcg_exec_init;
|
||||||
uc_args_uc_ram_size_t memory_map;
|
uc_args_uc_ram_size_t memory_map;
|
||||||
|
uc_args_uc_ram_size_ptr_t memory_map_ptr;
|
||||||
uc_mem_unmap_t memory_unmap;
|
uc_mem_unmap_t memory_unmap;
|
||||||
uc_readonly_mem_t readonly_mem;
|
uc_readonly_mem_t readonly_mem;
|
||||||
uc_mem_redirect_t mem_redirect;
|
uc_mem_redirect_t mem_redirect;
|
||||||
|
|
|
@ -446,6 +446,24 @@ typedef enum uc_prot {
|
||||||
UNICORN_EXPORT
|
UNICORN_EXPORT
|
||||||
uc_err uc_mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t perms);
|
uc_err uc_mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t perms);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Map existing host memory in for emulation.
|
||||||
|
This API adds a memory region that can be used by emulation.
|
||||||
|
|
||||||
|
@uc: handle returned by uc_open()
|
||||||
|
@address: starting address of the new memory region to be mapped in.
|
||||||
|
This address must be aligned to 4KB, or this will return with UC_ERR_ARG error.
|
||||||
|
@size: size of the new memory region to be mapped in.
|
||||||
|
This size must be multiple of 4KB, or this will return with UC_ERR_ARG error.
|
||||||
|
@ptr: pointer to host memory backing the newly mapped memory. Existing host
|
||||||
|
memory permissions are preserved.
|
||||||
|
|
||||||
|
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
|
||||||
|
for detailed error).
|
||||||
|
*/
|
||||||
|
UNICORN_EXPORT
|
||||||
|
uc_err uc_mem_map_ptr(uc_engine *uc, uint64_t address, size_t size, void *ptr);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Unmap a region of emulation memory.
|
Unmap a region of emulation memory.
|
||||||
This API deletes a memory mapping from the emulation memory space.
|
This API deletes a memory mapping from the emulation memory space.
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#define phys_mem_clean phys_mem_clean_aarch64
|
#define phys_mem_clean phys_mem_clean_aarch64
|
||||||
#define tb_cleanup tb_cleanup_aarch64
|
#define tb_cleanup tb_cleanup_aarch64
|
||||||
#define memory_map memory_map_aarch64
|
#define memory_map memory_map_aarch64
|
||||||
|
#define memory_map_ptr memory_map_ptr_aarch64
|
||||||
#define memory_unmap memory_unmap_aarch64
|
#define memory_unmap memory_unmap_aarch64
|
||||||
#define memory_free memory_free_aarch64
|
#define memory_free memory_free_aarch64
|
||||||
#define helper_raise_exception helper_raise_exception_aarch64
|
#define helper_raise_exception helper_raise_exception_aarch64
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#define phys_mem_clean phys_mem_clean_arm
|
#define phys_mem_clean phys_mem_clean_arm
|
||||||
#define tb_cleanup tb_cleanup_arm
|
#define tb_cleanup tb_cleanup_arm
|
||||||
#define memory_map memory_map_arm
|
#define memory_map memory_map_arm
|
||||||
|
#define memory_map_ptr memory_map_ptr_arm
|
||||||
#define memory_unmap memory_unmap_arm
|
#define memory_unmap memory_unmap_arm
|
||||||
#define memory_free memory_free_arm
|
#define memory_free memory_free_arm
|
||||||
#define helper_raise_exception helper_raise_exception_arm
|
#define helper_raise_exception helper_raise_exception_arm
|
||||||
|
|
|
@ -14,6 +14,7 @@ symbols = (
|
||||||
'phys_mem_clean',
|
'phys_mem_clean',
|
||||||
'tb_cleanup',
|
'tb_cleanup',
|
||||||
'memory_map',
|
'memory_map',
|
||||||
|
'memory_map_ptr',
|
||||||
'memory_unmap',
|
'memory_unmap',
|
||||||
'memory_free',
|
'memory_free',
|
||||||
'helper_raise_exception',
|
'helper_raise_exception',
|
||||||
|
|
|
@ -939,6 +939,7 @@ void address_space_unmap(AddressSpace *as, void *buffer, hwaddr len,
|
||||||
void memory_register_types(struct uc_struct *uc);
|
void memory_register_types(struct uc_struct *uc);
|
||||||
|
|
||||||
MemoryRegion *memory_map(struct uc_struct *uc, ram_addr_t begin, size_t size, uint32_t perms);
|
MemoryRegion *memory_map(struct uc_struct *uc, ram_addr_t begin, size_t size, uint32_t perms);
|
||||||
|
MemoryRegion *memory_map_ptr(struct uc_struct *uc, ram_addr_t begin, size_t size, void *ptr);
|
||||||
void memory_unmap(struct uc_struct *uc, MemoryRegion *mr);
|
void memory_unmap(struct uc_struct *uc, MemoryRegion *mr);
|
||||||
int memory_free(struct uc_struct *uc);
|
int memory_free(struct uc_struct *uc);
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#define phys_mem_clean phys_mem_clean_m68k
|
#define phys_mem_clean phys_mem_clean_m68k
|
||||||
#define tb_cleanup tb_cleanup_m68k
|
#define tb_cleanup tb_cleanup_m68k
|
||||||
#define memory_map memory_map_m68k
|
#define memory_map memory_map_m68k
|
||||||
|
#define memory_map_ptr memory_map_ptr_m68k
|
||||||
#define memory_unmap memory_unmap_m68k
|
#define memory_unmap memory_unmap_m68k
|
||||||
#define memory_free memory_free_m68k
|
#define memory_free memory_free_m68k
|
||||||
#define helper_raise_exception helper_raise_exception_m68k
|
#define helper_raise_exception helper_raise_exception_m68k
|
||||||
|
|
|
@ -48,6 +48,23 @@ MemoryRegion *memory_map(struct uc_struct *uc, ram_addr_t begin, size_t size, ui
|
||||||
return ram;
|
return ram;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MemoryRegion *memory_map_ptr(struct uc_struct *uc, ram_addr_t begin, size_t size, void *ptr)
|
||||||
|
{
|
||||||
|
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
||||||
|
|
||||||
|
memory_region_init_ram_ptr(uc, ram, NULL, "pc.ram", size, ptr);
|
||||||
|
if (ram->ram_addr == -1)
|
||||||
|
// out of memory
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
memory_region_add_subregion(get_system_memory(uc), begin, ram);
|
||||||
|
|
||||||
|
if (uc->current_cpu)
|
||||||
|
tlb_flush(uc->current_cpu, 1);
|
||||||
|
|
||||||
|
return ram;
|
||||||
|
}
|
||||||
|
|
||||||
void memory_unmap(struct uc_struct *uc, MemoryRegion *mr)
|
void memory_unmap(struct uc_struct *uc, MemoryRegion *mr)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#define phys_mem_clean phys_mem_clean_mips
|
#define phys_mem_clean phys_mem_clean_mips
|
||||||
#define tb_cleanup tb_cleanup_mips
|
#define tb_cleanup tb_cleanup_mips
|
||||||
#define memory_map memory_map_mips
|
#define memory_map memory_map_mips
|
||||||
|
#define memory_map_ptr memory_map_ptr_mips
|
||||||
#define memory_unmap memory_unmap_mips
|
#define memory_unmap memory_unmap_mips
|
||||||
#define memory_free memory_free_mips
|
#define memory_free memory_free_mips
|
||||||
#define helper_raise_exception helper_raise_exception_mips
|
#define helper_raise_exception helper_raise_exception_mips
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#define phys_mem_clean phys_mem_clean_mips64
|
#define phys_mem_clean phys_mem_clean_mips64
|
||||||
#define tb_cleanup tb_cleanup_mips64
|
#define tb_cleanup tb_cleanup_mips64
|
||||||
#define memory_map memory_map_mips64
|
#define memory_map memory_map_mips64
|
||||||
|
#define memory_map_ptr memory_map_ptr_mips64
|
||||||
#define memory_unmap memory_unmap_mips64
|
#define memory_unmap memory_unmap_mips64
|
||||||
#define memory_free memory_free_mips64
|
#define memory_free memory_free_mips64
|
||||||
#define helper_raise_exception helper_raise_exception_mips64
|
#define helper_raise_exception helper_raise_exception_mips64
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#define phys_mem_clean phys_mem_clean_mips64el
|
#define phys_mem_clean phys_mem_clean_mips64el
|
||||||
#define tb_cleanup tb_cleanup_mips64el
|
#define tb_cleanup tb_cleanup_mips64el
|
||||||
#define memory_map memory_map_mips64el
|
#define memory_map memory_map_mips64el
|
||||||
|
#define memory_map_ptr memory_map_ptr_mips64el
|
||||||
#define memory_unmap memory_unmap_mips64el
|
#define memory_unmap memory_unmap_mips64el
|
||||||
#define memory_free memory_free_mips64el
|
#define memory_free memory_free_mips64el
|
||||||
#define helper_raise_exception helper_raise_exception_mips64el
|
#define helper_raise_exception helper_raise_exception_mips64el
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#define phys_mem_clean phys_mem_clean_mipsel
|
#define phys_mem_clean phys_mem_clean_mipsel
|
||||||
#define tb_cleanup tb_cleanup_mipsel
|
#define tb_cleanup tb_cleanup_mipsel
|
||||||
#define memory_map memory_map_mipsel
|
#define memory_map memory_map_mipsel
|
||||||
|
#define memory_map_ptr memory_map_ptr_mipsel
|
||||||
#define memory_unmap memory_unmap_mipsel
|
#define memory_unmap memory_unmap_mipsel
|
||||||
#define memory_free memory_free_mipsel
|
#define memory_free memory_free_mipsel
|
||||||
#define helper_raise_exception helper_raise_exception_mipsel
|
#define helper_raise_exception helper_raise_exception_mipsel
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#define phys_mem_clean phys_mem_clean_sparc
|
#define phys_mem_clean phys_mem_clean_sparc
|
||||||
#define tb_cleanup tb_cleanup_sparc
|
#define tb_cleanup tb_cleanup_sparc
|
||||||
#define memory_map memory_map_sparc
|
#define memory_map memory_map_sparc
|
||||||
|
#define memory_map_ptr memory_map_ptr_sparc
|
||||||
#define memory_unmap memory_unmap_sparc
|
#define memory_unmap memory_unmap_sparc
|
||||||
#define memory_free memory_free_sparc
|
#define memory_free memory_free_sparc
|
||||||
#define helper_raise_exception helper_raise_exception_sparc
|
#define helper_raise_exception helper_raise_exception_sparc
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#define phys_mem_clean phys_mem_clean_sparc64
|
#define phys_mem_clean phys_mem_clean_sparc64
|
||||||
#define tb_cleanup tb_cleanup_sparc64
|
#define tb_cleanup tb_cleanup_sparc64
|
||||||
#define memory_map memory_map_sparc64
|
#define memory_map memory_map_sparc64
|
||||||
|
#define memory_map_ptr memory_map_ptr_sparc64
|
||||||
#define memory_unmap memory_unmap_sparc64
|
#define memory_unmap memory_unmap_sparc64
|
||||||
#define memory_free memory_free_sparc64
|
#define memory_free memory_free_sparc64
|
||||||
#define helper_raise_exception helper_raise_exception_sparc64
|
#define helper_raise_exception helper_raise_exception_sparc64
|
||||||
|
|
|
@ -73,6 +73,7 @@ static inline void uc_common_init(struct uc_struct* uc)
|
||||||
uc->pause_all_vcpus = pause_all_vcpus;
|
uc->pause_all_vcpus = pause_all_vcpus;
|
||||||
uc->vm_start = vm_start;
|
uc->vm_start = vm_start;
|
||||||
uc->memory_map = memory_map;
|
uc->memory_map = memory_map;
|
||||||
|
uc->memory_map_ptr = memory_map_ptr;
|
||||||
uc->memory_unmap = memory_unmap;
|
uc->memory_unmap = memory_unmap;
|
||||||
uc->readonly_mem = memory_region_set_readonly;
|
uc->readonly_mem = memory_region_set_readonly;
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#define phys_mem_clean phys_mem_clean_x86_64
|
#define phys_mem_clean phys_mem_clean_x86_64
|
||||||
#define tb_cleanup tb_cleanup_x86_64
|
#define tb_cleanup tb_cleanup_x86_64
|
||||||
#define memory_map memory_map_x86_64
|
#define memory_map memory_map_x86_64
|
||||||
|
#define memory_map_ptr memory_map_ptr_x86_64
|
||||||
#define memory_unmap memory_unmap_x86_64
|
#define memory_unmap memory_unmap_x86_64
|
||||||
#define memory_free memory_free_x86_64
|
#define memory_free memory_free_x86_64
|
||||||
#define helper_raise_exception helper_raise_exception_x86_64
|
#define helper_raise_exception helper_raise_exception_x86_64
|
||||||
|
|
|
@ -4,7 +4,7 @@ CFLAGS += -L ../../
|
||||||
CFLAGS += -lcmocka -lunicorn
|
CFLAGS += -lcmocka -lunicorn
|
||||||
CFLAGS += -I ../../include
|
CFLAGS += -I ../../include
|
||||||
|
|
||||||
ALL_TESTS = test_sanity test_x86 test_mem_map
|
ALL_TESTS = test_sanity test_x86 test_mem_map test_mem_map_ptr
|
||||||
|
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
all: ${ALL_TESTS}
|
all: ${ALL_TESTS}
|
||||||
|
@ -23,9 +23,7 @@ test: ${ALL_TESTS}
|
||||||
test_sanity: test_sanity.c
|
test_sanity: test_sanity.c
|
||||||
test_x86: test_x86.c
|
test_x86: test_x86.c
|
||||||
test_mem_map: test_mem_map.c
|
test_mem_map: test_mem_map.c
|
||||||
|
test_mem_map_ptr: test_mem_map_ptr.c
|
||||||
|
|
||||||
${ALL_TESTS}:
|
${ALL_TESTS}:
|
||||||
gcc ${CFLAGS} -o $@ $^
|
gcc ${CFLAGS} -o $@ $^
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
75
tests/unit/test_mem_map_ptr.c
Normal file
75
tests/unit/test_mem_map_ptr.c
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
/**
|
||||||
|
* Unicorn memory API tests
|
||||||
|
*
|
||||||
|
* This tests manual pointer-backed memory.
|
||||||
|
*/
|
||||||
|
#include "unicorn_test.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/* Called before every test to set up a new instance */
|
||||||
|
static int setup(void **state)
|
||||||
|
{
|
||||||
|
uc_engine *uc;
|
||||||
|
|
||||||
|
uc_assert_success(uc_open(UC_ARCH_X86, UC_MODE_32, &uc));
|
||||||
|
|
||||||
|
*state = uc;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Called after every test to clean up */
|
||||||
|
static int teardown(void **state)
|
||||||
|
{
|
||||||
|
uc_engine *uc = *state;
|
||||||
|
|
||||||
|
uc_assert_success(uc_close(uc));
|
||||||
|
|
||||||
|
*state = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A basic test showing mapping of memory, and reading/writing it
|
||||||
|
*/
|
||||||
|
static void test_basic(void **state)
|
||||||
|
{
|
||||||
|
uc_engine *uc = *state;
|
||||||
|
const uint64_t mem_start = 0x1000;
|
||||||
|
const uint64_t mem_len = 0x1000;
|
||||||
|
const uint64_t test_addr = mem_start;
|
||||||
|
|
||||||
|
void *host_mem = calloc(1, mem_len);
|
||||||
|
|
||||||
|
/* Map a region */
|
||||||
|
uc_assert_success(uc_mem_map_ptr(uc, mem_start, mem_len, host_mem));
|
||||||
|
|
||||||
|
/* Write some data to it */
|
||||||
|
uc_assert_success(uc_mem_write(uc, test_addr, "test", 4));
|
||||||
|
|
||||||
|
uint8_t buf[4];
|
||||||
|
memset(buf, 0xCC, sizeof(buf));
|
||||||
|
|
||||||
|
/* Read it back */
|
||||||
|
uc_assert_success(uc_mem_read(uc, test_addr, buf, sizeof(buf)));
|
||||||
|
|
||||||
|
/* And make sure it matches what we expect */
|
||||||
|
assert_memory_equal(buf, "test", 4);
|
||||||
|
|
||||||
|
/* Unmap the region */
|
||||||
|
uc_assert_success(uc_mem_unmap(uc, mem_start, mem_len));
|
||||||
|
|
||||||
|
assert_memory_equal(buf, host_mem, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
#define test(x) cmocka_unit_test_setup_teardown(x, setup, teardown)
|
||||||
|
const struct CMUnitTest tests[] = {
|
||||||
|
test(test_basic),
|
||||||
|
};
|
||||||
|
#undef test
|
||||||
|
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||||
|
}
|
35
uc.c
35
uc.c
|
@ -570,8 +570,8 @@ static uc_err _hook_mem_access(uc_engine *uc, uc_hook_type type,
|
||||||
return UC_ERR_OK;
|
return UC_ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
UNICORN_EXPORT
|
// common setup/error checking shared between uc_mem_map and uc_mem_map_ptr
|
||||||
uc_err uc_mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t perms)
|
static uc_err mem_map_start(uc_engine *uc, uint64_t address, size_t size, uint32_t perms)
|
||||||
{
|
{
|
||||||
MemoryRegion **regions;
|
MemoryRegion **regions;
|
||||||
|
|
||||||
|
@ -600,7 +600,13 @@ uc_err uc_mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t perms)
|
||||||
uc->mapped_blocks = regions;
|
uc->mapped_blocks = regions;
|
||||||
}
|
}
|
||||||
|
|
||||||
uc->mapped_blocks[uc->mapped_block_count] = uc->memory_map(uc, address, size, perms);
|
return UC_ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// common final step shared by uc_mem_map and uc_mem_map_ptr
|
||||||
|
static uc_err mem_map_finish(uc_engine *uc, MemoryRegion *block)
|
||||||
|
{
|
||||||
|
uc->mapped_blocks[uc->mapped_block_count] = block;
|
||||||
if (uc->mapped_blocks[uc->mapped_block_count] == NULL)
|
if (uc->mapped_blocks[uc->mapped_block_count] == NULL)
|
||||||
return UC_ERR_NOMEM;
|
return UC_ERR_NOMEM;
|
||||||
|
|
||||||
|
@ -609,6 +615,29 @@ uc_err uc_mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t perms)
|
||||||
return UC_ERR_OK;
|
return UC_ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UNICORN_EXPORT
|
||||||
|
uc_err uc_mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t perms)
|
||||||
|
{
|
||||||
|
uc_err err;
|
||||||
|
if ((err = mem_map_start(uc, address, size, perms)) != UC_ERR_OK)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
return mem_map_finish(uc, uc->memory_map(uc, address, size, perms));
|
||||||
|
}
|
||||||
|
|
||||||
|
UNICORN_EXPORT
|
||||||
|
uc_err uc_mem_map_ptr(uc_engine *uc, uint64_t address, size_t size, void *ptr)
|
||||||
|
{
|
||||||
|
if (ptr == NULL)
|
||||||
|
return UC_ERR_ARG;
|
||||||
|
|
||||||
|
uc_err err;
|
||||||
|
if ((err = mem_map_start(uc, address, size, UC_PROT_ALL)) != UC_ERR_OK)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
return mem_map_finish(uc, uc->memory_map_ptr(uc, address, size, ptr));
|
||||||
|
}
|
||||||
|
|
||||||
// Create a backup copy of the indicated MemoryRegion.
|
// Create a backup copy of the indicated MemoryRegion.
|
||||||
// Generally used in prepartion for splitting a MemoryRegion.
|
// Generally used in prepartion for splitting a MemoryRegion.
|
||||||
static uint8_t *copy_region(struct uc_struct *uc, MemoryRegion *mr)
|
static uint8_t *copy_region(struct uc_struct *uc, MemoryRegion *mr)
|
||||||
|
|
Loading…
Reference in a new issue