AM64x/AM243x硬件防火墙配置实战:从寄存器解析到安全内存模型构建
1. 从手册到实战:理解AM64x/AM243x防火墙的核心价值
如果你正在基于德州仪器(TI)的AM64x或AM243x这类多核异构处理器设计产品,尤其是在汽车电子、工业自动化或者高端消费电子领域,那么“系统安全”绝对是你绕不开的核心议题。这些应用场景对功能安全和信息安全的要求近乎苛刻,一个微小的内存访问越界都可能导致灾难性的后果。我经历过不止一次因为早期安全架构设计疏忽,导致后期调试时某个核心意外改写了另一个核心的关键数据,引发系统宕机,排查起来犹如大海捞针。硬件防火墙(Firewall)正是TI在这些处理器中内置的、用于从硬件层面实现内存访问隔离与控制的“守门员”。
简单来说,你可以把防火墙想象成内存空间的“保安”和“门禁系统”。它不像软件层面的权限检查,需要消耗CPU周期去执行代码判断。硬件防火墙是集成在芯片内部互联总线(如CBASS)上的一个硬件模块,它对所有试图通过它去访问受保护从设备(Slave,比如某块内部SRAM或外设)的访问请求进行实时、无延迟的裁决。它的裁决依据,就是我们今天要深入探讨的防火墙寄存器配置。这些寄存器定义了:谁(哪个主设备Master,具有何种安全属性和特权等级)可以访问哪段内存区域(从哪个地址到哪个地址),以及能进行何种操作(读、写、调试、缓存)。
输入材料中给出的寄存器片段,正是这个“门禁规则”的具体体现。例如,FW_MAIN_0_SLV_FW_REGION_3_PERMISSION_2这个寄存器,就负责为IMSRAM32KX64E_MAIN_0这个从设备(一块32Kx64的紧耦合存储器)的第三个防火墙区域,设置详细的访问权限位。而START_ADDRESS和END_ADDRESS寄存器则划定了这块受保护区域的物理边界。理解并正确配置这些寄存器,是确保你的系统在复杂的多核、多任务环境下稳定、安全运行的基础。无论是防止非安全世界的代码窥探安全世界的密钥,还是阻止用户模式的应用程序篡改操作系统内核数据,都依赖于这套精细的配置。
2. 防火墙寄存器全景解析:不止于权限位
只看手册中的寄存器列表和位域描述,很容易陷入“只见树木,不见森林”的困境。我们需要先建立起AM64x/AM243x防火墙寄存器的整体认知框架。通常,对于一个防火墙(FW)模块下的一个特定区域(Region),你需要配置一组协同工作的寄存器,它们共同构成了一条完整的“安全规则”。
2.1 区域控制寄存器:规则的开关与属性
以FW_MAIN_1_SLV_FW_REGION_0_CONTROL寄存器为例,它是整个区域规则的“总开关”和“属性设置器”。
- ENABLE (位[3:0]):这是区域的使能位。手册明确说明,只有写入特定值
0xA才能使能该区域,其他任何值都会禁用。这种设计是一种安全措施,防止因意外写操作(比如全0或全1)而误启用防火墙。在实际编程中,你必须显式地写入0xA来激活一条规则。 - LOCK (位[4]):这是一个写1置位(W1TS)的锁定位。一旦将此位置1,整个区域的所有配置寄存器(包括CONTROL、PERMISSION、ADDRESS寄存器)都将被锁定,无法再被修改,直到下一次系统复位。这是一个至关重要的安全特性。在系统启动早期,由可信的引导代码完成所有关键内存区域(如安全内核代码区、密钥存储区)的防火墙配置后,立即锁定这些区域,可以防止后续被入侵的应用程序或驱动程序恶意修改防火墙规则,绕过安全防护。
- BACKGROUND (位[8]):背景区域使能位。这是防火墙一个非常巧妙的设计。一个防火墙模块通常支持多个(比如8个)前景(Foreground)区域和一个背景(Background)区域。前景区域的地址范围不能相互重叠,但它们都可以与唯一的背景区域重叠。当一次访问请求没有匹配任何前景区域时,防火墙会去检查背景区域的规则。这允许你设置一个“默认策略”。例如,你可以将大部分内存设置为背景区域“仅允许安全监管者读/写”,然后针对几个特定的、需要开放给非安全域或用户模式访问的“窗口”,设置前景区域规则。这大大增强了配置的灵活性。
- CACHE_MODE (位[9]):缓存模式检查位。当此位置1时,防火墙在裁决访问权限时,不仅会检查主设备的安全状态(Secure/Non-secure)和特权等级(Supervisor/User),还会检查该访问是否是缓存操作(Cacheable)。这允许你实现更细粒度的控制,例如,允许非安全域读取某块数据,但禁止其将该数据缓存到自己的Cache中,以防止侧信道攻击。
2.2 权限寄存器:定义“谁”能“干什么”
这是防火墙的核心,定义了访问者的具体权限。输入材料中反复出现了PERMISSION_0,PERMISSION_1,PERMISSION_2等寄存器。它们结构相似,但服务于不同的“主设备ID”(Master ID)或“权限集”(Privilege ID Set)。这是防火墙支持多主设备的关键。
权限寄存器的位定义具有清晰的层次结构,通常按以下维度划分:
- 安全域(Security State):
- SEC_*: 安全世界(Secure World)的访问权限。通常运行可信固件、安全操作系统或安全服务。
- NONSEC_*: 非安全世界(Non-secure World)的访问权限。通常运行通用的操作系统和应用程序。
- 特权等级(Privilege Level):
- SUPV_*: 监管者模式(Supervisor Mode),如操作系统内核模式。
- USER_*: 用户模式(User Mode),如应用程序。
- 访问类型(Access Type):
- READ: 读权限。
- WRITE: 写权限。
- DEBUG: 调试访问权限(通过调试接口,如JTAG)。
- CACHEABLE: 是否允许该访问被缓存。
例如,SEC_SUPV_WRITE位为1,表示“安全世界的监管者模式”拥有“写”权限。NONSEC_USER_READ位为0,则表示“非安全世界的用户模式”没有“读”权限。
为什么有多个PERMISSION寄存器?这是因为一个防火墙区域可能需要针对不同的主设备定义不同的权限集。PRIV_ID字段(通常占一个字节,如位[23:16])用于标识这条权限规则适用于哪个或哪组主设备。处理器内部可能有数十个主设备(如Cortex-A53核心、Cortex-R5F核心、DMA控制器、各种外设等),每个主设备在发起总线访问时都会携带自己的ID。防火墙硬件会将这个ID与PRIV_ID字段进行匹配,以决定使用哪一组PERMISSION寄存器(如PERMISSION_0,PERMISSION_1,PERMISSION_2)中的规则来进行裁决。这实现了基于主设备的精细化控制。
2.3 地址寄存器:划定“保护范围”
地址寄存器定义了这条规则生效的物理内存范围。AM64x/AM243x采用48位物理地址,因此用两个32位寄存器来分别存储高16位和低32位。
- START_ADDRESS_H/L: 起始地址寄存器。关键点在于地址必须4KB对齐。这意味着你指定的起始地址的低12位必须为0。寄存器描述中也明确指出,低12位(
START_ADDRESS_LSB)是只读的,并且硬件会强制其为0。例如,如果你想保护从0x7004_0000开始的内存,你只需要向START_ADDRESS_L写入0x70040(即0x7004_0000 >> 12)。 - END_ADDRESS_H/L: 结束地址寄存器。同样要求4KB对齐,但它的含义是“包含的最后一个地址”。为了简化硬件比较逻辑,通常要求你写入的地址��“结束地址的高位”,而低12位硬件会强制为全1(
0xFFF)。例如,对于结束地址0x7007_FFFF,你向END_ADDRESS_L写入的值是0x7007F,硬件会自动将低12位补为0xFFF,从而构成完整的结束地址。
这种设计使得地址比较器在硬件上可以高效工作,只需比较地址的高位(bit[47:12]),低位对齐要求由硬件保证。
3. 实战配置:为一个安全数据缓冲区设置防火墙
理论说得再多,不如动手配置一次来得深刻。假设我们有一个典型场景:在IMSRAM32KX64E_MAIN_1(我们称之为主域1的TCM)中,划出一块4KB的区域(地址0x7004_0000到0x7004_0FFF),用于存放安全协处理器(如Cortex-R5F运行在安全态)与高性能应用核心(如Cortex-A53运行在非安全态)之间的共享数据。我们需要配置防火墙,使得:
- 安全态的R5F(作为监管者)可以完全读写此区域。
- 非安全态的A53核心,在用户模式下,只能读取此区域,不能写入,也不能调试。
- 禁止任何非安全态的访问缓存此区域数据(防止缓存侧信道攻击)。
- 配置完成后,锁定该区域防止篡改。
我们将使用FW_MAIN_1_SLV_FW_REGION_0这一组寄存器(从输入材料看,它的起始地址复位值正好是0x70040000,符合我们的需求)。
3.1 步骤一:确定物理地址与寄存器映射
首先,根据手册,FW_MAIN_1_SLV_FW_REGION_0_*这组寄存器的基地址位于CBASS0域的0x4500_3C00。这是一个配置总线(Configuration Bus)上的地址,需要通过运行在安全特权模式下的代码(通常是启动阶段的Bootloader或安全内核)来访问。
我们的目标区域是0x7004_0000到0x7004_0FFF。这是一个4KB对齐的空间。
- 起始地址高16位(
START_ADDRESS_H):0x0000 - 起始地址低32位(
START_ADDRESS_L):0x70040(0x7004_0000 >> 12) - 结束地址高16位(
END_ADDRESS_H):0x0000 - 结束地址低32位(
END_ADDRESS_L):0x70040(注意:对于结束地址,硬件要求写入的是(End_Address >> 12)。由于我们的区域只有4KB,结束地址0x7004_0FFF >> 12 = 0x70040,与起始地址相同。这意味着我们保护的是一个精确的4KB页面。硬件在比较时,会认为地址A在区域内,当(A >> 12)等于我们设置的值时成立。)
3.2 步骤二:配置地址寄存器
在使能区域前,先配置好地址范围。假设我们通过C语言指针访问这些内存映射寄存器。
// 假设 REG_BASE 是 0x4500_3C00 volatile uint32_t *fw_reg_base = (volatile uint32_t *)0x45003C00; // 配置 Region 0 起始地址低32位 (偏移 0x3C10) // 写入 0x70040, 硬件会自动处理低12位为0 *(fw_reg_base + 0x10/4) = 0x70040; // FW_MAIN_1_SLV_FW_REGION_0_START_ADDRESS_L // 配置 Region 0 起始地址高16位 (偏移 0x3C14) // 高16位为0 *(fw_reg_base + 0x14/4) = 0x0000; // FW_MAIN_1_SLV_FW_REGION_0_START_ADDRESS_H // 配置 Region 0 结束地址低32位 (偏移 0x3C18) // 对于4KB区域,结束地址高位与起始地址高位相同 *(fw_reg_base + 0x18/4) = 0x70040; // FW_MAIN_1_SLV_FW_REGION_0_END_ADDRESS_L // 配置 Region 0 结束地址高16位 (偏移 0x3C1C) *(fw_reg_base + 0x1C/4) = 0x0000; // FW_MAIN_1_SLV_FW_REGION_0_END_ADDRESS_H注意:在实际操作中,务必在访问这些配置寄存器前,确保CPU处于正确的安全状态和特权等级(通常是安全监管者模式)。同时,要注意内存访问的宽度和对齐。上述代码为简化的示例。
3.3 步骤三:配置权限寄存器
接下来,配置PERMISSION_0寄存器(偏移0x3C04)。我们需要根据需求设置相应的位。假设我们使用PRIV_ID = 0的这组权限(通常0是一个默认或通用的ID,具体ID映射需参考芯片的《技术参考手册》中关于主设备ID的章节)。
我们需要设置的位:
SEC_SUPV_READ(位1) = 1SEC_SUPV_WRITE(位0) = 1NONSEC_USER_READ(位13) = 1- 其他位,特别是
NONSEC_USER_WRITE(位12)、NONSEC_USER_DEBUG(位15)、NONSEC_USER_CACHEABLE(位14) 以及所有NONSEC_SUPV_*和SEC_USER_*位,根据需求设为0。 - 为了禁止缓存,我们需要将
CACHE_MODE位(在CONTROL寄存器)使能,并确保NONSEC_USER_CACHEABLE和NONSEC_SUPV_CACHEABLE为0。但注意,SEC_SUPV_CACHEABLE我们可能希望为1以提高安全核心访问效率。
计算权限值:
- 位0 (SEC_SUPV_WRITE) = 1 ->
0x0000_0001 - 位1 (SEC_SUPV_READ) = 1 ->
0x0000_0002 - 位13 (NONSEC_USER_READ) = 1 ->
0x0000_2000 - 假设我们允许安全监管者缓存(位2 SEC_SUPV_CACHEABLE = 1)->
0x0000_0004 - 权限值 =
0x0000_0001 | 0x0000_0002 | 0x0000_0004 | 0x0000_2000 = 0x0000_2007
同时,PRIV_ID字段(位[23:16])我们保持为0。
// 配置 Region 0 Permission 0 寄存器 (偏移 0x3C04) // PRIV_ID = 0, 权限位 = 0x2007 uint32_t perm_value = (0x00 << 16) | 0x2007; // PRIV_ID 在高字节 *(fw_reg_base + 0x04/4) = perm_value; // FW_MAIN_1_SLV_FW_REGION_0_PERMISSION_03.4 步骤四:配置控制寄存器并启用区域
最后,配置CONTROL寄存器(偏移0x3C00)。
ENABLE(位[3:0]) =0xALOCK(位[4]) = 0 (先不锁定,等确认配置无误后再锁定)BACKGROUND(位[8]) = 0 (这是前景区域)CACHE_MODE(位[9]) = 1 (启用缓存权限检查)
// 配置 Region 0 Control 寄存器 (偏移 0x3C00) // Bit[9] CACHE_MODE = 1, Bit[8] BACKGROUND = 0, Bit[4] LOCK = 0, Bit[3:0] ENABLE = 0xA uint32_t ctrl_value = (1 << 9) | (0xA); // 其他保留位为0 *(fw_reg_base + 0x00/4) = ctrl_value; // FW_MAIN_1_SLV_FW_REGION_0_CONTROL3.5 步骤五:验证与锁定
在使能区域后,应通过安全核心和非安全核心分别尝试读、写操作,以验证防火墙规则是否按预期工作。可以使用简单的内存测试模式。确认一切正常后,最后一步是锁定配置,防止被恶意软件修改。
// 锁定 Region 0 配置 // 对 LOCK 位 (位4) 执行写1操作。注意:该位是 W1TS (Write-1-to-Set),直接写1即可。 uint32_t current_ctrl = *(fw_reg_base + 0x00/4); current_ctrl |= (1 << 4); // 设置 LOCK 位 *(fw_reg_base + 0x00/4) = current_ctrl; // 写入后,该区域所有配置寄存器将被锁定重要提示:锁定操作是不可逆的(直到下次复位)。务必在充分测试后再进行锁定。一旦锁定,任何试图修改该区域寄存器(包括尝试再次写入ENABLE字段)的操作都将被硬件忽略。
4. 深入原理:防火墙如何裁决一次访问?
理解了寄存器配置,我们再来看看硬件是如何利用这些信息工作的。当处理器内部的一个主设备(例如Cortex-A53核心)发起一次内存访问(比如一次加载指令LD),这个访问请求会带着几个关键属性在芯片互联总线上传输:
- 物理地址: 要访问的目标地址。
- 主设备ID: 标识是哪个主设备发起的请求。
- 安全属性: 该请求是来自安全世界(Secure)还是非安全世界(Non-secure)。这由处理器核心的状态(如SCR.NS位)决定。
- 特权等级: 该请求是处于监管者模式(Supervisor)还是用户模式(User)。
- 访问类型: 是读(Read)、写(Write)、调试(Debug)还是指令获取(Fetch)���以及是否是缓存操作(Cacheable)。
防火墙硬件模块会拦截这次访问,并执行如下裁决流程:
- 地址匹配: 防火墙将请求的物理地址与所有已使能(ENABLE=0xA)的前景区域的
START_ADDRESS和END_ADDRESS进行比较。地址比较是基���高位(如bit[47:12])的,低位对齐特性简化了比较器设计。 - 区域选择:
- 如果地址匹配了一个或多个前景区域,则选择其中匹配的一个区域(具体优先级规则需查手册,通常可能是编号最小或特定的)。
- 如果地址没有匹配任何前景区域,但存在一个已使能的背景区域(BACKGROUND=1),则选择该背景区域。
- 如果两者都不匹配,则访问被默认拒绝(通常产生一个错误响应)。
- 权限检查: 对于选定的区域,防火墙根据请求的主设备ID,选择对应的
PRIV_ID字段与之匹配的PERMISSION寄存器组(如PERMISSION_0)。然后,根据请求的安全属性、特权等级和访问类型,去查表检查相应的权限位是否为1。- 例如,一个来自非安全世界、用户模式的读请求,硬件会去检查
NONSEC_USER_READ位。 - 如果
CACHE_MODE使能,对于缓存访问,还会检查对应的*_CACHEABLE位。
- 例如,一个来自非安全世界、用户模式的读请求,硬件会去检查
- 裁决结果:
- 允许: 如果所有检查的权限位都为1,则访问被放行,转发给目标从设备。
- 拒绝: 如果任一检查的权限位为0,则访问被阻止。防火墙会向发起请求的主设备返回一个错误(例如,对一个读操作返回全零或特定数据,对一个写操作忽略写入,并可能置位一个错误状态寄存器,甚至触发一个安全异常中断)。
这个过程完全由硬件并行完成,速度极快,几乎不增加访问延迟,这是软件实现权限检查无法比拟的优势。
5. 常见配置陷阱与调试心得
在实际项目中配置防火墙,远比看手册复杂。下面分享几个我踩过的“坑”和总结的经验。
5.1 陷阱一:地址对齐与范围计算错误
这是最常见的问题。手册明确要求地址必须4KB对齐,但开发者容易忽略结束地址的“包含”语义和对齐处理。
- 错误示例: 想保护
0x8000_0000到0x8000_FFFF(64KB)的区域。- 错误计算:
START_ADDRESS_L = 0x80000(正确),END_ADDRESS_L = 0x800FF(错误!)。 - 后果: 实际保护的可能是
0x8000_0000到0x800F_FFFF(1MB)的地址范围,远大于预期,可能意外覆盖其他关键区域。
- 错误计算:
- 正确计算:
- 起始地址页帧号:
Start_PFN = START >> 12(例如0x8000_0000 >> 12 = 0x80000) - 结束地址页帧号:
End_PFN = (END >> 12)(例如0x8000_FFFF >> 12 = 0x8000F) - 写入
END_ADDRESS_L的值就是End_PFN(0x8000F)。
- 起始地址页帧号:
心得: 在代码中,强烈建议使用宏或内联函数来处理地址转换,避免手动计算错误。
#define FW_PAGE_SIZE 0x1000 // 4KB #define FW_ADDR_TO_PFN(addr) ((uint32_t)((addr) / FW_PAGE_SIZE)) #define FW_PFN_TO_ADDR(pfn) ((uint64_t)(pfn) * FW_PAGE_SIZE) // 配置函数片段 void fw_configure_region(uintptr_t base_addr, size_t size) { uint32_t start_pfn = FW_ADDR_TO_PFN(base_addr); uint32_t end_pfn = FW_ADDR_TO_PFN(base_addr + size - 1); // 包含的最后一个地址 // ... 写入寄存器 }5.2 陷阱二:权限位组合的副作用
权限位的设置需要系统性地考虑。例如,你只设置了SEC_SUPV_READ为1,但SEC_SUPV_CACHEABLE为0。如果安全监管者代码尝试以缓存方式读取该区域,即使READ权限允许,也会因为CACHEABLE权限不足而被拒绝。这在调试时表现为:明明有读权限,但访问却失败,需要仔细核对所有相关的权限位。
心得: 在规划权限时,画一个简单的矩阵表非常有帮助。行是主设备/安全状态/特权等级,列是访问类型(读、写、调试、缓存)。确保每个单元格都有明确的定义。
| 访问者 | READ | WRITE | DEBUG | CACHEABLE |
|---|---|---|---|---|
| 安全监管者 (R5F) | 1 | 1 | 0 | 1 |
| 非安全用户 (A53 App) | 1 | 0 | 0 | 0 |
| 非安全监管者 (A53 OS) | 0 | 0 | 0 | 0 |
| 调试器 (Secure) | 1 | 0 | 1 | 0 |
5.3 陷阱三:锁定过早或遗忘锁定
锁定(LOCK)是一把双刃剑。
- 锁定过早: 在配置未经验证完全正确时就锁定,会导致后续无法调整,如果配置有误,只能通过复位来恢复,影响开发效率。
- 遗忘锁定: 在产品化软件中,如果忘记锁定关键的安全区域(如存放密钥的OTP镜像区、安全监控代码区),则攻击者有可能在系统运行时利用某些漏洞修改防火墙规则,从而打开一个后门。
心得: 建立明确的开发流程。
- 开发/调试阶段: 在初始化代码中暂时注释掉LOCK操作。利用调试器或日志,充分测试各个主设备在不同模式下的访问行为。
- 验证阶段: 编写专门的防火墙配置验证函数,在系统启动后,读取并回显所有已配置的防火墙寄存器值,与预期值比对。
- 发布阶段: 在确认所有配置无误后,务必启用LOCK代码。可以考虑将锁定操作放在启动序列的较后阶段,在所有关键外设和内存初始化完成之后。
5.4 调试技巧:如何定位防火墙违例?
当访问被防火墙拒绝时,通常不会像空指针解引用那样产生一个明显的CPU异常(虽然可以配置触发中断)。更多时候,表现是数据读取错误(比如总是读到0)、写入无效,或者更隐蔽的,DMA传输失败。如何定位?
- 检查防火墙状态寄存器: AM64x/AM243x的防火墙模块通常配有错误状态寄存器。当发生违例时,这些寄存器会记录违例的主设备ID、违例的地址、访问类型等信息。在怀疑防火墙问题时,第一件事就是去读取并解析这些寄存器。具体寄存器名称和格式需要查阅《技术参考手册》中Firewall章节的“Error Status”部分。
- 使用调试器进行单步跟踪: 在调试器(如CCS)中,让代码在可疑的访问指令处单步执行。观察访问前后寄存器和内存值的变化。如果读操作后目标寄存器值异常(如全0),而内存实际有数据,防火墙拦截的可能性很大。
- 简化与隔离测试: 如果问题复杂,创建一个最小的测试工程。只初始化最基本的系统时钟和内存,然后配置一个简单的防火墙规则,接着让核心发起一个明确的访问,观察结果。这能排除其他驱动或软件栈的干扰。
- 查看芯片勘误表: 有些防火墙相关的问题可能是芯片特定版本的硬件缺陷。务必查看你所用芯片型号和硅版本对应的勘误表(Silicon Errata),看是否有已知的防火墙配置限制或问题。
6. 进阶应用:构建分层的安全内存模型
掌握了单个区域的配置,我们就可以在系统层面构建一个分层的安全内存模型。这对于运行复杂操作系统(如Linux in Non-secure world + RTOS in Secure world)的场景至关重要。
一个典型的分层模型如下:
- 安全核心私有区域: 使用防火墙将安全核心(如R5F)的代码TCM、数据TCM以及关键安全外设(如加密加速器、真随机数发生器)配置为仅安全监管者可访问,并锁定。这是最内层、最安全的堡垒。
- 安全世界共享区域: 划分一块共享内存(如本例中的4KB SRAM),配置为安全监管者可读写,非安全用户只读。用于向非安全世界传递经过验证的命令或数据。禁止非安全缓存以防止信息泄漏。
- 非安全世界操作系统内核区域: 在DDR中,Linux内核的代码和数据区可以配置为非安全监管者可读写,非安全用户只读或不可访问。这可以防止用户态程序恶意破坏内核数据。
- 非安全世界用户空间区域: 普通应用程序内存。通常由MMU管理,但可以配合防火墙设置一个���景区域规则,默认允许非安全用户访问其分配的内存,但禁止任何调试访问(防止通过调试接口窃取数据),并对特定敏感区域(如映射的硬件寄存器)设置前景区域进行保护。
- 外设隔离: 不同的外设分配给不同的核心或域。例如,将某个通信接口(如SPI)的配置寄存器区域,通过防火墙设置为仅某个特定的R5F核心可访问,即使A53内核被攻破,也无法直接操作该外设。
这种模型的核心思想是“最小权限原则”。每个软件组件(核心、任务、驱动)只能访问它完成功能所必需的最少资源,其他访问一律禁止。硬件防火墙为实现这一原则提供了坚实、高效且难以绕过的硬件基础。
配置这样一个模型需要全局的地址空间规划和精密的启动顺序编排。通常由最先启动的安全引导加载器(Bootloader)完成所有防火墙的初始配置和锁定,然后再引导非安全世界的操作系统。这要求开发者在项目早期就参与系统架构设计,与软件、系统工程师共同制定内存映射和安全域划分方案。
