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_regionstruct, 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