02-基于01环境的U-Boot 制作与内核移植完整流程
项目嵌入式 Linux 系统设计实验U-Boot 制作与内核移植完整流程从 Bootloader 到 Linux 6.6、BusyBox RootFS 与文件系统挂载实验基线项目说明HOSTVMware Ubuntu 18.04 LTSx86_64TARGETWindows 原生 QEMU 11.1.0 / VExpress-A9 / Cortex-A9ARM 工具链Arm GNU Toolchain 12.3.Rel1 / GCC 12.3.1BootloaderU-Boot 2026.07Linux KernelLinux 6.6.0RootFSBusyBox 1.36.1 initramfs内存QEMU TARGET512 MiB共享目录Windows E:\EmbeddedLinuxLab ↔ Ubuntu /mnt/EmbeddedLinuxLab手册版本V1.0 · 2026-10实验目标完整经历“源码获取 → 交叉编译 → 镜像部署 → U-Boot 启动 → Kernel 接管 → RootFS 展开 → 文件系统挂载 → Shell 验收”的全过程。实验总览本手册按照“学生实际动手顺序”组织。每一步都区分 HOST 与 TARGET并给出命令、预期现象以及出错后的排查方向。HOSTUbuntu 18.04 │ ├─ 编译 U-Boot 2026.07 ├─ 编译 Linux 6.6 → zImage DTB ├─ 编译 BusyBox → RootFS │ └─ 复制最终产物到共享目录 │ ▼ Windows / QEMU VExpress-A9 │ ▼ U-Boot ┌───────┼─────────────┐ │ │ │ ▼ ▼ ▼ zImage DTB rootfs.cpio.gz │ │ │ └───────┴──────┬──────┘ ▼ Linux Kernel │ Kernel 自解压 / 解析 DTB │ 展开 initramfs │ /init │ /proc /sys /dev 挂载 │ ▼ BusyBox │ ▼ / #核心主线QEMU → U-Boot → Linux Kernel → Device Tree → RootFS → /init → Shell。整个实验围绕这条链展开。一、实验环境与目录约定1.1 HOST 与 TARGET 的分工层次环境职责HOSTUbuntu 18.04下载源码、配置、交叉编译、制作 RootFS交换区/mnt/EmbeddedLinuxLabHOST 与 Windows 之间传递最终镜像WindowsE:\EmbeddedLinuxLab保存 images/tftp/scripts/logsTARGETQEMU VExpress-A9运行 U-Boot 和 Linux模拟 Cortex-A9 开发板1.2 统一目录Ubuntu~/EmbeddedLinuxLab/ ├── src/ │ ├── u-boot-2026.07/ │ ├── linux-6.6/ │ └── busybox-1.36.1/ ├── build/ │ └── lab02/ │ └── rootfs/ └── env-arm32.shWindowsE:\EmbeddedLinuxLab\ ├── images\ │ └── u-boot ├── tftp\ │ ├── zImage_full │ ├── vexpress-v2p-ca9.dtb │ └── rootfs.cpio.gz ├── scripts\ └── logs\共享路径说明本手册统一写 /mnt/EmbeddedLinuxLab。若你的 VMware 共享目录实际显示为 /mnt/hgfs/EmbeddedLinuxLab只需把所有 /mnt/EmbeddedLinuxLab 替换成实际路径即可。编译原则源码与编译过程放在 Ubuntu 自己的 ext4 文件系统中不要直接在 VMware 共享目录中编译共享目录只作为交换区。1.3 ARM32 交叉编译环境source~/EmbeddedLinuxLab/env-arm32.shecho$ARCHecho$CROSS_COMPILEwhicharm-none-linux-gnueabihf-gcc arm-none-linux-gnueabihf-gcc--version期望ARCHarm CROSS_COMPILEarm-none-linux-gnueabihf- /opt/arm/gcc-12.3-arm32/bin/arm-none-linux-gnueabihf-gcc gcc version 12.3.1 ...二、U-Boot 2026.07下载、配置与编译2.1 获取源码可以通过浏览器下载U-Boot 2026.07 源码U-Boot 2026.07 源码包tar.bz2https://ftp.denx.de/pub/u-boot/u-boot-2026.07.tar.bz2或者直接在ubuntu中下载wget https://ftp.denx.de/pub/u-boot/u-boot-2026.07.tar.bz2将 U-Boot 2026.07 源码解压到~/EmbeddedLinuxLab/src/u-boot-2026.07进入源码目录source~/EmbeddedLinuxLab/env-arm32.shcd~/EmbeddedLinuxLab/src/u-boot-2026.072.2 清理旧配置并选择 VExpress-A9makedistcleanmakevexpress_ca9x4_defconfig确认grepCONFIG_TARGET_VEXPRESS .config应看到CONFIG_TARGET_VEXPRESS_CA9X4y2.3 编译 U-Bootmake-j2编译完成后检查ls-lhu-bootfileu-bootLC_ALLC arm-none-linux-gnueabihf-readelf-hu-boot|grepMachine应确认它是 ARM 32-bit ELF并显示Machine: ARM为什么使用 make -j2当前教学主机为 4 核 4 线程老平台VMware 内给太多并行任务会挤占宿主资源。教学环境优先稳定建议 2 vCPU make -j2。三、U-Boot 导入 QEMU 并启动3.1 复制 U-Boot 到共享目录cp~/EmbeddedLinuxLab/src/u-boot-2026.07/u-boot\/mnt/EmbeddedLinuxLab/images/Windows 应看到E:\EmbeddedLinuxLab\images\u-boot3.2 Windows 启动 QEMUWindows CMD 执行C:\Program Files\qemu\qemu-system-arm.exe ^ -machine vexpress-a9 ^ -m 512M ^ -nographic ^ -no-reboot ^ -kernel E:\EmbeddedLinuxLab\images\u-boot ^ -nic user,tftpE:\EmbeddedLinuxLab\tftp典型启动信息U-Boot 2026.07 ... DRAM: 512 MiB Flash: 128 MiB MMC: mmci5000: 0 In: uart9000 Out: uart9000 Err: uart9000 Net: eth0 关于 bad CRC首次运行若出现Warning: bad CRC, using default environment通常只是环境区尚未初始化并不代表 U-Boot 编译失败。3.3 U-Boot 基本命令命令作用实验观察version显示版本确认 U-Boot 2026.07help列出命令观察 Bootloader 的 Monitor 功能printenv查看环境变量bootargs、loadaddr 等bdinfo显示板级信息RAM、启动参数、地址md 0x60000000 20读内存观察 RAM 内容mw 0x61000000 0x12345678写内存直接修改 RAMmd 0x61000000 4读回验证看到 12345678dhcp获取网络地址QEMU user 网络通常得到 10.0.2.15tftpboot ${loadaddr} test.binTFTP 下载验证 HOST/Windows TFTP 交换链路QEMU user 网络中通常TARGET 为 10.0.2.15内置服务端地址为 10.0.2.2。阶段结论此时系统还没有 Linux。我们只是证明QEMU 仿真板可运行 U-Boot且 U-Boot 可以进行内存操作和网络下载。四、Linux 6.6下载、校验与配置4.1 获取 Linux 6.6 源码先回源码目录cd~/EmbeddedLinuxLab/src下载wgethttps://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.6.tar.xz推荐通过 Windows 浏览器下载 linux-6.6.tar.xz再放入共享目录。Linux 6.6 源码包tar.xzhttps://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.6.tar.xzUbuntu 侧复制到本地源码区cp/mnt/EmbeddedLinuxLab/tftp/linux-6.6.tar.xz\~/EmbeddedLinuxLab/src/先做完整性校验cd~/EmbeddedLinuxLab/src xz-tlinux-6.6.tar.xzecholinux-6.6.tar.xz 完整再解压tar-xJflinux-6.6.tar.xzcdlinux-6.6makekernelversion应显示6.6.0遇到 tar Unexpected EOF不要继续编译。说明压缩包不完整删除损坏文件和残缺源码目录重新下载并先用xz -t验证。4.2 生成 ARMv7 通用配置source~/EmbeddedLinuxLab/env-arm32.shcd~/EmbeddedLinuxLab/src/linux-6.6makemrpropermakemulti_v7_defconfig4.3 检查 VExpress、串口与 initramfs 支持grepCONFIG_ARCH_VEXPRESS .configgrepCONFIG_SERIAL_AMBA_PL011 .configgrepCONFIG_SERIAL_AMBA_PL011_CONSOLE .configgrepCONFIG_BLK_DEV_INITRD .config当前平台实测关键项CONFIG_ARCH_VEXPRESSy CONFIG_SERIAL_AMBA_PL011y CONFIG_SERIAL_AMBA_PL011_CONSOLEy CONFIG_BLK_DEV_INITRDy为什么 PL011 很重要QEMU -nographic 下Linux 控制台依赖 VExpress 的 PL011 串口。如果串口驱动或 console 选项缺失Kernel 可能已经启动但屏幕没有输出。五、Linux 6.6编译 zImage 与设备树5.1 编译make-j2zImage dtbs5.2 检查输出ls-lharch/arm/boot/zImagefindarch/arm/boot/dts-namevexpress-v2p-ca9.dtb我们使用的设备树vexpress-v2p-ca9.dtb5.3 保存“完整内核”基线mkdir-p~/EmbeddedLinuxLab/build/lab02cparch/arm/boot/zImage\~/EmbeddedLinuxLab/build/lab02/zImage_fullcp.config\~/EmbeddedLinuxLab/build/lab02/config_full当前平台实测zImage_full 10,904,064 bytes约 11 MiB5.4 部署到 TFTPcp~/EmbeddedLinuxLab/build/lab02/zImage_full\/mnt/EmbeddedLinuxLab/tftp/cp$(findarch/arm/boot/dts-namevexpress-v2p-ca9.dtb)\/mnt/EmbeddedLinuxLab/tftp/六、U-Boot 引导 Linux先做一次“无 RootFS”对照实验这一步故意不提供 RootFS。目的不是把系统完整启动而是验证 U-Boot→Kernel→DTB→串口这条链。6.1 U-Boot 下载 Kernel 与 DTB tftpboot 0x60008000 zImage_full tftpboot 0x62000000 vexpress-v2p-ca9.dtb setenv bootargs consolettyAMA0,38400n8 bootz 0x60008000 - 0x620000006.2 Kernel 接管 CPU 的标志应看到类似Starting kernel ... [ 0.000000] Booting Linux on physical CPU 0x0 [ 0.000000] Linux version 6.6.0 ... [ 0.000000] CPU: ARMv7 Processor ... [ 0.000000] OF: fdt: Machine model: V2P-CA9 ... [ x.xxxxxx] 10009000.serial: ttyAMA0 ... [ x.xxxxxx] printk: console [ttyAMA0] enabled6.3 为什么最后会 Kernel panic/dev/root: Cant open blockdev VFS: Cannot open root device or unknown-block(0,0) ... Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)这不是失败Kernel 已经成功启动到“准备挂载根文件系统”阶段。panic 的直接原因只是没有 RootFS。这个对照实验非常适合说明Kernel ≠ 完整 Linux 系统。七、BusyBox 最小 RootFS 制作7.1 安装构建工具sudoaptupdatesudoaptinstall-ybuild-essential libncurses5-dev cpio7.2 获取 BusyBox 1.36.1源码放到~/EmbeddedLinuxLab/src/busybox-1.36.17.3 配置 BusyBoxsource~/EmbeddedLinuxLab/env-arm32.shcd~/EmbeddedLinuxLab/src/busybox-1.36.1makedistcleanmakedefconfigmakemenuconfig在 menuconfig 中启用Settings └─ [*] Build static binary (no shared libs)7.4 编译并安装到 RootFSmake-j2mkdir-p~/EmbeddedLinuxLab/build/lab02/rootfsmakeCONFIG_PREFIX~/EmbeddedLinuxLab/build/lab02/rootfsinstall检查ls-l~/EmbeddedLinuxLab/build/lab02/rootfs/binfile~/EmbeddedLinuxLab/build/lab02/rootfs/bin/busybox为什么静态链接最小 RootFS 中还没有 ARM glibc 动态加载器和共享库。静态 BusyBox 可独立运行最适合第一版系统。八、建立最小 RootFS 目录与 /init8.1 创建目录cd~/EmbeddedLinuxLab/build/lab02/rootfsmkdir-petc proc sys dev tmpmkdir-pusr/bin usr/sbinchmod1777tmp8.2 创建 /initcatinitEOF #!/bin/sh mount -t proc proc /proc mount -t sysfs sysfs /sys mount -t devtmpfs devtmpfs /dev echo echo echo Minimal ARM Linux with BusyBox is running echo echo exec /bin/sh EOFchmodx init8.3 创建设备节点sudomknod-m600dev/console c51sudomknod-m666dev/null c13ls-ldev应看到 console 和 null且行首为 c表示字符设备。常见错误若 mknod 报dev/console: 没有那个文件或目录先检查 pwd你必须位于 rootfs 根目录并且 dev/ 已经创建。8.4 查看 RootFS 结构find.-maxdepth2-typed|sort最终至少应包含/ ├── bin ├── sbin ├── etc ├── proc ├── sys ├── dev ├── tmp └── usr ├── bin └── sbin九、把 RootFS 打包成 initramfs9.1 打包cd~/EmbeddedLinuxLab/build/lab02/rootfsfind.-print0|\cpio--null-ov--formatnewc|\gzip-9../rootfs.cpio.gz9.2 检查并部署cd..ls-lhrootfs.cpio.gzcprootfs.cpio.gz\/mnt/EmbeddedLinuxLab/tftp/Windows 端此时 TFTP 目录应至少有E:\EmbeddedLinuxLab\tftp\ ├── zImage_full ├── vexpress-v2p-ca9.dtb └── rootfs.cpio.gz十、U-Boot 同时加载 Kernel、RootFS 与 DTB10.1 下载三个镜像 tftpboot 0x60008000 zImage_full tftpboot 0x64000000 rootfs.cpio.gz setenv rdsize ${filesize} tftpboot 0x62000000 vexpress-v2p-ca9.dtb必须保存 rdsize每次 tftpboot 都会改写${filesize}。下载 RootFS 后立刻把它保存到 rdsize否则下载 DTB 后${filesize}就变成 DTB 大小。10.2 设置启动参数并启动 setenv bootargs consolettyAMA0,38400n8 rdinit/init bootz 0x60008000 0x64000000:${rdsize} 0x6200000010.3 三个加载地址地址镜像作用0x60008000zImage_fullLinux Kernel0x62000000vexpress-v2p-ca9.dtbVExpress-A9 硬件描述0x64000000rootfs.cpio.gzBusyBox initramfs这些地址都位于 VExpress-A9 的 512 MiB RAM 范围内并为当前镜像预留了足够间隔。十一、理解“展开”Kernel 和 RootFS 分别发生了什么11.1 zImage 的展开U-Boot │ bootz ▼ zImage │ ├─ ARM 解压启动代码运行 ▼ Linux Kernel 被解压到 RAM │ ▼ Kernel 正式接管 CPUU-Boot 负责加载和跳转但并不负责把 zImage 解压成内核本体zImage 自带解压启动代码。11.2 rootfs.cpio.gz 的展开rootfs.cpio.gz │ ▼ Kernel 解压 gzip │ ▼ 解析 cpio(newc) │ ▼ 展开成内存中的 rootfs │ ▼ 查找并执行 /init十二、文件系统挂载/proc、/sys、/dev/init 执行后首先完成三个关键挂载mount-tproc proc /procmount-tsysfs sysfs /sysmount-tdevtmpfs devtmpfs /dev挂载点文件系统主要内容/procprocfsCPU、内存、进程、内核运行信息/syssysfs设备、驱动、总线、class 等内核对象/devdevtmpfs设备节点什么叫挂载mount 不是复制文件。它是把一个文件系统连接到 Linux 统一目录树中的某个路径从此该路径成为这个文件系统的入口。十三、进入 BusyBox Shell 后的验收正常情况下最终出现/ #13.1 内核版本uname-acat/proc/version13.2 CPU 与内存cat/proc/cpuinfocat/proc/meminfo|head-n2013.3 文件系统pwdls/mountdf-hcat/proc/filesystems13.4 设备与驱动模型ls/dev|headls/sys/classcat/sys/class/net/eth0/address2/dev/null至此学生已经亲手完成一个最小但完整的嵌入式 Linux 系统Kernel Device Tree RootFS 用户空间 Shell。十四、内核裁剪体验“嵌入式软件可裁剪”在完整系统已经跑通后再做裁剪。这样学生能清楚区分“移植成功”与“按产品需求优化”。14.1 保存完整配置cd~/EmbeddedLinuxLab/src/linux-6.6cp.config ~/EmbeddedLinuxLab/build/lab02/config_full14.2 关闭 Linux 网络子系统makemenuconfig取消Networking support [ ] Networking support保存后检查grep^CONFIG_NET.config应看到# CONFIG_NET is not set14.3 编译裁剪后的 zImagemake-j2zImagecparch/arm/boot/zImage\~/EmbeddedLinuxLab/build/lab02/zImage_cutcp.config\~/EmbeddedLinuxLab/build/lab02/config_cut14.4 比较镜像与配置ls-l\~/EmbeddedLinuxLab/build/lab02/zImage_full\~/EmbeddedLinuxLab/build/lab02/zImage_cutdiff\~/EmbeddedLinuxLab/build/lab02/config_full\~/EmbeddedLinuxLab/build/lab02/config_cut把 zImage_cut 复制到 TFTP再用同一个 rootfs.cpio.gz 与 DTB 启动若仍可进入 / #即说明裁剪后的内核满足当前实验功能。关键理解U-Boot 的 TFTP 网络与 Linux Kernel 的网络子系统是两套独立软件。因此即使 Linux 的 CONFIG_NET 被裁掉U-Boot 仍然可以通过自己的网卡驱动和协议栈下载 zImage。十五、扩展从 initramfs 走向持久化文件系统当前 rootfs.cpio.gz 在启动时被展开到 RAM 中。运行时写入的文件QEMU 退出后不会保留。下一步可以加入虚拟 SD 卡和 ext4 数据分区initramfsRAM / ├── /bin ├── /etc └── /usr ↓ 系统程序 ext4虚拟 SD / Flash /data ├── config ├── logs └── records ↓ 掉电/重启后保留这就是后续“嵌入式设备配置 运行日志 持久化数据分区”实验的基础。工程化方向实际产品常把系统区做成只读或尽量少写把用户配置、日志和业务数据独立放在可写数据分区从而提高可靠性。十六、常见问题与排查现象主要原因处理方法U-Boot 编译后 file 显示 x86-64没有启用 CROSS_COMPILE重新 source env-arm32.sh再 make distclean / defconfig / makeQEMU 没有出现 u-boot 文件错误或 QEMU 参数错误检查 -machine vexpress-a9、-kernel 路径、u-boot 文件U-Boot 出现 bad CRC默认环境尚未初始化一般可忽略不影响当前实验tftpboot 找不到文件Windows tftp 目录或文件名不匹配检查 E:\EmbeddedLinuxLab\tftp 与命令中的文件名linux-6.6.tar.xz 解压 Unexpected EOF下载不完整先 xz -t重新下载不要在残缺源码上继续readelf grep Machine 无输出中文 locale 本地化字段名使用 LC_ALLCKernel 启动后没有串口输出PL011 或 console 配置/bootargs 错误检查 CONFIG_SERIAL_AMBA_PL011_CONSOLE 和 consolettyAMA0,38400n8Kernel 最终 VFS panic没有 RootFS 或 RootFS 参数错误无 RootFS 对照实验中属正常完整启动时检查 initramfsmknod dev/console 报目录不存在当前不在 rootfs 根目录或 dev 未创建pwdmkdir -p dev再 mknodBusyBox 存在但提示 No such file动态链接 BusyBox 缺 ARM loader/so重新配置为 static binarybootz 传入 initrd 大小错误${filesize} 被后续 tftpboot 覆盖下载 rootfs 后立即 setenv rdsize ${filesize}VMware 编译时卡死Guest/宿主资源争用或 VMware 问题2 vCPU、8 GB、make -j2不要不必要地 make clean十七、实验记录与验收17.1 当前平台已验证数据项目结果QEMU11.1.0TARGETVExpress-A9 / Cortex-A9U-Boot2026.07ARM GCC12.3.1Linux6.6.0DRAM512 MiB设备树模型V2P-CA9串口PL011 / ttyAMA0完整 zImage10,904,064 bytes约 11 MiB无 RootFS 的预期结局VFS: Unable to mount root fs on unknown-block(0,0)17.2 学生验收清单ARM 工具链环境变量正确。U-Boot 2026.07 成功编译确认是 ARM ELF。QEMU 能进入 U-Boot 提示符。完成 version/help/printenv/bdinfo/md/mw/dhcp/tftpboot 基本测试。Linux 6.6 使用 multi_v7_defconfig 配置成功。VExpress、PL011、initramfs 关键配置检查通过。成功生成 zImage 与 vexpress-v2p-ca9.dtb。无 RootFS 时 Kernel 能启动并到达 VFS 挂载阶段。BusyBox 静态编译并安装到 rootfs。建立 /init、/proc、/sys、/dev 等必要目录和设备节点。rootfs.cpio.gz 打包成功。U-Boot 同时加载 Kernel、RootFS、DTB 并 bootz。最终进入 BusyBox / #。能解释 zImage 自解压与 initramfs 展开的区别。能解释 /proc、/sys、/dev 的作用和 mount 的含义。完成至少一项 Kernel 裁剪并验证裁剪后仍能满足目标功能。17.3 实验记录表记录项目实测值U-Boot 编译耗时【填写】Linux 6.6 首次编译耗时【填写】zImage_full 字节数10,904,064DTB 实际路径【填写】rootfs.cpio.gz 大小【填写】第一次出现 / # 的时间点【填写】zImage_cut 字节数【填写】裁剪前后差值【填写】裁剪后是否仍能进入 / #【填写】十八、课程主线总结第一层Bootloader U-Boot ↓ 初始化 下载 启动 第二层Kernel Linux 6.6 ↓ CPU 内存 中断 驱动 第三层Device Tree vexpress-v2p-ca9.dtb ↓ 描述 TARGET 硬件 第四层RootFS BusyBox initramfs ↓ 提供用户空间 第五层File System /proc /sys /dev ↓ 内核对象与设备统一进入目录树 第六层Tailoring Kconfig / menuconfig ↓ 按产品需求裁剪 第七层扩展Persistent Storage ext4 /data ↓ 保存配置 日志 业务数据完成本实验后学生应能从系统角度说明U-Boot 为什么存在、Linux Kernel 如何被加载并接管处理器、Device Tree 在目标板移植中承担什么作用、RootFS 为什么是完整 Linux 系统不可缺少的一部分以及嵌入式 Linux 为什么可以根据产品需求裁剪和定制。《U-Boot 制作与内核移植完整流程》 V1.0