购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

2.3 PRTOS Hypervisor

本书以PRTOS Hypervisor为例来介绍SKH的设计与实现机制。PRTOS并非“白手起家”的Hypervisor,而是站在巨人们的肩膀上发展起来的。它主要借鉴了一些经典开源软件项目,比如XtratuM、Xen Hypervisor、Lguest Hypervisor以及Linux内核等。正因为如此,PRTOS Hypervisor以GPLv2许可证的方式发布。此外,本书会详细介绍PRTOS的设计原理与实现技术,方便读者更好地阅读和理解PRTOS源码,也希望借此形成一个PRTOS开放社区,让更多人参与进来,促进PRTOS的健康演化,以形成对ARMv8、RISC-V架构的支持,并适配更多的分区应用。更多信息请参考https://github.com/prtos-project/prtos-hypervisor#readme。

PRTOS具备以下特点。

1)支持在分区环境中运行多个虚拟机,确保分区应用的时间和空间隔离。

2)支持在分区环境中运行裸机应用、RTOS(如μC/OS-Ⅱ,详情请参考第13章)以及GPOS(如Linux,详情请参考第14章)。

3)通过PRTOS Hypervisor,用户可以在单个硬件平台上同时运行不同类型的应用程序,并为分区应用提供实时性保证。


提示: 在本书中,PRTOS是PRTOS Hypervisor的简写。如果没有特别说明的话,PRTOS和PRTOS Hypervisor完全同义。


2.3.1 PRTOS Hypervisor的架构

PRTOS采用半虚拟化技术实现。半虚拟化技术需要客户操作系统显式地调用PRTOS提供的半虚拟化接口,没有经过修改的客户操作系统是不能在PRTOS分区上运行的,因此客户操作系统的源码必须是可以获得的。PRTOS Hypervisor的架构如图2-2所示。

图2-2 PRTOS Hypervisor的架构

PRTOS为分区提供虚拟化服务。PRTOS内核运行在处理器特权模式下,虚拟出CPU、内存、中断,以及一些特定的外围设备。

在图2-2中,PRTOS Hypervisor分成以下4个组成部分。

(1)硬件依赖层

硬件依赖层代表和硬件打交道的对象,包含一组PRTOS内核必需的硬件驱动,比如硬件时钟、页表、分区上下文切换、硬件定时器、处理器和中断。硬件依赖层通过硬件抽象层接口和PRTOS的其他层隔离。硬件依赖层隐藏了底层硬件的复杂性,为底层硬件提供了更高层的抽象。

(2)内部服务层

内部服务层提供内部支持服务,这些服务对分区是不可见的。这一层包含一个微型精简的内核C库KLIBC(Kernel C Library for PRTOS,用于PRTOS的内核C库)。KLIBC提供了一组严格定义的标准C函数(比如strcpy()、memcpy()、sprint()等),以及一系列辅助数据结构封装,包含常见的数据结构实现(比如链表、队列)与分区启动代码。

(3)虚拟化服务层

虚拟化服务层提供了用于支持虚拟化的服务,这些服务程序通过Hypercall API提供给分区使用。这些服务的子集也可以被PRTOS的其他子模块使用。例如,物理内存管理器负责为PRTOS内核和分区分配物理内存页表项。

分区服务层包含的组件如下。

1)分区管理:负责分区的创建、删除、挂起等以及PCT(Partition Control Table,分区控制表)的管理 。

2)分区间通信:PRTOS实现了一种消息通信模型,这种模型借鉴自ARINC653标准。

3)虚拟处理器调度:负责分区中的vCPU调度。PRTOS内核vCPU调度器采用循环表调度(Cyclic Table-Driven Schedule)策略。

4)中断管理:物理中断由PRTOS进行管理,根据中断的性质将其投递到不同的分区。PRTOS处理硬件中断和陷阱,也负责激发分区的虚拟中断和虚拟陷阱。

5)超级调用派发:派发分区发给PRTOS内核的超级调用,类似于传统操作系统中系统调用的派发流程。

6)虚拟时钟和虚拟定时器管理的介绍如下。

①虚拟时钟:为系统提供微秒级精度的时钟。另外,PRTOS为每个分区提供了两种类型的时钟:一种是分区本地时钟,只有在分区处于执行状态时才会运行;另一种是分区全局时钟,从PRTOS系统启动后就开始运行,与当前分区的执行状态无关。

②虚拟定时器:具有微秒级精度的定时器,基于虚拟时钟实现。该组件为每个分区提供了两种类型的定时器:一种是分区本地定时器,只有在分区处于执行状态时才会被激活;另一种是全局定时器,无论分区是否处于执行状态,全局定时器始终处于激活状态。

7)内存管理:包含虚拟内存管理和物理内存管理。

①虚拟内存管理:负责管理虚拟内存到物理内存的页面映射,可以创建/释放虚拟内存映射。

②物理内存管理:负责管理系统物理内存页,追踪每一个物理内存页的状态(比如类型、所有者等),为PRTOS内核和所有创建的分区分配物理内存。

8)虚拟设备管理:PRTOS通过虚拟控制台将物理串行通信设备模拟为多个虚拟串行设备,以供各个分区使用;其他的外围设备(包括各种传感器、执行器、网络接口等)通过系统配置表可以分配给任何一个分区,PRTOS保证分区独占分配给它的资源。

9)健康监控:监测系统或者分区的异常事件或者状态,并做出反应措施,在错误发生的早期阶段试图解决错误,或者将错误限定在发生故障的子系统,避免或者减少可能的损失。

10)跟踪管理:存储和检索分区和PRTOS内核产生的跟踪信息。跟踪管理用于在应用的开发阶段辅助调试,也可以用于在产品阶段记录相关事件的日志信息。

(4)超级调用接口函数库

PRTOS将提供给分区的超级调用服务封装在超级调用接口函数库(libprtos)中。libprtos库屏蔽了与超级系统调用相关的底层细节,使得开发人员可以使用更高级别的编程语言(C语言)直接调用库中提供的函数来请求超级调用服务,降低了分区应用开发的复杂性。

2.3.2 PRTOS对处理器的功能需求

什么样的处理器才能部署半虚拟化的Hypervisor呢?通常来说,满足以下6点的处理器就可以部署半虚拟化的Hypervisor。

1)处理器必须具有足够的处理能力,以满足用户的最坏执行时间(Worst-Case Execution Time,WCET)需求。

2)处理器具有控制I/O和内存资源的能力,以便Hypervisor可以接管所有硬件资源。

3)处理器具有定时器资源,以便实现分区虚拟定时服务。

4)处理器至少具有特权模式和用户模式这两种运行模式,使Hypervisor分区可以运行在用户模式下,Hypervisor内核运行在特权模式下,以便当分区执行非法指令时,处理器可以截获非法指令,并将控制权转移到运行在特权模式下的Hypervisor内核,由Hypervisor内核接管分区系统。

5)处理器提供具有原子操作的指令。原子操作指令是不可中断的指令。在单核CPU系统中,能够在一个指令中完成的操作都可以视作原子操作,因为中断只发生在指令之间;在多核CPU系统中,原子操作应确保即使多个处理器核心同时访问同一内存位置,操作也能保持一致性和正确性。这依赖于CPU的硬件实现,比如X86 CPU提供了HLOCK引脚,允许CPU在执行LOCK前缀指令时拉低HLOCK引脚的电位,直到这个指令执行完毕才放开,从而锁住了总线。这样,在同一总线的其他CPU就暂时无法通过总线访问内存了,保证了多核处理器的原子性。

6)处理器提供MMU机制(即页式内存管理机制),以便实现分区空间隔离。严格地说,CPU只要具有MPU硬件组件即可实现内存管理。

本书介绍的PRTOS选择的是满足上述条件的Intel X86处理器平台(支持Pentium架构)。之所以选择X86处理器,一方面是因为Intel所有的处理器都兼容32位X86指令集;另一方面很多优秀的虚拟平台(比如QEMU、VMware Workstation)对X86指令集的支持都非常完善,方便读者在这些平台上运行PRTOS系统,验证软件功能。

2.3.3 PRTOS Hypervisor的多核支持

为了更清楚地描述PRTOS Hypervisor对多核处理器的支持情况,这里再次解释一下3个专用名词。

1)pCPU:硬件平台中可以识别出的物理CPU。

2)vCPU:PRTOS Hypervisor提供给分区的虚拟处理器。

3)分区:PRTOS Hypervisor提供的运行时环境,并提供给分区一组vCPU,这些vCPU对应物理环境中的pCPU。在PRTOS的设计中,vCPU和pCPU是多对多( M N )的关系。但是从系统的实时性角度考虑,每个分区中定义的vCPU的数量不应该超过硬件平台中pCPU的数量。

PRTOS的目标是向分区提供vCPU,就像支持多核的操作系统在没有虚拟化层的情况下提供pCPU的情况一样。从这个角度来看,虚拟化层的工作如下。

1)将所有pCPU虚拟化并映射到vCPU,提供vCPU给分区使用。

2)PRTOS Hypervisor在初始化阶段初始化每个pCPU。

3)初始化阶段结束后,开始执行循环调度表策略。

4)初始化每个分区中标识为vCPU0的虚拟CPU。从分区的角度来看,提供给分区的vCPU可以是一个或多个。

5)在只含有一个vCPU的分区中使用vCPU0标识这个vCPU,如图2-3a所示。

①PRTOS Hypervisor负责启动vCPU0。

②通过PRTOS系统配置文件,vCPU0可以分配给任何pCPU。

6)在多核分区中,只有vCPU0由PRTOS Hypervisor初始化,如图2-3b所示。

①在分区中,由vCPU0负责初始化剩余所需启动的vCPU。

②通过PRTOS系统配置文件,所有的vCPU都可以分配给任何pCPU。

图2-3 PRTOS单核/多核分区方案

2.3.4 PRTOS的安全性和可预测性

1.安全性

PRTOS的安全性体现在虚拟机之间的通信信息流受到PRTOS的保护,以避免被未授权的虚拟机和计划外的行为所访问。安全性意味着必须定义一组元素和机制,用于实现系统的安全功能。这个功能与系统资源的静态分配以及用于识别和限定系统脆弱性的故障模型密切相关,具体来说包含以下3个方面。

(1)系统资源静态分配

系统架构师负责系统定义和分配资源。

①通过PRTOS的系统配置文件定义所有的系统资源,即CPU数目、内存布局、外围设备、每个CPU的执行策略等。每个虚拟机必须指明内存区域、通信端口、时间需求以及其他用于执行虚拟机代码所需要的资源。

②静态资源分配是系统可预测性和安全性的基石。嵌入式Hypervisor应保证虚拟机可以访问分配给它的资源,而拒绝访问没有分配给它的资源。

(2)故障隔离和管理

健壮系统的核心功能之一是故障管理。当故障发生的时候,必须能被PRTOS的健康监控子系统识别到,并做出合适的处理。这样做的目的是隔离故障,并阻止其传播,因此必须定义用于处理不同类型错误的故障模型。PRTOS负责实现这些故障管理模型,并允许虚拟机运行过程中发生的错误由虚拟机自行处理。

(3)分离栈空间设计

分区具有独立的栈,PRTOS内核也有独立的内核栈。libprtos库利用分区栈为调用PRTOS内核的服务程序准备参数。一旦超级调用服务程序被启用,PRTOS将栈空间从分区栈切换到内核栈。内核栈中可能存在敏感信息,但是由于内核栈是在PRTOS的内核空间中,因此分区应用程序没有权限访问其中的数据。

2.可预测性

PRTOS内核的确定性体现在PRTOS Hypervisor所有的执行序列都必须满足可预测性,即WCET具有明确的上限。可预测性预示着PRTOS提供的机制是可界定和可测量的。

1)应用程序执行PRTOS提供的相关服务时,PRTOS通过超级系统调用提供服务。这里的超级系统调用的开销必须是可预测的。

2)当PRTOS提供的服务程序涉及搜索服务时,搜索算法的设计必须是可界定的。创建资源相关的服务时可以通过搜索名字来获得,比如基于端口名来创建通信端口,这样就可以通过名字来实现便捷的搜索。另外,在PRTOS超级调用中,搜索的耗时需要是可界定的,这依赖于在配置文件中定义的资源的数目。需要特别指出的是,这些服务必须在分区应用初始化时使用,而在分区应用正常的执行流程中禁止使用。

3)PRTOS在分区间通信中涉及的数据传递应尽可能地利用硬件实现。在分区间通信的服务中,涉及数据传送相关的服务时,操作的耗时是常量时间,即服务调用时间与传送数据时间之和。

2.3.5 PRTOS系统的状态转换流程

理解PRTOS在运行过程中的状态信息,可以更好地理解PRTOS系统。PRTOS Hypervisor的状态信息可以分成3个层次:系统层、分区层、vCPU层。下面介绍这3个层次的状态转换流程。

1.PRTOS系统层的状态转换流程

PRTOS系统层的状态转换流程如图2-4所示。

图2-4 PRTOS系统层的状态转换流程

在启动状态,引导程序RSW加载PRTOS系统映像到主内存中,并将控制权转移到PRTOS Hypervisor的从入口点。从入口点开始到执行分区的第一条指令为止,我们称这段时间为启动状态。在这种状态下,调度程序未启用,分区也未执行。在引导序列的末尾,PRTOS Hypervisor准备执行分区代码,系统状态变为正常状态,调度计划启动。从启动状态到正常状态是自动执行的,不需要额外的条件去激发。

PRTOS Hypervisor可以通过运行健康监控子系统处理检测到的错误,触发重置事件—PRTOS_HM_AC_HYPERVISOR_COLD_RESET(冷重置)或者PRTOS_HM_AC_HYPERVISOR_WARM_RESET(热重置),从而进入停止状态。系统分区也可以通过超级系统调用服务prtos_halt_system()切换到停止状态。在停止状态下,PRTOS调度器和硬件中断被禁用,处理器进入一个无限循环。退出这种状态的唯一方法是通过外部硬件重置。

2.PRTOS分区层的状态转换流程

PRTOS Hypervisor一旦处于正常状态,就会进入分区层的状态转换流程,如图2-5所示。

PRTOS Hypervisor进入正常状态后,每个分区都处于启动状态。PRTOS必须准备好一个完整的分区环境,以便能够运行应用程序。注意:这里考虑的是分区代码由一个操作系统和一组应用程序组成的情况。

1)分区初始化是指设置标准的执行环境(即初始化一个正确的栈空间并设置虚拟处理器控制寄存器),创建通信端口、请求硬件设备(I/O端口和中断线)等。初始化分区后,系统将切换到分区正常模式。

2)分区从PRTOS接收之前执行状态的信息(如果这个信息存在)。

图2-5 PRTOS分区层的状态转换流程

从Hypervisor的角度来看,分区启动状态与正常状态之间没有区别。在这两种状态下,分区都根据固定的循环调度表进行调度,并且每个分区在调度器看来地位是等同的。尽管不是强制的,但建议分区从初始化状态转换成正常状态的时候主动发出一个分区状态更改事件,以使PRTOS可以感知到这种变化。

1)正常状态可以进一步分为3个子状态。

①就绪状态:指该分区已经准备好执行代码,但还没有被调度,因为当前时刻不在它的调度时间槽(Time Slot)内。

②运行状态:指该分区正在被处理器执行。

③空闲状态:如果分区不想在分配的时间槽内使用处理器,可以主动调用prtos_idle_self()函数来让渡处理器,并等待中断或下一个时间槽。分区可以自己停止,也可以由系统停止。在停止状态下,PRTOS内核调度器不选择该分区,分配给它的时间槽将处于空闲状态。

2)停止状态:指分配给该分区的所有资源都将被释放,因此该状态无法恢复到正常状态。

3)挂起状态:指分区将不会被调度,中断也不会被传递,中断将保持挂起状态。如果分区恢复到正常状态,则将挂起的中断传递给该分区。如果系统分区通过调用prtos_resume_partition()恢复该分区,则该分区可以返回到就绪状态。

3.PRTOS vCPU层的状态转换流程

从CPU的角度来看,PRTOS模拟了多核系统的行为。当系统启动时,CPU0首先启动,系统软件(操作系统)负责启动其余CPU。PRTOS为分区内的vCPU定义了相同的行为。当启动每个分区时,分区内的vCPU0首先运行。如果需要的话,每个分区vCPU0负责启动分区内的其他vCPU。vCPU是每个分区处理器资源的内部抽象,它只能被当前分区看到和处理。一个分区不能访问任何与其他分区vCPU相关的服务。

分区内的vCPU通过一组超级服务程序来控制各个状态的流转。vCPU层的状态转换流程如图2-6所示。

图2-6 PRTOS vCPU层的状态转换流程

分区启动时,分区内的每个vCPU都处于启动状态。分区负责初始化vCPU的状态,确保vCPU能够运行应用程序。通常来说,分区会设置一个标准的执行环境,比如初始化栈空间,并设置每个vCPU的控制寄存器。

从Hypervisor的角度来看,vCPU的启动状态与正常状态之间没有区别。在这两种状态下,分区都根据固定的循环调度表进行调度,并且在PRTOS的内核调度器看来,每个分区的vCPU的地位是等同的。

vCPU的正常状态同分区一样,也可以被细分为3个子状态。

1)就绪状态:指vCPU已经准备好执行代码,但没有被调度,因为当前时刻不在它的时间槽内。

2)运行状态:指该分区的vCPU正在被分配给该vCPU的处理器执行。

3)空闲状态:如果vCPU在分配的时间槽内不想占用处理器,可以调用prtos_idle_self()函数放弃处理器,并等待一个中断或下一个时间槽的到来。

当对目标分区调用分区管理服务程序时,会产生以下效果。

1)当重置分区时,将停止该分区的所有vCPU,分区从vCPU0重新启动。

2)当挂起分区时,将挂起该分区的所有vCPU。

3)当恢复分区时,该分区的所有vCPU将恢复到该分区挂起前的状态。

4)当停止分区时,将停止该分区下的所有vCPU。 kHyFeNghQfeGO3oJt06R1FDFsHT+D9KblYcKZlUcbSn4f+LwALqcFSJluxZ1y0kq

点击中间区域
呼出菜单
上一章
目录
下一章
×