3. BSP目录结构解析:BSP源码目录组织、关键文件说明

在VxWorks BSP开发中,理解BSP目录结构是第一步。一个规范的BSP目录不仅决定了编译系统能否正确找到源文件,还直接影响了ROM启动阶段的寄存器配置与链接脚本加载。本章将深入解析BSP源码的目录组织方式,并对config.h、makefile、romInit.s、sysLib.c四个关键文件进行详细说明。

核心观点: BSP目录结构是VxWorks启动流程的“骨架”,关键文件是“血肉”。掌握目录组织与文件职责,是定制ROM启动与寄存器配置的基础。

3.1 BSP目录结构总览

一个典型的VxWorks BSP目录通常包含以下子目录和文件。不同CPU架构(如ARM、PowerPC、x86)的BSP目录结构基本一致,但部分文件(如romInit.s)的汇编指令会因架构而异。

VxWorks BSP 目录结构(典型) BSP 根目录 config.h makefile romInit.s sysLib.c target/ src/ include/ rom/ target/h/ src/drv/ include/h/ rom/romInit.s 目录说明: • target/:存放VxWorks内核镜像与目标文件,是编译输出目录。 • src/:存放BSP源码,包括驱动、板级初始化等C/汇编文件。 • include/:存放头文件,如寄存器地址宏定义、设备结构体。 • rom/:存放ROM启动相关文件,如romInit.s、romStart.c。

3.2 关键文件详解

3.2.1 config.h — 板级配置中心

config.h是BSP中最重要的头文件,它定义了板级硬件参数、内存布局、外设使能开关以及启动模式。VxWorks编译系统通过读取config.h中的宏定义来决定哪些功能被编译进内核。

宏定义 功能说明 典型值
LOCAL_MEM_LOCAL_ADRS 本地内存起始物理地址 0x80000000
LOCAL_MEM_SIZE 本地内存大小(字节) 0x10000000 (256MB)
ROM_BASE_ADRS ROM启动基地址 0xbfc00000
ROM_TEXT_ADRS ROM代码段起始地址 0xbfc00100
INCLUDE_MMU 是否启用MMU 1 或 0
INCLUDE_CACHE 是否启用Cache 1 或 0
实战提示: 在ROM启动场景中,ROM_BASE_ADRS和ROM_TEXT_ADRS必须与硬件复位向量地址一致。例如,MIPS架构的复位向量通常为0xbfc00000,而ARM Cortex-A系列通常为0x00000000或0xffff0000。

3.2.2 makefile — 编译构建规则

BSP的makefile定义了编译目标、源文件路径、链接脚本以及编译器选项。它通常包含以下关键部分:

  • 目标定义: 指定生成vxWorks、vxWorks_rom、vxWorks_romCompress等镜像。
  • 源文件列表: 通过MACH_EXTRA或BOOT_EXTRA变量添加BSP特有的源文件。
  • 链接脚本: 指定ldscript或linker.cmd,控制代码段、数据段在ROM/RAM中的布局。
  • 编译器标志: 如-mcpu=cortex-a9、-mno-unaligned-access等。
# 典型的BSP makefile片段
TARGET_BASE = vxWorks
MACH_EXTRA = \
    src/drv/timer/armGenericTimer.c \
    src/drv/serial/pl011Uart.c

BOOT_EXTRA = \
    rom/romInit.o \
    rom/romStart.o

LDSCRIPT = ${BSP_DIR}/linker.ld

CFLAGS += -mcpu=cortex-a9 -mthumb -Os

3.2.3 romInit.s — ROM启动汇编入口

romInit.s是ROM启动的第一个执行文件,通常由汇编语言编写。它负责完成CPU最底层的初始化,包括:

  1. 设置CPU模式与堆栈指针(SP):确保CPU处于特权模式,并初始化临时堆栈。
  2. 关闭中断与MMU/Cache:在早期启动阶段,必须关闭所有中断和内存管理单元,避免异常。
  3. 配置关键寄存器:如时钟、看门狗、PLL等,确保CPU能稳定运行。
  4. 跳转到C语言入口:通常跳转到romStart()或sysInit()。
/* romInit.s 典型代码结构(ARM Cortex-A9) */
.globl _romInit
_romInit:
    /* 1. 设置CPU为SVC模式,关闭IRQ/FIQ */
    mrs     r0, cpsr
    bic     r0, r0, #0x1F
    orr     r0, r0, #0xD3
    msr     cpsr, r0

    /* 2. 关闭MMU、Cache、分支预测 */
    mrc     p15, 0, r0, c1, c0, 0
    bic     r0, r0, #0x0005      @ 关闭MMU和DCache
    bic     r0, r0, #0x1000      @ 关闭ICache
    mcr     p15, 0, r0, c1, c0, 0

    /* 3. 初始化堆栈指针 */
    ldr     sp, =_stack_addr

    /* 4. 跳转到C语言入口 */
    bl      romStart
常见错误: 在romInit.s中忘记关闭看门狗定时器(WDT),导致在ROM启动过程中看门狗超时复位,系统陷入无限重启循环。务必在汇编阶段早期禁用WDT。

3.2.4 sysLib.c — 板级系统库

sysLib.c是BSP中C语言层面的板级初始化与驱动管理文件。它实现了VxWorks内核与硬件之间的抽象层,主要包含以下函数:

函数名 功能 调用时机
sysInit() 板级早期初始化,设置时钟、中断控制器 ROM启动早期
sysHwInit() 硬件设备初始化,如UART、GPIO、定时器 内核启动阶段
sysMemInit() 内存控制器初始化,配置SDRAM/DDR时序 ROM启动中期
sysSerialHwInit() 串口硬件初始化,用于调试输出 内核启动阶段
/* sysLib.c 中 sysMemInit 的典型实现 */
STATUS sysMemInit(void)
{
    /* 配置DDR控制器寄存器 */
    *(volatile UINT32 *)(DDR_CTRL_BASE + 0x00) = 0x01000001;  // 时序参数
    *(volatile UINT32 *)(DDR_CTRL_BASE + 0x04) = 0x00020002;  // 刷新周期
    *(volatile UINT32 *)(DDR_CTRL_BASE + 0x08) = 0x00000003;  // 使能DDR

    /* 等待DDR初始化完成 */
    while (!(*(volatile UINT32 *)(DDR_CTRL_BASE + 0x0C) & 0x01));

    return OK;
}

3.3 文件之间的调用关系

在ROM启动流程中,这四个关键文件按照严格的顺序被调用:

ROM启动关键文件调用流程 romInit.s sysLib.c config.h makefile romInit.s 调用 sysLib.c 中的 sysInit() → sysLib.c 读取 config.h 中的宏定义 → makefile 控制编译与链接顺序

3.4 目录结构最佳实践

  • 保持目录扁平化:避免过深的子目录嵌套,建议最多3层(如src/drv/serial/)。
  • 分离ROM与RAM代码:将ROM启动专用的汇编文件放在rom/目录下,与普通驱动代码隔离。
  • 使用版本控制:在BSP根目录添加.gitignore,忽略target/编译输出目录。
  • 统一头文件引用:所有寄存器地址宏定义集中在include/h/下的一个头文件中,如regs.h。
总结: BSP目录结构是VxWorks移植的“地图”,config.h是配置中心,makefile是构建引擎,romInit.s是启动入口,sysLib.c是硬件抽象层。掌握这四者的关系,就能在ROM启动与寄存器配置中游刃有余。