4. Sitara平台Linux BSP构建
在Sitara AM335x/AM57x这类ARM Cortex-A平台上构建可启动的Linux系统,本质上是把“宿主机上生成的代码”变成“目标板上可运行的镜像”。这条链路包含四个相互依赖的产物:交叉编译工具链、U-Boot引导程序、Linux内核与设备树、根文件系统。它们之间存在明确的依赖顺序——工具链决定ABI与浮点约定,U-Boot负责加载内核与设备树,内核在启动后期挂载根文件系统。任何一环参数不一致,都会在串口日志中以不同形式暴露出来。
交叉编译工具链:先确定ABI,再谈编译
Sitara AM335x使用ARM Cortex-A8,属于ARMv7-A架构,带NEON与VFPv3浮点单元。工具链选择的核心不是“哪个版本新”,而是ABI是否与目标板一致。常见约定为arm-linux-gnueabihf-,其中hf表示硬浮点,要求内核、U-Boot、根文件系统中的所有用户态程序都使用同一浮点约定。若混用gnueabi与gnueabihf,典型现象是用户态程序启动即报Illegal instruction或浮点异常。
以Linaro或TI SDK提供的工具链为例,安装后先验证:
arm-linux-gnueabihf-gcc -v
arm-linux-gnueabihf-gcc -dumpmachine
# 期望输出类似 arm-linux-gnueabihf
随后在构建环境中固定CROSS_COMPILE与ARCH两个变量,后续U-Boot、内核、BusyBox都复用它们,避免每个组件单独指定导致不一致。
U-Boot:从SPL到U-Boot proper
AM335x的启动采用两级结构:芯片内部ROM先加载SPL(MLO),SPL完成DDR初始化后再加载U-Boot proper。因此编译产物中必须同时存在MLO与u-boot.img。以AM335x EVM为例,配置与编译过程如下:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- am335x_evm_defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j8
# 产物:MLO、u-boot.img、u-boot.dtb(部分版本)
若目标板使用SD卡启动,需将MLO写入FAT分区起始位置,u-boot.img紧随其后。U-Boot阶段最值得关注的是bootcmd与bootargs:前者决定从哪里加载内核与设备树,后者把console、root、rootfstype等参数传递给内核。例如从SD卡第二分区加载:
setenv bootargs 'console=ttyO0,115200n8 root=/dev/mmcblk0p2 rw rootfstype=ext4 rootwait'
setenv bootcmd 'fatload mmc 0:1 0x82000000 zImage; fatload mmc 0:1 0x88000000 am335x-evm.dtb; bootz 0x82000000 - 0x88000000'
saveenv
这里0x82000000与0x88000000是DDR中的加载地址,必须避开内核解压后自身占用的区域,否则会出现“内核启动后卡死”或“设备树被覆盖”的现象。
内核与设备树:配置裁剪与硬件描述分离
内核编译的关键在于defconfig与设备树的配合。Sitara平台常用omap2plus_defconfig作为基础,再按需打开工业控制相关选项,例如CONFIG_PREEMPT_RT、CONFIG_HIGH_RES_TIMERS、CONFIG_GPIO_SYSFS、CONFIG_SPI_SPIDEV等。设备树则负责描述具体板级的引脚复用、外设地址与中断号,二者不能互相替代。
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- omap2plus_defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- zImage dtbs -j8
设备树源文件通常位于arch/arm/boot/dts/,例如am335x-evm.dts。若板卡使用了自定义的UART、CAN或PRU引脚,需要修改&am33xx_pinmux节点中的pinctrl子节点,并在对应外设节点中引用。一个常见的错误是只改了设备树却忘记在U-Boot中传递正确的fdtaddr,导致内核拿到旧设备树,表现为“外设识别不到但日志无报错”。
根文件系统:ABI一致性与最小可用集
根文件系统最容易出问题的地方不是“缺命令”,而是“动态链接器不匹配”。使用arm-linux-gnueabihf-工具链编译BusyBox后,/lib/ld-linux-armhf.so.3必须来自同一工具链的sysroot。若从其他来源拷贝了ld-linux.so.3,内核在启动/init时会报No such file or directory,而实际上文件存在——这是ABI不匹配的典型表现。
制作流程可概括为:编译BusyBox并make install到_install目录,补齐/dev、/proc、/sys、/etc/inittab与/etc/fstab,再用mkfs.ext4或genext2fs生成镜像。一个可用的最小inittab示例:
::sysinit:/etc/init.d/rcS
::respawn:-/bin/sh
::ctrlaltdel:/sbin/reboot
若使用systemd,则需保证/lib/systemd/systemd与工具链ABI一致,并在内核命令行中保留rootwait,否则MMC控制器尚未就绪时挂载根文件系统会失败。
启动流程调试:从串口日志定位断点
调试时不要一上来就改代码,先按启动阶段分段观察。串口无任何输出,优先检查启动介质选择(SYSBOOT引脚)与MLO是否写入正确偏移;出现U-Boot SPL但卡在DDR,检查DDR配置与电源时序;进入U-Boot后bootz报Bad Linux ARM zImage magic,说明加载地址或镜像类型不对;内核打印Kernel panic - not syncing: VFS: Unable to mount root fs,则回到bootargs中的root=与分区编号是否匹配。
fdt print /查看当前传递给内核的设备树内容,确认chosen节点中的bootargs与预期一致,再让内核启动。这样可以把“U-Boot传参错误”与“内核驱动问题”分开定位。
整个BSP构建的闭环可以这样验证:工具链-dumpmachine输出与目标ABI一致;U-Boot能打印版本并进入命令行;内核启动日志中出现Mounted root;根文件系统启动后uname -a与cat /proc/cpuinfo能正确识别AM335x。四步都通过,才说明交叉编译、引导、内核与根文件系统之间的参数已经对齐。