Description
Background
Many emulators, e.g. QEMU, represent the guest physical address space as an acyclic directed graph whose leaves provide backing memory (for RAM/ROM) and/or hooks for reading/writing (for IO). See: https://github.com/qemu/qemu/blob/master/docs/devel/memory.rst
As a result, the same backing HVA can be referenced at two different locations: For example, the 256 KB (0x40000 bytes) BIOS image is mapped into 0xFFFC0000-0xFFFFFFFF. But an alias into 128 KB at the bottom of the BIOS image region is mapped at 0xE0000-0xFFFFF.
Issue
The implementation of MapGuestMemory
and MapGuestMemoryLarge
in the HAXM module calls each two ioctl's in succession. Specifically:
- MapGuestMemory:
HAX_VM_IOCTL_ALLOC_RAM
HAX_VM_IOCTL_SET_RAM
- MapGuestMemoryLarge:
HAX_VM_IOCTL_ADD_RAMBLOCK
HAX_VM_IOCTL_SET_RAM2
If I understand HAXM correctly, The first ioctl is supposed to create the HVA-to-HPA mappings, and the second one is actually taking care of the GPA-to-HPA mappings (via EPT).
EPT-translation works in the same way as CR3-translation turns HVAs into HPAs, so it allows overlapping HPA ranges, so the second ioctl has no issue with overlapping ranges (like the BIOS one mentioned above). However, the first ioctl won't allow adding the same HVA range twice.
Since your approach merges the two steps, it won't allow aliases.
Possible solution
This might not be the most efficient way of dealing with this, but to fix it without changing your API, you could cache which HVA ranges have been already "added" to HAXM, and avoid them in future MapGuestMemory
calls.