Fix mmio unmap

This commit is contained in:
lazymio 2021-11-24 00:18:19 +01:00
parent 4ed1c4cff9
commit 78e0ddbc4d
No known key found for this signature in database
GPG Key ID: DFF27E34A47CB873
4 changed files with 122 additions and 11 deletions

View File

@ -46,6 +46,15 @@
struct TranslationBlock;
// Place the struct here since we need it in uc.c
typedef struct _mmio_cbs {
uc_cb_mmio_read_t read;
void *user_data_read;
uc_cb_mmio_write_t write;
void *user_data_write;
MemoryRegionOps ops;
} mmio_cbs;
typedef uc_err (*query_t)(struct uc_struct *uc, uc_query_type type,
size_t *result);

View File

@ -77,14 +77,6 @@ MemoryRegion *memory_map_ptr(struct uc_struct *uc, hwaddr begin, size_t size, ui
return ram;
}
typedef struct _mmio_cbs {
uc_cb_mmio_read_t read;
void *user_data_read;
uc_cb_mmio_write_t write;
void *user_data_write;
MemoryRegionOps ops;
} mmio_cbs;
static uint64_t mmio_read_wrapper(struct uc_struct *uc, void *opaque, hwaddr addr, unsigned size)
{
mmio_cbs* cbs = (mmio_cbs*)opaque;

View File

@ -74,15 +74,46 @@ static void test_splitting_mem_unmap()
OK(uc_close(uc));
}
static uint64_t test_splitting_mmio_unmap_read_callback(uc_engine *uc,
uint64_t offset,
unsigned size,
void *user_data)
{
TEST_CHECK(offset == 4);
TEST_CHECK(size == 4);
return 0x19260817;
}
static void test_splitting_mmio_unmap()
{
uc_engine *uc;
// mov ecx, [0x3004] <-- normal read
// mov ebx, [0x4004] <-- mmio read
char code[] = "\x8b\x0d\x04\x30\x00\x00\x8b\x1d\x04\x40\x00\x00";
int r_ecx, r_ebx;
int bytes = 0xdeadbeef;
OK(uc_open(UC_ARCH_X86, UC_MODE_32, &uc));
OK(uc_mmio_map(uc, 0x3000, 0x2000, NULL, NULL, NULL, NULL));
OK(uc_mem_map(uc, 0x1000, 0x1000, UC_PROT_ALL));
OK(uc_mem_write(uc, 0x1000, code, sizeof(code) - 1));
OK(uc_mmio_map(uc, 0x3000, 0x2000, test_splitting_mmio_unmap_read_callback,
NULL, NULL, NULL));
// Map a ram area instead
OK(uc_mem_unmap(uc, 0x3000, 0x1000));
OK(uc_mem_map(uc, 0x3000, 0x1000, UC_PROT_ALL));
OK(uc_mem_write(uc, 0x3004, &bytes, 4));
OK(uc_emu_start(uc, 0x1000, 0x1000 + sizeof(code) - 1, 0, 0));
OK(uc_reg_read(uc, UC_X86_REG_ECX, &r_ecx));
OK(uc_reg_read(uc, UC_X86_REG_EBX, &r_ebx));
TEST_CHECK(r_ecx == 0xdeadbeef);
TEST_CHECK(r_ebx == 0x19260817);
OK(uc_close(uc));
}

83
uc.c
View File

@ -1045,6 +1045,79 @@ static uint8_t *copy_region(struct uc_struct *uc, MemoryRegion *mr)
return block;
}
/*
This function is similar to split_region, but for MMIO memory.
This function would delete the region unconditionally.
Note this function may be called recursively.
*/
static bool split_mmio_region(struct uc_struct *uc, MemoryRegion *mr,
uint64_t address, size_t size)
{
uint64_t begin, end, chunk_end;
size_t l_size, r_size;
mmio_cbs backup;
chunk_end = address + size;
// This branch also break recursion.
if (address <= mr->addr && chunk_end >= mr->end) {
return true;
}
if (size == 0) {
return false;
}
begin = mr->addr;
end = mr->end;
memcpy(&backup, mr->opaque, sizeof(mmio_cbs));
/* overlapping cases
* |------mr------|
* case 1 |---size--| // Is it possible???
* case 2 |--size--|
* case 3 |---size--|
*/
// unmap this region first, then do split it later
if (uc_mem_unmap(uc, mr->addr, (size_t)int128_get64(mr->size)) !=
UC_ERR_OK) {
return false;
}
// adjust some things
if (address < begin) {
address = begin;
}
if (chunk_end > end) {
chunk_end = end;
}
// compute sub region sizes
l_size = (size_t)(address - begin);
r_size = (size_t)(end - chunk_end);
if (l_size > 0) {
if (uc_mmio_map(uc, begin, l_size, backup.read, backup.user_data_read,
backup.write, backup.user_data_write) != UC_ERR_OK) {
return false;
}
}
if (r_size > 0) {
if (uc_mmio_map(uc, chunk_end, r_size, backup.read,
backup.user_data_read, backup.write,
backup.user_data_write) != UC_ERR_OK) {
return false;
}
}
return true;
}
/*
Split the given MemoryRegion at the indicated address for the indicated size
this may result in the create of up to 3 spanning sections. If the delete
@ -1325,8 +1398,14 @@ uc_err uc_mem_unmap(struct uc_struct *uc, uint64_t address, size_t size)
while (count < size) {
mr = memory_mapping(uc, addr);
len = (size_t)MIN(size - count, mr->end - addr);
if (!split_region(uc, mr, addr, len, true)) {
return UC_ERR_NOMEM;
if (!mr->ram) {
if (!split_mmio_region(uc, mr, addr, len)) {
return UC_ERR_NOMEM;
}
} else {
if (!split_region(uc, mr, addr, len, true)) {
return UC_ERR_NOMEM;
}
}
// if we can retrieve the mapping, then no splitting took place