3. 配置安全世界与普通世界内存隔离

配置安全世界与普通世界内存隔离 学习卡片

任务说明

本案例目标是在ARM TrustZone环境中,通过TZASC(TrustZone Address Space Controller)将一段物理内存配置为安全世界专用区域,并验证普通世界(Normal World)对该区域的访问被硬件阻断。完成本案例后,您将掌握TZASC寄存器配置流程及安全内存隔离的验证方法。

环境依赖

  • 支持TrustZone的ARM处理器(如Cortex-A53/A72)
  • TZASC外设(如ARM TZC-400或SoC集成版本)
  • 运行在EL3/安全世界中的裸机代码或Trusted Firmware环境

核心实现

以下代码演示了TZASC-400的完整配置流程:将地址0x80000000~0x8000FFFF(64KB)配置为安全区域,其余地址保持非安全可访问。代码包含寄存器定义、初始化函数和验证逻辑。

#include <stdint.h>

// TZC-400 寄存器映射(基地址0x40000000)
#define TZC_BASE        0x40000000UL
#define TZC_REGION_BASE(n)  (TZC_BASE + 0x100 + (n)*0x10)
#define TZC_REGION_TOP(n)   (TZC_BASE + 0x104 + (n)*0x10)
#define TZC_REGION_ATTR(n)  (TZC_BASE + 0x108 + (n)*0x10)
#define TZC_REGION_ID(n)    (TZC_BASE + 0x10C + (n)*0x10)
#define TZC_GATE_KEEPER     (TZC_BASE + 0x008)
#define TZC_ACTION          (TZC_BASE + 0x004)

// 寄存器位定义
#define TZC_ACTION_INT      (1 << 0)   // 违规时触发中断
#define TZC_ATTR_SEC        (1 << 0)   // 安全访问使能
#define TZC_ATTR_NS         (1 << 1)   // 非安全访问使能
#define TZC_ATTR_FILTER_EN  (1 << 4)   // 过滤使能
#define TZC_GATE_OPEN       (1 << 0)   // 门控开启

// 配置TZASC区域为安全内存
void tzasc_config_secure_region(void) {
    uint32_t region_base = 0x80000000UL;
    uint32_t region_size = 0x10000UL;   // 64KB
    uint32_t region_top = region_base + region_size - 1;

    // 1. 关闭所有区域过滤(先清空配置)
    for (int i = 0; i < 8; i++) {
        *(volatile uint32_t *)TZC_REGION_ATTR(i) = 0;
    }

    // 2. 配置区域0:安全内存区域
    *(volatile uint32_t *)TZC_REGION_BASE(0) = region_base & ~0xFFFUL;
    *(volatile uint32_t *)TZC_REGION_TOP(0)  = region_top & ~0xFFFUL;
    // 仅允许安全访问,非安全访问被拒绝
    *(volatile uint32_t *)TZC_REGION_ATTR(0) = TZC_ATTR_SEC | TZC_ATTR_FILTER_EN;
    *(volatile uint32_t *)TZC_REGION_ID(0)   = 0xFFFFFFFFUL;  // 所有安全世界master

    // 3. 设置违规响应为中断(便于验证)
    *(volatile uint32_t *)TZC_ACTION = TZC_ACTION_INT;

    // 4. 开启门控,使配置生效
    *(volatile uint32_t *)TZC_GATE_KEEPER = TZC_GATE_OPEN;
}

// 验证函数:尝试非安全访问安全区域
// 返回0表示访问被拒绝(正确),返回1表示访问成功(配置错误)
int tzasc_verify_ns_access_denied(void) {
    volatile uint32_t *secure_addr = (volatile uint32_t *)0x80000000UL;
    uint32_t val;

    // 模拟非安全访问(实际环境中需切换至Normal World执行)
    // 此处通过读取TZC状态寄存器判断是否触发违规
    val = *(volatile uint32_t *)(TZC_BASE + 0x00C);  // TZC_INT_STATUS

    // 若违规中断状态置位,说明访问被正确阻断
    if (val & 0x1) {
        // 清除中断状态
        *(volatile uint32_t *)(TZC_BASE + 0x010) = 0x1;
        return 0;  // 访问被拒绝
    }
    return 1;  // 未触发违规,配置可能错误
}

// 简单测试入口
void tzasc_test(void) {
    tzasc_config_secure_region();

    // 尝试从安全世界读取安全区域(应成功)
    volatile uint32_t *secure_addr = (volatile uint32_t *)0x80000000UL;
    *secure_addr = 0xDEADBEEF;
    uint32_t readback = *secure_addr;

    if (readback == 0xDEADBEEF) {
        // 安全世界访问正常
    }

    // 验证非安全访问被拒绝
    int denied = tzasc_verify_ns_access_denied();
    // denied == 0 表示验证通过
}

编译与运行

  1. 将上述代码编译为安全世界固件的一部分,链接地址需避开0x80000000区域
  2. 在EL3或S-EL1初始化阶段调用tzasc_config_secure_region()
  3. 使用调试器或测试代码调用tzasc_test()执行验证

验证方法与判定标准

  • 安全访问验证:在安全世界中对0x80000000地址执行写读操作,数据能正确写回(0xDEADBEEF),说明安全访问正常
  • 非安全访问验证:切换到普通世界(或通过模拟非安全事务),尝试访问0x80000000地址,系统应触发TZASC中断(TZC_INT_STATUS置位),且访问被硬件阻断
  • 通过条件:安全世界读写正常,且非安全访问触发中断且无法读取数据

常见问题

  • 区域地址对齐:TZASC要求区域基地址和结束地址按4KB对齐,配置前需检查地址值
  • 门控未开启:若配置后不生效,确认GATE_KEEPER寄存器已写入开启值
  • 中断未触发:检查TZC_ACTION寄存器是否配置为中断模式,以及中断控制器是否正确使能