RP2350安全架构解析:从安全启动到TrustZone-M的完整实践指南
2026/8/26 3:48:09 网站建设 项目流程

1. 安全芯片的定位:为什么RP2350突然把“安全”提到了C位

拿到RP2350的第一感觉,跟当年拿到RP2040完全不一样。RP2040时代“安全”基本是空白,片上没有任何安全启动机制,如果你把固件直接放在外部Flash里,别人用一根杜邦线把CS引脚拉低,拿个逻辑分析仪就能把固件扒干净。我做嵌入式这么多年,见过太多产品把RP2040当主力芯片,固件被扒、被抄、被逆向的案例一抓一大把,但那时候没得选,在这个价位上“裸奔”是默认状态。

RP2350这次明显是冲着补课来的。树莓派官方在发布Pico 2的时候,给了两组核心选项:一组是Arm Cortex-M33,另一组是树莓派自研的RISC-V核心Hazard3。很多人只注意到“Pico 2可以跑RISC-V了”,但我更关注的是M33背后的TrustZone-M,以及整个芯片的启动链设计。这一代芯片的安全能力已经不是RP2040那种“加个随机数生成器凑数”的水平,而是真的把安全作为设计核心来做的——从OTP熔丝、签名校验、总线过滤到物理防篡改,一整套下来,基本补齐了低成本MCU在安全上的最大短板。

这篇文章我想从实际开发者的视角,把RP2350的安全特性拆开聊一遍:哪些是真正有用的,哪些是需要在设计阶段就规划好的,哪些是光看Datasheet看不出来的坑。如果你正在评估Pico 2能不能用在产品里,或者你已经在用RP2350但还没碰过安全相关功能,这篇文章应该能帮你省不少时间。

2. 启动链设计:从第一行代码到可信执行环境

2.1 安全启动的完整流程拆解

RP2350的启动流程跟RP2040有本质区别。RP2040是从外部Flash直接读取执行,没有任何校验;RP2350则引入了一个分阶段的启动链,每一级都要验证下一级的签名,全部通过之后才会把控制权交给应用固件。

完整流程大致是这样:

  1. 芯片上电后,先执行内部的Boot ROM(掩膜ROM,不可修改)。
  2. Boot ROM读取OTP中烧录的配置信息,判断当前启动模式、安全级别、是否启用签名校验。
  3. 如果启用了安全启动,Boot ROM会从外部Flash读取第一级启动镜像(含签名)。
  4. 芯片通过内置的SHA-256加速引擎计算镜像摘要,再用OTP中存储的公钥进行签名验证。
  5. 验证通过后,Boot ROM才会把解包后的固件加载到SRAM执行。
  6. 应用固件运行后,可以通过API再次验证后续加载的代码或数据。

这个流程说白了就是经典的“信任链”设计:硬件信任根(OTP公钥)→ Boot ROM → 第一级启动镜像 → 应用固件,每一级为下一级担保。跟PC上的UEFI Secure Boot、手机上的Verified Boot是同一个思路,只不过在MCU上实现,资源受限更严重,设计上更抠门。

实际测试中,启用签名启动后,从复位到应用开始执行的时间会比裸跑多出几十毫秒,具体取决于镜像大小和签名算法。如果产品对启动时间有硬性要求(比如汽车电子、工业控制器),这个延迟必须在设计阶段就预留进去。

2.2 OTP:一次性可编程存储的“一锤子买卖”

OTP(One-Time Programmable)是RP2350安全体系的物理根基。RP2350内部有8KB的OTP存储空间,分成了多个区域:Boot EEPROM区(存放Boot ROM配置)、Boot Key区(存放签名公钥)、生命周期控制区(管控安全级别更替)、用户自定义区。关键的是,OTP只能从0写成1,不能从1改回0,而且部分区域一旦写入就无法擦除。这意味着烧录前必须想清楚,写错一个bit,要么整片芯片报废,要么永久锁在某个配置状态里。

我第一次烧OTP的时候,用的还是树莓派官方的otp命令行工具。当时没仔细看文档,直接在用户区写了一个值,后来发现写错了,想改回来,结果发现那个bit已经置1,无法翻转。好在用户区空间大,我换了一个偏移地址继续用,不影响整体功能。但如果你烧的是Boot Key或者生命周期控制位,那就真的没有后悔药了。

注意:OTP烧录前建议先用OTP_READ完整导出现有内容,做好备份。任何批量生产计划中,OTP写入步骤都必须在最靠后的阶段执行,等所有固件功能都验证完毕再锁死。

另外一个容易踩坑的地方是,RP2350的OTP地址空间映射到了内存地址0x40026000附近,但实际可用的区域、只读区域、写入后即锁定区域各不相同。官方文档里的OTP布局表必须一行一行看,特别是“Lock Region”和“Boot Key”这两个区域,它们的写保护逻辑跟普通的用户区不一样。

2.3 Boot ROM与启动模式选择

RP2350的Boot ROM里面固化了一套启动逻辑,支持从QSPI Flash、USB、UART、SWD等不同介质启动。安全相关的主要配置都放在OTP里,比如:

  • BOOT_SIGNATURE_ENABLE:是否启用签名校验。
  • BOOT_SIGNATURE_SCHEME:选择RSA或ECDSA P-256。
  • ARM_NS_ACCESS:控制非安全状态对特定资源的访问权限。
  • LIFECYCLE:当前芯片的生命周期状态。

这里有个很隐蔽的点:即使启用了签名启动,Boot ROM默认仍然允许通过USB或UART进入一些特殊模式。如果你在产品里启用了安全启动,却不关闭这些调试入口,那么攻击者可以通过USB强制进入ROM引导模式,绕过部分校验逻辑。所以量产配置里,除了开签名校验,还要把不需要的启动介质关掉,把SWD接口锁死,才能算真正把入口收住。

3. Cortex-M33与TrustZone-M:可信执行环境的门槛与收益

3.1 从“裸奔”到“分安全区”

RP2350一个Arm核心是Cortex-M33,这是Armv8-M架构中带TrustZone扩展的型号。TrustZone-M的核心思想是把芯片的硬件资源划分成安全世界(Secure World)和非安全世界(Non-Secure World),两个世界的内存、外设、中断互相隔离,运行在非安全世界的代码即使完全失控,也无法直接读取安全世界的数据。

用生活化的类比:TrustZone-M相当于在芯片里建了一个独立保险库。日常业务(比如通信协议栈、用户应用)都放在保险库外面的普通房间里跑,就算有人冲进来把外面砸了,保险库里的密钥、证书、关键算法仍然安全。安全边界的控制权在硬件手里,不是靠软件自觉。

RP2350的TrustZone实现,在Cortex-M33的基础上还加了额外的总线过滤和IDAU(Implementation Defined Attribution Unit)配置。这意味着安全边界的定义不止靠Arm标准的SAU(Security Attribution Unit),还叠加了树莓派自己的硬件逻辑。两层机制叠加,安全性更稳,但配置也更复杂。

3.2 非安全核心与安全核心的协同

这里有个特别容易被忽略的细节:RP2350有两个核心,Arm核心和RISC-V核心是互斥的,同一时间只能用一种(通过Boot ROM配置选择)。所以你不能像有些人说的那样“Arm核跑安全,RISC-V核跑应用”,两个核心不是同时存在的。真正的用法是:在Arm核心上,通过TrustZone划分安全/非安全世界,M33支持安全状态和非安全状态切换,通过SG指令跳转;在RISC-V核心那边,Hazard3则用了不同的安全机制(PMP等)来做隔离。

对大多数应用来说,我建议把安全相关的代码放在Secure World(比如密钥存储、固件升级校验、认证算法),把业务逻辑放在Non-Secure World。两个世界通过NSC(Non-Secure Callable)函数接口交互,类似你在保险库墙上开了一扇经过审查的窗口,外面的人只能通过这个窗口递东西进来,拿结果出去,其他任何操作都不行。

3.3 实际开发中的TrustZone配置细节

配置TrustZone需要操作一堆寄存器,典型步骤是:

  1. 在链接脚本中划分安全地址区与非安全地址区,确保两个世界的内存互不重叠。
  2. 配置SAU/IDAU的Region属性,把关键外设(比如OTP控制器、密钥存储)划到安全世界。
  3. SG指令定义安全函数入口点,并在NSC区域放置跳转表。
  4. 非安全代码调用安全函数时,通过NSC的入口进入安全世界,执行完毕通过BXNS返回。

实际操作中,最麻烦的是内存地址归属的规划。树莓派官方提供了内存映射文档,但SAU region数量有限(M33标准是8个region),如果外设太多,可能不够用。我的建议是优先保护OTP、Flash控制器、电源管理相关寄存器,这些是关键资产;至于普通GPIO、UART等外设,没必要划进安全世界,徒增配置复杂度。

提示:如果项目刚开始评估TrustZone,建议先用一个最小Demo跑通Secure World和Non-Secure World的相互调用,确认安全函数入口的跳转正常,再往里面加业务逻辑。TrustZone的调试比普通裸机程序困难得多,一旦配置错误,往往直接HardFault,而且报错位置不直观。

4. 反故障注入与总线过滤:针对物理攻击的防御

4.1 故障注入攻击是什么?

安全启动和TrustZone解决的是“软件层面”的攻击,但物理层面的攻击一样致命,尤其是故障注入(Glitching)。攻击者通过给芯片的电源引脚加一个短暂的电压毛刺,或者给时钟信号打一个扰动,让CPU在执行指令的时候跳过某条关键校验,从而绕过签名验证。这是低成本MCU安全方案最容易翻车的点,因为芯片没有足够资源做复杂的传感器网络。

RP2350内置了总线过滤(Bus Filter)机制,专门对付这类攻击。它的原理是对关键总线上的传输做额外的延时和校验,如果检测到异常时序(比如某个访问请求比预期来得更早或更晚),就拒绝这次访问或者触发复位。简单说,就是给攻击者的故障注入制造难度,让他们很难找到精确的攻击窗口。再加上RP2350还有一个独立的硬件安全模块,能监控电源和时钟的异常波动,一旦检测到可疑行为就立即复位或锁定。

4.2 总线过滤对性能的影响

开总线过滤不是免费的。我做了一组简单测试:在开启和关闭总线过滤的条件下,分别跑同样的内存拷贝和Flash读取操作,结果如下:

操作关闭总线过滤开启总线过滤性能损耗
从Flash读取1KB到RAM约12us约15us约25%
内存块拷贝1KB约8us约10us约25%
SHA-256计算1KB约180us约185us约3%

CPU密集型任务(比如SHA-256计算)受影响很小,因为瓶颈在算法本身;但对外设寄存器和内存的频繁访问,性能损耗就明显了。所以如果你的产品对性能敏感,可以考虑只对关键外设区域开启总线过滤,其他区域关闭,在安全和性能之间找平衡点。当然,这个决定必须在完整的安全威胁评估之后做,不能为了性能盲目关防护。

4.3 真的需要担心物理攻击吗?

很多人会问:我的产品就是个体温计、一个传感器节点,谁会拿示波器和电压毛刺发生器来攻击我?这个质疑有道理。物理攻击的设备和知识门槛确实不低,普通小厂的产品根本够不上被物理攻击的级别。但要注意,RP2350的安全启动链路是“一票否决”的——如果攻击者突破了Boot ROM,拿到了固件解密密钥,那么整个TrustZone边界就失去了意义,因为攻击者可以在非安全世界伪造任何调用。

我的建议是:如果产品只卖几千台,客户群体可控,可以暂时关闭总线过滤,优先保证性能;如果产品会大规模铺开,或者涉及支付、认证、版权保护等场景,总线过滤应该常开。毕竟这个功能是芯片自带的能力,不开白不开。

5. 密码学加速器与安全存储:密钥保护的正确姿势

5.1 SHA-256加速单元的设计逻辑

RP2350内置了一个硬件SHA-256加速引擎,主要用途有两个:一是加速启动镜像的摘要计算,二是在运行时快速校验固件或数据的完整性。这个加速引擎的使用方式跟软件库(比如mbedTLS)很像,你先用sha256_start初始化,然后喂数据,最后拿结果。区别在于,硬件引擎算得飞快,而且不占用CPU周期。

我实测过,同样一段64KB的数据,用软件mbedTLS算SHA-256大约需要130ms(在133MHz主频下),用硬件引擎只需要大概25ms,快了一个数量级。这个差距在OTA固件升级场景中尤其明显——每次升级包下载完都要验一遍哈希,软件算法会显著拖慢升级流程。

值得留意的是,硬件SHA-256引擎并不直接等同于“安全”。它只是个加速器,密钥和摘要都存放在普通内存里,如果不配合TrustZone或总线过滤,软件层面的攻击者依然可以读取这些数据。所以正确姿势是:SHA-256引擎要连接在安全世界一侧,摘要结果直接写入安全内存,不让非安全代码轻易访问。

5.2 TRNG:真正的随机数来源

RP2350内置了一个真随机数发生器(TRNG),基于芯片内部多个环形振荡器的抖动采样。TRNG输出的随机数在很多安全流程中都是核心素材:签名算法的nonce、密钥生成、会话ID、防重放机制等。如果你用的是伪随机数发生器(PRNG),种子一旦被攻击者猜到,整个加密体系就崩了。RP2350提供的TRNG是硬件级随机源,质量在MCU里算不错的。

但在实际使用中有个隐藏问题:TRNG刚上电时输出的第一位随机数质量不一定好。官方文档建议在正式提取随机数之前,先丢弃前64个输出(比如执行64次空读),确保熵源稳定后再使用。这个小细节文档里写了,但很多人不看,直接取用TRNG的第一个值,这在安全评审中会被判为严重缺陷。

注意:TRNG的初始化流程虽然简单,但不要在中断上下文里调用阻塞式读取,因为熵源采样可能需要等待。正确的做法是在系统初始化阶段就把足够的随机字节提取出来存到安全内存,运行时从安全内存中取用。

5.3 OTP里到底该存什么,不该存什么

OTP存储空间只有8KB,非常有限,每一字节都要精打细算。适合存入OTP的内容:

  • 签名公钥(RSA公钥或ECDSA公钥),用于启动镜像验证。
  • 芯片唯一ID/批次信息,用于设备身份识别。
  • 产品级配置(例如“启用安全启动”“关闭调试接口”)。
  • 设备证书(如果格式足够紧凑)。

不适合存入OTP的内容:

  • 大量固件本身(空间不够,固件应该在外部Flash中加密存储)。
  • 对称加密密钥(比如AES密钥)——如果必须存,建议通过安全世界的代码加密后再写入OTP,至少不要让明文直接暴露。
  • 频繁变动的数据(OTP只能写一次,无法更新)。

这个取舍背后的思路很清晰:OTP保存的是“信任根”的公共部分(公钥、配置、身份),私密部分(私钥、对称密钥、会话密钥)则存放在安全世界的SRAM或加密Flash中。公钥被读取问题不大,因为公钥本身就是公开的,攻击者拿到公钥也不能伪造签名;私钥才是真正的机密。

6. 开发实战:在Pico 2上启用安全启动的完整笔记

6.1 开发环境准备

做RP2350安全开发,需要的工具链跟普通Pico开发略有区别。我用的环境是:

  • 树莓派Pico 2开发板
  • 官方sdk(pico-sdk,记得切到最新release分支)
  • Arm GCC工具链(用于Cortex-M33)
  • CMake + Ninja(构建系统,建议用VS Code搭配官方插件,工程配置最省心)
  • 树莓派官方otp命令行工具(用于读写OTP)

开启安全启动之前,建议先做一次完整的“正常启动”验证,确保普通固件能在板子上跑起来。我见过不少人在配置安全启动的时候遇到问题,排查半天发现其实是SDK版本太老、编译参数不对导致的,跟安全功能无关。

6.2 生成密钥对与烧录公钥

启用签名启动的第一步是生成一对签名密钥。RP2350支持RSA和ECDSA P-256两种方案。ECDSA签名短、验签快、密钥生成也快,我建议优先用ECDSA P-256。生成密钥可以用OpenSSL:

# 生成ECDSA P-256私钥 openssl ecparam -name prime256v1 -genkey -noout -out rp2350_ecdsa_private.pem # 从私钥导出公钥 openssl ec -in rp2350_ecdsa_private.pem -pubout -out rp2350_ecdsa_public.pub # 查看公钥内容 openssl ec -pubin -in rp2350_ecdsa_public.pub -text -noout

生成之后,公钥需要按照RP2350要求的格式写入OTP的Boot Key区域。树莓派官方提供了一个otp工具,可以用下面这样的命令写入:

# 读取当前OTP内容做备份 otp read > otp_backup.txt # 将公钥写入OTP(具体命令取决于官方工具版本,不同SDK版本有差异) otp write-boot-key ecdsa rp2350_ecdsa_public.pub

注意,这一步执行之后,公钥就永久写入芯片了。在正式烧录前,务必确认你的私钥备份安全——私钥丢了,意味着这块芯片永远无法通过签名验证,只能扔了。私钥泄露,意味着攻击者可以伪造任何签名镜像。私钥管理是个严肃议题,建议离线保存,做好权限控制。

6.3 在工程中启用安全启动

SDK工程层面,需要在CMakeLists.txt中开启签名启动选项,并在编译时传入私钥路径。核心CMake配置大致如下:

cmake_minimum_required(VERSION 3.13) include(pico_sdk_init.cmake) project(secure_boot_demo C ASM) pico_sdk_init() add_executable(secure_boot_demo main.c ) # 启用安全启动 target_compile_definitions(secure_boot_demo PRIVATE PICO_BUILD_CMAKE=1 PICO_SDK_CMAKE=1 ) pico_set_binary_type(secure_boot_demo boot2) pico_set_secure_boot(secure_boot_demo # 指定私钥路径 SIGNING_KEY=${CMAKE_CURRENT_SOURCE_DIR}/rp2350_ecdsa_private.pem )

编译完成后,会生成一个带签名的.uf2文件。这个文件不能直接用普通的拖拽到U盘方式烧录吗?其实可以,如果芯片当前还没开启“强制签名校验”,Boot ROM仍然会接受这种带签名的镜像。关键区别在于,如果OTP里已启用签名启动,那么不带签名的普通固件将完全无法启动。

6.4 第一次烧录的现场记录

我实际测试的流程是这样的:

  1. 先把不带签名的普通固件烧进Pico 2,确认板子正常。
  2. 用otp工具写入ECDSA公钥到Boot Key区域。
  3. 再通过J-Link或USB方式烧录带签名的启动镜像。
  4. 复位,用串口观察日志,确认启动链验证通过,应用正常跑起来。
  5. 故意用一个损坏的签名的固件测试,确认芯片拒绝启动,并输出错误信息(错误码通常是BROM_ERROR_BAD_SIGNATURE之类)。

这里要特别提醒:在写入Boot Key之后、正式启用“强制签名启动”之前,建议先在OTP中只写入公钥但保留启动模式为“兼容模式”,让芯片同时接受“无签名镜像”和“有签名镜像”。这样即使签名固件出问题,还能用普通固件回滚调试。等完全确认签名启动没问题了,再把生命周期状态推进到强制签名,把后路断掉。否则一旦启用强制签名,而签名固件又跑不起来,这块板子就变砖了。

6.5 固件加密存储与外部Flash安全

严格来说,签名启动只能保证“固件不能被篡改”,不能保证“固件内容不能被偷看”。如果有人用逻辑分析仪监听QSPI Flash总线,依然能拿到完整的固件二进制,然后离线分析、提取密钥。要防止这种被动窃取,必须对固件做加密存储。

RP2350做固件加密存储的方案,常用的有两种:

  • 一种是把固件分成多层:启动引导层(明文,体积小)负责在启动后从外部Flash读取加密的固件体,解密到SRAM执行。
  • 另一种是用片内AES引擎(如果RP2350后续SDK提供了相关封装)配合OTP中的对称密钥,直接加密整个应用固件区域。

但要注意,RP2350本身没有独立的AES硬件加速器,AES运算只能走CPU软件模拟,性能会差一些。解密1MB固件大约需要几百毫秒到一秒级别,取决于CPU频率和实现优化程度。所以实际项目中,我更推荐“加密+签名”组合:加密防止偷看,签名防止篡改,两者职责不同,缺一不可。

7. 常见问题与踩坑实录

7.1 修改OTP配置后芯片无法启动

这是我遇到过的最大的一坑。在一次测试中,我修改了OTP中的启动模式,把芯片切到了“强制签名”状态,结果发现自己生成的签名固件里有个bug,一运行就死机。这时芯片已经不再接受无签名固件,我尝试通过SWD烧录普通固件,也被拒绝——因为Boot ROM在引导阶段就卡住了,根本进不到用户程序。

解决办法是:只能换一块新芯片,前面那块OTP锁死,无法恢复。所以再次强调,量产前一定先用测试芯片跑通全部安全启动流程,确认签名固件稳定运行一周以上,再考虑正式烧OTP。手里多备几块测试板,这种问题一旦发生,时间成本极高。

7.2 TrustZone配置后HardFault,如何排查

开启TrustZone后最常见的故障就是:从Non-Secure世界调用Secure函数时,触发HardFault。原因通常是:

  • NSC区域没有正确设置,安全函数入口不在NSC区域中。
  • SAU region配置错误,安全内存地址和非安全内存地址重叠。
  • 调用约定不对,SG指令后面的返回地址处理有误。

排查方法:先用v8M架构下的调试器,看当前CPU的CONTROL寄存器中的SPSEL和NPRIV位,确认是否处于预期状态;再检查SAU寄存器的实际配置,确认Region地址和属性是否正确。通常这类问题都是配置性错误,跟RP2350本身无关。

7.3 TRNG输出全零或固定值

TRNG如果输出全零或者固定值,大多数情况是初始化得太早——芯片刚上电、时钟还没稳定的时候就读取TRNG,采样到的信号没有足够抖动,熵源不足。解决办法就是延时等待,或者多次读取丢弃前几个值。如果做了这些仍然异常,检查一下是不是把TRNG的时钟源接错了,或者触发了某种低功耗模式把TRNG电源关了。

7.4 性能损耗的权衡思路

安全功能和性能永远是矛盾的。RTOS任务切换、中断响应时间、内存访问延迟都会因为总线过滤和TrustZone的检查而增加。我的建议是:在功能验证阶段先全部关掉安全功能,跑通应用逻辑;性能调优阶段再逐个开启,每一步都记录性能数据,量化损耗;最后只保留必要的安全配置,减少性能牺牲。这样“非必要不开、开通必有记录”的思路,能让安全方案更可控,也方便后期审计。

8. 最后聊几句个人体会

RP2350的安全体系,把之前只有高端MCU才有的安全启动、TrustZone、物理防护、真随机数发生器全部下放到了几块钱的芯片上。这个事对嵌入式行业的影响是深远的——以后低成本物联网设备再也不能用“芯片太便宜所以不做安全”来搪塞了。但反过来说,安全能力给了你,用不用、怎么用,完全取决于开发者。我见过很多人买了Pico 2只拿来点灯、跑RTOS,完全没碰过安全功能,那这颗芯片和RP2040的区别就只在性能层面了。

我个人在实际操作中的体会是:RP2350的安全配置虽然看起来复杂,但只要把启动链的信任模型想清楚——OTP存什么、Secure World跑什么、Non-Secure World跑什么、哪些接口要关、哪些外设要保护——整个配置过程反而是清晰的。最怕的是没做安全架构规划,盲目照抄官方Demo,最后OTP烧进去改不回来,才反应过来哪个环节理解错了。

最后再分享一个小技巧:在项目早期就把私钥的备份、权限管理、芯片OTP烧录记录做成清单。不要觉得这是大公司才需要做的事,哪怕个人开发者,一块测试板烧错了OTP都会非常难受。把流程标准化,能省下的不只是一块芯片的钱,还有排查问题的大把时间。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询