双核MCU架构解析:从AMP/SMP到TrustZone与安全岛

发布时间:2026/8/27 11:36:47
双核MCU架构解析:从AMP/SMP到TrustZone与安全岛 这款芯片方案我最近刚好在项目中实际评估过也跟几个做工业物联网网关的朋友聊了很多。Dual-Core MCUs 在2023年之后明显已经不是尝鲜定位而是大量进入了需要同时满足高性能计算和安全合规的正式选型清单。传统单核 MCU 在跑复杂协议栈和实时控制时经常捉襟见肘而双核架构可以让应用任务与安全任务各占一个核心互不拖累。这篇文章我会从双核到底解决了什么问题讲起拆解 AMP/SMP 架构差异、TrustZone 与安全岛的工作机制、核间通信的设计要点再给出一套从启动流程到安全配置的实操思路最后聊聊主流型号的选型对比和我踩过的几个真实坑。不管你是正在做 IoT 设备、工业控制器还是对 PSA 认证有硬性要求的产品这篇内容应该都能帮你少走不少弯路。1. 双核 MCU 到底解决什么问题1.1 单核 MCU 为什么开始不够用先说个很典型的场景。去年有个做智能门锁的客户找我评估方案他们的需求是指纹识别算法要跑得快、蓝牙协议栈要稳定、本地存储的关键数据要加密同时还要过客户的网络安全审查。单核 MCU 不是不能做但把所有任务塞进去之后CPU 占用率常年维持在 80% 以上一旦蓝牙传输大文件或者算法误匹配率高一点系统响应延迟直接飙升。更要命的是安全任务和应用任务跑在同一个核上本质上没有任何隔离一个缓冲区溢出漏洞就可能把整个系统打穿。这种情况在过去十年里其实一直存在但矛盾并不突出。以前的 MCU 应用相对简单裸机程序 中断就能搞定安全需求也停留在能用 AES 加密就行的层面。但现在的嵌入式设备尤其是物联网终端、工业控制器、医疗设备普遍要面对三座大山第一通信协议栈越来越重MQTT、TLS、EtherCAT、PROFINET 这些基础连接成本就吃掉大量算力第二算力需求越来越高的本地处理任务比如边缘 AI 推理、语音识别、图像预处理第三安全已经不是加分项而是合规项PSA Certified、SESIP、IEC 62443 这些认证要求产品必须具备可信启动、安全存储、安全更新能力。单核方案应对这三座大山的方式基本只有硬扛用更强的内核比如从 Cortex-M4 升级到 M7或者拉高主频。但问题在于安全任务和应用任务跑在一个核上底层的隔离问题是频率解决不了的。哪怕你用 MPU内存保护单元勉强划出几个区域MPU 的粒度也是有限的而且配置复杂、极易出错。更重要的是MPU 隔离的只是内存访问权并没有对系统做架构级的可信分区攻击面依然很大。1.2 性能与安全为什么非要拆到两个核很多人会问我换一颗更强的主频更高的单核 M33/M7 MCU再加一颗外部安全芯片不是也能同时满足性能和安全吗确实可以而且这是很多产品的常规做法。但你仔细算一笔账就会发现问题外置安全芯片SE的方案首先 BOM 成本增加一颗稍微像样点的安全芯片批发价少说也要两三美金其次安全芯片和主控之间要跑 SPI 或 I2C 通信协议通信本身就有性能和延迟瓶颈其三外置 SE 的功能边界是固定的很难根据你的产品做深度定制比如你的设备需要特定的安全启动流程、需要生命周期管理外部 SE 往往给不了那么细的颗粒度。双核 MCU 的思路是在同一颗芯片上放两个 CPU 核心一个核心专门负责安全功能可信启动、密钥管理、安全存储另一个核心处理应用逻辑和通信协议。两个核心之间通过硬件隔离机制划分权限边界互不干扰。这个方案有几个立竿见影的好处首先是成本单芯片双核通常比 MCU SE 便宜其次是性能核间通信走内部总线远比 SPI 快最重要的是隔离性安全关键代码跑在单独的物理核心上即使应用核被攻破攻击者也无法直接读取安全核的密钥和关键数据。双核还有一个常被忽略的好处它把功能安全和信息安全拆开处理了。这两类安全目标在工程上其实经常互相打架——功能安全要求系统做出确定性响应信息安全要求系统做认证、加密、阻止恶意访问。跑在一个核上优先级怎么排都是问题拆到两个核上功能安全逻辑放在应用核按实时优先级调度信息安全逻辑放在安全核独立运行边界一下子就清晰了。2. 双核 MCU 的核心架构AMP、SMP 与安全岛2.1 AMP 与 SMP两种主流双核工作模式聊双核架构绕不开 AMP 和 SMP 这两个概念。SMP对称多处理指的是两个核心运行同一个操作系统操作系统负责把任务分配给任意一个核心这对软件开发者来说比较友好因为不需要太关心任务跑在哪个核上。但在 MCU 领域SMP 其实不是常见方案原因也很直白MCU 上跑的 RTOS 多以实时性为核心诉求任务在哪个核上执行、缓存一致性怎么保证、中断如何分配这些在 SMP 模式下会引入大量复杂度和不确定性而且小资源 MCU 本身也不太需要这种能力。SMP 更多见于 Linux 跑在应用处理器上的场景MCU 的 SMP 支持近几年虽然有点进展实际量产项目里依然很少看到。AMP非对称多处理才是 MCU 双核架构的主流形态。AMP 模式下两个核心各跑各的——可以一个跑 RTOS、一个跑裸机或者两个跑不同的 RTOS甚至一个高性能应用核配一个低功耗安全核。两个核心之间的分工是明确的各有各的代码、各有各的外设资源和内存区域。这种模式之所以在 MCU 上受欢迎核心原因就是确定性关键任务的执行时间可预测、隔离边界清晰、调试相对简单。常见的 AMP 搭配有几种类型我实际接触最多的是Cortex-M33 Cortex-M4和Cortex-M4 Cortex-M0这两种组合。前者是 NXP LPC55S6x 系列那一类双 M33 核或者 M33 M4两个核都能独立跑应用后者是 Infineon PSoC 64 这类高主频 M4 做主应用核小核 M0 做安全岛安全核的固件在出厂前就被锁定用户改不了只能调用固定的安全服务接口。还有一种是 STM32H7 系列的M7 M4组合M7 主核跑高算力任务M4 从核跑通信协议或外设管理。这种架构没有 TrustZone硬件隔离主要靠两个核各自的 MPU 以及总线层面的访问控制整体安全强度比 M33 TrustZone 弱但对于不需要顶级安全认证的工业控制、电机驱动场景性能和成本平衡得非常好。2.2 安全岛与 TrustZone 怎么承担安全双核 MCU 里面的安全不能只说是有个独立核就算数关键看芯片有没有提供配套的硬件安全机制。目前主流的实现方案有两条技术路线一条是 Arm 的 TrustZone 技术另一条是安全岛Secure Enclave架构。TrustZone 是 Armv8-M 架构引入的硬件安全扩展Cortex-M33 和 Cortex-M23 内核都支持。它把整个系统划分为 Secure安全和 Non-Secure非安全两个世界通过 SAUSecurity Attribution Unit、IDAU、以及外设访问控制单元PPC来控制每个地址区域和外设的访问权限。运行在 Non-Secure 状态的应用代码物理上无法访问被标记为 Secure 的内存和外设。这等于说即使应用核的程序被人逆向、甚至被植入恶意代码攻击者也够不到安全区里的密钥和关键代码。配合 CMSECortex-M Security Extensions机制Non-Secure 代码还可以通过安全网关SG 指令调用 Secure 世界提供的接口函数实现我可以叫你帮忙但不能看你的内部实现这种受控访问。安全岛架构则是另一种思路以 PSoC 64 为代表。芯片里固化了一个极小极精简的安全核心通常是 Cortex-M0它在出厂时就被刷入了预配置的信任根固件并且被锁死用户的任何调试接口都无法访问这个核心的内部。应用核通常是 M4只能通过定义好的 API 接口向安全岛请求密钥操作、安全存储、设备身份认证等服务。这种方案的优点是安全边界极其清晰安全岛内部的代码永远不会被用户搞坏非常适合对安全有强合规要求、又要控制开发风险的产品团队。缺点也比较明显灵活性低安全岛的固件是厂商预置的你想定制某些安全逻辑基本没门。TrustZone 方案相对更灵活安全区代码完全由开发者自己写配合不同芯片的安全启动方案可以打造完全定制化的安全系统。但灵活性也意味着责任TrustZone 的配置非常容易出错——SAU 划分不对、NSC 区域没设置好、外设授权遗漏任何一个环节出错都可能导致系统崩溃或者在启动后留下可被利用的漏洞。2.3 核间通信双核协同的关键机制双核架构真正难的地方不在核本身而在两个核之间怎么高效、可靠地通信。我见过不少开发者在选型阶段觉得双核很香结果一到写代码阶段就卡在核间通信上。常见的核间通信IPCInter-Processor Communication机制有几种共享内存 软中断、硬件邮箱Mailbox、以及厂商专门提供的双核通信框架。共享内存是最直接的方式两个核共同访问一段内存区域通过标志位或者自旋锁来避免冲突数据交换效率高但需要开发者自己维护同步逻辑稍不留神就可能出现竞态条件。硬件邮箱由芯片提供专用寄存器或 SRAM 区通过硬件机制保证写入的原子性通常还配有邮箱中断收发双方不用轮询性能稳定但传输数据量有限一般用于传控制消息大块数据还是得走共享内存。值得一提的是很多厂商现在都会提供开源的核间通信框架比如 NXP 的 RPMsg-Lite、OpenAMPST 也有基于消息缓冲区的双核通信例程。这些框架封装了底层细节让你可以像调用普通 API 一样在两个核之间收发消息极大降低了开发门槛。但框架不是万能的实际项目中我还是建议开发者对底层机制有基本理解至少要清楚消息是存在哪里的、中断是哪个优先级、如果缓冲区满了会怎样否则出了问题现场根本没法快速排查。核间通信的设计里还有一个容易踩坑的点内存屏障和缓存一致性。比如 STM32H7 的 M7 核心带 L1 Cache如果两个核通过共享内存通信M7 写数据时先写进缓存M4 读取时没有失效相应缓存行拿到的是旧数据。这个坑特别隐蔽排查起来很费劲。解决办法是共享内存区域强制配置为不缓存Non-Cacheable或者在通信协议里显式执行缓存清理和失效操作。3. 双核安全 MCU 项目怎么落地从启动到安全配置3.1 功能拆分与启动流程设计拿到一颗双核 MCU 之后第一步工作不是写代码而是做功能拆分。拆分的核心原则很简单安全相关的任务密钥管理、安全启动校验、固件更新验证、设备身份放安全核实时控制、通信协议、上层业务逻辑放应用核。但实际操作起来没有那么理所当然。比如设备里如果有指纹识别之类对算力要求高的任务放哪个核这要综合考虑功耗、热、调度延迟和内存占用。一个我在项目中常用的判断方式是任务的实时性要求越高、与物理外设交互越频繁就越应该放在主应用核任务的安全属性越强、越怕被应用层干扰就越应该放进安全核。启动流程是整个双核系统的地基。典型的双核安全 MCU 启动流程大致是这样的芯片上电后先由 ROM 的 BootROM 代码执行验证并启动第一个核心通常是安全核。安全核运行安全启动代码检查应用核固件的签名和哈希值确认固件完整可信之后把应用核从复位状态释放并设置好安全核与应用核之间的通信通道。安全核然后进入服务循环等待应用核通过 IPC 发来的安全请求。这个流程保证了所有核心都运行在可信基础之上任何一步校验失败系统都不会把控制权交到不可信的代码手里。需要注意不同厂商的启动细节差很多比如有些芯片是固定某个核心先启动有些芯片支持启动源选择有些芯片的应用核需要等待安全核完成初始化并显式拉高复位脚。选型的时候一定要仔细看 reference manual 里 reset 和 boot 那一章搞清楚自己的目标芯片到底怎么把两个核拉起来。我见过不止一个团队在移植代码时想当然地认为应用核上电就会运行结果外设初始化全部写在了应用核的启动代码里实际却因为安全核没有初始化时钟而卡死。3.2 TrustZone / 安全岛的隔离配置实操配置 TrustZone 隔离说简单也简单说复杂也复杂。以常见工程为例你可以先用厂商的配置工具比如 NXP 的 MCUXpresso Config Tools、ST 的 STM32CubeMX图形化地划分 Secure 和 Non-Secure 区域。工具的便利性体现在它能自动生成 SAU 配置、内存映射和外设授权设置大幅度降低上手门槛。但我要说的是工具生成的东西必须理解后再接手不然出问题根本无从下手。实际双核 TrustZone 工程里至少要做好这几件事首先划分安全内存区和非安全内存区。一般建议把 Flash 的前段放安全启动代码和可信固件标记为 Secure后段放应用固件标记为 Non-SecureSRAM 也类似靠近安全固件数据区的部分标 Secure应用使用的部分标 Non-Secure。分区时要特别注意区域对齐——SAU 配置要求区域按 32 字节粒度对齐标错或者没对齐代码一执行就触发 SecureFault。其次设置外设访问权限。TrustZone 的外设隔离不是靠 SAU 完成的而是靠 PPC 等外设保护控制器。你需要明确配置 UART、SPI、GPIO 等外设属于 Secure 还是 Non-Secure。比如如果你用 Non-Secure 的应用核通过 SPI 读写外部 Flash而这个 SPI 控制器被配置为 Secure only那应用核一访问就是总线错误。这类问题在配置工具上可能看不太出来只有运行起来才会发现。第三定义非安全可调用区域NSC。Non-Secure 世界要想调用 Secure 世界的函数必须通过 NSC 区域跳转。NSC 区域要在安全侧的链接脚本里预留出一段空间并填充安全网关指令。很多新手在这步容易出错NSC 区域大小不够、或者函数地址对齐不对、或者没有在向量表里正确导出入口结果就是 Non-Secure 代码一调用就进 HardFault。对于安全岛类架构PSoC 64 这类配置相对简单因为安全核的代码是厂商预先烧录的你只需要在应用核里调用厂商提供的 SDK API。不过要注意一点安全岛服务的调用通常有权限和速率限制不要在主中断服务函数里直接调用否则可能因为调度导致中断响应超时。3.3 安全启动与密钥管理的落地要点安全启动Secure Boot是双核 MCU 安全方案里最核心的一环。它要解决的核心问题是设备上电后如何确保运行的固件是原始开发者签发的、没有被篡改过的版本。安全启动的典型流程分层递进芯片内部 ROM 代码先检查一级启动加载器通常叫 SBL / Secondary Boot Loader的签名SBL 通过后再由 SBL 检查应用固件的签名和哈希值只有所有校验通过才把控制权交给应用代码。每一级校验都建立在前一级的可信基础上这就是信任根Root of Trust的概念。实际落地时有几个关键点必须处理到位。第一根密钥Root Key要放在芯片的 eFuse 或一次性可编程存储区OTP里存储后要禁止再编程和读取。我看过有厂商的参考设计把根密钥放在普通 Flash 区这等于把安全启动变成了摆设攻击者直接改 Flash 内容就能替换根密钥。第二密钥更新机制要设计好产品出厂后如果密钥泄露需要更换怎么保证旧设备能够安全更新根密钥同时中间人又不能截获这个问题在联网设备里非常敏感。第三固件更新流程要配合安全启动使用下载的固件先验证签名再写入备份分区防止更新到一半断电导致设备变砖。另外值得一提的是现在很多双核 MCU 集成了硬件加密引擎比如 AES、RSA、ECC、SHA-256 这些算法的硬件加速器以及真随机数发生器TRNG。这不仅是性能考虑更是安全考虑——软件实现的密码学算法容易受到时序侧信道攻击硬件密码引擎则会做专门防护。因此在代码里尽量使用厂商的加密库来调用硬件引擎而不是自己用软件实现 AES这样既省算力又规避了安全审计时可能被指出来的软实现漏洞。4. 主流双核 MCU 选型几款代表产品与我的建议4.1 常见双核 MCU 横向对比双核 MCU 的型号这两年越来越多但真正值得放进选型对比列表的其实有限。我基于自己的项目经验整理了几款代表性产品按不同的安全路线做了个分类对比表方便你按需参考型号内核组合典型主频Flash/SRAM安全方案典型应用场景STM32H743Cortex-M7 Cortex-M4480/240 MHz2MB / 1MBMPU 隔离 硬件加密引擎工业控制、电机驱动、高性能网关NXP LPC55S69双 Cortex-M33150 MHz640KB / 320KBTrustZone PRINCE 加密引擎 安全启动IoT 终端、嵌入式安全模块Infineon PSoC 64Cortex-M4 Cortex-M0150/100 MHz1MB / 288KB安全岛M0 预配置信任根云连接设备、AWS/阿里云接入Microchip PIC32CM LS60Cortex-M23 Cortex-M064 MHz512KB / 64KBTrustZone 安全子系统和密钥管理消费 IoT、车规级子模块TI CC26X2双 Cortex-M4?48 MHz352KB / 80KB无线协议栈 应用并行BLE/Thread 协议网关从表格可以看出同样叫双核 MCU产品的定位差异还是相当大的。STM32H7 系列性能最强但安全隔离相对传统适合不需要强加密认证的性能导向型应用。LPC55S69 是 M33 双核 TrustZone 的典型代表在性能和安全的平衡上做得很好是当前很多消费类和轻工业产品的热门选择。PSoC 64 则是开箱即安全的路线安全核固件出厂前锁死产品开发时你甚至不太需要懂安全底层但同时也意味着你不能深度定制。4.2 选型时容易踩的坑选型阶段我踩过的坑不少有些看似合理的选择到了后期才发现代价很大。这里分享几条最值得注意的经验。第一别只看最高主频。双核 MCU 的主频数值很漂亮但实际应用时能不能一直跑满主频取决于功耗散热、供电设计和 DVFS 策略。很多双核 MCU 在双核同时全速运行时电流轻松超过 200mA对于电池供电的产品这是一个必须提前评估的现实问题。我遇到过一个团队选择了高主频双核 M7M4结果产品电池续航达不到宣传值最后只能降频运行性能还不如当初选一颗单核 M7。第二购买评估板之前先确认厂商的双核调试工具是否好用。这个好用不是说能不能点 Run而是要确认能否在一个 IDE 会话里同时加载两个核的 ELF 文件能否同时打断点断点打断时另一个核的行为是继续运行还是同步 halt这些体验差异在实际开发中影响巨大。有些厂商对双核调试的支持做得比较差应用核和调试器之间经常出现断点失效、单步错乱的问题开发效率大打折扣。第三安全分级与认证等级要提前对齐。如果目标产品需要过 PSA Level 2 或 Level 3 认证就要确认所选 MCU 的厂商是否已经获得对应认证以及你基于该芯片做的安全方案是否在认证范围内。不同芯片的可信根能力差异比较大有的芯片支持安全启动的根密钥存储在 eFuse 中并且可配置多层生命周期有的芯片则只支持单层锁定。选型时把这些差距搞清楚才能避免开发到后期才发现根本没法满足认证要求被迫换平台的窘境。5. 双核 MCU 调试中的高频问题与排查思路5.1 启动与调试时最常见的几个问题刚开始接触双核 MCU 的团队几乎都会在启动阶段遇到问题。第一个经典问题是应用核没有任何反应。现象通常是安全核正常启动printf 或者 LED 指示都正常但应用核代码就是不执行。排查思路很直接先看复位配置——确认应用核到底是由安全核释放复位的还是由某个引脚、某个 ROM 状态决定的。另外要看启动地址是否正确双核芯片的应用核启动时要确认它读到的向量表地址和你在链接脚本里设置的一致有些芯片的应用核启动地址是可配置的配错了就读到了一个空的 Flash 区域什么都不会执行。第二个高频问题是双核调试时的死锁。这个我印象太深了。用调试器单步调试应用核代码的时候如果安全核还在正常运行它可能正在等一个共享资源的信号量或者正在访问某个外设而你的单步操作刚好把总线锁住了整个系统就完全卡死。解决方法是优先使用支持多核同步调试的工具链或者在你的调试配置里把不调试的那个核在断点时也设为暂停。如果你的调试器不支持同步暂停那就老老实实加日志输出用真实运行方式配合 printf 来定位问题别硬着头皮上单步调试。第三个问题最容易让人崩溃改一行代码之后整个系统启动不了了。双核项目的编译和链接比单核复杂很多——两个核的代码段、数据段如何安排、安全区非安全区的链接脚本如何配合一个地方改错就会导致运行地址在 Flash 里重叠或者区段越界。遇到这种情况先把安全核的启动日志打开看它是在哪一步失败的——是根密钥校验没过还是应用镜像签名不对再对应到具体是 Flash 编程地址问题还是编译配置问题。5.2 核间通信与共享资源的经典坑核间通信的坑大多集中在这几个方面。首先是共享内存的缓存一致性问题。前面提到的如果核心带 Cache共享内存区域没有配置为非缓存就会出现数据写过去了但另一个核读取时还是旧值的诡异现象。排查方法很简单在共享内存操作前后做缓存清理和失效操作如果问题消失那就说明缓存一致性没有处理好。这里的经验是把共享内存区放在 SRAM 中特定区域并在 MPU 或系统配置里把它标记为 Non-Cacheable最稳妥。其次是资源竞争问题。两个核同时访问同一个外设比如共用一个 UART 打印日志、共用一个 I2C 总线如果没有仲裁机制轻则日志乱码重则总线死锁。很多双核 MCU 的外设总线结构里不同核访问外设的路由不一样配置不当还会出现一个核等另一个核释放总线锁结果死等的情形。建议在设计阶段就把外设资源明确分配到两个核尽量避免共享外设如果实在没法避免比如共用一个 Flash就用硬件信号量Hardware Semaphore或者邮箱机制做同步不要自己用软件标志位。第三个坑是编译器优化导致的通信结构体问题。如果你在共享内存里定义了一个结构体用于两个核之间交换数据但结构体里的成员在某些平台上有内存对齐和填充padding问题两个核访问同一字段时可能读到错位的数据。另外如果共享变量没有用 volatile 修饰编译器在优化时可能把它缓存在寄存器里只要代码逻辑上有一方在另一个核或中断里修改这个变量实际运行结果就可能完全不对。我查过不少这类bug最终都归结为通信结构体声明不够严谨。5.3 安全子系统相关的疑难杂症最后聊几个安全子系统的疑难问题这些问题排查起来比较费时间但一旦想通整个安全体系的运行逻辑就会清晰很多。第一个是调用安全世界接口时出现 HardFault。前面已经提到 NSC 区域的问题这是最常见的根因。此外还有一个容易被忽略的细节SAU 区域配置和链接脚本里的区域定义必须一致。如果链接脚本把安全代码段放在了一个标记为 Non-Secure 的地址范围里执行是不可能成功的。排查时要同时检查 SAU 寄存器实际配置值可以在调试器里读 SAU_RBAR/SAU_RLAR和内存映射表对照起来看哪个区域被分到了哪个世界。第二个是安全启动校验一直过不去。这类问题通常发生在密钥写入和签名工具的使用上。有些芯片的出厂哈希是通过一次性 fuses 烧录的一旦烧错或者烧入的密钥和开发者手里的签名密钥不匹配芯片就永远只能处于开发模式没法进入安全启动的正式流程。处理方式是开发阶段先不烧 eFuse用芯片厂商提供的开发认证模式跑通整个流程确认软件和签名工具链完全正确后再进入量产的锁死流程。这个经验说起来简单但很多团队为了省事直接烧了 eFuse出了问题只能直接报废芯片。第三个是Secure 和 Non-Secure 之间的调试权限。TrustZone 方案中Secure 世界在最终产品里通常是被调试锁保护的也就是说烧录完正式固件后连接调试器无法读取安全代码区域。这本来是安全设计但如果你是长期维护产品的开发人员就会遇到设备发回去维修想通过调试器读日志却发现读不了 Secure 区的痛苦。建议在产品的维护版本里预留一个可控的调试授权机制比如通过安全接口验证管理员身份后临时开放 Secure 世界的调试权限否则后期运维成本会很高。我个人实际做下来最深的体会是双核 MCU 不是多核 CPU 的缩小版它的架构设计思路、安全模型、调试方式都和单核时代有本质区别。无论你选的是 TrustZone 路线还是安全岛路线最关键的一点都是先把安全边界想清楚再动手写代码。如果一上来就急于点亮外设、跑协议栈大概率会在后期被各种隔离问题和安全漏洞拖得焦头烂额。在项目立项阶段多花一天梳理核心分工、启动流程和隔离策略比开发阶段多花一周排查诡异 Bug 要划算得多。