QNX
最初是Gordon Bell
与Dan Dodge
两人在1980年代初期创建的一个实时微内核操作系统(RTOS(Real-Time Operating System
), 后来被黑莓(BlackBerry
)公司收购,因此也叫做Blackberry QNX
系统。QNX
被世人熟知还是因为其高安全性、QNX hypervisor
等特性在汽车领域的广泛应用。
这篇文章,我们就来看看QNX
虚拟化平台的基本架构与实现原理,着重会介绍虚拟化方案:
- 介绍
QNX
以及虚拟化平台的基本概念与架构 - 介绍QNX虚拟化的实现方法,包括
CPU
虚拟化,内存虚拟化,设备虚拟化等
QNX虚拟化平台的架构组成
QNX
系统是一个微内核(microkernel
)的类UNIX
的实时操作系统,支持x86/ARM/PowerPC/MIPS
等多个芯片架构,可以应用到从小型的嵌入式硬件到大型的分布式系统中。总结来说,主要有如下几个特点:
- 微内核的实时操作系统: 与Linux这样的宏内核(
Monolithic
)操作系统不同的是,QNX采用的微内核的实现。内核只实现了很少一部分功能,比如进程管理与进程通讯,进程同步与调度等,其他的如文件系统,设备驱动以及网络协议栈都在用户空间中实现。这么做一个明显的好处是,内核不会设备驱动或者网络协议栈等异常崩溃而卡死,从而提升了系统的稳定性与可用性;进程的上下文切换效率更高,因而实时性更好。 - 支持
POSIX
接口: 与大部分UNIX
的操作系统类似,QNX
支持POSIX
标准接口,这样其他很多比如在Linux
上写的程序就可以直接移植到QNX
上,减少了开发成本。 - 系统级别的HA(
High Availability
)框架:QNX
专门提供了一套高可用的开发框架,可以用于进程的快速恢复,确保系统业务功能的高可用性。 - 多个行业安全认证:
QNX
代码经过多个行业安全标准,如通信行业的FIPS 140-2
, 工控行业的IEC 61508
, 汽车电子领域的ISO 26262
等等,从代码级别上提升了系统的安全性。 - 支持多个硬件平台:支持市面上大部分
SoC
供应商如AMD
、Intel
、Nvidia
、NXP
、Qualcomm
的芯片
如上图所示,是QNX
系统的一个架构简图,可以看到,内核为所有进程通讯提供了一个软总线(software bus
),进程之间的通讯都是通过这条软总线传递消息。内核只是实现了诸如线程管理、消息传递、发送信号、中断处理、并发同步等功能,其他的如显示驱动,文件系统,网络协议栈、字符设备等统一在用户空间实现。
QNX
在原有系统上进行了虚拟化扩展,支持了hypervisor
功能;在hypervisor
的基础上,QVM
(QNX Virtual Machine
)支持运行如Linux
、Android
、QNX
等Guest
操作系统。目前常见的汽车座舱芯片如Renesas R-Car H3
, 高通820A
、8155
以及NXP i.MX 8
等都支持QNX
虚拟化方案。
下图是QNX
虚拟化平台的一个框架简图,每个运行的客户操作系统(Guest OS
)都对应个QVM
进程;客户操作系统可以通过虚拟设备或者pass-through
的方式访问控制硬件。实际上,对QNX
来说,客户操作系统并不一定运行在虚拟的环境,而是大部分时候都直接在物理CPU
上执行指令,只有当需要访问一些特权指令或者无法访问的内存时,hypervisor
才会介入,执行虚拟化相关的指令,让虚拟机退出。
以单个CPU
的执行流程为例,当hypervisor
陷入到虚拟化相关的指令后,首先会尝试保存当前虚拟机的上下文信息,此时虚拟机退出,由hypervisor
完成必要的工作后再恢复虚拟机的上下文,重新执行虚拟机被打断的流程(具体路程参考下图):
接下来我们就具体来看看QNX
是如何实现CPU
、内存、I/O
设备以及中断是如何处理的。
QNX虚拟化实现
CPU的虚拟化
虚拟机上的进程的调度实际是以虚拟CPU
(vCPU)为基础进行的,每个虚拟机在启动时,可以配置vCPU
的数量;vCPU
的调度是由在hypervisor
中的调度线程负责执行的。一个物理CPU
可能对应着多个vCPU
;类似的,一个vCPU
也可以选择在多个物理CPU
上电调度执行。需要注意的是,虚拟机中的线程优先级与宿主机中QNX
的线程优先级没有关系,具体何时执行哪个vCPU
完全是由hypervisor
中的调度线程的优先级决定的: 两个vCPU
竞争物理CPU
时,对应的hypervisor
调度线程的优先级更高的任务获得对应的物理CPU
执行权。
虚拟机的线程调度到物理CPU
的过程类似与普通操作系统中进程上下文切换的过程: 在虚拟机上需要保存当前线程的上下文信息,接着通过一个虚拟指令陷入(trap
, 这个跟Linux
下的系统调用从用户空间切换到内核空间的过程很类似)到hypervisor
中,然后由hypervisor
最终完成整个调度上下文的状态保存与切换。当一个客户虚拟机中发生如QNX
的中断,虚拟设备访问(不一定放弃CPU
的控制权),虚拟时钟到期等事件时,虚拟机就会让出当前CPU
的控制权。
内存虚拟化
QNX
中使用stage 2 translation
(二阶转换)来完成内存的虚拟化,虚拟机看到的物理内存
实际上是QNX
宿主系统管理的非连续虚拟内存而已:二阶内存转换就是在正常的VA->PA
之间增加一个地址转换过程IPA(Intermediate Physical Address)
,于是虚拟机的内存访问就变成了VA->IPA->PA
这样一个二阶段的过程。
- 阶段1的内存地址转换
VA->IPA
由虚拟机来控制完成 - 阶段2的内存地址转换
IPA->PA
由QNX
宿主机系统来完成
由于增加了中间地址的转换层IPA
,这样虚拟机与QNX
宿主机之间的内存空间就完全隔离了,虚拟机只能看到QNX
宿主机分配好的内存,无法访问其他虚拟机或者宿主机的内存空间。除此之外,QNX
还提供了额外的内存访问方式:
Pass-through memory
:直通内存允许虚拟机将某些设备直接映射到某个内存区域,然后直接访问这个物理设备;直通模式下的设备只有该虚拟机才能访问,在性能上比虚拟的设备会更高。有关直通设备的详细信息可以参考直通设备Shared Memory
: 共享内存允许不同虚拟机共享同一块物理内存,通过该内存区域进行数据交互
I/O设备虚拟化
在QNX
中,物理设备可以由宿主机或者虚拟机独占,也可以由虚拟机与宿主机之间共享。虚拟机要访问物理设备,可以通过直通或者虚拟化的方式实现:
Pass-through device
: 直通设备的访问完全由虚拟机控制,驱动也在虚拟机中实现, 而hypervisor
只是负责识别、传递来自设备的中断,传递来自虚拟机发送过来的信号。
Virtual Devices
: 虚拟设备vdev
可以是一个物理设备的模拟,也可以只是提供了一个类似物理设备功能的模拟设备。与直通设备类似,虚拟机要使用虚拟设备也需要提供驱动。目前QNX hypervisor
提供了两种形式的虚拟设备-一个是模拟(Emulation
)设备,一个是半虚拟化设备(para-virtualized
, 见下图)。QNX
中很多设备都是通过半虚拟化提供给虚拟机的,如输入设备、虚拟网卡都是通过半虚拟化方式virtio
实现的,后面我们会专门用一篇文章来分析下virtio
的虚拟化设备怎样的工作原理。
更多有关QNX
支持的虚拟设备的可以参考vdev references。
虚拟机的中断处理流程
每个中断都有一个中断号,如果设备需要处理中断,需要通过vdev
或者pass
直通的方式传递给虚拟机:
1 |
|
当一个中断发生时,如下图所示一般分为两种情况:
- 如果当前中断发生的
CPU
执行是虚拟机线程,则首先虚拟机的线程退出,将中断丢给hypervisor
处理,并切换到宿主机,由QNX
判断该中断属于虚拟机还是宿主机:如果中断属于宿主机QNX
,则由其处理中断即可;如果是属于虚拟机的中断,则需要通过hypervisor
发送一个中断信号给虚拟机,然后交由虚拟机处理 - 如果当前中断发生的
CPU
执行的是宿主机QNX
线程,QNX
判断是虚拟机的线程则按照前述的步骤交由虚拟机处理。
参考资料
- QNX 系统资料
- QNX hypervisor
- ARM virtualization文档
- hardware and software support for virtualization(Edouard Bugnion, Jason Nieh, and Dan Tsafrir)