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 查看安全寄存器当前值。