4. 实现第一个安全世界驱动
任务说明
在TrustZone架构中,安全世界(Secure World)驱动运行于TEE(可信执行环境)侧,负责访问安全硬件资源。本案例实现一个最小可用的安全世界驱动,完成对一块模拟安全寄存器的硬件访问控制:驱动初始化时读取硬件版本寄存器,提供读取/写入安全状态寄存器的接口,并校验写入值仅允许特定安全标志位被修改。
环境依赖
本案例基于ARM TrustZone固件框架(如OP-TEE或裸机TEE环境),驱动代码运行在安全世界。需要以下环境:
- ARM交叉编译工具链(aarch64-none-elf-gcc 或 arm-none-eabi-gcc)
- 支持TrustZone的硬件平台或QEMU虚拟化平台(qemu-system-aarch64 with TrustZone support)
- 安全世界内存映射:安全寄存器基地址
0x3A00_0000(示例地址,实际平台需按硬件手册调整)
核心实现
以下代码实现安全世界驱动的完整功能:硬件寄存器访问、状态读取、安全标志位校验写入。驱动通过内存映射I/O直接操作安全外设寄存器。
#include <stdint.h>
#include <stdbool.h>
/* 安全世界硬件寄存器映射(示例基地址) */
#define SECURE_HW_BASE 0x3A000000UL
#define HW_VERSION_REG (*(volatile uint32_t *)(SECURE_HW_BASE + 0x00))
#define HW_STATUS_REG (*(volatile uint32_t *)(SECURE_HW_BASE + 0x04))
#define HW_CTRL_REG (*(volatile uint32_t *)(SECURE_HW_BASE + 0x08))
/* 安全标志位定义 */
#define SECURE_FLAG_MASK 0x0000000FUL /* bit[3:0] 为安全状态标志 */
#define SECURE_ACTIVE_BIT (1UL << 0) /* bit0: 安全模式激活 */
#define SECURE_LOCK_BIT (1UL << 1) /* bit1: 安全锁定 */
#define SECURE_DEBUG_BIT (1UL << 2) /* bit2: 安全调试允许 */
#define SECURE_RESERVED_BIT (1UL << 3) /* bit3: 保留位,必须为0 */
/* 驱动状态 */
static bool drv_initialized = false;
static uint32_t drv_hw_version = 0;
/* 初始化安全世界驱动:读取硬件版本并验证硬件可用性 */
int secure_drv_init(void)
{
uint32_t ver;
if (drv_initialized) {
return 0; /* 重复初始化直接返回成功 */
}
/* 读取硬件版本寄存器 */
ver = HW_VERSION_REG;
/* 简单校验:版本号非0且bit[31:28]为0xA表示硬件就绪 */
if ((ver == 0) || ((ver >> 28) != 0xA)) {
return -1; /* 硬件不可用 */
}
drv_hw_version = ver;
drv_initialized = true;
/* 上电默认状态:安全模式激活,未锁定,禁止调试 */
HW_STATUS_REG = SECURE_ACTIVE_BIT;
return 0;
}
/* 读取当前安全状态寄存器值 */
uint32_t secure_drv_get_status(void)
{
if (!drv_initialized) {
return 0;
}
return HW_STATUS_REG;
}
/* 写入安全状态寄存器,仅允许修改安全标志位,保留位强制清零 */
int secure_drv_set_status(uint32_t new_status)
{
uint32_t current;
uint32_t updated;
if (!drv_initialized) {
return -1;
}
/* 强制保留位为0 */
new_status &= ~SECURE_RESERVED_BIT;
/* 只允许修改安全标志位范围内的位 */
current = HW_STATUS_REG;
updated = (current & ~SECURE_FLAG_MASK) | (new_status & SECURE_FLAG_MASK);
/* 安全锁定后禁止修改 */
if (current & SECURE_LOCK_BIT) {
return -2; /* 已锁定,拒绝写入 */
}
HW_STATUS_REG = updated;
return 0;
}
/* 获取硬件版本号(初始化后有效) */
uint32_t secure_drv_get_version(void)
{
return drv_hw_version;
}
编译与链接
将上述代码保存为 secure_drv.c,编译为安全世界固件对象文件:
aarch64-none-elf-gcc -c secure_drv.c -o secure_drv.o -O2 -ffreestanding -nostdlib
链接时需将安全外设基地址 0x3A000000 映射到安全世界页表中(在TEE启动代码中配置MMU),确保该地址区域标记为设备内存(Device-nGnRnE),关闭缓存与推测访问。
验证方法
在TEE环境初始化完成后,调用以下测试序列验证驱动功能:
/* 测试代码(在安全世界入口调用) */
int test_secure_drv(void)
{
uint32_t ver, status;
int ret;
/* 1. 初始化驱动 */
ret = secure_drv_init();
if (ret != 0) return -1;
/* 2. 读取硬件版本,预期高4位为0xA */
ver = secure_drv_get_version();
if ((ver >> 28) != 0xA) return -2;
/* 3. 初始状态应为SECURE_ACTIVE_BIT */
status = secure_drv_get_status();
if (status != SECURE_ACTIVE_BIT) return -3;
/* 4. 写入合法状态:激活+锁定 */
ret = secure_drv_set_status(SECURE_ACTIVE_BIT | SECURE_LOCK_BIT);
if (ret != 0) return -4;
/* 5. 验证写入生效 */
status = secure_drv_get_status();
if (status != (SECURE_ACTIVE_BIT | SECURE_LOCK_BIT)) return -5;
/* 6. 锁定后尝试修改,应返回-2 */
ret = secure_drv_set_status(SECURE_ACTIVE_BIT | SECURE_DEBUG_BIT);
if (ret != -2) return -6;
/* 7. 验证状态未被修改 */
status = secure_drv_get_status();
if (status != (SECURE_ACTIVE_BIT | SECURE_LOCK_BIT)) return -7;
return 0; /* 全部通过 */
}
通过条件:测试函数返回0,表示以下行为全部符合预期:
- 初始化成功读取硬件版本(高4位为0xA)
- 初始状态为安全模式激活
- 允许写入安全标志位(激活+锁定)
- 锁定后拒绝进一步修改,返回错误码-2
- 保留位(bit3)在写入时被强制清零
若在真实硬件上运行,需通过逻辑分析仪或安全世界调试串口观察寄存器地址 0x3A000004 的写入值变化。在QEMU环境中,可通过监视器命令 xp 0x3A000004 查看安全寄存器当前值。