1. 引言:隔离世界之间的通信需求

从事过ARM平台安全开发的工程师对Trustzone应该并不陌生。
ARM TrustZone 技术通过硬件将处理器划分为 Secure World(安全世界)Normal World(非安全世界)。二者在物理上隔离——各自拥有独立的内存地址空间、外设访问权限和执行特权级:

  • 内存地址空间(通过 TZASC 等控制器划分)
  • 外设访问权限(通过 TZPC 等控制器控制)
  • 异常级(Exception Level)执行环境

在高通芯片平台上,Secure World 运行 QTEE(Qualcomm Trusted Execution Environment),其中包含一个微型内核 MINK 和若干 Trusted Application(TA)(如 Keymaster、Widevine DRM、Gatekeeper)。Normal World 运行 HLOS(Linux / Android),需要调用 TA 提供的安全服务,如生成密钥、验证指纹、解密 DRM 内容。

两个世界之间的硬件隔离决定了 HLOS 无法直接调用 TA 的函数,必须依赖一套受控的通信机制,在 Secure Monitor 的仲裁下让请求安全穿越。
高通第一代解决方案就是 QSEECOM
在这里插入图片描述

2. ARMv8 异常级模型与 SMC 指令

理解 QSEECOM 前需要掌握 ARMv8 的异常级模型和世界切换机制:

异常级 典型运行内容 所属世界
EL0 用户态应用(App) Normal / Secure
EL1 OS 内核 / QTEE 内核 Normal / Secure
EL2 Hypervisor(QHEE) Normal
EL3 Secure Monitor(ARM FW / TZBSP) Secure
block-beta
  columns 1
  block:normal["Normal World"]
    block:el0n["EL0"]
      ua["User App (HLOS userspace)"]
    end
    block:el1n["EL1"]
      lk["Linux Kernel (HLOS kernel)"]
    end
    block:el2n["EL2"]
      hv["Hypervisor (QHEE)"]
    end
  end
  block:el3["EL3 — Secure Monitor (ARM FW / TZBSP)"]
    block:secure["Secure World"]
      block:el0s["EL0"]
        ta["Trusted Applications (TA)"]
      end
      block:el1s["EL1"]
        qtee["QTEE Kernel (MINK + TZBSP)"]
      end
    end
  end
  ua --> lk
  lk --> hv
  hv --> el3
  ta --> qtee
  qtee --> el3

ARMv8 异常级与世界划分,参考 [5] ARM Architecture Reference Manual、[4] 80-NH537-4 §2.

两个世界切换的唯一硬件入口SMC(Secure Monitor Call)指令。当 HLOS kernel 执行 SMC 时:

  1. CPU 从 Normal World EL1 陷入 Secure World EL3
  2. Secure Monitor 保存 Normal World 上下文
  3. 根据 SMC 功能号(SMC ID)路由到对应的 TrustZone 处理函数
  4. TrustZone 处理完成后原路返回

QSEECOM 以及后续的 SMCInvoke 都建立在 SMC 之上,区别在于上层封装与抽象层次。

3. QSEECOM 整体架构

QSEECOM 是一套完整的 HLOS ↔ TustZone 通信框架,覆盖从 HLOS 用户态进程到 TrustZone 中 TA 的全链路。

block-beta
  columns 1
  block:us["HLOS Userspace"]
    tca["TA Client\nApplication"]
    lsnr["Listener\nApplication"]
    api["QSEECom API\n(libQSEEComAPI)"]
  end
  block:ks["HLOS Kernel"]
    drv["QSEECom Driver\n(/dev/qseecom)"]
  end
  block:sw["Secure World"]
    qtee["QTEE\n(MINK Kernel + TZBSP)"]
    ta2["Trusted Application\n(TA)"]
  end

  tca --> drv
  lsnr --> drv
  api --> drv
  drv -- "SMC" --> qtee
  qtee --> ta2

QSEECOM 端到端架构,参考 [1] 80-PK177-40 §TrustZone、[4] 80-NH537-4 §8.5

核心组件表:

组件 位置 职责
libQSEEComAPI HLOS Userspace C 库,封装 ioctl 调用,提供 QSEECom_start_app / send_cmd 等 API
QSEECom Driver HLOS Kernel 字符设备驱动 /dev/qseecom,处理 ioctl,执行 SMC
QTEE (MINK) Secure World EL1 接收 SMC 请求,调度到对应 TA
TA Secure World EL0 安全应用,实现具体业务(如密码验证、DRM 解密)

端到端数据流简述:

  • HLOS 用户态 Client 调用 libQSEEComAPI 函数
  • API 内部通过 ioctl 进入 QSEECom Driver
  • Driver 构建 SMC 命令并触发 SMC 指令
  • Secure Monitor 跳转到 QTEE
  • QTEE 将请求路由到目标 TA
  • TA 处理请求,结果写回共享内存
  • SMC 返回,HLOS 从共享内存读取结果

4. Client 与 Listener 双角色模型

QSEECOM 定义了两种 HLOS 侧角色:

Client(客户端,主动方)

  • 负责启动(load)一个 TA
  • 向 TA 发送命令(SendCommand)
  • 接收 TA 的响应
  • 关闭(shutdown)TA

Listener(监听器,被动方 / 服务方)

  • 在 HLOS 用户态注册一个监听器
  • 阻塞等待 TA 发来的请求
  • 处理请求(如文件 I/O、网络访问)
  • 将结果返回给 TA

被动等待 TA 请求的一方。当 TA 需要 HLOS 提供某些服务(比如文件 I/O、网络访问)时,TA 会向已注册的 Listener 发送请求,Listener 处理后再将结果返回给 TA。这实现了 TA → HLOS 的反向通信。

sequenceDiagram
  participant C as Client
  participant T as TA
  participant L as Listener

  C->>T: Send Command
  T-->>C: Response
  T->>L: Request to Listener
  L-->>T: Response from Listener

QSEECOM Client/Listener 双向通信模型,参考 [4] 80-NH537-4 §8.5

这种双向通信模型解决了 TA 需要 HLOS 服务的场景(例如安全文件系统读写)。但 Listener 需要独立线程阻塞等待,资源开销较大。

5. 通信数据结构与共享内存模型

QSEECOM 的数据交换基于 共享内存(Shared Memory)

struct qsecom_req {
    void *req;          // 请求缓冲区指针
    uint32_t req_len;   // 请求长度
    void *rsp;          // 响应缓冲区指针
    uint32_t rsp_len;   // 响应缓冲区大小
};

数据流详细步骤:

  1. HLOS Client 在用户态分配内存,填充请求数据
  2. 通过 ioctl 传递请求/响应缓冲区的用户态虚拟地址及长度
  3. QSEECom Driver 将用户态地址转换为物理地址(或 ION 句柄)
  4. Driver 执行 SMC,将物理地址传递给 TrustZone
  5. QTEE 将该物理地址映射到 Secure World 地址空间
  6. TA 直接读写该共享内存区域
  7. SMC 返回后,HLOS 从响应缓冲区读取结果

大块数据零拷贝:
QSEECom_send_modified_cmd 允许传递 ION 文件描述符。HLOS 先通过 ION 分配大块连续物理内存,将 fd 传给 TrustZone,TrustZone 可直接访问同一块物理内存,避免数据拷贝,适用于 DRM 视频帧等场景。

6. 关键 API 清单

Client 侧 API:

int QSEECom_start_app(struct QSEECom_handle **handle,
                      const char *app_name, uint32_t size);
int QSEECom_shutdown_app(struct QSEECom_handle *handle);
int QSEECom_send_cmd(struct QSEECom_handle *handle,
                     void *send_buf, uint32_t buf_len,
                     void *recv_buf, uint32_t rbuf_len);
int QSEECom_send_modified_cmd(struct QSEECom_handle *handle,
                              void *send_buf, uint32_t buf_len,
                              void *recv_buf, uint32_t rbuf_len,
                              struct qsecom_ion_fd_info *ion_fd_info);

Listener 侧 API:

int QSEECom_register_listener(struct QSEECom_handle *handle,
                              uint32_t listener_id, uint32_t sb_length);
int QSEECom_unregister_listener(struct QSEECom_handle *handle);
int QSEECom_receive_req(struct QSEECom_handle *handle,
                        void *req_buf, uint32_t req_buf_len);
int QSEECom_send_resp(struct QSEECom_handle *handle,
                      void *resp_buf, uint32_t resp_buf_len);

7. 典型通信流程(无 Listener)

  • 流程一:Client 向 TA 发送命令(无需 Listener)
sequenceDiagram
  participant C as HLOS Userspace<br/>(TA Client)
  participant D as HLOS Kernel<br/>(QSEECom Driver)
  participant T as Secure World<br/>(QTEE + TA)

  C->>D: QSEECom_start_app()
  D->>T: ioctl → SMC (LOAD_APP)
  T-->>T: Load & start TA
  T-->>D: return
  D-->>C: handle

  C->>C: 填充 send_buf
  C->>D: QSEECom_send_cmd()
  D->>T: ioctl → SMC (SEND_CMD)
  T-->>T: TA 处理请求
  T-->>D: SMC return
  D-->>C: 读取 recv_buf

  C->>D: QSEECom_shutdown_app()
  D->>T: ioctl → SMC (SHUTDOWN_APP)
  T-->>T: Unload TA
  T-->>D: return
  D-->>C: done
  1. Client 调用 QSEECom_start_app → Driver 发送 LOAD_APP SMC → QTEE 加载 TA
  2. Client 填充 send_buf,调用 QSEECom_send_cmd → Driver 发送 SEND_CMD SMC → TA 处理
  3. TA 写 recv_buf → SMC 返回 → Client 读取结果
  4. Client 调用 QSEECom_shutdown_app → Driver 发送 SHUTDOWN_APP SMC → QTEE 卸载 TA

Client→TA 命令发送流程,参考 [4] 80-NH537-4 §8.9 Figure 8-1/8-2

  • 流程二:TA 请求 Listener 服务
    当 TA 需要访问 HLOS 的资源时(例如安全文件系统的 I/O 操作),可以通过已注册的 Listener 反向请求 HLOS:
sequenceDiagram
  participant L as HLOS Userspace<br/>(Listener)
  participant D as HLOS Kernel<br/>(QSEECom Driver)
  participant T as Secure World<br/>(QTEE + TA)

  L->>D: QSEECom_register_listener()
  D->>T: ioctl → SMC (REGISTER_LSNR)
  T-->>D: return
  D-->>L: handle

  L->>D: QSEECom_receive_req()
  Note over L,D: 阻塞等待 TA 请求...
  T->>D: TA 发起请求 (SMC)
  D-->>L: 唤醒 Listener,交付请求数据

  L->>L: 处理请求,填充响应
  L->>D: QSEECom_send_resp()
  D->>T: ioctl → SMC (SEND_RESP)
  T-->>T: TA 获得结果
  T-->>D: return

TA→Listener 反向请求流程,参考 [4] 80-NH537-4 §8.9 Figure 8-3/8-4

8. 小结

QSEECOM 是第一代实用的 HLOS↔TrustZone 通信框架,它基于 SMC + 共享内存 + ION 零拷贝提供了基础能力,并支持 Listener 反向通信。然而,其扁平模型、缺乏类型安全、无身份传递等设计局限,在高版本芯片和高安全需求场景下逐渐暴露,为后续 SMCInvoke 的诞生埋下了技术驱动力。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐