Skip to content

Commit 479b0c2

Browse files
add uc_mem_read_virtual (#2121)
* x86 mmu allow probe requests * add api to access memory by virtuall addresses New api to read from, translate, or write to a virtual address. When using the MMU it's useful to direct use the virtual addresses. * fixup! add api to access memory by virtuall addresses
1 parent 7394a6c commit 479b0c2

File tree

29 files changed

+564
-8
lines changed

29 files changed

+564
-8
lines changed

bindings/rust/src/ffi.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,19 @@ extern "C" {
4848
bytes: *mut u8,
4949
size: u64,
5050
) -> uc_error;
51+
pub fn uc_vmem_read(
52+
engine: uc_handle,
53+
address: u64,
54+
prot: u32,
55+
bytes: *mut u8,
56+
size: libc::size_t,
57+
) -> uc_error;
58+
pub fn uc_vmem_translate(
59+
engine: uc_handle,
60+
address: u64,
61+
prot: u32,
62+
paddr: *mut u64,
63+
) -> uc_error;
5164
pub fn uc_mem_map(engine: uc_handle, address: u64, size: u64, perms: u32) -> uc_error;
5265
pub fn uc_mem_map_ptr(
5366
engine: uc_handle,

bindings/rust/src/lib.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,17 @@ impl<'a, D> Unicorn<'a, D> {
328328
.and(Ok(buf))
329329
}
330330

331+
/// Read a range of bytes from memory at the specified emulated virtual address.
332+
pub fn vmem_read(&self, address: u64, prot: Prot, buf: &mut [u8]) -> Result<(), uc_error> {
333+
unsafe { uc_vmem_read(self.get_handle(), address, prot.0 as _, buf.as_mut_ptr() as _, buf.len()) }.into()
334+
}
335+
336+
/// Return a range of bytes from memory at the specified emulated virtual address as vector.
337+
pub fn vmem_read_as_vec(&self, address: u64, prot: Prot, size: usize) -> Result<Vec<u8>, uc_error> {
338+
let mut buf = vec![0; size];
339+
unsafe { uc_vmem_read(self.get_handle(), address, prot.0 as _, buf.as_mut_ptr() as _, buf.len()) }.and(Ok(buf))
340+
}
341+
331342
/// Write the data in `bytes` to the emulated physical address `address`
332343
pub fn mem_write(&mut self, address: u64, bytes: &[u8]) -> Result<(), uc_error> {
333344
unsafe {
@@ -341,6 +352,16 @@ impl<'a, D> Unicorn<'a, D> {
341352
.into()
342353
}
343354

355+
/// translate virtual to physical address
356+
pub fn vmem_translate(&mut self, address: u64, prot: Prot) -> Result<u64, uc_error> {
357+
let mut physical: u64 = 0;
358+
let err = unsafe { uc_vmem_translate(self.get_handle(), address, prot.0 as _, &mut physical) };
359+
if err != uc_error::OK {
360+
return Err(err);
361+
}
362+
return Ok(physical);
363+
}
364+
344365
/// Map an existing memory region in the emulator at the specified address.
345366
///
346367
/// # Safety

include/uc_priv.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,12 @@ typedef bool (*uc_write_mem_t)(AddressSpace *as, hwaddr addr,
8080
typedef bool (*uc_read_mem_t)(AddressSpace *as, hwaddr addr, uint8_t *buf,
8181
hwaddr len);
8282

83+
typedef bool (*uc_read_mem_virtual_t)(struct uc_struct *uc, vaddr addr,
84+
uint32_t prot, uint8_t *buf, int len);
85+
86+
typedef bool (*uc_virtual_to_physical_t)(struct uc_struct *uc, vaddr addr,
87+
uint32_t prot, uint64_t *res);
88+
8389
typedef MemoryRegion *(*uc_mem_cow_t)(struct uc_struct *uc,
8490
MemoryRegion *current, hwaddr begin,
8591
size_t size);
@@ -276,6 +282,8 @@ struct uc_struct {
276282

277283
uc_write_mem_t write_mem;
278284
uc_read_mem_t read_mem;
285+
uc_read_mem_virtual_t read_mem_virtual;
286+
uc_virtual_to_physical_t virtual_to_physical;
279287
uc_mem_cow_t memory_cow;
280288
uc_args_void_t release; // release resource when uc_close()
281289
uc_args_uc_u64_t set_pc; // set PC for tracecode

include/unicorn/unicorn.h

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -934,6 +934,82 @@ uc_err uc_mem_write(uc_engine *uc, uint64_t address, const void *bytes,
934934
UNICORN_EXPORT
935935
uc_err uc_mem_read(uc_engine *uc, uint64_t address, void *bytes, uint64_t size);
936936

937+
/*
938+
Read a range of bytes in memory after mmu translation.
939+
940+
@uc: handle returned by uc_open()
941+
@address: starting virtual memory address of bytes to get.
942+
@prot: The access type for the tlb lookup
943+
@bytes: pointer to a variable containing data copied from memory.
944+
@size: size of memory to read.
945+
946+
NOTE: @bytes must be big enough to contain @size bytes.
947+
948+
This function will translate the address with the MMU. Therefore all
949+
pages needs to be memory mapped with the proper access rights. The MMU
950+
will not translate the virtual address when the pages are not mapped
951+
with the given access rights.
952+
953+
When the pages are mapped with the given access rights the read will
954+
happen indipenden from the access rights of the mapping. So when you
955+
have a page write only mapped, a call with prot == UC_PROT_WRITE will
956+
be able to read the stored data.
957+
958+
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
959+
for detailed error).
960+
*/
961+
UNICORN_EXPORT
962+
uc_err uc_vmem_read(uc_engine *uc, uint64_t address, uint32_t prot,
963+
void *bytes, size_t size);
964+
965+
/*
966+
Write to a range of bytes in memory after mmu translation.
967+
968+
@uc: handle returned by uc_open()
969+
@address: starting memory address of bytes to set.
970+
@prot: The access type for the tlb lookup
971+
@bytes: pointer to a variable containing data to be written to memory.
972+
@size: size of memory to write to.
973+
974+
This function will translate the address with the MMU. Therefore all
975+
pages needs to be memory mapped with the proper access rights. The MMU
976+
will not translate the virtual address when the pages are not mapped
977+
with the given access rights.
978+
979+
When the pages are mapped with the given access rights the write will
980+
happen indipenden from the access rights of the mapping. So when you
981+
have a page read only mapped, a call with prot == UC_PROT_READ will
982+
be able to write the data.
983+
984+
NOTE: @bytes must be big enough to contain @size bytes.
985+
986+
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
987+
for detailed error).
988+
*/
989+
UNICORN_EXPORT
990+
uc_err uc_vmem_write(uc_engine *uc, uint64_t address, uint32_t prot,
991+
void *bytes, size_t size);
992+
993+
/*
994+
Translate a virtuall address to a physical address
995+
996+
@uc:
997+
@address: virtual address to translate
998+
@prot: The access type for the tlb lookup
999+
@paddress: A pointer to store the result
1000+
1001+
This function will translate the address with the MMU. Therefore all
1002+
pages needs to be memory mapped with the proper access rights. The MMU
1003+
will not translate the virtual address when the pages are not mapped
1004+
with the given access rights.
1005+
1006+
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
1007+
for detailed error).
1008+
*/
1009+
UNICORN_EXPORT
1010+
uc_err uc_vmem_translate(uc_engine *uc, uint64_t address, uint32_t prot,
1011+
uint64_t *paddress);
1012+
9371013
/*
9381014
Emulate machine code in a specific duration of time.
9391015

qemu/aarch64.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -797,6 +797,7 @@
797797
#define get_page_addr_code get_page_addr_code_aarch64
798798
#define probe_access probe_access_aarch64
799799
#define tlb_vaddr_to_host tlb_vaddr_to_host_aarch64
800+
#define tlb_vaddr_to_paddr tlb_vaddr_to_paddr_aarch64
800801
#define helper_ret_ldub_mmu helper_ret_ldub_mmu_aarch64
801802
#define helper_le_lduw_mmu helper_le_lduw_mmu_aarch64
802803
#define helper_be_lduw_mmu helper_be_lduw_mmu_aarch64

qemu/accel/tcg/cputlb.c

Lines changed: 47 additions & 0 deletions
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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -797,6 +797,7 @@
797797
#define get_page_addr_code get_page_addr_code_arm
798798
#define probe_access probe_access_arm
799799
#define tlb_vaddr_to_host tlb_vaddr_to_host_arm
800+
#define tlb_vaddr_to_paddr tlb_vaddr_to_paddr_arm
800801
#define helper_ret_ldub_mmu helper_ret_ldub_mmu_arm
801802
#define helper_le_lduw_mmu helper_le_lduw_mmu_arm
802803
#define helper_be_lduw_mmu helper_be_lduw_mmu_arm

qemu/include/exec/cpu_ldst.h

Lines changed: 18 additions & 0 deletions
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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -797,6 +797,7 @@
797797
#define get_page_addr_code get_page_addr_code_m68k
798798
#define probe_access probe_access_m68k
799799
#define tlb_vaddr_to_host tlb_vaddr_to_host_m68k
800+
#define tlb_vaddr_to_paddr tlb_vaddr_to_paddr_m68k
800801
#define helper_ret_ldub_mmu helper_ret_ldub_mmu_m68k
801802
#define helper_le_lduw_mmu helper_le_lduw_mmu_m68k
802803
#define helper_be_lduw_mmu helper_be_lduw_mmu_m68k

qemu/mips.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -797,6 +797,7 @@
797797
#define get_page_addr_code get_page_addr_code_mips
798798
#define probe_access probe_access_mips
799799
#define tlb_vaddr_to_host tlb_vaddr_to_host_mips
800+
#define tlb_vaddr_to_paddr tlb_vaddr_to_paddr_mips
800801
#define helper_ret_ldub_mmu helper_ret_ldub_mmu_mips
801802
#define helper_le_lduw_mmu helper_le_lduw_mmu_mips
802803
#define helper_be_lduw_mmu helper_be_lduw_mmu_mips

0 commit comments

Comments
 (0)