时间:2020-08-31来源:www.pcxitongcheng.com作者:电脑系统城
Read the fucking source code!
--By 鲁迅A picture is worth a thousand words.
--By 高尔基说明:
Hypervisor
软件,涵盖的功能包括:内存管理、设备模拟、设备分配、异常处理、指令捕获、虚拟异常管理、中断控制器管理、调度、上下文切换、内存转换、多个虚拟地址空间管理等;arch/arm64/kvm
下的代码很重要,脱离硬件去看Architecture-Specific代码,那是耍流氓;开始旅程!
USR, FIQ, IRQ, SVC, ABT, UND, SYS, HYP, MON
等,各个异常模式所处的特权级不一样,比如USR
模式的特权级就为PL0
,对应为用户态程序运行;CPSR
寄存器,也可以被动进行异常模式切换,典型的比如中断来临时切换到IRQ模式
;ARMv7处理器的异常模式如下表所示:
然鹅,到了ARMv8,Exception Level(EL)
取代了特权级,其中处理器的异常模式与Exception Level
的映射关系如下图:
Exception Level
(相当于ARMv7中的处理器模式切换),来处理异常类型;Hypervisor
运行在EL2
,而Guest OS
运行在EL1
,可以通过HVC (Hypervisor Call)
指令向Hypervisor
请求服务,响应虚拟化请求时就涉及到了Exception Level
的切换;Stage 2转换
与内存虚拟化息息相关,这部分内容不仅包括常规的内存映射访问,还包含了基于内存映射的I/O(MMIO
)访问,以及系统内存管理单元(SMMUs
)控制下的内存访问。
OS在访问物理内存前,需要先建立页表来维护虚拟地址到物理地址的映射关系,看过之前内存管理分析的同学应该熟悉下边这张图,这个可以认为是Stage 1转换
:
Guest OS
所认为自己访问的物理地址,其实是Linux的用户进程虚拟地址,到最终的物理地址还需要进一步的映射;Hypervisor
可以通过Stage 2转换
来控制虚拟机的内存视图,控制虚拟机是否可以访问某块物理内存,进而达到隔离的目的;整个地址的映射分成了两个阶段:
Stage 1: VA(Virutal Address) -> IPA(Intermediate Physical Address)
,操作系统控制Stage 1转换
;Stage 2: IPA(Intermediate Physical Address) -> PA(Physical Address)
,Hypervisor
控制Stage 2转换
;Stage 2转换
与Stage 1
转换机制很类似,不同点在于Stage 2转换
时判断内存类型是normal还是device时,是存放进页表信息里了,而不是通过MAIR_ELx
寄存器来判断;
每个虚拟机(VM,Virtual Machine)都会分配一个VMID
,用于标识TLB entry
所属的VM,允许在TLB中同时存在多个不同VM的转换;
操作系统会给应用程序分配一个ASID(Address Space Identifier)
,也可以用于标识TLB entry
,属于同一个应用程序的TLB entry
都有相同的ASID
,不同的应用程序可以共享同一块TLB缓存
。每个VM都有自己的ASID
空间,通常会结合VMID
和ASID
来同时使用;
Stage 1
和Stage 2
的转换页表中,都包含了属性的相关设备,比如访问权限,存储类型等,在两级转换的过程中,MMU
会整合成一个最终的也有效值,选择限制更严格的属性,如下图:
Device
属性限制更严格,则选择Device
类型;Hypervisor
如果想要改变默认整合行为,可以通过寄存器HCR_EL2(Hypervisor Configuration Register)
来配置,比如设置Non-cacheable
, Write-Back Cacheable
等特性;MMIO(Memory-Mapped Input/Output)
Guest OS
认为的物理地址空间,实际是IPA
地址空间,就像真实物理机中一样,IPA
的地址空间,也分成内存地址空间和I/O
地址空间:
fault
,Hypervisor
通过软件来模拟;VTTBR_EL2
:Virtualization Translation Table Base Register
,虚拟转换表基地址寄存器,存放Stage 2转换
的页表;Hypervisor
需要知道访问的是哪个外设以及访问的寄存器,读访问还是写访问,访问长度是多少,使用哪些寄存器来传送数据等。Stage 2转换
有一个专门的Hypervisor IPA Fault Address Register, EL2(HPFAR_EL2)
寄存器,用于捕获Stage 2转换
过程中的fault;软件模拟外设的示例流程如下:
Stage 2转换
被block住,并触发abort异常路由到EL2
。异常处理程序查询ESR_EL2(Exception Syndrome Register)
寄存器关于异常的信息,如访问长度、目标寄存器,Load/Store操作等,异常处理程序还会查询HPFAR_EL2
寄存器,获取abort的IPA地址;Hypervisor
通过ESR_EL2
和HPFAR_EL2
里的相关信息对相关虚拟外围设备进行模拟,完成后通过ERET
指令返回给vCPU
,从发生异常的下一条指令继续运行;SMMUs(System Memory Management Units)
访问内存的另外一种case就是DMA控制器。
非虚拟化下DMA控制器的工作情况如下:
虚拟化下DMA控制器,VM中的驱动直接与DMA控制器交互会出现什么问题呢?如下图:
Stage 2转换
的约束,会破坏VM的隔离性;SMMUs
可以用于解决这个问题:
SMMU
也叫IOMMU
,对IO部件提供MMU功能,虚拟化只是SMMU的一个应用;Hypervisor
可以负责对SMMU
进行编程,以便让上层的控制器和虚拟机VM以同一个视角对待内存,同时也保持了隔离性;Hypervisor
也需要具备捕获(trap
)和模拟指令的能力,比如当VM中的软件需要配置底层处理器来进行功耗管理或者缓存一致性操作时,为了不破坏隔离性,Hypervisor
就需要捕获操作并进行模拟,以便不影响其他的VM。如果设置了捕获某个操作时,当该操作被执行时会向更高一级的Exception Level
触发异常(比如Hypervisor
为EL2),从而在相应的异常处理中完成模拟。
例子来了:
WFI(wait for interrupt)
命令,可以让CPU处于一个低功耗的状态;HCR_EL2(Hypervisor Control Register)
,当该寄存器的TWI==1
时,vCPU执行WFI
指令会触发EL2异常,从而Hypervisor
可以对其进行模拟,将任务调度到另外一个vCPU即可;捕获(traps
)的另一个作用是可以用于向Guest OS呈现寄存器的虚拟值,如下:
ID_AA64MMFR0_EL1
寄存器用于查询处理器对内存系统相关特性的支持,系统可能在启动阶段会读取该寄存器,Hypervisor
可以向Guest OS呈现一个不同的虚拟值;Hypervisor
在trap_handler
中进行处理,设置一个虚拟值,并最终返回给vCPU;trap
来虚拟化一个操作需要大量的计算,包括触发异常、捕获,模拟、返回等一系列操作,像ID_AA64MMFR0_EL1
寄存器访问并不频繁,这种方式问题不大。但是当需要频繁访问的寄存器,比如MIDR_EL1
和MPIDR_EL1
等,出于性能的考虑,应该避免陷入到Hypervisor
中进行模拟处理,可以通过其他机制,比如提供VPIDR_EL2
和VMIDR_EL2
寄存器,在进入VM前就设置好该值,当读取MIDR_EL1
和MPIDR_EL1
时,硬件就返回VPIDR_EL2
和VMIDR_EL2
的值,避免了陷入处理;Hypervisor
对虚拟中断的处理比较复杂,Hypervisor
本身需要机制来在EL2处理中断,还需要机制来将外设的中断信号发送到目标虚拟机VM(或vCPU)上,为了使能这些机制,ARM体系架构包含了对虚拟中断的支持(vIRQs,vFIQs,vSErrors);Hypervisor
通过设置HCR_EL2
寄存器来控制向EL0/EL1发送虚拟中断,比如为了使能vIRQ,需要设置HCR_EL2.IMO
,设置后便会将物理中断发送至EL2,然后使能将虚拟中断发送至EL1;有两种方式可以产生虚拟中断:1)在处理器内部控制HCR_EL2
寄存器;2)通过GIC中断控制器(v2版本以上);其中方式一使用比较简单,但是它只提供了产生中断的方式,需要Hypervisor
来模拟VM中的中断控制器,通过捕获然后模拟的方式,会带来overhead,当然不是一个最优解。
让我们来看看GIC
吧,看过之前中断子系统系列文章的同学,应该见过下图:
Hypervisor
可以将GIC中的Virtual CPU Interface
映射到VM中,从而允许VM中的软件直接与GIC进行通信,Hypervisor
只需要进行配置即可,这样可以减少虚拟中断的overhead;来个虚拟中断的例子吧:
IRQ
或者FIQ
信号,如果设置了HCR_EL2.IMO/FMO
,中断信号将被路由到Hypervisor
,Hypervisor
会检查中断信号转发给哪个vCPU
;Hypervisor
设置GIC,将该物理中断信号以虚拟中断的形式发送给某个vCPU
,如果此时处理器运行在EL2,中断信号会被忽略;Hypervisor
将控制权返回给vCPU
;PSTATE
中的比特位来控制(比如PSTATE.I
),虚拟化时比特位的作用有些不一样,比如设置HCR_EL2.IMO
时,表明物理IRQ路由到EL2,并且对EL0/EL1开启vIRQs
,因此,当运行在EL0/EL1时,PSTATE.I
比特位针对的是虚拟vIRQs
而不是物理的pIRQs
。先来看一下SoC的内部:
简化之后是这样的:
Comparators
和Counter Module
,当Comparators
的值小于等于系统的count值时便会产生中断,我们都知道在操作系统中timer
的中断就是系统的脉搏了;下图展示虚拟化系统中运行的vCPU
的时序:
vCPU
运行2ms,如果设置vCPU0
在T=0
之后的3ms后产生中断,那希望是物理时间的3ms后(也就是vCPU0
的虚拟时间2ms)产生中断,还是虚拟时间3ms后产生中断?ARM体系结构支持这两种设置;vCPU
上的软件可以同时访问两种时钟:EL1物理时钟
和EL1虚拟时钟
;EL1物理时钟
和EL1虚拟时钟
:
EL1物理时钟
与系统计数器模块直接比较,使用的是wall-clock
时间;EL1虚拟时钟
与虚拟计数器比较,而虚拟计数器是在物理计数器上减去一个偏移;Hypervisor
负责为当前调度运行的vCPU
指定对应的偏移,这种方式使得虚拟时间只会覆盖vCPU
实际运行的那部分时间;来一张示例图:
vCPU
运行3ms,Hypervisor
可以使用偏移寄存器来将vCPU
的时间调整为其实际的运行时间;Host OS
的内核都运行在EL1,而控制虚拟化的代码运行在EL2,这就意味着传统的上下文切换,这个显然是比较低效的;VHE
用于支持type-2
的Hypervisor
,这种扩展可以让内核直接跑在EL2,减少host和guest之间共享的系统寄存器数量,同时也减少虚拟化的overhead;VHE
由系统寄存器HCR_EL2
的E2H
和TGE
两个比特位来控制,如下图:
VHE
的引入,需要考虑虚拟地址空间的问题,如下图:
EL0
)和内核地址空间(EL1
),两者的区域不一致,而在EL2
只有一个虚拟地址空间区域,这是因为Hypervisor
不支持应用程序,因此也就不需要分成内核空间和用户空间了;EL0/EL1
虚拟地址空间也同时支持ASID(Address Space Identifiers)
,而EL2
不支持,原因也是Hypervisor
不需要支持应用程序;从上两点可以看出,为了支持Host OS
能运行在EL2
,需要添加一个地址空间区域,以及支持ASID
,设置HCR_EL2.E2H
的寄存器位可以解决这个问题,如下图:
Host OS
运行在EL2
需要解决的另一个问题就是寄存器访问重定向,在内核中需要访问EL1
的寄存器,比如TTBR0_EL1
,而当内核运行在EL2
时,不需要修改内核代码,可以通过寄存器的设置来控制访问流,如下图:
Hypervisor
在某些情况下需要访问真正的EL1
寄存器,ARM架构引入了一套新的别名机制,以_EL12/_EL02
结尾,如下图,可以在ECH==1
的EL2
访问TTBR0_EL1
:Host OS
运行在EL2
还需要考虑异常处理的问题,前边提到过HCR_EL2.IMO/FMO/AMO
的比特位可以用来控制物理异常路由到EL1/EL2
。当运行在EL0
且TGE==1
时,所有物理异常都会被路由到EL2
(除了SCR_EL3控制的),这是因为Host Apps
运行在EL0
,而Host OS
运行在EL2
。
trap and emulation
等内容;EL2
去处理,如果有硬件支持的则硬件负责处理,否则可以通过软件进行模拟;《ArmV8-A virtualization.pdf》
《vm-support-ARM-may6-2019.pdf》
《aarch64_virtualization_100942_0100_en.pdf》
《ARM Cortex-A Series Programmer's Guide for ARMv8-A》
2024-07-18
Centos 7 二进制安装配置 MariaDB数据库2024-07-18
Centos7默认firewalld防火墙使用命令大全2024-07-07
四种执行python系统命令的方法常用权限linux系统内有档案有三种身份 u:拥有者 g:群组 o:其他人这些身份对于文档常用的有下面权限:r:读权限,用户可以读取文档的内容,如用cat,more查看w:写权限,用户可以编辑文档x...
2024-07-07
然而,如果我们遵循通常的 WordPress 最佳实践,这些安全问题可以避免。在本篇中,我们会向你展示如何使用 WPSeku,一个 Linux 中的 WordPress 漏洞扫描器,它可以被用来找出你安装...
2024-07-03