自动启动失败怎么用手工把内核拽起来?——U-Boot手动引导完整步骤
| 理解U‑Boot自动启动背后到底做了什么,最好的方法是在U‑Boot命令行中手动完成一次内核引导。当自动启动失败时,手动引导也是最重要的调试手段。本文以RK3576为例,展示从eMMC、SD卡和TFTP三种方式手动引导Linux内核的完整命令序列。 |
自动启动卡住或者进入shell后不知下一步做什么。此时最好的调试方法就是手动执行一遍引导步骤——每一步的输出都揭示了问题所在。加载内核失败?检查文件系统。启动后卡死?检查bootargs。本文整理了RK3576上最常用的三种手动引导方案,附带所有关键地址和命令。
一、手动引导概览
自动启动时,U‑Boot根据bootcmd环境变量中的命令序列执行引导。手动引导就是把这一系列命令逐一在命令行中执行,细致观察每个步骤的输出和结果。
二、通用环境变量
在开始手动引导前,需要确认以下关键环境变量:
# 查看加载地址=> printenv kernel_addr_r fdt_addr_r ramdisk_addr_rkernel_addr_r=0x40400000fdt_addr_r=0x48300000ramdisk_addr_r=0x4a200000
这些地址必须:
1.在可用内存范围内
2.不与U‑Boot自身重叠
3.与内核Image的解压地址兼容
三、方式一:从eMMC引导
eMMC在RK3576上通常为mmc dev 0,根文件系统在第五分区。
完整命令序列
# ── 第1步:选择eMMC设备 ──=> mmc dev0switch to partitions#0, OKmmc0 is current device# ── 第2步:查看eMMC分区表 ──=> mmc partPartitionMapforMMCdevice0 -- PartitionType:EFIPart StartLBA EndLBA NameAttributesTypeGUIDPartitionGUID1 0x00008000 0x0000a000 "boot"2 0x0000a000 0x0000c000 "trust"3 0x0000c000 0x0000f000 "misc"4 0x0000f000 0x0005f000 "resource"5 0x0005f000 0x00200000 "rootfs"# ── 第3步:加载内核Image ──# 如果rootfs分区是ext4格式:=> ext4load mmc0:5${kernel_addr_r} /boot/Image18667520bytes readin789ms (22.6MiB/s)# ── 第4步:加载DTB ──=> ext4load mmc0:5${fdt_addr_r} /boot/rk3576‑evb.dtb65241bytes readin21ms (2.9MiB/s)# ── 第5步:设置bootargs ──=> setenv bootargs console=ttyS2,1500000root=/dev/mmcblk0p5 rootfstype=ext4 rw# ── 第6步:引导内核 ──=> booti${kernel_addr_r} -${fdt_addr_r}## Loading kernel from Image at 0x40400000 ...Imagename:Linux5.10.160Imagetype:AArch64LinuxKernelImage## Flattened Device Tree blob at 0x48300000Bootingusing the fdt blob at0x48300000## bootargs: console=ttyS2,1500000 root=/dev/mmcblk0p5 rootfstype=ext4 rwLoadingDeviceTreeto 00000000af5e0000,end00000000af5fefff ...OKStartingkernel ...
参数说明
| 命令 |
含义 |
| mmc dev 0 |
选择eMMC设备(设备0) |
| ext4load mmc 0:5 |
从eMMC设备0的分区5(ext4)加载文件 |
| ${kernel_addr_r} |
内核加载地址,通常为0x40400000 |
| ${fdt_addr_r} |
DTB加载地址,通常为0x48300000 |
| booti ${kernel_addr_r} - ${fdt_addr_r} |
引导Image内核,‑表示无ramdisk |
四、方式二:从SD卡引导
SD卡在RK3576上通常为mmc dev 1,分区格式可能是FAT或ext4。
FAT格式SD卡
# ── 第1步:选择SD卡设备 ──=> mmc dev1switch to partitions#0, OKmmc1 is current device# ── 第2步:加载内核 ──=> fatload mmc1:1${kernel_addr_r}Image18667520bytes readin801ms (22.2MiB/s)# ── 第3步:加载DTB ──=> fatload mmc1:1${fdt_addr_r} rk3576‑evb.dtb65241bytes readin22ms (2.8MiB/s)# ── 第4步:设置bootargs ──# 注意root设备是mmcblk1而非mmcblk0=> setenv bootargs console=ttyS2,1500000root=/dev/mmcblk1p5 rootfstype=ext4 rw# ── 第5步:引导 ──=> booti${kernel_addr_r} -${fdt_addr_r}
ext4格式SD卡
=> mmc dev1=> ext4load mmc1:1${kernel_addr_r} /boot/Image=> ext4load mmc1:1${fdt_addr_r} /boot/rk3576‑evb.dtb=> setenv bootargs console=ttyS2,1500000root=/dev/mmcblk1p5 rootfstype=ext4 rw=> booti${kernel_addr_r} -${fdt_addr_r}
| 注意:从SD卡引导时,root=参数中mmcblk1对应SD卡,mmcblk0对应eMMC。混用将导致内核尝试从错误的设备挂载根文件系统。 |
五、方式三:从TFTP网络引导
网络引导在开发阶段非常有用,可以避免反复烧录存储介质。
前提条件
‑ U‑Boot已通过ethaddr环境变量配置了MAC地址
‑网络中有DHCP服务器提供IP分配
‑ TFTP服务器上放置了内核Image和DTB
完整命令序列
# ── 第1步:初始化网络(DHCP获取IP) ──=> dhcpBOOTPbroadcast1DHCPclient bound to address192.168.1.100***Warning: no boot file name; using'C0A80064.img'# ── 第2步:从TFTP加载内核Image ──=> tftp${kernel_addr_r}192.168.1.200:ImageUsingethernet@fe2c0000deviceTFTPfrom server192.168.1.200; ourIPaddress is192.168.1.100Filename'Image'.Loadaddress:0xa200000Loading:################################################18667520bytes loadedin2.3seconds (7.7MiB/s)# ── 第3步:加载DTB ──=> tftp${fdt_addr_r}192.168.1.200:rk3576‑evb.dtb65241bytes loadedin0.12seconds# ── 第4步:设置bootargs ──# NFS根文件系统(开发阶段常用)=> setenv bootargs console=ttyS2,1500000root=/dev/nfsrwnfsroot=192.168.1.200:/srv/nfs/rootfs,v3 ip=dhcp# ── 第5步:引导 ──=> booti${kernel_addr_r} -${fdt_addr_r}
六、三种方式的对比
| 维度 |
eMMC |
SD卡 |
TFTP |
| 速度 |
最快(~30MB/s) |
中等(~20MB/s) |
依赖网络(~8MB/s) |
| 持久性 |
断电保留 |
断电保留 |
不保留 |
| 方便迭代 |
需要烧录 |
需要插拔卡 |
最方便(仅需编译+上传) |
| 依赖硬件 |
无 |
SD卡槽 |
网线+ DHCP+TFTP服务器 |
| 适用场景 |
量产/最终产品 |
早期调试 |
开发阶段调试 |
七、调试技巧
7.1检查内核镜像Magic
在跳转前,确认加载的内核Image是有效的:
=> md${kernel_addr_r}440400000:38400000000000040000000000020000 .8@.............# 偏移0x38处检查magic=> md${kernel_addr_r}0x38140400038: 644d5241 ARMd
7.2验证DTB完整性
=> fdt addr${fdt_addr_r}=> fdt list / # 检查根节点=> fdt list /chosen # 检查bootargs=> fdt list /memory # 检查内存信息
7.3保存常用命令序列
对于经常使用的手动引导步骤,可以保存为环境变量宏:
=> setenv my_boot_cmd'mmc dev 0; ext4load mmc 0:5 ${kernel_addr_r} /boot/Image;ext4load mmc 0:5 ${fdt_addr_r} /boot/rk3576‑evb.dtb;setenv bootargs console=ttyS2,1500000 root=/dev/mmcblk0p5 rw;booti ${kernel_addr_r} - ${fdt_addr_r}'=> saveenv# 之后只需运行:=> run my_boot_cmd
八、小结
‑手动引导是理解U‑Boot到内核启动流程的最佳实践方法
‑ eMMC、SD卡、TFTP三种方式各有适用场景,TFTP最适合开发调试
‑关键步骤为:选择设备/初始化网络→加载内核→加载DTB →设置bootargs → booti引导
‑从SD卡引导时注意root=参数中的设备号应为mmcblk1而非mmcblk0
‑网络引导需要DHCP + TFTP服务器支持,但免去了反复烧录的麻烦
‑善用fdt命令和md命令,可以在跳转前验证镜像和DTB的完整性
‑常用命令序列可以保存为环境变量宏,实现"半自动"引导
