implement uc_mem_unmap with snapshots
still has todos and need tests
This commit is contained in:
parent
716c8f1c4c
commit
df18756234
@ -289,6 +289,8 @@ struct uc_struct {
|
||||
uc_memory_mapping_t memory_mapping;
|
||||
uc_memory_filter_t memory_filter_subregions;
|
||||
uc_mem_unmap_t memory_unmap;
|
||||
uc_mem_unmap_t memory_moveout;
|
||||
uc_mem_unmap_t memory_movein;
|
||||
uc_readonly_mem_t readonly_mem;
|
||||
uc_cpus_init cpus_init;
|
||||
uc_target_page_init target_page;
|
||||
@ -412,6 +414,7 @@ struct uc_struct {
|
||||
PVOID seh_handle;
|
||||
void *seh_closure;
|
||||
#endif
|
||||
GArray *unmapped_regions;
|
||||
int32_t snapshot_level;
|
||||
};
|
||||
|
||||
|
@ -125,6 +125,8 @@
|
||||
#define memory_map_ptr memory_map_ptr_aarch64
|
||||
#define memory_cow memory_cow_aarch64
|
||||
#define memory_unmap memory_unmap_aarch64
|
||||
#define memory_moveout memory_moveout_aarch64
|
||||
#define memory_movein memory_movein_aarch64
|
||||
#define memory_free memory_free_aarch64
|
||||
#define flatview_unref flatview_unref_aarch64
|
||||
#define address_space_get_flatview address_space_get_flatview_aarch64
|
||||
|
@ -125,6 +125,8 @@
|
||||
#define memory_map_ptr memory_map_ptr_arm
|
||||
#define memory_cow memory_cow_arm
|
||||
#define memory_unmap memory_unmap_arm
|
||||
#define memory_moveout memory_moveout_arm
|
||||
#define memory_movein memory_movein_arm
|
||||
#define memory_free memory_free_arm
|
||||
#define flatview_unref flatview_unref_arm
|
||||
#define address_space_get_flatview address_space_get_flatview_arm
|
||||
|
@ -1217,6 +1217,8 @@ MemoryRegion *memory_map_ptr(struct uc_struct *uc, hwaddr begin, size_t size, ui
|
||||
uc_cb_mmio_write_t write_cb, void *user_data_read, void *user_data_write);
|
||||
MemoryRegion *memory_cow(struct uc_struct *uc, MemoryRegion *parrent, hwaddr begin, size_t size);
|
||||
void memory_unmap(struct uc_struct *uc, MemoryRegion *mr);
|
||||
void memory_moveout(struct uc_struct *uc, MemoryRegion *mr);
|
||||
void memory_movein(struct uc_struct *uc, MemoryRegion *mr);
|
||||
int memory_free(struct uc_struct *uc);
|
||||
|
||||
#endif
|
||||
|
@ -125,6 +125,8 @@
|
||||
#define memory_map_ptr memory_map_ptr_m68k
|
||||
#define memory_cow memory_cow_m68k
|
||||
#define memory_unmap memory_unmap_m68k
|
||||
#define memory_moveout memory_moveout_m68k
|
||||
#define memory_movein memory_movein_m68k
|
||||
#define memory_free memory_free_m68k
|
||||
#define flatview_unref flatview_unref_m68k
|
||||
#define address_space_get_flatview address_space_get_flatview_m68k
|
||||
|
@ -125,6 +125,8 @@
|
||||
#define memory_map_ptr memory_map_ptr_mips
|
||||
#define memory_cow memory_cow_mips
|
||||
#define memory_unmap memory_unmap_mips
|
||||
#define memory_moveout memory_moveout_mips
|
||||
#define memory_movein memory_movein_mips
|
||||
#define memory_free memory_free_mips
|
||||
#define flatview_unref flatview_unref_mips
|
||||
#define address_space_get_flatview address_space_get_flatview_mips
|
||||
|
@ -125,6 +125,8 @@
|
||||
#define memory_map_ptr memory_map_ptr_mips64
|
||||
#define memory_cow memory_cow_mips64
|
||||
#define memory_unmap memory_unmap_mips64
|
||||
#define memory_moveout memory_moveout_mips64
|
||||
#define memory_movein memory_movein_mips64
|
||||
#define memory_free memory_free_mips64
|
||||
#define flatview_unref flatview_unref_mips64
|
||||
#define address_space_get_flatview address_space_get_flatview_mips64
|
||||
|
@ -125,6 +125,8 @@
|
||||
#define memory_map_ptr memory_map_ptr_mips64el
|
||||
#define memory_cow memory_cow_mips64el
|
||||
#define memory_unmap memory_unmap_mips64el
|
||||
#define memory_moveout memory_moveout_mips64el
|
||||
#define memory_movein memory_movein_mips64el
|
||||
#define memory_free memory_free_mips64el
|
||||
#define flatview_unref flatview_unref_mips64el
|
||||
#define address_space_get_flatview address_space_get_flatview_mips64el
|
||||
|
@ -125,6 +125,8 @@
|
||||
#define memory_map_ptr memory_map_ptr_mipsel
|
||||
#define memory_cow memory_cow_mipsel
|
||||
#define memory_unmap memory_unmap_mipsel
|
||||
#define memory_moveout memory_moveout_mipsel
|
||||
#define memory_movein memory_movein_mipsel
|
||||
#define memory_free memory_free_mipsel
|
||||
#define flatview_unref flatview_unref_mipsel
|
||||
#define address_space_get_flatview address_space_get_flatview_mipsel
|
||||
|
@ -125,6 +125,8 @@
|
||||
#define memory_map_ptr memory_map_ptr_ppc
|
||||
#define memory_cow memory_cow_ppc
|
||||
#define memory_unmap memory_unmap_ppc
|
||||
#define memory_moveout memory_moveout_ppc
|
||||
#define memory_movein memory_movein_ppc
|
||||
#define memory_free memory_free_ppc
|
||||
#define flatview_unref flatview_unref_ppc
|
||||
#define address_space_get_flatview address_space_get_flatview_ppc
|
||||
|
@ -125,6 +125,8 @@
|
||||
#define memory_map_ptr memory_map_ptr_ppc64
|
||||
#define memory_cow memory_cow_ppc64
|
||||
#define memory_unmap memory_unmap_ppc64
|
||||
#define memory_moveout memory_moveout_ppc64
|
||||
#define memory_movein memory_movein_ppc64
|
||||
#define memory_free memory_free_ppc64
|
||||
#define flatview_unref flatview_unref_ppc64
|
||||
#define address_space_get_flatview address_space_get_flatview_ppc64
|
||||
|
@ -125,6 +125,8 @@
|
||||
#define memory_map_ptr memory_map_ptr_riscv32
|
||||
#define memory_cow memory_cow_riscv32
|
||||
#define memory_unmap memory_unmap_riscv32
|
||||
#define memory_moveout memory_moveout_riscv32
|
||||
#define memory_movein memory_movein_riscv32
|
||||
#define memory_free memory_free_riscv32
|
||||
#define flatview_unref flatview_unref_riscv32
|
||||
#define address_space_get_flatview address_space_get_flatview_riscv32
|
||||
|
@ -125,6 +125,8 @@
|
||||
#define memory_map_ptr memory_map_ptr_riscv64
|
||||
#define memory_cow memory_cow_riscv64
|
||||
#define memory_unmap memory_unmap_riscv64
|
||||
#define memory_moveout memory_moveout_riscv64
|
||||
#define memory_movein memory_movein_riscv64
|
||||
#define memory_free memory_free_riscv64
|
||||
#define flatview_unref flatview_unref_riscv64
|
||||
#define address_space_get_flatview address_space_get_flatview_riscv64
|
||||
|
@ -125,6 +125,8 @@
|
||||
#define memory_map_ptr memory_map_ptr_s390x
|
||||
#define memory_cow memory_cow_s390x
|
||||
#define memory_unmap memory_unmap_s390x
|
||||
#define memory_moveout memory_moveout_s390x
|
||||
#define memory_movein memory_movein_s390x
|
||||
#define memory_free memory_free_s390x
|
||||
#define flatview_unref flatview_unref_s390x
|
||||
#define address_space_get_flatview address_space_get_flatview_s390x
|
||||
|
@ -208,9 +208,69 @@ void memory_region_filter_subregions(MemoryRegion *mr, int32_t level)
|
||||
memory_region_transaction_commit(mr);
|
||||
}
|
||||
|
||||
static void memory_region_remove_mapped_block(struct uc_struct *uc, MemoryRegion *mr, bool free)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < uc->mapped_block_count; i++) {
|
||||
if (uc->mapped_blocks[i] == mr) {
|
||||
uc->mapped_block_count--;
|
||||
//shift remainder of array down over deleted pointer
|
||||
memmove(&uc->mapped_blocks[i], &uc->mapped_blocks[i + 1], sizeof(MemoryRegion*) * (uc->mapped_block_count - i));
|
||||
if (free) {
|
||||
mr->destructor(mr);
|
||||
g_free(mr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void memory_moveout(struct uc_struct *uc, MemoryRegion *mr)
|
||||
{
|
||||
hwaddr addr;
|
||||
/* A bit dirty, but it works.
|
||||
* The first subregion will be the one with the smalest priority.
|
||||
* In case of CoW this will always be the region which is mapped initial and later be moved in the subregion of the container.
|
||||
* The initial subregion is the one stored in mapped_blocks
|
||||
* Because CoW is done after the snapshot level is increased there is only on subregion with
|
||||
*/
|
||||
memory_region_transaction_begin();
|
||||
MemoryRegion *mr_block = QTAILQ_FIRST(&mr->subregions);
|
||||
|
||||
if (!mr_block) {
|
||||
mr_block = mr;
|
||||
}
|
||||
|
||||
if (uc->cpu) {
|
||||
// We also need to remove all tb cache
|
||||
uc->uc_invalidate_tb(uc, mr->addr, int128_get64(mr->size));
|
||||
|
||||
// Make sure all pages associated with the MemoryRegion are flushed
|
||||
// Only need to do this if we are in a running state
|
||||
for (addr = mr->addr; (int64_t)(mr->end - addr) > 0; addr += uc->target_page_size) {
|
||||
tlb_flush_page(uc->cpu, addr);
|
||||
}
|
||||
}
|
||||
|
||||
memory_region_del_subregion(uc->system_memory, mr);
|
||||
g_array_append_val(uc->unmapped_regions, mr);
|
||||
memory_region_remove_mapped_block(uc, mr_block, false);
|
||||
uc->memory_region_update_pending = true;
|
||||
memory_region_transaction_commit(uc->system_memory);
|
||||
/* dirty hack to save the snapshot level */
|
||||
mr->container = (void *)(intptr_t)uc->snapshot_level;
|
||||
}
|
||||
|
||||
void memory_movein(struct uc_struct *uc, MemoryRegion *mr)
|
||||
{
|
||||
memory_region_transaction_begin();
|
||||
memory_region_add_subregion_overlap(uc->system_memory, mr->addr, mr, mr->priority);
|
||||
uc->memory_region_update_pending = true;
|
||||
memory_region_transaction_commit(uc->system_memory);
|
||||
}
|
||||
|
||||
void memory_unmap(struct uc_struct *uc, MemoryRegion *mr)
|
||||
{
|
||||
int i;
|
||||
hwaddr addr;
|
||||
|
||||
if (uc->cpu) {
|
||||
@ -224,17 +284,7 @@ void memory_unmap(struct uc_struct *uc, MemoryRegion *mr)
|
||||
}
|
||||
}
|
||||
memory_region_del_subregion(uc->system_memory, mr);
|
||||
|
||||
for (i = 0; i < uc->mapped_block_count; i++) {
|
||||
if (uc->mapped_blocks[i] == mr) {
|
||||
uc->mapped_block_count--;
|
||||
//shift remainder of array down over deleted pointer
|
||||
memmove(&uc->mapped_blocks[i], &uc->mapped_blocks[i + 1], sizeof(MemoryRegion*) * (uc->mapped_block_count - i));
|
||||
mr->destructor(mr);
|
||||
g_free(mr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
memory_region_remove_mapped_block(uc, mr, true);
|
||||
}
|
||||
|
||||
int memory_free(struct uc_struct *uc)
|
||||
|
@ -125,6 +125,8 @@
|
||||
#define memory_map_ptr memory_map_ptr_sparc
|
||||
#define memory_cow memory_cow_sparc
|
||||
#define memory_unmap memory_unmap_sparc
|
||||
#define memory_moveout memory_moveout_sparc
|
||||
#define memory_movein memory_movein_sparc
|
||||
#define memory_free memory_free_sparc
|
||||
#define flatview_unref flatview_unref_sparc
|
||||
#define address_space_get_flatview address_space_get_flatview_sparc
|
||||
|
@ -125,6 +125,8 @@
|
||||
#define memory_map_ptr memory_map_ptr_sparc64
|
||||
#define memory_cow memory_cow_sparc64
|
||||
#define memory_unmap memory_unmap_sparc64
|
||||
#define memory_moveout memory_moveout_sparc64
|
||||
#define memory_movein memory_movein_sparc64
|
||||
#define memory_free memory_free_sparc64
|
||||
#define flatview_unref flatview_unref_sparc64
|
||||
#define address_space_get_flatview address_space_get_flatview_sparc64
|
||||
|
@ -125,6 +125,8 @@
|
||||
#define memory_map_ptr memory_map_ptr_tricore
|
||||
#define memory_cow memory_cow_tricore
|
||||
#define memory_unmap memory_unmap_tricore
|
||||
#define memory_moveout memory_moveout_tricore
|
||||
#define memory_movein memory_movein_tricore
|
||||
#define memory_free memory_free_tricore
|
||||
#define flatview_unref flatview_unref_tricore
|
||||
#define address_space_get_flatview address_space_get_flatview_tricore
|
||||
|
@ -130,6 +130,8 @@ static inline void uc_common_init(struct uc_struct* uc)
|
||||
uc->memory_map = memory_map;
|
||||
uc->memory_map_ptr = memory_map_ptr;
|
||||
uc->memory_unmap = memory_unmap;
|
||||
uc->memory_moveout = memory_moveout;
|
||||
uc->memory_movein = memory_movein;
|
||||
uc->readonly_mem = memory_region_set_readonly;
|
||||
uc->target_page = target_page_init;
|
||||
uc->softfloat_initialize = softfloat_init;
|
||||
|
@ -125,6 +125,8 @@
|
||||
#define memory_map_ptr memory_map_ptr_x86_64
|
||||
#define memory_cow memory_cow_x86_64
|
||||
#define memory_unmap memory_unmap_x86_64
|
||||
#define memory_moveout memory_moveout_x86_64
|
||||
#define memory_movein memory_movein_x86_64
|
||||
#define memory_free memory_free_x86_64
|
||||
#define flatview_unref flatview_unref_x86_64
|
||||
#define address_space_get_flatview address_space_get_flatview_x86_64
|
||||
|
@ -125,6 +125,8 @@ memory_map_io \
|
||||
memory_map_ptr \
|
||||
memory_cow \
|
||||
memory_unmap \
|
||||
memory_moveout \
|
||||
memory_movein \
|
||||
memory_free \
|
||||
flatview_unref \
|
||||
address_space_get_flatview \
|
||||
|
@ -346,6 +346,39 @@ static void test_context_snapshot(void)
|
||||
OK(uc_close(uc));
|
||||
}
|
||||
|
||||
static void test_snapshot_unmap(void)
|
||||
{
|
||||
uc_engine *uc;
|
||||
uc_context *ctx;
|
||||
uint64_t tmp;
|
||||
|
||||
OK(uc_open(UC_ARCH_X86, UC_MODE_64, &uc));
|
||||
OK(uc_ctl_context_mode(uc, UC_CTL_CONTEXT_MEMORY|UC_CTL_CONTEXT_CPU));
|
||||
OK(uc_mem_map(uc, 0x1000, 0x2000, UC_PROT_ALL));
|
||||
|
||||
tmp = 1;
|
||||
OK(uc_mem_write(uc, 0x1000, &tmp, sizeof(tmp)));
|
||||
tmp = 2;
|
||||
OK(uc_mem_write(uc, 0x2000, &tmp, sizeof(tmp)));
|
||||
|
||||
OK(uc_context_alloc(uc, &ctx));
|
||||
OK(uc_context_save(uc, ctx));
|
||||
|
||||
uc_assert_err(UC_ERR_ARG, uc_mem_unmap(uc, 0x1000, 0x1000));
|
||||
OK(uc_mem_unmap(uc, 0x1000, 0x2000));
|
||||
uc_assert_err(UC_ERR_READ_UNMAPPED, uc_mem_read(uc, 0x1000, &tmp, sizeof(tmp)));
|
||||
uc_assert_err(UC_ERR_READ_UNMAPPED, uc_mem_read(uc, 0x2000, &tmp, sizeof(tmp)));
|
||||
|
||||
OK(uc_context_restore(uc, ctx));
|
||||
OK(uc_mem_read(uc, 0x1000, &tmp, sizeof(tmp)));
|
||||
TEST_CHECK(tmp == 1);
|
||||
OK(uc_mem_read(uc, 0x2000, &tmp, sizeof(tmp)));
|
||||
TEST_CHECK(tmp == 2);
|
||||
|
||||
OK(uc_context_free(ctx));
|
||||
OK(uc_close(uc));
|
||||
}
|
||||
|
||||
TEST_LIST = {{"test_map_correct", test_map_correct},
|
||||
{"test_map_wrapping", test_map_wrapping},
|
||||
{"test_mem_protect", test_mem_protect},
|
||||
@ -359,4 +392,5 @@ TEST_LIST = {{"test_map_correct", test_map_correct},
|
||||
{"test_mem_protect_mmio", test_mem_protect_mmio},
|
||||
{"test_snapshot", test_snapshot},
|
||||
{"test_context_snapshot", test_context_snapshot},
|
||||
{"test_snapshot_unmap", test_snapshot_unmap},
|
||||
{NULL, NULL}};
|
||||
|
70
uc.c
70
uc.c
@ -260,6 +260,8 @@ static uc_err uc_init_engine(uc_engine *uc)
|
||||
|
||||
uc->context_content = UC_CTL_CONTEXT_CPU;
|
||||
|
||||
uc->unmapped_regions = g_array_new(false, false, sizeof(MemoryRegion*));
|
||||
|
||||
uc->init_done = true;
|
||||
|
||||
return UC_ERR_OK;
|
||||
@ -490,6 +492,12 @@ uc_err uc_close(uc_engine *uc)
|
||||
mr->destructor(mr);
|
||||
g_free(uc->system_memory);
|
||||
g_free(uc->system_io);
|
||||
for (size_t i = 0; i < uc->unmapped_regions->len; i++) {
|
||||
mr = g_array_index(uc->unmapped_regions, MemoryRegion *, i);
|
||||
mr->destructor(mr);
|
||||
g_free(mr);
|
||||
}
|
||||
g_array_free(uc->unmapped_regions, true);
|
||||
|
||||
// Thread relateds.
|
||||
if (uc->qemu_thread_data) {
|
||||
@ -1579,6 +1587,29 @@ uc_err uc_mem_protect(struct uc_struct *uc, uint64_t address, size_t size,
|
||||
return UC_ERR_OK;
|
||||
}
|
||||
|
||||
static
|
||||
uc_err uc_mem_unmap_snapshot(struct uc_struct *uc, uint64_t address, size_t size, MemoryRegion **ret)
|
||||
{
|
||||
MemoryRegion *mr;
|
||||
|
||||
mr = uc->memory_mapping(uc, address);
|
||||
while (mr->container != uc->system_memory) {
|
||||
mr = mr->container;
|
||||
}
|
||||
|
||||
if (mr->addr != address || int128_get64(mr->size) != size) {
|
||||
return UC_ERR_ARG;
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
*ret = mr;
|
||||
}
|
||||
|
||||
uc->memory_moveout(uc, mr);
|
||||
|
||||
return UC_ERR_OK;
|
||||
}
|
||||
|
||||
UNICORN_EXPORT
|
||||
uc_err uc_mem_unmap(struct uc_struct *uc, uint64_t address, size_t size)
|
||||
{
|
||||
@ -1588,11 +1619,6 @@ uc_err uc_mem_unmap(struct uc_struct *uc, uint64_t address, size_t size)
|
||||
|
||||
UC_INIT(uc);
|
||||
|
||||
// snapshot and unmapping can't be mixed
|
||||
if (uc->snapshot_level > 0) {
|
||||
return UC_ERR_ARG;
|
||||
}
|
||||
|
||||
if (size == 0) {
|
||||
// nothing to unmap
|
||||
return UC_ERR_OK;
|
||||
@ -1609,11 +1635,14 @@ uc_err uc_mem_unmap(struct uc_struct *uc, uint64_t address, size_t size)
|
||||
}
|
||||
|
||||
// check that user's entire requested block is mapped
|
||||
// TODO check for cow
|
||||
if (!check_mem_area(uc, address, size)) {
|
||||
return UC_ERR_NOMEM;
|
||||
}
|
||||
|
||||
if (uc->snapshot_level > 0) {
|
||||
return uc_mem_unmap_snapshot(uc, address, size, NULL);
|
||||
}
|
||||
|
||||
// Now we know entire region is mapped, so do the unmap
|
||||
// We may need to split regions if this area spans adjacent regions
|
||||
addr = address;
|
||||
@ -2652,7 +2681,8 @@ static uc_err uc_snapshot(struct uc_struct *uc)
|
||||
|
||||
static uc_err uc_restore_latest_snapshot(struct uc_struct *uc)
|
||||
{
|
||||
MemoryRegion *subregion, *subregion_next;
|
||||
MemoryRegion *subregion, *subregion_next, *mr, *initial_mr;
|
||||
int level;
|
||||
|
||||
QTAILQ_FOREACH_SAFE(subregion, &uc->system_memory->subregions, subregions_link, subregion_next) {
|
||||
uc->memory_filter_subregions(subregion, uc->snapshot_level);
|
||||
@ -2660,6 +2690,32 @@ static uc_err uc_restore_latest_snapshot(struct uc_struct *uc)
|
||||
uc->memory_unmap(uc, subregion);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = uc->unmapped_regions->len; i-- > 0;) {
|
||||
mr = g_array_index(uc->unmapped_regions, MemoryRegion *, i);
|
||||
// same dirty hack as in memory_moveout see qemu/softmmu/memory.c
|
||||
initial_mr = QTAILQ_FIRST(&mr->subregions);
|
||||
if (!initial_mr) {
|
||||
initial_mr = mr;
|
||||
}
|
||||
/* same dirty hack as in memory_moveout see qemu/softmmu/memory.c */
|
||||
level = (intptr_t)mr->container;
|
||||
mr->container = NULL;
|
||||
|
||||
if (level < uc->snapshot_level) {
|
||||
break;
|
||||
}
|
||||
if (memory_overlap(uc, mr->addr, int128_get64(mr->size))) {
|
||||
return UC_ERR_MAP;
|
||||
}
|
||||
uc->memory_movein(uc, mr);
|
||||
uc->memory_filter_subregions(mr, uc->snapshot_level);
|
||||
if (initial_mr != mr && QTAILQ_EMPTY(&mr->subregions)) {
|
||||
uc->memory_unmap(uc, subregion);
|
||||
}
|
||||
mem_map(uc, initial_mr);
|
||||
g_array_remove_range(uc->unmapped_regions, i, 1);
|
||||
}
|
||||
uc->snapshot_level--;
|
||||
return UC_ERR_OK;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user