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 表示验证通过
}
编译与运行
- 将上述代码编译为安全世界固件的一部分,链接地址需避开0x80000000区域
- 在EL3或S-EL1初始化阶段调用
tzasc_config_secure_region() - 使用调试器或测试代码调用
tzasc_test()执行验证
验证方法与判定标准
- 安全访问验证:在安全世界中对0x80000000地址执行写读操作,数据能正确写回(0xDEADBEEF),说明安全访问正常
- 非安全访问验证:切换到普通世界(或通过模拟非安全事务),尝试访问0x80000000地址,系统应触发TZASC中断(TZC_INT_STATUS置位),且访问被硬件阻断
- 通过条件:安全世界读写正常,且非安全访问触发中断且无法读取数据
常见问题
- 区域地址对齐:TZASC要求区域基地址和结束地址按4KB对齐,配置前需检查地址值
- 门控未开启:若配置后不生效,确认GATE_KEEPER寄存器已写入开启值
- 中断未触发:检查TZC_ACTION寄存器是否配置为中断模式,以及中断控制器是否正确使能