【原创】Linux虚拟化KVM-Qemu分析(五)之内存虚拟化

Read the fucking source code! --By 鲁迅

A picture is worth a thousand words. --By 高尔基

说明:

KVM版本:5.9.1

QEMU版本:5.0.0

工具:Source Insight 3.5, Visio

文章同步在博客园:https://www.cnblogs.com/LoyenWang/

1. 概述

Linux虚拟化KVM-Qemu分析(二)之ARMv8虚拟化》文中描述过内存虚拟化大体框架,再来回顾一下:

非虚拟化下的内存的访问

【原创】Linux虚拟化KVM-Qemu分析(五)之内存虚拟化

CPU访问物理内存前,需要先建立页表映射(虚拟地址到物理地址的映射),最终通过查表的方式来完成访问。在ARMv8中,内核页表基地址存放在TTBR1_EL1中,用户空间页表基地址存放在TTBR0_EL0中;

虚拟化下的内存访问

【原创】Linux虚拟化KVM-Qemu分析(五)之内存虚拟化

虚拟化情况下,内存的访问会分为两个Stage,Hypervisor通过Stage 2来控制虚拟机的内存视图,控制虚拟机是否可以访问某块物理内存,进而达到隔离的目的;

Stage 1:VA(Virtual Address)->IPA(Intermediate Physical Address),Host的操作系统控制Stage 1的转换;

Stage 2:IPA(Intermediate Physical Address)->PA(Physical Address),Hypervisor控制Stage 2的转换;

猛一看上边两个图,好像明白了啥,仔细一想,啥也不明白,本文的目标就是将这个过程讲明白。

在开始细节讲解之前,需要先描述几个概念:

gva - guest virtual address gpa - guest physical address hva - host virtual address hpa - host physical address

【原创】Linux虚拟化KVM-Qemu分析(五)之内存虚拟化

Guest OS中的虚拟地址到物理地址的映射,就是典型的常规操作,参考之前的内存管理模块系列文章;

铺垫了这么久,来到了本文的两个主题:

GPA->HVA;

HVA->HPA;

开始吧!

2. GPA->HVA

还记得上一篇文章《Linux虚拟化KVM-Qemu分析(四)之CPU虚拟化(2)》中的Sample Code吗?
KVM-Qemu方案中,GPA->HVA的转换,是通过ioctl中的KVM_SET_USER_MEMORY_REGION命令来实现的,如下图:

【原创】Linux虚拟化KVM-Qemu分析(五)之内存虚拟化

找到了入口,让我们进一步揭开神秘的面纱。

2.1 数据结构

关键的数据结构如下:

【原创】Linux虚拟化KVM-Qemu分析(五)之内存虚拟化

虚拟机使用slot来组织物理内存,每个slot对应一个struct kvm_memory_slot,一个虚拟机的所有slot构成了它的物理地址空间;

用户态使用struct kvm_userspace_memory_region来设置内存slot,在内核中使用struct kvm_memslots结构来将kvm_memory_slot组织起来;

struct kvm_userspace_memory_region结构体中,包含了slot的ID号用于查找对应的slot,此外还包含了物理内存起始地址及大小,以及HVA地址,HVA地址是在用户进程地址空间中分配的,也就是Qemu进程地址空间中的一段区域;

2.2 流程分析

数据结构部分已经罗列了大体的关系,那么在KVM_SET_USER_MEMORY_REGION时,围绕的操作就是slots的创建、删除,更新等操作,话不多说,来图了:

【原创】Linux虚拟化KVM-Qemu分析(五)之内存虚拟化

当用户要设置内存区域时,最终会调用到__kvm_set_memory_region函数,在该函数中完成所有的逻辑处理;

__kvm_set_memory_region函数,首先会对传入的struct kvm_userspace_memory_region的各个字段进行合法性检测判断,主要是包括了地址的对齐,范围的检测等;

根据用户传递的slot索引号,去查找虚拟机中对应的slot,查找的结果只有两种:1)找到一个现有的slot;2)找不到则新建一个slot;

如果传入的参数中memory_size为0,那么会将对应slot进行删除操作;

根据用户传入的参数,设置slot的处理方式:KVM_MR_CREATE,KVM_MR_MOVE,KVM_MEM_READONLY;

根据用户传递的参数决定是否需要分配脏页的bitmap,标识页是否可用;

最终调用kvm_set_memslot来设置和更新slot信息;

2.2.1 kvm_set_memslot

具体的memslot的设置在kvm_set_memslot函数中完成,slot的操作流程如下:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpxsxj.html