4、嵌入式Linux系统移植:U-Boot引导加载、Linux内核配置与编译、根文件系统构建
好,咱们今天聊点硬核的。嵌入式Linux系统移植,说白了就是给咱们的CT或MRI设备装上大脑和神经系统。我做了这么多年嵌入式,每次做系统移植都像在组装一台精密仪器——少一颗螺丝都不行。
这一章,我带你走一遍完整的流程:从U-Boot引导加载,到Linux内核配置编译,再到根文件系统构建。每一步我都会说说我踩过的坑,你照着做,能省不少时间。
4.1 U-Boot引导加载——设备的第一口呼吸
U-Boot是什么?你可以把它理解成设备的BIOS。上电后,CPU第一个跑的就是它。它的任务很简单:初始化硬件,然后找到内核,把它加载到内存里跑起来。
我个人习惯,拿到一块新板子,第一件事就是看它的启动流程。不同的SoC,启动方式千差万别。比如有些用SD卡启动,有些用NAND Flash,还有些用eMMC。
核心要点:U-Boot的移植,本质上是让它在你的板子上能正常跑起来。关键在板级配置文件和设备树。
具体怎么做?我一般分三步走:
- 获取源码——从官方仓库拉一份,或者用芯片厂商提供的BSP包。
- 配置板级文件——在
board/目录下找到最接近的参考板,复制一份,改名字。 - 编译烧录——设置交叉编译工具链,然后
make。
嗯,这里要注意。很多新手一上来就改代码,结果连编译都过不了。我建议你先用默认配置编译一次,确保环境没问题。
# 以TI的AM335x为例
make distclean
make am335x_evm_defconfig
make CROSS_COMPILE=arm-linux-gnueabihf-
编译完会生成u-boot.img和MLO两个文件。MLO是第一阶段引导程序,u-boot.img是主体。烧到SD卡上,插进板子,串口能看到启动信息,就算成了。
小技巧:我习惯在U-Boot里加一个bootdelay变量,设成3秒。这样调试时能打断自动启动,进命令行看看环境变量对不对。
4.2 Linux内核配置与编译——裁剪的艺术
内核移植,说白了就是让Linux认识你的硬件。CT和MRI设备对实时性和稳定性要求极高,所以内核不能大而全,得精打细算。
我记得有一次,客户说设备启动太慢。我查了半天,发现内核里编译了一堆用不上的驱动——什么Wi-Fi、蓝牙、声卡。你想想看,医疗设备要这些干嘛?
所以,内核配置的核心思路是:只编译你需要的。
具体步骤:
- 获取内核源码——建议用LTS版本,稳定第一。
- 配置内核——运行
make menuconfig,逐项选择。 - 编译内核和设备树——
make zImage和make dtbs。
配置时,我重点关注这几个地方:
| 配置项 | 说明 | 我的建议 |
|---|---|---|
| Processor type | CPU架构和特性 | 选对型号,别选错 |
| Device Drivers | 外设驱动 | 只勾选你板子上有的 |
| File systems | 文件系统支持 | ext4、yaffs2、ubifs看情况 |
| Networking support | 网络协议栈 | CT/MRI一般需要TCP/IP |
警告:千万不要用make allyesconfig!我曾经见过有人这么干,编译出来的内核镜像有200多MB,根本烧不进去。而且启动时加载驱动就要花半分钟,你说这设备还能用吗?
编译命令很简单:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- zImage -j4
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- dtbs
编译完,你会得到arch/arm/boot/zImage和一堆.dtb文件。zImage是压缩后的内核镜像,dtb是设备树二进制文件。
设备树这块,我多说两句。它描述了板子的硬件信息——哪个GPIO接了LED,哪个I2C挂了传感器。以前老内核把这些写死在代码里,改个引脚都得重新编译。现在用设备树,改个dts文件就行,方便多了。
4.3 根文件系统构建——让设备有“家”
内核跑起来后,需要挂载根文件系统。没有它,设备就是个空壳子,啥也干不了。
根文件系统里有什么?说白了就是目录结构、库文件、应用程序、配置文件。CT和MRI设备一般用BusyBox来构建,轻量、稳定。
我常用的构建方式有两种:
- BusyBox + 手动构建——适合定制化需求,每个文件都自己放。
- Buildroot——自动化工具,一键生成根文件系统镜像。
我个人更推荐Buildroot,尤其是项目初期。它帮你处理了依赖关系,省心不少。
用Buildroot构建根文件系统,大概分这几步:
- 配置目标架构——选ARM,指定交叉编译器。
- 选择软件包——比如你需要SSH、NFS、Python等。
- 生成文件系统镜像——支持ext4、squashfs、cpio等多种格式。
# Buildroot配置示例
make menuconfig
# 设置 Target options -> Target Architecture = ARM
# 设置 Toolchain -> Toolchain type = External toolchain
# 设置 System configuration -> Root filesystem overlay directory
make
编译完,在output/images/目录下会生成rootfs.ext4之类的镜像文件。烧到存储设备上,内核启动时挂载它,系统就活了。
避坑指南:我曾经在根文件系统里漏了/dev/console节点,结果内核启动到一半卡住了,串口没有任何输出。查了两天才发现是缺少这个设备节点。所以,构建完一定要检查/dev目录下的基本节点。
还有一个容易忽略的点——init进程。根文件系统挂载后,内核会执行/sbin/init。如果这个文件不存在或者权限不对,系统会直接panic。我一般用BusyBox的init,或者自己写一个简单的启动脚本。
4.4 三者的协同——让设备真正跑起来
U-Boot、内核、根文件系统,这三者不是孤立的。它们通过启动参数串联在一起。
U-Boot启动时,会读取环境变量bootargs,里面指定了内核启动参数。比如:
setenv bootargs 'console=ttyO0,115200 root=/dev/mmcblk0p2 rw rootfstype=ext4'
这个参数告诉内核:串口用ttyO0,波特率115200,根文件系统在SD卡第二个分区,格式是ext4。
然后U-Boot用bootz命令加载内核和设备树:
load mmc 0:1 0x82000000 zImage
load mmc 0:1 0x88000000 am335x-evm.dtb
bootz 0x82000000 - 0x88000000
你看,整个过程环环相扣。U-Boot负责引导,内核负责管理硬件,根文件系统提供运行环境。任何一个环节出问题,设备都起不来。
总结一下:系统移植不是一蹴而就的事。我建议你从最简单的配置开始,一步步验证。先让U-Boot能打印信息,再让内核能启动到挂载根文件系统,最后再优化裁剪。每一步都稳扎稳打,后面才不会出幺蛾子。
好了,这一章的内容就到这里。下一章我们聊聊设备驱动开发——那才是真正让硬件“动起来”的关键。