I am working on a project where I need to translate qemu-guest
physical addresses to host virtual/physical addresses.
I am using VMI (virtual machine introspection) to introspect into the qemu process (the KVM VM) and to read guest physical addresses stored in virtio ring buffer descriptors. Therefore, I am looking for a simple way to translate the qemu physical addresses to host virtual addresses at the host side. (i.e., to extract as less info as possible from the qemu process).
I read online that in previous versions, qemu stored the physical RAM base in the variable phys_ram_base
, so that the host virtual address could be obtained as follows:
host_virtual = phys_ram_base + guest_physical_address
Is something like this possible in newer versions of qemu (e.g., how could I obtain the qemu-physical base address -- the former phys_ram_base
?)
I had to solve the same problem: translating a guest-virtual address to a host-physical address. My approach was the following:
Step 1 (native host): virtual address to physical address
vaddr2paddr
that takes a process ID (PID) and a virtual address, then returns the associated physical address./proc/<pid>/pagemap
to determine the physical address of the programvaddr2paddr
script and then check using devmem2
tool (or with xxd
in /dev/mem
by loading devmem-full-access kernel module) whether my previously written data is indeed thereStep 2 (VM): guest-virtual address to host-physical address
vaddr2paddr
with the guest-virtual address of the allocated buffer to get the guest-physical address (gpa
)/dev/<pid>/maps
which shows the allocated virtual memory regions of a process. In my case, the VM had 2 GB of memory and I found an area that was roughly 2 GB (all others were significantly smaller). I then take the start address of that area (vm_start_address
)
hpa = vm_start_address + gpa
devmem2
tool whether the written data is at the calculated hpa
NOTE: This approach requires sudo
to access /proc/<pid>/pagemap
and also /proc/<pid>/maps
.
I had to solve the same problem and I come up with the following solution.
When using QEMU with the -enable-kvm option, memory is allocated to the guest through the KVM_SET_USER_MEMORY_REGION
ioctl. Basically, QEMU prepares a kvm_userspace_memory_region
struct, where the physical addresses of the guest are associated to host virtual addresses, and then the ioctl is issued. Now, it turned out that the KVMSlot
struct is (almost) 1:1 with the struct offered by the KVM API. QEMU stores all the information to perform the translation from guest physical to host virtual addresses there.
The KVMSlot struct is defined like this:
typedef struct KVMSlot
{
hwaddr start_addr;
ram_addr_t memory_size;
void *ram;
int slot;
int flags;
int old_flags;
/* Dirty bitmap cache for the slot */
unsigned long *dirty_bmap;
} KVMSlot;
start_addr
is the physical address corresponding to the begininnig of the considered slot, ram
is its corresponding host virtual address and then memory_size
is the size of the slot.
Now to perform the translation you have to:
KVMSlot
elements. The head of the list is stored in KVMMemoryListener
. To find it, you can check if the guest physical address is in the range between start_addr
and start_addr + memory_size
.offset = gpa - start_addr
)hva = ram + offset
. The offset of course is the same both in the guest physical addresses and in the host virtual addresses, that's why you can use it.Finally you can check that the translation was right using the function gpa2hva
of the QEMU Monitor.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With