欢迎光临
我们一直在努力

高通Gunyah Hypervisor 深度拆解(1): 从设备树定位 Gunyah Hypervisor 的内存布局

💡前言

如果手边有一台高通设备,没有内核源码,又想知道 Gunyah Hypervisor 到底占了多少内存、管理着哪些 VM、VM 之间怎么通信。那么用 adb 黑盒手段试试能摸到什么:

  • 从设备中提取 DTB 并反编译为完整 DTS,全文搜索 Gunyah 相关节点
  • 从 reserved-memory 和 guestvm_loader 节点定位所有 VM 的内存布局和 VMID
  • 用 /proc/iomem 和 dmesg 交叉验证

背景

Gunyah 是高通自研的 Type-1 Hypervisor,运行在 ARMv9 的 EL2,比 Linux 内核 (EL1) 更高特权。它在内核启动之前就已经占据了 EL2,并通过修改 DTB(Device Tree Blob) 的 reserved-memory 节点,告知 Linux 哪些物理内存区域不可触碰。Linux 解析设备树后会主动避开这些区域。

设备树就是切入点。本文以骁龙SM8450平台为例,层层拨开迷雾吧。

一、确认平台

adb devices List of devices attached 442daf63 device

adb shell “getprop ro.board.platform; getprop ro.build.type” taro userdebug

taro 是骁龙 SM8450 平台的内部代号。userdebug 构建可以通过 su 获取 root。

二、提取并反编译设备树

先 adb root,不然 adb pull 会因为 DAC 权限不足报 Permission denied:

adb root restarting adbd as root

adb pull /sys/firmware/fdt sm8450_live.dtb /sys/firmware/fdt: 1 file pulled, 0 skipped. 11.0 MB/s (746676 bytes in 0.065s)

746 KB 完整 DTB。用 dtc 反编译:

dtc -I dtb -O dts -o sm8450_live.dts sm8450_live.dtb

dtc 没装的话:sudo apt install device-tree-compiler。

拿到约 30000 行的 DTS,直接 grep 搜 Gunyah 相关节点:

grep -ni “gunyah|hyp_|guestvm|mem-buf|mem-offline” sm8450_live.dts

命中的节点(按功能分组):

类别节点路径作用
Hyperviso 声明 /hypervisor Gunyah Hypervisor 1.0 主节点
预留内存 /reserved-memory/hyp_region@80000000 Hypervisor 代码/数据
预留内存 /reserved-memory/hyp_reserved_region@e0a00000 Hypervisor 附加预留
VM 加载 /soc/qcom,guestvm_loader@e0b00000 Trusted UI VM 加载器
VM 加载 /soc/qcom,guestvm_loader@e0600000 CPUSYS VM 加载器
跨 VM 通信 /soc/qrtr-gunyah QRTR over Gunyah
跨 VM 通信 /soc/gunyah-vsock vsock over Gunyah
内存共享 /soc/qcom,mem-buf 动态内存供给(HLOS 为 supplier)
Virtio 后端 /soc/qcom,virtio_backend@0 块设备透传给 Trust UI VM
CPU 调度 /soc/qcom,hyp-core-ctl Hypervisor 核心调度控制
内存热插拔 /mem-offline 运行时内存回收,4 MB 粒度

DTS 全文搜索比逐节点 ls /proc/device-tree/ 高效得多 — guestvm_loader、qrtr-gunyah、mem-buf、virtio_backend 这些散落在 /soc 下的节点,光靠目录遍历很难发现。

三、读取 hypervisor 节点

根目录下直接有个 hypervisor 节点,展开看看里面有什么:

adb shell “ls -R /proc/device-tree/hypervisor/” /proc/device-tree/hypervisor: compatible name qcom,gh-watchdog qcom,gunyah-vm qcom,resource-manager-rpc@ca6f43103373c01c

/proc/device-tree/hypervisor/qcom,gunyah-vm: compatible name qcom,vendor qcom,vmid

/proc/device-tree/hypervisor/qcom,resource-manager-rpc@ca6f43103373c01c: compatible interrupts name qcom,free-irq-start qcom,rx-message-size qcom,rx-queue-depth qcom,tx-message-size qcom,tx-queue-depth reg

三个子节点:Watchdog、VM 身份、Resource Manager RPC 通道。直接从 DTS 里看完整定义:

// DTS: /hypervisor
hypervisor {
compatible = "qcom,gunyah-hypervisor-1.0", "qcom,gunyah-hypervisor", "simple-bus";

qcom,gunyah-vm {
compatible = "qcom,gunyah-vm-id-1.0", "qcom,gunyah-vm-id";
qcom,vmid = <0x03>;
qcom,vendor = "Qualcomm";
};
qcom,gh-watchdog {
compatible = "qcom,gh-watchdog";
interrupts = <0x00 0x00 0x01>; // GIC SPI 0,Hypervisor 级看门狗
};
qcom,resource-manager-rpc@ca6f43103373c01c {
compatible = "qcom,resource-manager-1-0", "qcom,resource-manager",
"qcom,gunyah-message-queue", "qcom,gunyah-capability";
reg = <0xca6f4310 0x3373c01c 0xca6f4310 0x33737e8e>; // TX/RX capability ID
interrupts = <0x00 0x03a0 0x01 0x00 0x03a1 0x01>; // GIC SPI 928/929
qcom,is-full-duplex;

};
};

“VMID = 3” 即当前 Android 所在的 HLOS。不是 0 或 1,说明 Gunyah 在 Linux 启动前已经创建了更高优先级的 VM。

Resource Manager RPC 通道

reg 中两个 64-bit 值是 Gunyah capability ID,分别对应 TX/RX 消息队列。RM-RPC 底层基于 Gunyah Message Queue,通过 Capability(能力令牌)做权限控制。

消息队列配置(xxd 输出省略重复格式):

参数原始值解析
tx-message-size 0x00F0 240 字节
rx-message-size 0x00F0 240 字节
tx/rx-queue-depth 0x0008 各 8 条
free-irq-start 0x03C0 IRQ 960 起
interrupts 0x03A0, 0x03A1 GIC SPI 928 (TX), 929 (RX)
is-full-duplex 存在 TX/RX 同时工作,不需要半双工仲裁

DTS 中还能看到 qcom,gh-watchdog 子节点,中断号 GIC SPI 0 即 Hypervisor 级别的看门狗,用于检测 VM 挂死。

四、Guest VM 加载器与跨 VM 通信

Guest VM 加载器

// DTS 节点(简化格式)
qcom,guestvm_loader@e0b00000 {
compatible = "qcom,guestvm-loader";
qcom,pas-id = <0x1c>; // PAS ID 28
qcom,vmid = <0x2d>; // VMID 45 → Trusted UI VM
qcom,firmware-name = "trustedvm";
qcom,isolate-cpus; // 启动时隔离 CPU
qcom,reserved-cpus = <5 6>; // 独占 CPU 5、6
qcom,unisolate-timeout-ms = <12000>; // 12 秒后释放 CPU
memory-region = <&trust_ui_vm_region>;
};

qcom,guestvm_loader@e0600000 {
compatible = "qcom,guestvm-loader";
qcom,pas-id = <0x23>; // PAS ID 35
qcom,vmid = <0x32>; // VMID 50 → CPUSYS VM
qcom,firmware-name = "cpusys_vm";
memory-region = <&cpusys_vm_region>;
};

从这两个节点直接得到了之前缺失的信息:

  • **VMID 45 (0x2D) = Trusted UI VM **:之前 dmesg 里 qcom_guestvm_loader@e0b00000 报的就是它
  • VMID 50 (0x32) = CPUSYS VM:之前 dmesg 里 hyp_core_ctl: skipped for vmid50 就是这个
  • Trusted UI VM 独占 CPU 5、6: qcom,reserved-cpus 加上 qcom,isolate-cpus 意味着启动该 VM 时,Linux 的调度器会被要求让出这两个核心
  • 两个 VM 还各有一个 qcom,gh_vm_loader_sec 安全加载器对应节点,CPUSYS VM 的安全加载器额外带 qcom,no-shutdown

跨 VM 通信节点

qrtr-gunyah {
compatible = "qcom,qrtr-gunyah";
qcom,master;
gunyah-label = <3>;
peer-name = <2>; // 对端 peer ID
shared-buffer = <&trust_ui_vm_qrtr>; // 共享缓冲区 0xe55f3000
};

gunyah-vsock {
compatible = "qcom,gunyah-vsock";
qcom,master;
peer-name = <2>;
msgq-label = <3>;
};

HLOS 和 Trusted UI VM 之间有两条独立通信链路:

  • QRTR over Gunyah :Qualcomm IPC Router 协议,走共享内存 trust_ui_vm_qrtr@e55f3000(36 KB),gunyah-label = 3 标识通道
  • Gunyah vsock :类 Linux AF_VSOCK 的虚拟套接字,同样走 Gunyah Message Queue 两条链路的 peer-name = 2 指向同一个对端(Trusted UI VM 的内部标识)。

Virtio 块设备透传

qcom,trust_ui_vm@e55fc000 {
vm_name = "trustedvm";
shared-buffers = <&trust_ui_vm_vblk0_ring &trust_ui_vm_swiotlb>;
};

qcom,virtio_backend@0 {
compatible = "qcom,virtio_backend";
qcom,vm = <&trust_ui_vm>;
qcom,label = <0x11>; // 对应 vblk0_ring 的 gunyah-label
};

HLOS 为 Trusted UI VM 提供了一个 Virtio block 后端。vblk0_ring(16 KB)是 Virtio vring 描述符环,swiotlb(1 MB)是 DMA bounce buffer — Trusted UI VM 通过这个通道读写块设备,典型用途是加载安全界面所需的资源文件。

动态内存管理

qcom,mem-buf { compatible = “qcom,mem-buf”; qcom,mem-buf-capabilities = “supplier”; qcom,vmid = <3>; // HLOS 是内存供给方 };

mem-buf 让 HLOS 作为 “supplier” 向其他 VM 按需提供物理内存页。配合根节点下的 mem-offline 节点:

mem-offline { compatible = “qcom,mem-offline”; offline-sizes = <…>; granule = <0x400>; // 1024 页 = 4 MB };

Hypervisor 以 4 MB 粒度 从 HLOS 热移除物理内存段,转交其他 VM 使用,用完后再归还。dmesg 中 mem-offline: sent msg successfully to offline segment at phys addr 0x980000000 就是这个机制在工作。

五、reserved-memory 完整解析

DTS 里 reserved-memory 下的所有节点一次性全部可见。reg 属性格式为 <addr_hi addr_lo size_hi size_lo>,每个字段 32 位。以下数据直接从反编译后的 DTS 提取:

Hypervisor 核心区域

// DTS hyp_region@80000000 { no-map; reg = <0x00 0x80000000 0x00 0x00600000>; }; qheebsp_reserved_region@e0000000 { no-map; reg = <0x00 0xe0000000 0x00 0x00600000>; }; hyp_reserved_region@e0a00000 { no-map; reg = <0x00 0xe0a00000 0x00 0x00100000>; };

节点基地址大小
hyp_region 0x80000000 6 MB
qheebsp_reserved 0xE0000000 6 MB
hyp_reserved 0xE0A00000 1 MB

虚拟机区域

cpusys_vm_region@e0600000 { no-map; reg = <0x00 0xe0600000 0x00 0x00400000>; }; trust_ui_vm_region@e0b00000 { no-map; reg = <0x00 0xe0b00000 0x00 0x04af3000>; }; oem_vm_region@bb000000 { no-map; reg = <0x00 0xbb000000 0x00 0x05000000>; };

节点基地址大小
cpusys_vm 0xE0600000 4 MB
trust_ui_vm 0xE0B00000 ~75 MB
oem_vm 0xBB000000 80 MB

Trusted UI VM 区域内部还有三个子区域,DTS 里带 gunyah-label 标记:

trust_ui_vm_qrtr@e55f3000 { no-map; reg = <0x00 0xe55f3000 0x00 0x00009000>; // 36 KB, QRTR 共享缓冲 }; trust_ui_vm_vblk0_ring@e55fc000 { no-map; reg = <0x00 0xe55fc000 0x00 0x00004000>; // 16 KB, Virtio vring gunyah-label = <0x11>; }; trust_ui_vm_swiotlb@e5600000 { no-map; reg = <0x00 0xe5600000 0x00 0x00100000>; // 1 MB, DMA bounce buffer gunyah-label = <0x12>; };

gunyah-label 是 Gunyah Hypervisor 用于匹配共享内存段与 Virtio 后端的标识。0x11 对应 /soc/qcom,virtio_backend@0 的 qcom,label。

安全子系统与其他

节点基地址大小说明
qtee 0xE9B00000 5 MB QTEE 安全环境
smem 0x80900000 2 MB 多处理器共享内存
tz_stat 0xE8800000 1 MB TrustZone 统计
tags 0xE8900000 18 MB TrustZone tags
cdsp_secure_heap 0x80C00000 70 MB CDSP 安全堆
mpss 0x8BC00000 306 MB Modem 子系统
adsp 0x85E00000 33 MB Audio DSP
slpi 0x88000000 25 MB Sensor Low Power Island
cdsp 0x89900000 32 MB Compute DSP

六、/proc/iomem 交叉验证

adb shell cat /proc/iomem

输出很长,摘出 Hypervisor/VM 相关的段(省略外设寄存器部分):

80000000-808f3fff : reserved 80900000-851fffff : reserved 85700000-87efffff : reserved 88000000-8b91bfff : reserved 8ba00000-9fcfffff : reserved … bb000000-bfffffff : reserved ← oem_vm (80 MB) … e0000000-e56fffff : reserved ← qheebsp + cpusys_vm + hyp_reserved + trust_ui_vm e55f3000-e55fbfff : soc:qrtr-gunyah trust_ui_vm_qrtr@e55f3000 e8800000-e9ffffff : reserved ← tz_stat + tags + qtee

/proc/iomem 中唯一直接出现 gunyah 字样的条目是 soc:qrtr-gunyah trust_ui_vm_qrtr@e55f3000,这是 Trusted UI VM 与 HLOS 之间的 QRTR 通信缓冲区。

以 oem_vm_region 为例验证地址对应关系:

0xBB00_0000 + 0x0500_0000 – 1 = 0xBFFF_FFFF

与 iomem 中的 bb000000-bfffffff 完全吻合。

七、dmesg 运行时日志

adb shell dmesg | grep -i “gh_|hyp_core|guestvm|mem-offline|vmid” [ 10.591707] gh_msgq: Registered client for label: 2 [ 34.661075] qcom_guestvm_loader soc:qcom,guestvm_loader@e0b00000: Expected a notification from vmid = 45, but received one from vmid = 50 [ 34.681893] hyp_core_ctl: Reservation scheme skipped for other VM vmid50 [ 122.181100] mem-offline: sent msg successfully to offline segment at phys addr 0x980000000 [ 122.317201] mem-offline: sent msg successfully to offline segment at phys addr 0x9c0000000

日志含义
gh_msgq: Registered client for label: 2 Gunyah Message Queue 驱动注册,label 2 对应 RM-RPC 通道
qcom_guestvm_loader@e0b00000 加载 Trusted UI VM(VMID 45),对应 DTS 中 guestvm_loader 节点
Expected vmid=45, received vmid=50 先收到了 CPUSYS VM (vmid 50) 的通知,再收到 Trusted UI VM (vmid 45)
hyp_core_ctl: skipped for vmid50 CPUSYS VM 没有 qcom,isolate-cpus,不需要核心预留
mem-offline: offline segment at 0x980000000 Gunyah 以 4 MB 粒度从 HLOS 回收物理内存页,地址在高位 DDR

对照 DTS 里 guestvm_loader 的 VMID 定义,dmesg 中之前不确定的 vmid 50 现在确认就是 CPUSYS VM。mem-offline 配合 DTS 中 granule = <0x400> (4 MB),说明 Gunyah 支持运行时内存热插拔 — Hypervisor 动态从 HLOS 回收物理内存段转交其他 VM,用完后归还。

八、内存布局总览

物理地址空间 (Gunyah 相关)

┌─────────────────────────────────────┐ 0x80000000
│ hyp_region (6 MB) │ Gunyah Hypervisor 代码/数据
├─────────────────────────────────────┤ 0x80600000
│ xbl_dt_log (256 KB) │ 引导日志
├─────────────────────────────────────┤ 0x80900000
│ smem_region (2 MB) │ 共享内存
├─────────────────────────────────────┤
│ (ADSP/SLPI/CDSP/MPSS 等子系统) │
├─────────────────────────────────────┤ 0xBB000000
│ oem_vm_region (80 MB) │ OEM 虚拟机 (VMID ?)
├═════════════════════════════════════╡ 0xE0000000
│ qheebsp_reserved (6 MB) │ QHEE BSP
├─────────────────────────────────────┤ 0xE0600000
│ cpusys_vm_region (4 MB) │ CPUSYS 虚拟机 (VMID 50)
├─────────────────────────────────────┤ 0xE0A00000
│ hyp_reserved (1 MB) │ Hypervisor 附加预留
├─────────────────────────────────────┤ 0xE0B00000
│ trust_ui_vm_region (~75 MB) │ Trusted UI 虚拟机 (VMID 45)
│ ├ qrtr@e55f3000 (36 KB) │ QRTR 共享缓冲
│ ├ vblk0_ring@e55fc000 (16 KB) │ Virtio vring [label=0x11]
│ └ swiotlb@e5600000 (1 MB) │ DMA bounce [label=0x12]
├─────────────────────────────────────┤ 0xE8800000
│ tz_stat (1 MB) + tags (18 MB) │ TrustZone
├─────────────────────────────────────┤ 0xE9B00000
│ qtee_region (5 MB) │ QTEE 安全环境
└─────────────────────────────────────┘ 0xEA000000

仅 Hypervisor + VM 区域合计约 172 MB,加上 TZ、QTEE 和各子系统固件,总预留内存超过 500 MB。

九、已确认的 VM 列表

VMID名称内存区域固件名备注
3 HLOS (Android) 主系统内存 高级操作系统,mem-buf supplier
45 (0x2D) Trusted UI VM 0xE0B00000 (~75 MB) trustedvm 独占 CPU 5/6,PAS ID 28
50 (0x32) CPUSYS VM 0xE0600000 (4 MB) cpusys_vm PAS ID 35,secure loader 带 no-shutdown
OEM VM 0xBB000000 (80 MB) DTS 中仅有 reserved-memory 定义
Resource Manager 运行在 EL2 资源协调,通过 RM-RPC 与 HLOS 通信

特权层级和通信关系:

EL3: TrustZone / QTEE
↓ │
EL2: Gunyah Hypervisor + Resource Manager

└─ RM-RPC (全双工消息队列)
↓ │
EL1: HLOS VM (VMID 3) ←→ Trusted UI VM (VMID 45)
│ CPU 5,6
│ mem-buf (supplier→consumer)

├─ CPUSYS VM (VMID 50)
└─ OEM VM (VMID ?)

EL0: Android 用户空间

附录 — 命令速查

本文所有 adb shell 命令均在 adb root 之后执行。不 adb root 的话,adb pull fdt 和属性读取会 Permission denied,/proc/iomem 地址显示全零,dmesg 报 klogctl 权限不足。ls /proc/device-tree/ 是唯一不需要 root 就能用的。

# 平台确认
adb shell "getprop ro.board.platform; getprop ro.build.type"

# 提取并反编译设备树
adb root
adb pull /sys/firmware/fdt sm8450_live.dtb
dtc -I dtb -O dts -o sm8450_live.dts sm8450_live.dtb

# DTS 全文搜索
grep -ni "gunyah\\|hyp_\\|guestvm\\|mem-buf\\|mem-offline" sm8450_live.dts

# 交叉验证
adb shell cat /proc/iomem
adb shell dmesg | grep -i "gh_\\|hyp_core\\|gunyah\\|guestvm\\|vmid\\|mem-offline"

📢下一篇介绍

下一篇,我们将详细介绍从 HVC 指令到消息队列:Gunyah 通信栈拆解。

参考:

  • 高通骁龙SM8450平台简介:Snapdragon 8 Gen 1 Mobile Platform
  • 赞(0)
    未经允许不得转载:171主机测评 » 高通Gunyah Hypervisor 深度拆解(1): 从设备树定位 Gunyah Hypervisor 的内存布局
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址