3. 系统启动与初始化过程监控
VxWorks 系统的启动不是一次“上电即运行”的瞬时动作,而是一条由多个阶段串联而成的链:从 CPU 复位向量进入 BootROM,到引导参数解析、VxWorks 映像搬运与解压,再到内核对象建立、驱动挂接、应用任务创建。任何一个阶段失败,最终表现往往都是“系统起不来”或“卡在某处”,但根因位置完全不同。因此,启动监控的核心思路是:把启动链拆成可观测的阶段,为每个阶段找到独立的观测点和判定依据,而不是只盯着最后的应用是否运行。
启动链的阶段划分与观测点
以常见的 ARM/PowerPC 目标板为例,一次典型启动可划分为五个阶段,每个阶段都有其“活着”的证据:
- BootROM 阶段:CPU 复位后执行 ROM 中的引导代码,初始化内存控制器、串口、时钟,并进入引导命令行。观测点是串口输出的引导版本号与提示符(如
->或BootROM>)。 - 映像加载阶段:BootROM 根据引导参数(boot device、host IP、file name)通过 TFTP/Flash/磁盘读取 VxWorks 映像,校验后搬运到 RAM 入口地址。观测点是加载进度、映像长度、校验结果。
- 内核初始化阶段:映像入口执行
usrInit,建立内核数据结构、中断向量表、系统时钟、内存池,随后启动tUsrRoot根任务。观测点是内核版本打印、内存池大小、时钟 tick 是否正常。 - 驱动初始化阶段:根任务按
sysHwInit/sysClkInit/usrDrvInit顺序挂接串口、网口、存储等驱动。观测点是各驱动注册日志、设备节点是否出现。 - 应用启动阶段:
usrAppInit创建应用任务、打开设备、建立通信。观测点是应用任务名、优先级、首条业务日志。
下图给出这五个阶段的信号链关系,并标注每个阶段的关键观测点与典型异常表现,便于在排障时快速定位“卡在哪一段”。
BootROM 阶段:先确认“最小系统”活着
BootROM 是启动链的第一环,它的职责是在没有任何操作系统支持的情况下,把 CPU 带到“能读内存、能输出串口”的状态。监控这一阶段最直接的手段就是串口。上电后应能看到类似下面的输出(示例为合理假设的引导信息):
VxWorks BootROM 2.2 (build 2024-05-10)
Copyright 1984-2024 Wind River Systems
CPU: ARM Cortex-A9 @ 800 MHz
Memory: 512 MB DDR3 @ 0x80000000
Boot Device: motetsec0
Boot File: vxWorks
Host IP: 192.168.1.100
Target IP: 192.168.1.200
如果串口完全无输出,问题通常不在 VxWorks 映像,而在更底层:复位向量是否正确、时钟是否起振、串口引脚复用是否配置、波特率是否匹配。此时应先用示波器或 JTAG 确认 CPU 是否在取指,再检查 BootROM 是否被正确烧写到启动介质。若能看到部分输出但中途停止,则重点看停止位置对应的初始化项——例如内存容量打印后卡住,往往是 DDR 训练或内存控制器参数问题。
映像加载阶段:校验与地址是两大关键
BootROM 进入命令行后,会根据引导参数从网络或 Flash 读取 VxWorks 映像。这一阶段最值得监控的是三个量:读取字节数、校验结果、入口地址。以 TFTP 加载为例,正常输出会显示类似:
Loading vxWorks ... 3145728 bytes read
Checksum: 0x8f3a21c7 OK
Entry point: 0x80010000
Starting at 0x80010000...
若校验失败,说明映像在传输或存储中损坏,应重新生成或重新下载;若校验通过但跳转后无反应,则要核对 Entry point 是否与映像实际链接地址一致。常见错误是把加载地址(load address)与入口地址(entry point)混为一谈:前者是映像被放到 RAM 的位置,后者是 CPU 开始执行的第一条指令地址,两者可以不同,但必须与链接脚本匹配。
内核初始化阶段:看内存池与根任务
映像入口执行后进入 usrInit,这是内核真正开始建立自身运行环境的阶段。此时应关注:内核版本与编译时间是否与预期一致、内存池(system memory pool)的起始地址和大小是否合理、系统时钟 tick 是否正常、根任务 tUsrRoot 是否被创建。一个健康的内核初始化输出通常包含:
VxWorks 6.9 (build 2024-05-10)
Kernel: WIND kernel version 3.0
Memory pool: 0x80100000 - 0x9fffffff (511 MB)
System clock rate: 100 Hz
tUsrRoot started, priority 0
如果内存池大小明显小于物理内存,可能是 sysMemTop 或内存描述表配置错误;如果时钟 tick 不推进,则依赖延时的驱动和应用都会异常。这一阶段还可以通过 memShow 或 ti 命令在后续 shell 中复查内存与任务状态。
驱动初始化阶段:逐项确认设备挂接
根任务随后调用 sysHwInit、sysClkInit、usrDrvInit 等,按顺序初始化硬件和驱动。监控要点是“每个驱动是否成功注册、设备节点是否出现、中断是否绑定”。例如串口驱动应打印设备名,网口驱动应显示 MAC 与链路状态,存储驱动应报告容量。若系统卡死,可用二分法:在 usrDrvInit 中逐项注释驱动初始化,观察最后一条成功日志,从而锁定问题驱动。常见异常包括中断号冲突、DMA 缓冲区地址越界、驱动与硬件版本不匹配。
应用启动阶段:从任务列表确认业务就绪
最后进入 usrAppInit,应用任务被创建。此时应通过 taskShow 或 i 命令查看任务名、优先级、状态和栈使用情况,确认应用任务处于 READY 或 PEND 而非 SUSPEND。若应用未运行,先检查 usrAppInit 是否被正确挂接(在 configAll.h 或 usrConfig.c 中),再检查任务栈是否溢出、优先级是否被高优先级任务长期抢占。首条业务日志的出现,通常可作为应用真正开始工作的标志。