3. 配置TZASC地址空间控制器

任务说明

本案例目标是在支持TrustZone的ARM平台上,通过编程方式配置TZASC(TrustZone Address Space Controller),将外部DDR内存划分为安全区域与非安全区域,并验证安全世界与非安全世界对各自区域的访问权限是否符合预期。

环境依赖

  • 硬件:ARM Cortex-A系列处理器(支持TrustZone)+ TZASC-400或TZASC-380控制器
  • 软件:裸机环境或最小RTOS,使用ARM GCC交叉编译工具链
  • 内存布局:假设DDR基地址0x80000000,总大小256MB

核心实现

以下代码完成TZASC的初始化配置:将低64MB划分为安全区域(Region 0),其余192MB划分为非安全区域(Region 1),并设置访问权限。代码直接操作TZASC寄存器,不依赖操作系统驱动。

#include <stdint.h>

// TZASC寄存器映射(以TZASC-400为例,基地址0xE1200000)
#define TZASC_BASE          0xE1200000UL
#define TZASC_REGION_BASE   0x100UL  // Region Base Address寄存器偏移

// 寄存器偏移定义
#define TZASC_CONFIG        0x000UL  // 配置寄存器
#define TZASC_GATE_KEEPER   0x00CUL  // Gate Keeper寄存器
#define TZASC_REGION_CTRL   0x110UL  // Region Control寄存器(Region 0)
#define TZASC_REGION_ATTR   0x114UL  // Region Attributes寄存器

// 寄存器位定义
#define GATE_KEEPER_OPEN    (1UL << 0)   // 允许region访问
#define REGION_ENABLE       (1UL << 0)   // Region使能
#define REGION_SECURITY     (1UL << 1)   // 1=安全, 0=非安全
#define REGION_SIZE_64MB    (0x1BUL << 4) // 64MB大小编码
#define REGION_SIZE_192MB   (0x1DUL << 4) // 192MB大小编码
#define REGION_READ_WRITE   (0x3UL << 8)  // 安全世界读写权限

// 内存区域定义
#define DDR_BASE            0x80000000UL
#define SECURE_REGION_SIZE  0x04000000UL   // 64MB安全区域
#define NON_SECURE_REGION_SIZE 0x0C000000UL // 192MB非安全区域

// 寄存器访问宏
#define TZASC_REG(offset)   (*(volatile uint32_t *)(TZASC_BASE + offset))

// 配置Region 0为安全区域(低64MB)
static void tzasc_configure_secure_region(void) {
    // 设置Region 0基地址
    TZASC_REG(TZASC_REGION_BASE + 0x00) = DDR_BASE;
    
    // 设置Region 0控制:使能,安全,64MB大小
    TZASC_REG(TZASC_REGION_CTRL) = REGION_ENABLE | REGION_SECURITY | 
                                    REGION_SIZE_64MB | REGION_READ_WRITE;
    
    // 设置Region 0属性:允许安全世界读写,非安全世界不可访问
    TZASC_REG(TZASC_REGION_ATTR) = 0x0;  // 非安全世界无访问权限
}

// 配置Region 1为非安全区域(高192MB)
static void tzasc_configure_nonsecure_region(void) {
    uint32_t region1_base = DDR_BASE + SECURE_REGION_SIZE;
    
    // 设置Region 1基地址
    TZASC_REG(TZASC_REGION_BASE + 0x20) = region1_base;
    
    // 设置Region 1控制:使能,非安全,192MB大小
    TZASC_REG(TZASC_REGION_BASE + 0x24) = REGION_ENABLE | REGION_SIZE_192MB;
    
    // 设置Region 1属性:允许所有世界读写
    TZASC_REG(TZASC_REGION_BASE + 0x28) = 0x3;  // 非安全世界可读写
}

// 初始化TZASC
void tzasc_init(void) {
    // 关闭所有region访问(安全起见)
    TZASC_REG(TZASC_GATE_KEEPER) = 0x0;
    
    // 配置两个内存区域
    tzasc_configure_secure_region();
    tzasc_configure_nonsecure_region();
    
    // 打开gate keeper,允许region访问
    TZASC_REG(TZASC_GATE_KEEPER) = GATE_KEEPER_OPEN;
}

// 验证函数:检查TZASC配置是否生效
uint32_t tzasc_verify_config(void) {
    uint32_t status = 0;
    
    // 检查Region 0控制寄存器
    uint32_t ctrl0 = TZASC_REG(TZASC_REGION_CTRL);
    if ((ctrl0 & REGION_ENABLE) && (ctrl0 & REGION_SECURITY)) {
        status |= 0x1;  // Region 0配置正确
    }
    
    // 检查Region 1控制寄存器
    uint32_t ctrl1 = TZASC_REG(TZASC_REGION_BASE + 0x24);
    if ((ctrl1 & REGION_ENABLE) && !(ctrl1 & REGION_SECURITY)) {
        status |= 0x2;  // Region 1配置正确
    }
    
    return status;
}

// 主函数入口
int main(void) {
    tzasc_init();
    
    uint32_t verify_result = tzasc_verify_config();
    
    // 验证结果:0x3表示两个region均配置正确
    if (verify_result == 0x3) {
        // 配置成功
        return 0;
    } else {
        // 配置失败
        return -1;
    }
}

编译与运行

# 交叉编译(以ARMv8-A为例)
aarch64-none-elf-gcc -c tzasc_config.c -o tzasc_config.o
aarch64-none-elf-ld -Ttext=0x80000000 tzasc_config.o -o tzasc_config.elf

# 烧录到目标板或使用QEMU验证
qemu-system-aarch64 -machine virt -cpu cortex-a57 -nographic -kernel tzasc_config.elf

验证方法

通过以下步骤验证访问控制是否生效:

  1. 寄存器回读验证:程序执行后,检查返回值。返回0表示两个Region配置均正确写入。
  2. 功能验证:在安全世界(Secure World)尝试访问非安全区域(0x84000000),应成功;在非安全世界(Normal World)尝试访问安全区域(0x80000000),应触发异常或返回错误。
  3. 判定标准:tzasc_verify_config()返回0x3,且安全/非安全世界的访问行为符合预期,即判定配置成功。

注意事项

  • 实际TZASC寄存器偏移可能因具体芯片型号而异,请参考对应芯片手册调整基地址和偏移量。
  • Region大小编码(如64MB对应0x1B)需根据TZASC版本确认,不同版本编码可能不同。
  • 在切换安全/非安全世界时,需确保CPU的SCR.NS位设置正确,否则TZASC的过滤规则不会生效。