3. Layerscape启动流程与BSP目录结构

Layerscape系列处理器的启动过程是一条严格分阶段的信任链:从上电那一刻起,芯片内部固化的代码依次把控制权交给下一级软件,每一级都负责把下一级从存储介质搬到内存并校验,最终把Linux内核交给CPU执行。理解这条链路,是后续修改U-Boot环境、替换ATF固件、调整设备树和排查"卡在启动某一行"问题的前提。同时,NXP官方BSP把这条链路上每一级的源码、二进制、配置和产物按目录组织起来,只有把目录职责与启动阶段对应上,才能在正确的位置改正确的东西。

一、五级启动链路的分工

Layerscape的启动链可以概括为PBL → SPL → ATF → U-Boot → Linux五个阶段,但不同芯片(如LS1046A、LS1043A、LS2088A、LX2160A)在细节上略有差异,下面以常见的LS1046A为例说明。

PBL(Pre-Boot Loader)是芯片ROM中固化的不可修改代码。上电复位后,CPU从BootROM开始执行,PBL根据RCW(Reset Configuration Word)中配置的启动介质(QSPI、SD/eMMC、NAND、NOR等)去读取一个固定格式的镜像头,通常称为Boot Header或PBI/PSA结构。PBL会解析这个头部,把其中的PBI命令(如写寄存器、初始化DDR控制器)执行掉,然后把SPL镜像搬运到片上SRAM(OCRAM)或已初始化的DDR中,跳转执行。PBL阶段的关键输入是RCW和Boot Header,输出是"SPL已经在内存中并开始运行"。

SPL(Secondary Program Loader)是U-Boot体系中的第一阶段引导程序,在Layerscape上通常由U-Boot源码编译生成u-boot-spl.bin。SPL体积很小,运行在OCRAM中,主要职责是完成DDR初始化(如果PBI没有完全做完)、时钟和引脚复用配置,然后从启动介质中把完整的ATF+U-Boot镜像加载到DDR,最后跳转到ATF入口。SPL是"从SRAM到DDR"的桥梁。

ATF(ARM Trusted Firmware)是ARMv8架构下的安全固件,在Layerscape上以BL2/BL31的形式存在。ATF负责建立异常等级(EL3)环境、配置安全相关寄存器、初始化PSCI服务,然后以BL33的身份跳转到U-Boot。ATF是"安全世界与普通世界的分界点",也是后续Linux使用CPU热插拔、电源管理的基础。

U-Boot是大家最熟悉的引导程序,运行在EL2或EL1。它负责加载设备树(DTB)、加载内核镜像(Image或fitImage)、准备启动参数(bootargs),最后通过booti或bootm命令跳转到内核。U-Boot还承担环境变量管理、网络启动(TFTP/NFS)、固件更新等工程任务。

Linux内核接管后完成驱动初始化、挂载rootfs、启动init进程,系统进入用户态。

Layerscape 五级启动链路与BSP目录对应关系 PBL BootROM固化 解析RCW/Boot Header SPL u-boot-spl.bin DDR初始化/搬运 ATF (BL2/BL31) EL3安全环境 PSCI服务 U-Boot 加载DTB/Image booti/bootm Linux Kernel 驱动初始化 挂载rootfs 运行于:BootROM 运行于:OCRAM 运行于:DDR 运行于:DDR 运行于:DDR BSP 目录职责与依赖 bootloader/ u-boot源码、SPL ATF源码、RCW 生成u-boot.bin等 kernel/ Linux源码与配置 defconfig、补丁 生成Image/fitImage dtb/ 设备树源文件.dts 编译为.dtb 描述板级硬件 rootfs/ 根文件系统镜像 busybox/yocto ext4/ubifs格式 firmware/ ATF二进制 MC固件、PHY固件 DPL/DPC配置 依赖方向:bootloader → kernel → dtb → rootfs → firmware(后者被前者加载或引用) 关键判断:串口无输出→查PBL/RCW;SPL后卡住→查DDR/ATF;U-Boot后卡住→查DTB/Image/bootargs;内核panic→查rootfs与驱动

二、BSP目录的职责划分

NXP官方BSP(如LSDK或flexbuild体系)通常把源码和产物按功能分目录管理,常见结构如下:

  • bootloader/:存放U-Boot源码、ATF源码、RCW配置以及编译脚本。U-Boot源码中arch/arm/cpu/armv8/fsl-layerscape/是Layerscape平台的核心目录,SPL和U-Boot共用同一套源码,通过CONFIG_SPL_BUILD区分编译阶段。ATF源码通常放在atf/子目录,编译生成bl2.bin和bl31.bin,最终与U-Boot打包成u-boot-with-spl.bin或fip.bin。
  • kernel/:Linux内核源码、板级defconfig(如ls1046a_defconfig)、NXP补丁集。编译产物是arch/arm64/boot/Image或打包后的fitImage。内核目录还包含DTS文件,但通常与dtb目录有交叉引用。
  • dtb/:设备树源文件(.dts/.dtsi)和编译后的.dtb。Layerscape的DTS通常按"芯片级dtsi + 板级dts"组织,例如fsl-ls1046a.dtsi描述SoC内部外设,fsl-ls1046a-rdb.dts描述具体开发板。设备树是U-Boot和内核共享的硬件描述,U-Boot阶段用u-boot.dtb,内核阶段用kernel.dtb。
  • rootfs/:根文件系统镜像,可能是Yocto构建的.ext4、.tar.gz,或BusyBox手工制作的最小系统。rootfs的格式必须与U-Boot的bootargs中root=参数一致,例如root=/dev/mmcblk0p2 rootwait rw。
  • firmware/:存放ATF二进制、管理复杂(MC)固件、网络PHY固件、DPAA2的DPL/DPC配置文件等。这些文件通常由U-Boot或内核在运行时加载到指定内存地址,例如DPAA2的MC固件通过fsl_mc驱动加载。

三、启动链与目录的对应关系

把启动阶段和目录对应起来,排查问题时会非常高效。PBL阶段依赖的是RCW和Boot Header,它们通常由bootloader/rcw/下的.rcw文件编译生成,烧录到QSPI的0x0偏移或SD卡的特定扇区。SPL来自bootloader/u-boot/编译产物。ATF来自firmware/或bootloader/atf/。U-Boot主体、DTB、Image、rootfs则分别来自bootloader/、dtb/、kernel/、rootfs/。

一个典型的工程判断流程是:如果串口完全无输出,问题在PBL或RCW,检查启动介质选择和Boot Header是否正确;如果SPL打印了"U-Boot SPL"后卡住,问题多在DDR初始化或ATF加载;如果U-Boot命令行出现但booti后无输出,检查DTB地址、Image加载地址和bootargs;如果内核打印到"VFS: Cannot open root device"则说明rootfs参数或存储驱动有问题。

在修改BSP时,建议先确认当前启动介质和镜像布局。例如QSPI启动时,通常0x0放RCW+PBI+SPL,0x100000放FIP(ATF+U-Boot),0x500000放内核和DTB。用sf probe和sf read可以在U-Boot中验证各分区内容,避免"改了源码但烧录位置不对"的常见错误。

四、实操示例:从源码到可启动镜像

以LS1046A RDB为例,假设BSP根目录为~/lsdk,一次完整的构建流程大致如下:

# 1. 编译U-Boot(含SPL)
cd ~/lsdk/bootloader/u-boot
make distclean
make ls1046ardb_qspi_defconfig
make -j8

# 2. 编译ATF
cd ~/lsdk/bootloader/atf
make PLAT=ls1046a bl2 bl31 -j8

# 3. 打包FIP(ATF + U-Boot)
cd ~/lsdk/bootloader
./build_fip.sh

# 4. 编译内核与DTB
cd ~/lsdk/kernel
make ARCH=arm64 ls1046a_defconfig
make ARCH=arm64 Image dtbs -j8

# 5. 生成最终烧录镜像
cd ~/lsdk
./build_image.sh -b qspi -r rootfs.ext4

构建完成后,bootloader/下会生成u-boot-with-spl.bin和fip.bin,kernel/arch/arm64/boot/下生成Image,dtb/下生成fsl-ls1046a-rdb.dtb。把这些文件按QSPI分区表烧录后,上电应能看到类似下面的启动日志片段:

U-Boot SPL 2022.04 (Jan 10 2025 - 10:23:45)
DDR init done
NOTICE:  BL2: v2.6(release)
NOTICE:  BL31: v2.6(release)
U-Boot 2022.04
Hit any key to stop autoboot: 0
Loading Image from QSPI...
Loading fsl-ls1046a-rdb.dtb...
Booting Linux...
[    0.000000] Linux version 5.15.0

看到"Linux version"这一行,说明五级链路全部打通。如果卡在"BL2"之前,重点查ATF编译参数和FIP打包;如果卡在"Loading Image"之后,重点查内核加载地址与DTB是否匹配。

五、常见误区与检查要点

  • 混淆SPL与ATF的顺序:在Layerscape上,SPL先运行,然后跳转到ATF的BL2,再由BL31跳转到U-Boot。不要以为ATF在SPL之前。
  • DTB地址与内核地址冲突:U-Boot的bootargs和fdt_addr_r、kernel_addr_r必须落在DDR有效范围内且不重叠,否则会出现"内核启动后找不到设备树"。
  • rootfs格式与bootargs不匹配:ext4镜像却写root=/dev/ram0,或ubifs却写root=/dev/mmcblk0p2,都会导致VFS挂载失败。
  • firmware未随镜像烧录:DPAA2的MC固件、PHY固件如果缺失,网络接口可能无法up,但内核仍能启动,这类问题容易被误判为驱动bug。

把启动链和BSP目录的对应关系记牢,后续修改U-Boot环境变量、替换ATF、调整设备树或更换rootfs时,就能快速定位到正确的源码目录和烧录位置,而不是在几十个文件夹里盲目搜索。