一、相关参考(请仅参考,任意一篇足矣)
1.https://www.cnblogs.com/LoyenWang/p/13584020.html
2.https://zhuanlan.zhihu.com/p/470045640
3.万字剖析 Armv8 架构虚拟化-腾讯云开发者社区-腾讯云
4.https://zhuanlan.zhihu.com/p/529084234
二、虚拟化原理部分知识点----持续更新
2.0 说明
其实上部分的几篇链接文章,基本上已经把armv8虚拟化原理说的挺清楚了,为什么我还要写一篇?重复造轮子没有意义和价值,其实这几篇文章重复率极高,不排除时一个人撰写或多个人直接抄袭搬运。所以再写一篇原因有下:
1)之前文章只讲原理,没有相关验证,可能理解起来不直观;
2)有几处原理出现标识错误,而且是全部错在同一个点,可能是他们参考老版本导致(更有甚者,尼玛第一个人写错了导致后面所有人都抄错了)。
所以,本篇文章直接追本溯源,只参考arm官方给的文章,然后针对前人错误的地方辅以佐证,文章是虚拟化中的一个个模块,想要连贯性还是读官方文档,当然英语不好的可以直接看参考连接。
接下来,进入正文……
2.1 寄存器重定向
VHE开启后(HCR_EL2.H2E == 1),可以通过寄存器重定向,使得host os在访问EL1层的寄存器是被重定向到EL2层面(访问到el2的寄存器),这样就可以使得kernel二进制可以不做任何修改。此时只需要HCR_EL2.H2E == 1这一比特被置位,即vhe使能,那Host OS对所有EL1寄存器的访问操作都被硬件转换为对相应EL2寄存器的访问,如OS访问ttbr0_el1寄存器,则会按下图方式被重定向到ttbr0_el2:
可以看到上图中验证的,在HCR的第34bit=1时,即VHE使能,此时host在el2层面访问ttbr_el1的值(被重定向到el2)就等于el2的值!
但重定向访问寄存器会引入一个新的问题,Hypervisor为了实现任务切换(如EL2层面处理完后返回到EL1的Guest)需要访问真正的EL1寄存器。为了解决这个问题,Arm架构引入了一种新的别名机制,以_EL12或_EL02结尾。如需要访问实际的ttbr0_el1时,则可通过访问ttbr0_el12的方式实现。
上述文章无一例外的指明此时需要置位ECH==1,以使得在EL2层面访问TTBR0_EL12就是访问TTBR0_EL1,奈何我在官方UM中搜遍了armv8所有寄存器的所有字段,也没发现有个ECH的比特的。最终只能怀疑他们借鉴的可能是老版本,或者说写错了,而且后来者又一遍遍抄错了。(其实弄清楚这个问题很简单,直接找个机器验证一遍就可以了)后来我直接去官网找,最终找到了第一手资料Documentation – Arm Developer,这个功能其实就是要求E2H==1,而不是所谓的ECH,哪有这个字段。
验证此功能时,首先读取el12的值,目前读取为全0,以为出错了。但转念一想,因为此时Host在EL2,根本不会跑到EL1,那EL1的页表基地址确实就用不上了。Guest的ttbr0是ok的,多个vm的基地址也千差万别。此处先留个疑问吧。
2.1.2 关于寄存器读写工具
上述实验中的regtool为自写工具,如果没有类似工具的话,可以考虑写一个模块然后去读reg。具体操作就跟之前写的linux kernel单独编译某项驱动----网卡驱动_kernel-devel-CSDN博客单独编译某一驱动一样。
其中就俩文件:1)Makefile:
PWD = $(shell pwd)
KDIR ?= /lib/modules/$(shell uname -r)/build
obj-m += regRead.o #有时候MODNAME识别不了,则直接用原始名字即可
all:
make -C $(KDIR) M=$(PWD) src=$(PWD) modules #复制的话可能会使Tab变成空格,记得修改
clean:
make -C $(KDIR) M=$(PWD) src=$(PWD) clean
2)readReg.c
arm架构下关于reg的定义以及读写函数可见 linux-5.10/arch/arm64/include/asm/sysreg.h,写头文件时去掉include之前的路径即可。
然后以模块进行编译、装载、然后验证……
本来还想验证下第二个ttbr0_el12重定向的功能,奈何我司的机器上CPU显示这个寄存器不支持,估计是cpu设计的问题了。