2. 理解VxWorks启动流程与BSP初始化顺序

任务目标

在VxWorks BSP开发中,启动流程的初始化顺序直接决定硬件环境是否就绪、内核能否正常引导。本案例通过阅读BSP源码并在关键阶段插入打印函数,梳理从复位向量到usrInit、usrKernelInit等阶段的执行顺序,建立对启动链路的清晰认知。

前置条件

  • 已安装Wind River Workbench或VxWorks开发环境,目标板为x86或PowerPC架构(本案例以x86为例)。
  • 已创建或获取一个可编译的VxWorks BSP工程(如mv4100或pcPentium)。
  • 具备串口终端或调试器输出通道,用于观察打印信息。

启动阶段与关键源码位置

VxWorks启动流程分为两个阶段:Boot ROM阶段与VxWorks内核阶段。Boot ROM负责最小硬件初始化和加载VxWorks镜像;内核阶段从sysInit开始,依次经过usrInit、usrKernelInit、usrRoot等函数完成系统初始化。以下为x86 BSP中典型的调用顺序:

  1. 复位向量:CPU上电后跳转到sysInit(位于sysAlib.s),完成关中断、设置栈指针等基础操作。
  2. usrInit(usrConfig.c):关闭中断、初始化Cache、清零BSS段,然后调用usrKernelInit。
  3. usrKernelInit(usrKernel.c):创建内核对象、初始化任务调度器,随后启动usrRoot任务。
  4. usrRoot(usrConfig.c):完成设备驱动挂载、网络协议栈初始化、启动应用任务。

实现步骤

在BSP源码的上述关键函数入口处添加打印语句,编译后通过串口观察输出顺序。以下代码展示了在usrInit和usrKernelInit中添加打印的实现:

// 文件:usrConfig.c(部分)
#include <vxWorks.h>
#include <stdio.h>
#include <usrLib.h>

// 在usrInit函数入口处添加打印
void usrInit(int memStart, int memEnd)
{
    printf("\n[BOOT] Enter usrInit: memStart=0x%x, memEnd=0x%x\n", memStart, memEnd);

    /* 原有初始化代码:关闭中断、初始化Cache等 */
    cacheLibInit();
    usrKernelInit();
}

// 文件:usrKernel.c(部分)
void usrKernelInit(void)
{
    printf("[BOOT] Enter usrKernelInit\n");

    /* 原有内核初始化代码 */
    kernelInit(usrRoot, ...);
}

// 在usrRoot入口处添加打印
void usrRoot(void)
{
    printf("[BOOT] Enter usrRoot\n");

    /* 原有系统初始化代码 */
    usrIosLibInit();
    usrNetInit();
}

对于Boot ROM阶段的sysInit(汇编文件),可在C语言可调用处添加打印,或通过调试器设置断点观察。若需在汇编阶段输出,可调用sysSerialHwInit后的串口发送函数,但更简单的方式是使用调试器在sysInit处打断点,单步跟踪执行流。

编译与运行

  1. 在Workbench中重新编译BSP工程,生成bootrom.bin和vxWorks镜像。
  2. 将Boot ROM烧录到目标板(或通过仿真器加载),连接串口终端(波特率通常为9600或115200,视BSP配置而定)。
  3. 上电或复位目标板,观察串口输出。

验证方法

串口输出应依次出现以下打印信息(顺序严格匹配):

[BOOT] Enter usrInit: memStart=0x..., memEnd=0x...
[BOOT] Enter usrKernelInit
[BOOT] Enter usrRoot

若打印顺序与上述一致,且系统最终进入VxWorks shell提示符(如->),则说明启动流程梳理正确。若缺少某条打印或顺序错乱,则需检查对应函数是否被调用、链接脚本中入口地址是否正确。

常见问题

  • 无串口输出:检查串口驱动是否在sysHwInit中完成初始化,或Boot ROM阶段是否已配置串口参数。
  • 打印顺序与预期不符:确认修改的源码文件确实被编译进当前镜像(检查Makefile中是否包含该文件),并清除旧镜像重新编译。
  • 系统启动崩溃:若在usrInit前添加打印导致崩溃,说明串口尚未就绪,此时应改用调试器观察,而非直接打印。