3. 多核启动与复位调试
多核处理器的启动过程与单核系统有本质区别:上电后并非所有核同时开始执行用户代码,而是由硬件复位逻辑决定哪个核先运行、其余核处于什么状态、何时被唤醒。调试多核启动问题的核心,是沿着复位序列把“谁先跑、跑到哪、为什么停”这条链路看清楚。TRACE32 提供了从复位向量抓取、核状态观测到核间同步点设置的完整手段,本节围绕这条链路展开。
上电复位序列与复位向量
以典型的 ARM Cortex-A 多核 SoC 为例,上电后 PMIC 释放复位信号,芯片内部复位控制器依次释放各电源域和时钟域。此时所有核的 PC 都被硬件强制指向各自的复位向量地址。多数 SoC 采用“主核启动、从核等待”的策略:主核(如 CPU0)从 BootROM 开始执行,完成 PLL 锁定、DDR 初始化、时钟树配置后,再通过写核间寄存器释放从核。从核被释放前通常停在 WFI/WFE 低功耗状态或内部自旋循环中。
复位向量地址由芯片的 RVBAR(Reset Vector Base Address)寄存器或硬件引脚决定。调试时首先要确认这个地址是否与链接脚本中 .vectors 段的实际加载地址一致。若不一致,主核会跳转到错误位置,表现为“上电后 PC 乱飞”或直接进入异常。TRACE32 中可用 SYStem.CPU 指定核,再用 Register.Set PC <addr> 与 Register.View 核对复位后的实际 PC 值。
; 查看 CPU0 复位后的寄存器状态
SYStem.CPU CortexA53
SYStem.Mode Attach
Register.View /All
; 读取 RVBAR(示例地址,需按手册替换)
Data.Long 0x1C000000 /Long
主核与从核启动流程
主核启动流程一般分为三段:BootROM 阶段完成最基础的时钟与存储初始化;Bootloader 阶段加载并校验镜像;OS/应用阶段建立多核运行环境。从核的启动则由主核在合适时机触发,常见方式有三种:写 SoC 的 CPU release 寄存器、发送 SGI(软件生成中断)、或通过 spin-table 让从核轮询一个约定内存地址。无论哪种方式,从核被唤醒后都需要一个入口地址,这个地址通常由主核写入从核的 RVBAR 或约定变量。
调试时应在主核写释放寄存器处下断点,确认写入的值与从核入口地址匹配;再切换到从核观察其 PC 是否已跳到该入口。TRACE32 支持多核同时 attach,用 SYStem.CPU 切换当前核,或用 SYStem.MultiCore 建立多核调试会话,在一个窗口内同时观察多个核的 PC 与状态。
核间启动同步
从核被释放后,往往需要等待主核完成某些初始化(如页表建立、缓存一致性配置)才能继续。常见的同步原语包括:自旋锁、屏障(barrier)、事件标志、以及 ARM 的 SEV/WFE 配对。调试同步问题的关键是找到“等待点”和“释放点”:等待点通常是一个循环读取内存标志的指令序列,释放点是主核写该标志的位置。
在 TRACE32 中,可以在等待循环处设置断点,观察从核是否长时间停在该处;再在主核写标志处设断点,确认写操作是否真正发生、写的值是否正确。若从核一直不退出等待,常见原因有:标志地址因缓存不一致而读到旧值、内存屏障缺失导致写顺序被重排、或释放条件依赖的中断未使能。
复位向量与异常向量检查
复位向量只是异常向量表中的一个入口。多核系统中,每个核都有自己的异常向量表基址(VBAR),若从核的 VBAR 未正确设置,一旦发生中断或异常就会跳转到错误地址。检查步骤是:先确认各核 VBAR 寄存器的值,再核对向量表中复位、IRQ、FIQ、SError 等入口是否指向有效处理函数。
TRACE32 中可用 Register.View 查看 VBAR,用 Data.List 反汇编向量表内容。若发现某入口为 0 或指向未初始化内存,说明该核的异常处理尚未建立。对于从核,常见问题是主核只设置了自身 VBAR,忘记在释放从核前为从核设置,导致从核一收到 IPI 就崩溃。
启动失败定位方法
启动失败的表现形式多样:主核卡在 BootROM、从核一直不启动、从核启动后跑飞、或系统在某个核上反复复位。定位时建议按以下顺序排查:
- 确认复位源:读取 SoC 的复位状态寄存器,区分是上电复位、看门狗复位还是软件复位。反复复位往往意味着看门狗未被及时喂狗。
- 抓取各核 PC:用 TRACE32 多核视图同时查看所有核的 PC。若某核 PC 停在 0x0 或 0xFFFF0000 附近,说明它从未被正确释放或入口地址错误。
- 检查释放寄存器写入:在主核写释放寄存器处设断点,确认写入的核掩码和入口地址。常见错误是掩码写错,只释放了部分从核。
- 检查同步标志与缓存一致性:若从核停在自旋等待,用
Data.Long读取标志地址,对比主核写入的值。若主核已写但从核读到旧值,需检查该内存区域是否配置为 non-cacheable 或是否缺少 DSB/ISB 屏障。 - 检查异常向量:若从核 PC 跳到了异常入口,查看 ESR/FAR 等异常状态寄存器,判断是取指异常、数据异常还是未定义指令。
一个典型的启动失败案例是:主核写释放寄存器后,从核 PC 确实跳到了入口,但执行几条指令后触发数据异常。用 TRACE32 查看 FAR 发现访问地址为 0x0,进一步检查发现从核的 MMU 尚未使能,而入口代码却使用了虚拟地址。解决办法是在从核入口的最前面加上 MMU 初始化,或让从核先运行在物理地址模式直到页表就绪。这类问题的定位依赖“PC → 异常状态 → 访问地址 → 配置寄存器”的逐层回溯,TRACE32 的寄存器窗口和内存窗口配合使用即可完成。
启动调试的最终目标是让所有核在预期的时间点到达预期的位置。做到这一点的标志是:多核视图中各核 PC 按设计顺序推进,同步标志按预期翻转,异常状态寄存器无异常记录,且系统能稳定进入 OS 调度。若其中任一环节不满足,就回到对应的断点处继续缩小范围。