1 KVM memory listener的注册
在KVM初始化kvm_init()中会通过函数km_memory_listener_regiter()注册KVM所对应的memory listener,其中设置KVM region_add回调,KVM region_del回调以及KVM log_start/log_stop的回调。
2 region_add回调
当添加内存区域时,会调用注册的memory_listener对应的region_add回调函数。对于KVM memory listener,region_add回调函数为kvm_region_add()。
该回调函数会将内存区域所对应的虚拟机物理地址gpa和host上虚拟内存hva之间的关系通过mem结构体,通过系统调用KVM_SET_USER_MEMORY_REGION通知KVM。
3 系统调用KVM_SET_USER_MEMORY_REGION
系统调用KVM_SET_USER_MEMORY_REGION最终向KVM提交虚拟机物理地址gpa和host上虚拟地址hva之间的对应关系,以便在产生stage2缺页时根据gpa找到对应的hva,最终建立起gpa到hpa之间的映射。
在KVM中,内存相关的结构体以及之间的关系如下图所示:
KVM结构体中成员__memslots[1][2]表示每个地址空间存在active和inactive memslot组。正常情况下两组memslots指向一组相同的memslots。但在通过memslot管理操作将copy替代memslot时这两组memslots出现不同。当完成这些操作后,这两组memslots又指向相同的memslots。暂不分析两者差异(待分析)。
Kvm_memslots结构体为一组memslot组,将包含GPA和HVA映射的memslot组以hva加入到hva_tree红黑树中,以gpa加入到gfn_tree红黑树中。其中成员last_used_slot缓存上一次使用的memslot。
Kvm_mem_slot结构体体现gpa和hva之间映射关系。其中hva_node用于链入到kvm_memslots中的hva_tree红黑树中,gfn_node用于链入到kvm_memslots中的gfn_tree红黑树中,base_gfn表示虚拟机的物理地址gpa,userspace_addr表示QEMU线程的虚拟地址即hva,npages表示大小。
系统调用KVM_SET_USER_MEMORY_REGION调用关系如下:
函数kvm_set_memslot()处理如下,它根据增加MR或删除MR或移动MR等操作执行不同的处理:
KVM_MR_CREATE针对创建MR情况,将新创建的MR插入到memslots中,同时根据hva值将该MR插入到hva_tree红黑树中(在stage2 unmap中可以快速找到),根据gfn值将该MR插入到gfn_tree红黑树中(在stage2缺页异常中可以从gfn快速找到hva)。
KM_MR_DELETE针对删除MR情况,将旧的MR从memslots中移除,首先它会将memslot无效化,并unmap stage2映射(函数kvm_invalidate_memslot()实现),然后通过kvm_delete_memslot()移除旧的memslot。