【问题标题】:QEMU-KVM: Is Guest Physical Address(GBA) same as QEMU-KVM's Virtual Address on the host?QEMU-KVM:Guest Physical Address(GBA) 是否与 QEMU-KVM 在主机上的虚拟地址相同?
【发布时间】:2021-05-31 12:56:27
【问题描述】:
例如,如果来宾上的一个进程在 0x8000(如来宾虚拟内存中)分配了数据,并且已映射到来宾物理内存地址空间中的 0x4000,则数据位于虚拟内存地址中的 0x4000主机端 QEMU-KVM 的(子)进程(每个 VM)的空间?换句话说,如果我在QEMU的源代码中编写新代码(这样我可以使用QEMU-KVM的页表),编译并运行它,那么我可以直接访问guest进程的数据,只需与guest的物理内存地址匹配到来宾虚拟内存地址?
【问题讨论】:
标签:
memory-management
virtual-machine
qemu
virtual-memory
kvm
【解决方案1】:
不,用于用户空间 QEMU 进程的页表映射与客户本身用于客户虚拟 -> 客户物理地址映射的页表或 KVM 内核代码使用的页表无关用于来宾物理地址 -> 用于 RAM 的主机物理地址映射。
当您在 QEMU 中编写需要访问客户内存的代码时,您应该使用 QEMU 提供的 API 来执行此操作,这些 API 处理将客户地址转换为 RAM 的主机虚拟地址,并处理客户地址具有模拟设备而不是 RAM 的情况。 QEMU 开发者内部文档有a section on APIs for loads and stores,函数也记录在头文件的doc cmets 中。
通常最好的建议是“在 QEMU 中找到一些与您正在尝试做的事情基本相同的现有代码,并以此为例”。
【解决方案2】:
我假设您的问题是关于 x86 平台的。
QEMU+KVM 使用扩展页表 (EPT) 将主机虚拟地址 (HVA) 映射到客户物理地址 (GPA)。要找到GPA对应的HVA,你应该遍历你的客人的EPT。
当你需要从你的客户机读取一个虚拟地址时,你可以使用 QEMU 源码中的 GDB 函数。此 sn-p 将在您的 guest 的当前执行进程中读取 virtualAddress 的 4 个字节:
uint8_t instr[4];
if( cpu_memory_rw_debug( cpu, virtualAddress, (uint8_t *)instr, sizeof( instr ), 0 ) )
{
printf( "Failed to read instr!\n" );
return;
}
cpu 是您客人的 CPU 的 CPUState*。
当你想在你的guest中读取一个具体进程的地址时,你应该设置env->cr[3]到CR3这个进程的值(env是一个CPUX86State*)。看完后别忘了恢复原值。当然,只有在您的客人未执行时才读取内存,否则可能会出现竞争。