2. VxWorks多核启动与镜像构建

VxWorks 多核系统的启动过程,本质上是“一个引导核先把系统跑起来,再把其余核拉入同一运行环境”的过程。SMP 与 AMP 的差别,不在于是否使用多核,而在于各核是否共享同一个内核实例、同一份系统镜像和同一套调度器。理解这一点,后续的镜像配置、核间初始化和启动参数才有统一的判断依据。

SMP 与 AMP 的启动路径差异

在 SMP 配置下,VxWorks 只加载一份内核镜像,所有 CPU 核共享同一份内核代码段、数据段和调度器。上电后由 BootROM 或 U-Boot 完成基本硬件初始化,把 VxWorks 镜像搬到内存并跳转到入口点。此时只有一个核真正执行内核初始化,通常称为引导核(boot core);其余核处于等待状态,由内核通过核间中断或平台特定的释放寄存器逐个唤醒,进入调度器参与任务执行。

AMP 则不同:每个核可以运行独立的 VxWorks 镜像,或一个核跑 VxWorks、另一个核跑裸机程序/Linux。各核有各自的入口地址、各自的内存区域和各自的中断控制器视图。启动时通常由主核先完成共享资源(DDR、时钟、外设、核间通信通道)的初始化,再通过写释放地址的方式让从核从指定入口开始执行。因此 AMP 的启动参数必须明确“哪个核、从哪个地址、用什么镜像、访问哪段内存”。

VxWorks 多核启动:SMP 与 AMP 路径对比 SMP:单镜像 · 共享内核 BootROM / U-Boot DDR、时钟、串口初始化 加载单一 vxWorks 镜像 vxWorks_rom / vxWorks.bin 引导核执行内核初始化 usrappInit → kernelInit → 调度器就绪 核间中断 / 释放寄存器唤醒从核 从核进入同一内核,加入共享调度器 共享代码段、数据段、任务队列 所有核运行同一内核实例 任务可在任意核上调度 AMP:多镜像 · 独立内核 主核 BootROM / U-Boot 初始化共享 DDR、时钟、IPC 通道 加载主核镜像 + 从核镜像 core0.bin / core1.bin 各自独立 主核写从核释放地址 如 0x1FF80000 → 从核入口 从核从指定入口启动独立镜像 各自初始化 MMU、中断、任务 通过共享内存 / 消息队列通信 各核独立运行、独立调度 核间通过 IPC 显式同步

镜像配置的关键项

镜像配置决定了内核“看到”多少核、内存如何划分、启动后执行什么。在 Workbench 或命令行构建时,VIP(VxWorks Image Project)中的内核配置组件是核心入口。与多核启动直接相关的配置项包括:

  • CPU 核数:SMP 下由 VX_SMP_NUM_CPUS 或 BSP 中的 NUM_CPUS 指定,必须与实际硬件核数一致,否则会出现核未被唤醒或访问越界。
  • 内存布局:SMP 共享同一份系统内存池;AMP 需要为每个核划分独立的代码段、数据段和堆栈区域,并在链接脚本中固定地址,避免相互踩踏。
  • 入口地址:AMP 从核镜像的入口地址必须与主核写入释放寄存器的值一致,通常由链接脚本的 ENTRY 或 BSP 中的 sysAmpCoreEntry 决定。
  • 启动参数:包括引导核编号、从核释放方式(寄存器地址/中断号)、共享内存基址与大小、IPC 通道编号等。

一个典型的 AMP 启动参数配置片段如下,用于说明主核如何描述从核的启动信息:

/* AMP 启动参数示例(教学假设值) */
#define AMP_CORE1_ENTRY      0x00200000   /* 从核镜像入口 */
#define AMP_CORE1_STACK      0x00300000   /* 从核独立栈顶 */
#define AMP_RELEASE_REG      0x1FF80000   /* 核释放寄存器 */
#define AMP_SHARED_MEM_BASE  0x10000000   /* 共享内存基址 */
#define AMP_SHARED_MEM_SIZE  0x00100000   /* 共享内存 1MB */
#define AMP_IPC_CHANNEL      1            /* 消息队列通道号 */

这些参数不是随意填写的:入口地址必须落在从核镜像实际加载的位置,共享内存区域必须避开各核私有数据段,释放寄存器地址必须与 SoC 手册一致。配置完成后,通常通过串口日志确认每个核是否打印出自己的核编号和启动状态。

核间初始化与启动参数的实际处理

核间初始化发生在引导核完成基本内核初始化之后、从核正式参与调度之前。SMP 下,内核会自动完成从核的栈分配、每核数据区(per-CPU data)初始化和调度器挂接;开发者需要关注的是共享资源的并发保护,例如全局变量、外设寄存器和缓存一致性。AMP 下,核间初始化需要手动完成,典型顺序是:主核初始化共享内存和 IPC 通道 → 主核写释放寄存器 → 从核从入口启动 → 从核初始化自身 MMU/中断 → 从核通过 IPC 向主核报告就绪。

启动参数在这一过程中起到“契约”作用。以核间通信为例,如果主核使用共享内存基址 0x10000000、大小 1MB,从核也必须使用同一组参数,否则双方看到的消息队列控制结构不一致,表现为发送成功但接收端永远收不到。实际调试时,可以先用一个最小的“心跳”任务验证:主核每 100ms 向通道 1 发送一个递增计数,从核收到后回送确认,通过串口打印双方计数是否同步增长。若计数停滞,优先检查释放寄存器是否写对、从核入口是否指向正确镜像、共享内存是否被 MMU 映射为可缓存/非缓存一致。

SMP 调试时,若发现只有引导核在跑任务,先确认 VX_SMP_NUM_CPUS 是否大于 1,再检查 BSP 的核释放函数是否被正确调用。AMP 调试时,若从核没有任何输出,优先用调试器读释放寄存器地址,确认主核确实写入了预期值。

配置检查清单

在镜像构建完成、下载到目标板之前,建议按以下清单逐项核对,避免把启动问题带到运行阶段:

检查项SMP 关注点AMP 关注点
核数配置与实际核数一致主/从核镜像分别对应
内存布局共享系统内存池各核私有段不重叠
入口地址由内核统一管理与释放寄存器写入值一致
共享资源自旋锁/原子操作保护IPC 通道与共享内存参数一致
启动日志各核打印核编号从核报告就绪、心跳同步

把启动流程、镜像配置和核间初始化放在一起看,SMP 的关键是“让所有核进入同一个内核并安全共享资源”,AMP 的关键是“让每个核从正确的地址启动、用一致的参数通信”。启动参数就是这两条路径上的连接点:写错一个地址或一个基址,系统可能仍然能启动,但多核协作会在运行阶段以难以定位的方式失败。因此,构建镜像时逐项核对参数,比启动后再排查要高效得多。