Skip to content

Commit 6461b19

Browse files
committed
add uc_virtuall_to_physical
this allows to lookup the mmu state of uc
1 parent 10a8f2b commit 6461b19

24 files changed

+189
-0
lines changed

include/uc_priv.h

+4
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ typedef bool (*uc_read_mem_t)(AddressSpace *as, hwaddr addr, uint8_t *buf,
8383
typedef bool (*uc_read_mem_virtual_t)(struct uc_struct *uc, vaddr addr,
8484
uint32_t prot, uint8_t *buf, int len);
8585

86+
typedef bool (*uc_virtual_to_physical_t)(struct uc_struct *uc, vaddr addr,
87+
uint32_t prot, uint64_t *res);
88+
8689
typedef MemoryRegion *(*uc_mem_cow_t)(struct uc_struct *uc,
8790
MemoryRegion *current, hwaddr begin,
8891
size_t size);
@@ -280,6 +283,7 @@ struct uc_struct {
280283
uc_write_mem_t write_mem;
281284
uc_read_mem_t read_mem;
282285
uc_read_mem_virtual_t read_mem_virtual;
286+
uc_virtual_to_physical_t virtual_to_physical;
283287
uc_mem_cow_t memory_cow;
284288
uc_args_void_t release; // release resource when uc_close()
285289
uc_args_uc_u64_t set_pc; // set PC for tracecode

include/unicorn/unicorn.h

+15
Original file line numberDiff line numberDiff line change
@@ -954,6 +954,21 @@ UNICORN_EXPORT
954954
uc_err uc_mem_read_virtual(uc_engine *uc, uint64_t address, uint32_t prot,
955955
void *bytes, size_t size);
956956

957+
/*
958+
Translate a virtuall address to a physical address
959+
960+
@uc:
961+
@address: virtual address to translate
962+
@prot: The access type for the tlb lookup
963+
@paddress: A pointer to store the result
964+
965+
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
966+
for detailed error).
967+
*/
968+
UNICORN_EXPORT
969+
uc_err uc_virtual_to_physical(uc_engine *uc, uint64_t address, uint32_t prot,
970+
uint64_t *paddress);
971+
957972
/*
958973
Emulate machine code in a specific duration of time.
959974

qemu/aarch64.h

+1
Original file line numberDiff line numberDiff line change
@@ -796,6 +796,7 @@
796796
#define get_page_addr_code get_page_addr_code_aarch64
797797
#define probe_access probe_access_aarch64
798798
#define tlb_vaddr_to_host tlb_vaddr_to_host_aarch64
799+
#define tlb_vaddr_to_paddr tlb_vaddr_to_paddr_aarch64
799800
#define helper_ret_ldub_mmu helper_ret_ldub_mmu_aarch64
800801
#define helper_le_lduw_mmu helper_le_lduw_mmu_aarch64
801802
#define helper_be_lduw_mmu helper_be_lduw_mmu_aarch64

qemu/accel/tcg/cputlb.c

+47
Original file line numberDiff line numberDiff line change
@@ -1296,6 +1296,53 @@ void *probe_access(CPUArchState *env, target_ulong addr, int size,
12961296
return (void *)((uintptr_t)addr + entry->addend);
12971297
}
12981298

1299+
bool tlb_vaddr_to_paddr(CPUArchState *env, abi_ptr addr,
1300+
MMUAccessType access_type, int mmu_idx, target_ulong *paddr)
1301+
{
1302+
struct uc_struct *uc = env->uc;
1303+
CPUTLBEntry *entry = tlb_entry(env, mmu_idx, addr);
1304+
target_ulong tlb_addr, page;
1305+
size_t elt_ofs = 0;
1306+
1307+
switch (access_type) {
1308+
case MMU_DATA_LOAD:
1309+
elt_ofs = offsetof(CPUTLBEntry, addr_read);
1310+
break;
1311+
case MMU_DATA_STORE:
1312+
elt_ofs = offsetof(CPUTLBEntry, addr_write);
1313+
break;
1314+
case MMU_INST_FETCH:
1315+
elt_ofs = offsetof(CPUTLBEntry, addr_code);
1316+
break;
1317+
default:
1318+
g_assert_not_reached();
1319+
}
1320+
1321+
page = addr & TARGET_PAGE_MASK;
1322+
tlb_addr = tlb_read_ofs(entry, elt_ofs);
1323+
1324+
if (!tlb_hit_page(uc, tlb_addr, page)) {
1325+
uintptr_t index = tlb_index(env, mmu_idx, addr);
1326+
1327+
if (!victim_tlb_hit(env, mmu_idx, index, elt_ofs, page)) {
1328+
CPUState *cs = env_cpu(env);
1329+
CPUClass *cc = CPU_GET_CLASS(cs);
1330+
1331+
if (!cc->tlb_fill(cs, addr, 0, access_type, mmu_idx, true, 0)) {
1332+
/* Non-faulting page table read failed. */
1333+
return false;
1334+
}
1335+
1336+
/* TLB resize via tlb_fill may have moved the entry. */
1337+
entry = tlb_entry(env, mmu_idx, addr);
1338+
}
1339+
tlb_addr = tlb_read_ofs(entry, elt_ofs);
1340+
}
1341+
1342+
*paddr = entry->paddr | (addr & ~TARGET_PAGE_MASK);
1343+
return true;
1344+
}
1345+
12991346
void *tlb_vaddr_to_host(CPUArchState *env, abi_ptr addr,
13001347
MMUAccessType access_type, int mmu_idx)
13011348
{

qemu/arm.h

+1
Original file line numberDiff line numberDiff line change
@@ -796,6 +796,7 @@
796796
#define get_page_addr_code get_page_addr_code_arm
797797
#define probe_access probe_access_arm
798798
#define tlb_vaddr_to_host tlb_vaddr_to_host_arm
799+
#define tlb_vaddr_to_paddr tlb_vaddr_to_paddr_arm
799800
#define helper_ret_ldub_mmu helper_ret_ldub_mmu_arm
800801
#define helper_le_lduw_mmu helper_le_lduw_mmu_arm
801802
#define helper_be_lduw_mmu helper_be_lduw_mmu_arm

qemu/include/exec/cpu_ldst.h

+18
Original file line numberDiff line numberDiff line change
@@ -168,4 +168,22 @@ static inline int cpu_ldsw_code(CPUArchState *env, abi_ptr addr)
168168
void *tlb_vaddr_to_host(CPUArchState *env, abi_ptr addr,
169169
MMUAccessType access_type, int mmu_idx);
170170

171+
172+
/**
173+
* tlb_vaddr_to_paddr:
174+
* @env: CPUArchState
175+
* @addr: guest virtual address to look up
176+
* @access_type: 0 for read, 1 for write, 2 for execute
177+
* @mmu_idx: MMU index to use for lookup
178+
* @paddr: pointer to store the physical address
179+
*
180+
* Look up the specified guest virtual index in the TCG softmmu TLB.
181+
* If we can translate a host virtual address to a host physical address,
182+
* without causing a guest exception, then save the physical address in
183+
* paddr pointer.
184+
*
185+
* Returns true when posible to translate, otherwhise false
186+
*/
187+
bool tlb_vaddr_to_paddr(CPUArchState *env, abi_ptr addr,
188+
MMUAccessType access_type, int mmu_idx, target_ulong *paddr);
171189
#endif /* CPU_LDST_H */

qemu/m68k.h

+1
Original file line numberDiff line numberDiff line change
@@ -796,6 +796,7 @@
796796
#define get_page_addr_code get_page_addr_code_m68k
797797
#define probe_access probe_access_m68k
798798
#define tlb_vaddr_to_host tlb_vaddr_to_host_m68k
799+
#define tlb_vaddr_to_paddr tlb_vaddr_to_paddr_m68k
799800
#define helper_ret_ldub_mmu helper_ret_ldub_mmu_m68k
800801
#define helper_le_lduw_mmu helper_le_lduw_mmu_m68k
801802
#define helper_be_lduw_mmu helper_be_lduw_mmu_m68k

qemu/mips.h

+1
Original file line numberDiff line numberDiff line change
@@ -796,6 +796,7 @@
796796
#define get_page_addr_code get_page_addr_code_mips
797797
#define probe_access probe_access_mips
798798
#define tlb_vaddr_to_host tlb_vaddr_to_host_mips
799+
#define tlb_vaddr_to_paddr tlb_vaddr_to_paddr_mips
799800
#define helper_ret_ldub_mmu helper_ret_ldub_mmu_mips
800801
#define helper_le_lduw_mmu helper_le_lduw_mmu_mips
801802
#define helper_be_lduw_mmu helper_be_lduw_mmu_mips

qemu/mips64.h

+1
Original file line numberDiff line numberDiff line change
@@ -796,6 +796,7 @@
796796
#define get_page_addr_code get_page_addr_code_mips64
797797
#define probe_access probe_access_mips64
798798
#define tlb_vaddr_to_host tlb_vaddr_to_host_mips64
799+
#define tlb_vaddr_to_paddr tlb_vaddr_to_paddr_mips64
799800
#define helper_ret_ldub_mmu helper_ret_ldub_mmu_mips64
800801
#define helper_le_lduw_mmu helper_le_lduw_mmu_mips64
801802
#define helper_be_lduw_mmu helper_be_lduw_mmu_mips64

qemu/mips64el.h

+1
Original file line numberDiff line numberDiff line change
@@ -796,6 +796,7 @@
796796
#define get_page_addr_code get_page_addr_code_mips64el
797797
#define probe_access probe_access_mips64el
798798
#define tlb_vaddr_to_host tlb_vaddr_to_host_mips64el
799+
#define tlb_vaddr_to_paddr tlb_vaddr_to_paddr_mips64el
799800
#define helper_ret_ldub_mmu helper_ret_ldub_mmu_mips64el
800801
#define helper_le_lduw_mmu helper_le_lduw_mmu_mips64el
801802
#define helper_be_lduw_mmu helper_be_lduw_mmu_mips64el

qemu/mipsel.h

+1
Original file line numberDiff line numberDiff line change
@@ -796,6 +796,7 @@
796796
#define get_page_addr_code get_page_addr_code_mipsel
797797
#define probe_access probe_access_mipsel
798798
#define tlb_vaddr_to_host tlb_vaddr_to_host_mipsel
799+
#define tlb_vaddr_to_paddr tlb_vaddr_to_paddr_mipsel
799800
#define helper_ret_ldub_mmu helper_ret_ldub_mmu_mipsel
800801
#define helper_le_lduw_mmu helper_le_lduw_mmu_mipsel
801802
#define helper_be_lduw_mmu helper_be_lduw_mmu_mipsel

qemu/ppc.h

+1
Original file line numberDiff line numberDiff line change
@@ -796,6 +796,7 @@
796796
#define get_page_addr_code get_page_addr_code_ppc
797797
#define probe_access probe_access_ppc
798798
#define tlb_vaddr_to_host tlb_vaddr_to_host_ppc
799+
#define tlb_vaddr_to_paddr tlb_vaddr_to_paddr_ppc
799800
#define helper_ret_ldub_mmu helper_ret_ldub_mmu_ppc
800801
#define helper_le_lduw_mmu helper_le_lduw_mmu_ppc
801802
#define helper_be_lduw_mmu helper_be_lduw_mmu_ppc

qemu/ppc64.h

+1
Original file line numberDiff line numberDiff line change
@@ -796,6 +796,7 @@
796796
#define get_page_addr_code get_page_addr_code_ppc64
797797
#define probe_access probe_access_ppc64
798798
#define tlb_vaddr_to_host tlb_vaddr_to_host_ppc64
799+
#define tlb_vaddr_to_paddr tlb_vaddr_to_paddr_ppc64
799800
#define helper_ret_ldub_mmu helper_ret_ldub_mmu_ppc64
800801
#define helper_le_lduw_mmu helper_le_lduw_mmu_ppc64
801802
#define helper_be_lduw_mmu helper_be_lduw_mmu_ppc64

qemu/riscv32.h

+1
Original file line numberDiff line numberDiff line change
@@ -796,6 +796,7 @@
796796
#define get_page_addr_code get_page_addr_code_riscv32
797797
#define probe_access probe_access_riscv32
798798
#define tlb_vaddr_to_host tlb_vaddr_to_host_riscv32
799+
#define tlb_vaddr_to_paddr tlb_vaddr_to_paddr_riscv32
799800
#define helper_ret_ldub_mmu helper_ret_ldub_mmu_riscv32
800801
#define helper_le_lduw_mmu helper_le_lduw_mmu_riscv32
801802
#define helper_be_lduw_mmu helper_be_lduw_mmu_riscv32

qemu/riscv64.h

+1
Original file line numberDiff line numberDiff line change
@@ -796,6 +796,7 @@
796796
#define get_page_addr_code get_page_addr_code_riscv64
797797
#define probe_access probe_access_riscv64
798798
#define tlb_vaddr_to_host tlb_vaddr_to_host_riscv64
799+
#define tlb_vaddr_to_paddr tlb_vaddr_to_paddr_riscv64
799800
#define helper_ret_ldub_mmu helper_ret_ldub_mmu_riscv64
800801
#define helper_le_lduw_mmu helper_le_lduw_mmu_riscv64
801802
#define helper_be_lduw_mmu helper_be_lduw_mmu_riscv64

qemu/s390x.h

+1
Original file line numberDiff line numberDiff line change
@@ -796,6 +796,7 @@
796796
#define get_page_addr_code get_page_addr_code_s390x
797797
#define probe_access probe_access_s390x
798798
#define tlb_vaddr_to_host tlb_vaddr_to_host_s390x
799+
#define tlb_vaddr_to_paddr tlb_vaddr_to_paddr_s390x
799800
#define helper_ret_ldub_mmu helper_ret_ldub_mmu_s390x
800801
#define helper_le_lduw_mmu helper_le_lduw_mmu_s390x
801802
#define helper_be_lduw_mmu helper_be_lduw_mmu_s390x

qemu/sparc.h

+1
Original file line numberDiff line numberDiff line change
@@ -796,6 +796,7 @@
796796
#define get_page_addr_code get_page_addr_code_sparc
797797
#define probe_access probe_access_sparc
798798
#define tlb_vaddr_to_host tlb_vaddr_to_host_sparc
799+
#define tlb_vaddr_to_paddr tlb_vaddr_to_paddr_sparc
799800
#define helper_ret_ldub_mmu helper_ret_ldub_mmu_sparc
800801
#define helper_le_lduw_mmu helper_le_lduw_mmu_sparc
801802
#define helper_be_lduw_mmu helper_be_lduw_mmu_sparc

qemu/sparc64.h

+1
Original file line numberDiff line numberDiff line change
@@ -796,6 +796,7 @@
796796
#define get_page_addr_code get_page_addr_code_sparc64
797797
#define probe_access probe_access_sparc64
798798
#define tlb_vaddr_to_host tlb_vaddr_to_host_sparc64
799+
#define tlb_vaddr_to_paddr tlb_vaddr_to_paddr_sparc64
799800
#define helper_ret_ldub_mmu helper_ret_ldub_mmu_sparc64
800801
#define helper_le_lduw_mmu helper_le_lduw_mmu_sparc64
801802
#define helper_be_lduw_mmu helper_be_lduw_mmu_sparc64

qemu/tricore.h

+1
Original file line numberDiff line numberDiff line change
@@ -796,6 +796,7 @@
796796
#define get_page_addr_code get_page_addr_code_tricore
797797
#define probe_access probe_access_tricore
798798
#define tlb_vaddr_to_host tlb_vaddr_to_host_tricore
799+
#define tlb_vaddr_to_paddr tlb_vaddr_to_paddr_tricore
799800
#define helper_ret_ldub_mmu helper_ret_ldub_mmu_tricore
800801
#define helper_le_lduw_mmu helper_le_lduw_mmu_tricore
801802
#define helper_be_lduw_mmu helper_be_lduw_mmu_tricore

qemu/unicorn_common.h

+29
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,34 @@ static bool cpu_virtual_mem_read(struct uc_struct *uc, vaddr addr, uint32_t prot
6363
return true;
6464
}
6565

66+
static bool cpu_virtual_to_physical(struct uc_struct *uc, vaddr addr, uint32_t prot, uint64_t *paddr)
67+
{
68+
target_ulong res;
69+
MMUAccessType access_type;
70+
int mmu_idx = cpu_mmu_index(uc->cpu->env_ptr, false);
71+
72+
switch(prot) {
73+
case UC_PROT_READ:
74+
access_type = MMU_DATA_LOAD;
75+
break;
76+
case UC_PROT_WRITE:
77+
access_type = MMU_DATA_STORE;
78+
break;
79+
case UC_PROT_EXEC:
80+
access_type = MMU_INST_FETCH;
81+
break;
82+
default:
83+
return false;
84+
}
85+
86+
if (!tlb_vaddr_to_paddr(uc->cpu->env_ptr, addr, access_type, mmu_idx, &res)) {
87+
return false;
88+
}
89+
90+
*paddr = res;
91+
return true;
92+
}
93+
6694
void tb_cleanup(struct uc_struct *uc);
6795
void free_code_gen_buffer(struct uc_struct *uc);
6896

@@ -162,6 +190,7 @@ static inline void uc_common_init(struct uc_struct* uc)
162190
uc->write_mem = cpu_physical_mem_write;
163191
uc->read_mem = cpu_physical_mem_read;
164192
uc->read_mem_virtual = cpu_virtual_mem_read;
193+
uc->virtual_to_physical = cpu_virtual_to_physical;
165194
uc->tcg_exec_init = tcg_exec_init;
166195
uc->cpu_exec_init_all = cpu_exec_init_all;
167196
uc->vm_start = vm_start;

qemu/x86_64.h

+1
Original file line numberDiff line numberDiff line change
@@ -796,6 +796,7 @@
796796
#define get_page_addr_code get_page_addr_code_x86_64
797797
#define probe_access probe_access_x86_64
798798
#define tlb_vaddr_to_host tlb_vaddr_to_host_x86_64
799+
#define tlb_vaddr_to_paddr tlb_vaddr_to_paddr_x86_64
799800
#define helper_ret_ldub_mmu helper_ret_ldub_mmu_x86_64
800801
#define helper_le_lduw_mmu helper_le_lduw_mmu_x86_64
801802
#define helper_be_lduw_mmu helper_be_lduw_mmu_x86_64

symbols.sh

+1
Original file line numberDiff line numberDiff line change
@@ -796,6 +796,7 @@ get_page_addr_code_hostp \
796796
get_page_addr_code \
797797
probe_access \
798798
tlb_vaddr_to_host \
799+
tlb_vaddr_to_paddr \
799800
helper_ret_ldub_mmu \
800801
helper_le_lduw_mmu \
801802
helper_be_lduw_mmu \

tests/unit/test_mem.c

+26
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,31 @@ static void test_snapshot_unmap(void)
449449
OK(uc_close(uc));
450450
}
451451

452+
static bool test_v2p_tlb_fill(uc_engine *uc, uint64_t addr, uc_mem_type type,
453+
uc_tlb_entry *result, void *user_data)
454+
{
455+
if (type != UC_MEM_READ)
456+
return false;
457+
result->paddr = addr;
458+
result->perms = UC_PROT_READ;
459+
return true;
460+
}
461+
462+
static void test_virtual_to_physical(void)
463+
{
464+
uc_engine *uc;
465+
uc_hook hook;
466+
uint64_t res;
467+
468+
OK(uc_open(UC_ARCH_X86, UC_MODE_64, &uc));
469+
OK(uc_ctl_tlb_mode(uc, UC_TLB_VIRTUAL));
470+
OK(uc_hook_add(uc, &hook, UC_HOOK_TLB_FILL, test_v2p_tlb_fill, NULL, 1, 0));
471+
472+
OK(uc_virtual_to_physical(uc, 0x1000, UC_PROT_READ, &res));
473+
uc_assert_err(UC_ERR_WRITE_PROT,
474+
uc_virtual_to_physical(uc, 0x1000, UC_PROT_WRITE, &res));
475+
}
476+
452477
TEST_LIST = {{"test_map_correct", test_map_correct},
453478
{"test_map_wrapping", test_map_wrapping},
454479
{"test_mem_protect", test_mem_protect},
@@ -464,4 +489,5 @@ TEST_LIST = {{"test_map_correct", test_map_correct},
464489
{"test_snapshot_with_vtlb", test_snapshot_with_vtlb},
465490
{"test_context_snapshot", test_context_snapshot},
466491
{"test_snapshot_unmap", test_snapshot_unmap},
492+
{"test_virtual_to_physical", test_virtual_to_physical},
467493
{NULL, NULL}};

uc.c

+33
Original file line numberDiff line numberDiff line change
@@ -773,6 +773,39 @@ static bool check_mem_area(uc_engine *uc, uint64_t address, size_t size)
773773
return (count == size);
774774
}
775775

776+
uc_err uc_virtual_to_physical(uc_engine *uc, uint64_t address, uc_prot prot,
777+
uint64_t *paddress)
778+
{
779+
UC_INIT(uc);
780+
781+
if (!(UC_PROT_READ == prot || UC_PROT_WRITE == prot ||
782+
UC_PROT_EXEC == prot)) {
783+
restore_jit_state(uc);
784+
return UC_ERR_ARG;
785+
}
786+
787+
// The sparc mmu doesn't support probe mode
788+
if (uc->arch == UC_ARCH_SPARC && uc->cpu->cc->tlb_fill == uc->cpu->cc->tlb_fill_cpu) {
789+
restore_jit_state(uc);
790+
return UC_ERR_ARG;
791+
}
792+
793+
if (!uc->virtual_to_physical(uc, address, prot, paddress)) {
794+
restore_jit_state(uc);
795+
switch (prot) {
796+
case UC_PROT_READ:
797+
return UC_ERR_READ_PROT;
798+
case UC_PROT_WRITE:
799+
return UC_ERR_WRITE_PROT;
800+
case UC_PROT_EXEC:
801+
return UC_ERR_FETCH_PROT;
802+
}
803+
}
804+
805+
restore_jit_state(uc);
806+
return UC_ERR_OK;
807+
}
808+
776809
UNICORN_EXPORT
777810
uc_err uc_mem_read_virtual(uc_engine *uc, uint64_t address, uc_prot prot,
778811
void *_bytes, size_t size)

0 commit comments

Comments
 (0)