24
社区成员
发帖
与我相关
我的任务
分享原文:Virtualization: Jailhouse Hypervisor on AM572x Reference Design,TI Designs TIDEP-0095,文档号 TIDUDF8A,2017 年 10 月(含 A 版修订)
这份 2017 年的 TI 官方参考设计,今天读起来依然有分量,原因有三:
工业嵌入式系统正面临一个两难:
TI 在文档里把 Linux 的短板说得非常直白:
「然而,尽管 Linux 千好万好,即便打了实时(RT)补丁,Linux 也可能无法满足『切换 IO 引脚、以纳秒计数』这类实时约束。」
注意这句话的分量:它不是否定 RT Linux,而是划出了 RT Linux 的能力边界——对于真正硬实时的场合,需要把确定性的 RTOS 或裸机控制循环隔离出来与 Linux 并存。
TI 没有一上来就吹 Jailhouse,而是逐个比较了四条技术路线:
| 方案 | TI 的评价 |
|---|---|
| 分立器件(实时一颗芯片、Linux 一颗芯片) | 可行,但集成到单 SoC 有尺寸、通信延迟、成本三重优势 |
| 用 AM5728 的 Cortex-M4 / C66x DSP 核跑实时 | 某些场景比虚拟化一个 A15 核更高效——取决于应用与未来功能演进 |
| RT Linux + CPU 亲和性(实时线程绑到第二个 A15 核) | 缺点是最坏情况中断延迟比 RTOS 或静态 hypervisor 方案高一个数量级 |
| Jailhouse 静态分区 | 本文的主角 |
这段论证的精彩之处在于它点出了嵌入式虚拟化的目的差异:
「某种意义上这比传统虚拟化更简单——传统虚拟化往往有隔离之外的目标,比如把多个 guest OS 整合到单个处理器核上,或 guest 的在线迁移。在嵌入式系统中,这些用例要么不存在,要么相比满足实时性能只是次要价值。」
划重点:嵌入式要的是「隔离」,不是「整合」与「迁移」。 这句话可以直接搬进论文引言的动机部分。
TI 交付的不是一个 demo,而是一套可复现的参考设计:
vmalloc 扩容方案:32 位平台上连续虚拟内存不够用的坑与解法一句话:Jailhouse 是一个基于 Linux 加载的静态分区(static partitioning)hypervisor,能让裸机程序或(经过适配的)操作系统与 Linux 并肩运行。
四个必须记住的特征:
Jailhouse 由三部分构成,理解它们的分工是上手的起点:
| 组件 | 作用 |
|---|---|
| 内核模块(kernel module) | 在 Linux 侧运行,负责把 hypervisor 装入内存、提供管理接口 |
| Hypervisor 固件(firmware) | 真正的分区管理者,激活后裸机运行于 EL2/HYP |
| 工具集(tools) | jailhouse 命令行工具:启用 hypervisor、创建 cell、加载 inmate 二进制、启动与停止 |
这是全文最值得背下来的一段流程,它解释了「Linux 如何把自己降级」:
jailhouse enable 后,hypervisor 接管,Linux 被移入 root cell——注意此刻 root cell 仍然使用两个核cpu_down(),把核关掉留给新 cell——此时 Linux 只剩核 0在 AM5728 上,通常只建两个 cell:
资源归属的设计原则(原文明确给出):
「一个好的通用原则是:让 inmate 拥有的外设数量和资源量尽可能小。这样划分,既是为了管理满足实时性的复杂度,也是为了通过复用现有且持续维护的 Linux 驱动来最小化软件工程工作量。」
这条原则在工程上极重要——它意味着 inmate 越「瘦」,你的维护成本越低。
具体的资源归属建议:
这是 ARM 平台 Jailhouse 移植的核心动作,原文给出完整示例:
/* 追加到 Linux 使用的设备树,am57xx-evm-reva3.dts 是 GP EVM 的设备树 */
#include "am57xx-evm-reva3.dts"
/ {
reserved-memory {
/* 为 hypervisor 特权软件预留物理内存,16MB (0x1000000) */
jailhouse: jailhouse@ef000000 {
reg = <0x0 0xef000000 0x0 0x1000000>;
no-map;
status = "okay";
};
/* 为 inmate 软件预留物理内存 */
jh_inmate: jh_inmate@ee000000 {
reg = <0x0 0xe0000000 0x0 0xf000000>;
no-map;
status = "okay";
};
};
};
/* 把 timer8 分配给 inmate,但允许 Linux 为它配置时钟 */
&timer8 {
status = "disabled";
ti,no-idle;
};
/* 把 uart9 分配给 inmate,但允许 Linux 为它配置时钟 */
&uart9 {
status = "disabled";
ti,no-idle;
};
/* 配置中断交叉开关,使上述设备相关的中断不被 Linux 使用。
AM5728 上的 Linux 动态管理中断交叉开关,而我们要把这些中断静态分配给 inmate */
/ {
ocp {
crossbar_mpu: crossbar@4a002a48 {
ti,irqs-skip = <10 133 134 135 139 140>;
};
};
};
逐项拆解,这是本节最有移植参考价值的部分:
reserved-memory 节点:为 hypervisor 留 16MB(0xef000000,长度 0x1000000)、为 inmate 留 240MB(0xe0000000,长度 0xf000000)。no-map 是关键——告诉 Linux 内核不要在页表里建立映射,防止内核碰这块内存status = "disabled"**:让 Linux 不驱动这个外设(不占用、不初始化中断)ti,no-idle:但时钟仍由 Linux 配置——这是一个精妙的折中:Linux 先完成时钟树初始化,再把设备让给 inmate。若不写这句,inmate 拿到的可能是个没时钟的死外设ti,irqs-skip:AM5728 的中断路由是动态管理的,这份配置把属于 inmate 的中断(10、133、134、135、139、140)从 Linux 的动态管理中排除出去,实现静态归属内存账本:240MB 给 inmate + 16MB 给 hypervisor,其中 hypervisor 的那 16MB 主要用于存放第二阶段虚拟地址转换页表。
而 .cell 文件,就是描述 root cell 与各 inmate 所获内存和外设的编译产物。
原文 2.4.2 节回答了一个实际问题:外设能不能两边都用?
一句话总结:谁来管硬件,取决于谁的性能要求更苛刻。
这是两个实验里技术含量最高的一处细节,做 RTOS inmate 移植一定会遇到:
0x80000000(AM572x DDR 起始地址),但 Jailhouse 却把程序加载到 IPA 空间的 0x0linux-loader.bin——linux-loader.bin 自己被加载到 0x00x80005128)的指令0x100 处的字符串传给它对应的加载命令是这样的(注意 -a 指定地址、-s 传字符串):
root@am57xx-evm:~# modprobe jailhouse
root@am57xx-evm:~# jailhouse enable /usr/share/jailhouse/examples/am57xx-evm.cell
root@am57xx-evm:~# jailhouse cell create /usr/share/jailhouse/examples/am572x-rtos-pruss.cell
root@am57xx-evm:~# jailhouse cell load 1 linux-loader.bin -a 0 -s "kernel=0x80005128" \
-a 0x100 pruss.bin -a 0x80000000
root@am57xx-evm:~# jailhouse cell start 1
这个坑的通用性:任何「按物理地址链接的 RTOS 或裸机镜像」迁到 Jailhouse 下,都可能需要类似的地址重定位处理。记住 IPA 这个概念,能省你很多调试时间。
另外,RTOS 侧还需要移除 UART、GIC 的初始化代码与 IO 延时——因为这些在 Jailhouse 场景下已由 Linux 完成。TI 把改动后的配置文件与板级初始化文件都放在了 SDK 里对比。
| 指标 | Linux 空载(core 0) | Linux 跑 STREAM(core 0) |
|---|---|---|
| 落在 1.6–3.2 µs 桶 | 99.3756% | 33.9323% |
| 落在 3.2–6.4 µs 桶 | 0.6244% | 66.0632% |
| 落在 6.4–12.8 µs 桶 | 无 | 0.0045% |
| 最小中断延迟 | 2.2(µs) | 1.8(µs) |
| 最大中断延迟 | 5(µs) | 8.8(µs) |
原文给出了三条关键判断,值得逐条记住:
① 轮询驱动的 inmate,性能与无虚拟化系统完全相同
「在 Jailhouse 这样的静态分区系统中,基于轮询模式驱动的 inmate 应用性能,应当与无虚拟化系统完全一致。」
这是 Jailhouse 相对其他 hypervisor 的核心优势——静态分区 + 无调度,意味着延迟路径上几乎不存在 hypervisor 干预。如果你的实时任务能用轮询(polling)而非中断驱动,那虚拟化几乎零代价。
② 只要用中断,就要共享 GIC,就必然引入干扰
「任何基于中断的东西,都必须共享中断控制器(GIC),这会引入从 Linux 到实时应用的一定干扰。」
这就是上表两组数据差异的根源——干扰不来自 hypervisor 的调度,而来自共享的硬件资源。这也是为什么 Jailhouse 文档反复强调「inmate 拥有的资源越少越好」。
③ 最坏情况上界:8.8 µs
百万次中断下,最坏情况 8.8 µs。对多数工业实时场景,这个量级是可接受的——对照一下文档开头的论断:RT Linux 方案的最坏中断延迟比这高一个数量级。
reserved-memory(含 no-map)+ status="disabled" 与 ti,no-idle 的组合 + 中断控制器的静态排除配置——这是 ARM 平台 Jailhouse 移植的标准动作,不同 SoC 上细节不同但骨架一致。| 坑 | 现象 | 解法 |
|---|---|---|
| 32 位平台 vmalloc 不足 | 启动后 enable hypervisor 失败 | 在 U-Boot 里 vmalloc=512M(AM5728 默认 240M 不够静态分配 16MB+16MB) |
| inmate 看到的是 IPA 不是物理地址 | RTOS 镜像按物理地址链接,加载后跑飞 | 用 linux-loader.bin 跳板(或自行实现等价重定位) |
| 外设时钟没配 | inmate 拿到外设但不工作 | 设备树里保留 ti,no-idle,让 Linux 先把时钟配好 |
这两句是回答「为什么不用 RT Linux」「为什么需要静态分区 hypervisor」的标准答案,比我们自己组织措辞更权威。
TI 在文档里明确列出了这份参考设计面向的应用,这份清单本身就是「产业需求真实性」的证据:
对国内做电力、工控方向的同行,这份清单可以直接对照自己的产品线评估适用性。
把这份 AM572x 的经验映射到 Zynq UltraScale+ 上,需要注意的差异:
reserved-memory 与 no-map、外设 status="disabled"、中断静态排除——骨架一致,具体节点的名字与中断号需要按 ZynqMP 的平台文档重写这份文档最可贵的地方,是它同时给了「为什么」和「要多少」:
对正在做 Jailhouse 移植或实时性研究的同学,这份文档的价值排序建议是:先读第 3 节(设备树三件套 + IPA 坑)→ 再读第 4 节(压测方法)→ 最后回头看第 2 节的选型论证。前两节直接决定你的工程能否跑通,后一节决定你的论文引言能否写透。
原文 Table 1 中「Minimum / Maximum interrupt latency」两行的单位标为 ms(2.2 ms / 5 ms / 8.8 ms),但结合该表三个分桶均为 µs 级(1.6–3.2 µs、3.2–6.4 µs、6.4–12.8 µs),且正文论述始终以微秒为尺度,此处应为 µs 之误,本文表格已按 µs 修正标注。
(这类印刷错误不影响结论,但引用时要注意别把 8.8 µs 写成 8.8 ms——那就从一个「优秀」的数字变成一个「灾难」的数字了。)
第 2.4.1 节设备树注释写「reserve physical memory for the inmate SW, 256MB」,但正文明确说明 inmate 划分到的是 240MB,且代码中 inmate 节点长度为 0xf000000 = 251,658,240 字节 = 240 MiB——因此代码注释里的「256MB」为笔误,以正文与地址长度为准。
原文获取:TI 官网搜索文档号 TIDUDF8A,或参考设计编号 TIDEP-0095。