0. 这一节要解决什么
一次内核编译结束后,构建目录里会出现十几个文件。哪些要部署到板子、哪些只是调试用、哪些根本不该手动碰——先把名称和用途对上,部署与排障才不会拿错文件。
读完这一节,应能对每个产物说出:它是什么、谁产生、去哪里。
1. 产物总表
| 产物 | 是什么 | 去向 / 用途 |
|---|---|---|
Image |
ARM64 裸内核镜像 | U-Boot 用 booti 加载的对象(第 1 课时 6/6 手动启动的就是它) |
vmlinux |
带符号的 ELF 内核 | 调试分析用;不能直接 booti |
System.map |
内核符号地址表 | 对照 oops / panic 日志里的调用栈地址 |
*.dtb |
编译后的设备树 | 描述板级硬件,交给内核 |
*.dtbo |
overlay 的编译结果 | 叠加在基础 DTB 之上的片段 |
*.ko |
可加载内核模块 | 安装到 rootfs,开机后按需加载 |
extboot.img |
boot 分区镜像(本 SDK) | 打包 Image + DTB + extlinux 配置 |
标准路径:
kernel/arch/arm64/boot/Image
kernel/arch/arm64/boot/dts/rockchip/rk3576-firefly-roc-rk3576-pc.dtb
kernel/vmlinux
kernel/extboot.img ./build.sh extboot 生成
kernel/extboot/ 同一打包结果的目录形式
2. 三个「看起来像内核」的文件
| 文件 | 格式 | 能否被 U-Boot booti 加载 |
|---|---|---|
vmlinux |
ELF,带符号 | |
Image |
裸二进制 | |
Image.gz |
gzip 压缩 | 视 U-Boot 支持而定;需先解压 |
判断文件类型不要靠文件名猜,用 file:
file arch/arm64/boot/Image arch/arm64/boot/dts/rockchip/*.dtb vmlinux
# Image → data (裸二进制)
# *.dtb → device tree blob
# vmlinux→ ELF 64-bit LSB executable, ARM aarch64
3. .ko:编进内核与编成模块的区别
内核编译讲过 Y/M/N,落到产物上就是:
Y→ 对应代码链进Image,开机即有,根设备驱动必须这样M→ 生成独立.ko文件,位于drivers/**/*.ko,需安装到 rootfs(make modules_install或 SDK 打包时自动完成)
# 板子上看已加载的模块
lsmod
modinfo xxx.ko # 查看模块信息(在 PC 上)
insmod /lib/modules/.../xxx.ko
排障含义:某设备不工作时,先分清「驱动没编」/「编成模块但没加载」/「probe 失败」三种情况——对应手段分别是查 .config、lsmod、dmesg。
4. extboot.img:boot 分区的封装
本 SDK 的板级配置带 USE_EXTBOOT=y,单独编译内核的命令 ./build.sh extboot 产物不是散的 Image + dtb,而是一个 boot 分区镜像:
kernel/extboot.img ← 可整分区烧写(upgrade_tool di -boot)
kernel/extboot/ ← 同一内容的目录形式
├── Image
├── <board>.dtb
└── extlinux/extlinux.conf ← U-Boot 读它决定加载哪个内核与 DTB
两种部署方式等价:把 kernel/extboot/ 下的文件拷到板子 /boot/ 后重启,或把 extboot.img 烧进 boot 分区。细节在第 7、8 节展开。
观念:
extboot.img只是封装容器,不是启动链路中的一棒。封装与启动阶段是两回事。
5. Lab:反编译 DTB,眼见为实
# device-tree-compiler 已在 SDK 依赖列表中
dtc -I dtb -O dts kernel/extboot/rk3576-firefly-roc-rk3576-pc.dtb | less
对照观察:
- 反编译结果与源码
arch/arm64/boot/dts/rockchip/rk3576-firefly-roc-rk3576-pc.dts的model一致 - dtsi 里的节点全部展开进了 DTB——include 只是源码层的组织手段,编译后是一个整体
/chosen节点此时可能还没有bootargs——它是 U-Boot 交接时才写进去的
6. 本节小结
- 产物分三类:启动用的(Image、DTB、extboot.img)、调试用的(vmlinux、System.map)、运行期加载的(.ko)
file判类型;booti只吃裸 Image- extboot.img 是本 SDK 的 boot 分区封装:Image + DTB + extlinux 配置
- 封装 ≠ 启动阶段
7. 本节思考
Q1:为什么 vmlinux 明明是"完整内核"却不能用来启动?
查看答案
vmlinux 是 ELF 格式、带完整符号与调试信息,体积可达数十 MB,入口与加载布局是给调试器用的。内核启动要求把裸机器码放到固定物理地址直接跳转执行——Image 正是从 vmlinux 去掉符号、按启动约定裁剪出的二进制。U-Boot 的 booti 只认后者的格式与布局。
Q2:一个驱动编成了 .ko,板子启动后该设备没出现。按顺序检查什么?
查看答案
① .ko 是否在 rootfs 里(find /lib/modules -name 'xxx.ko');② 是否已加载(lsmod),没有则 modprobe xxx 并看报错;③ 加载后 dmesg 里有没有 probe 成功或失败的日志;④ 若 probe 失败,回到设备树核对节点与资源(6/8 的三条件)。注意与 Y 情况区分:若驱动编进了 Image,则根本不存在 .ko。
Q3:extboot.img 和第 1 课时讲的 boot.img 是什么关系?
查看答案
两者都是「boot 分区镜像」这一层封装的名字,本质相同:把内核启动所需的对象(Image、DTB、加载配置)打包成一个可整分区烧写的镜像。区别在组织方式——本 SDK 用 USE_EXTBOOT=y 走 extlinux 风格,产物命名为 extboot.img,内部是 extlinux/extlinux.conf 描述加载哪个内核与 DTB。名字随 SDK 而变,封装的角色不变。