为什么内存管理和IO映射要放一起呢?因为IO映射有memory map io(MMIO)和port map io(PMIO)两种,其中MMIO和内存管理有关的。
MMIO和普通内存的访问的汇编指令是相同的;PMIO有自己的汇编指令。
kvm如果执行到了PMIO的指令,那么退出状态是KVM_EXIT_IO。
kvm怎么知道某段内存是MMIO,从而退出状态是KVM_EXIT_MMIO,而某段内存是普通内存,由kvm处理缺页,而不退出呢?这是本文想要探究的一个东西。
PS:kvm退出状态是KVM_EXIT_IO或者KVM_EXIT_MMIO,那么将由qemu进行读写虚拟设备IO端口的模拟,如何模拟?
PMIO的看《android qemu-kvm i8254 pit虚拟设备》,MMIO的看《android emulator虚拟设备分析第一篇之battery》。
阅读本文前,需要对MMU,页表,虚拟内存空间,物理内存空间有一些了解。对于kvm的影子页表的工作原理,kvm的vcpu的执行,以及kvm的ioctl有一些了解。
前提知识:
KVM之内存虚拟化:http://royluo.org/2016/03/13/kvm-mmu-virtualization/,重点看GVA,GPA,HVA,HPA,影子页表的东西
kvm api:https://kernel.org/doc/Documentation/virtual/kvm/api.txt,重点看ioctl的东西,并对kvm的使用有所印象
kvm api使用实例:https://lwn.net/Articles/658511/,https://lwn.net/Articles/658512/
QEMU-MEMORY-MANAGEMENT.TXT:https://android.googlesource.com/platform/external/qemu.git/+/master/docs/QEMU-MEMORY-MANAGEMENT.TXT
本文使用的android版本是5.1.0,x86的img;host机器是intel x86_64,ubuntu12.04
先来一个大图:
普通内存的申请(external/qemu/hw/i386/pc.c):
/*
* Allocate a single contiguous RAM so that the goldfish
* framebuffer can work well especially when the frame buffer is
* large.
*/
ram_addr = qemu_ram_alloc(NULL, "pc.ram", below_4g_mem_size);
cpu_register_physical_memory(0, below_4g_mem_size, ram_addr);
由于kvm可以使用硬件提供的EPT影子页表,所以我们只需要将HVA和GPA的关系通过ioctl告知kvm即可(KVM_SET_USER_MEMORY_REGION)。
先介绍一下qemu内存