实验二十 编译内核与设备树——第一次编出自己的 uImage 和 fsmp1a.dtb
对应课件:《第5章 移植Linux内核》5.4 节步骤 3~4(Slide 41~46)
系列说明:本系列基于华清远见 FS-MP1A(STM32MP157A)开发板,对应课件《第5章 移植Linux内核》。地基打好(实验十九),本篇一口气产出第 5 章最重要的两个文件:自己编的
uImage和自己编的stm32mp157a-fsmp1a.dtb。编完先不改任何东西——这份"零修改"内核加上老师给的设备树,就是我们后面移植 eMMC、网卡驱动的底版;eMMC 驱动和网卡驱动是实验二十一、二十二的事。前置:实验十九(源码、23 个补丁、配置、两套工具全部就位)。
一、本篇要产出的两个文件,和它们的"去处"
| 产出 | 生成位置 | 后面怎么用 |
|---|---|---|
arch/arm/boot/uImage | 编内核的终点产物 | 拷进/home/cnu/tftpboot,实验二十三tftp c2000000 my_uImage点火 |
arch/arm/boot/dts/stm32mp157a-fsmp1a.dtb | 编设备树的产物 | 同上,tftp c4000000 stm32mp157a-fsmp1a.dtb |
与出厂件的区别只在"谁编的":出厂uImage是华清拿 ST 包编的(7,546,640 字节),我们这份大小不会一样——大小不同没关系,能不能点火由实验二十三验收。还有一个更好认的记号:我们编的 uImage 版本串带 git 哈希(Linux-5.4.31-g<哈希>,实验十九步骤 3.3 说过原因),出厂那份是干净的Linux-5.4.31——以后从 U-Boot 的Image Name:一行就能看出点的哪份内核。
二、实验环境(实际)
| 项目 | 实际值 |
|---|---|
| 操作位置 | Ubuntu 虚拟机,实验十九那棵源码树(在共享目录~/Desktop/LINUX-gy/Test2/...或本地~/kernel/linux-5.4.31/,以你实际位置为准) |
| 编译器 | arm-none-linux-gnueabihf-(实验十九装的 ARM 官方 gcc 9.2) |
| 配置基线 | .config(由multi_v7_defconfig+ fragment 合并而来),已存档stm32_fsmp1a_defconfig |
| 板子 | 本篇不开(编译全程在虚拟机) |
开工自检(10 秒):四条都在才开工——① 当前目录是内核源码顶层(提示符末段是
linux-5.4.31,层级图与认层判据见实验十九步骤 3;不在就cd过去,完整路径见步骤 3 的①);②ls arch/arm/configs/stm32_fsmp1a_defconfig(实验十九的存档);③mkimage -V有版本输出(实验十九装的 u-boot-tools);④arm-none-linux-gnueabihf-gcc单独敲一下报"没有输入文件"(编译器在 PATH)。哪条不对回实验十九对应步骤。
三、课件 ↔ 步骤对应表
| 课件 Slide | 内容 | 对应步骤 |
|---|---|---|
| 41 | 顶层 Makefile 加 ARCH/CROSS_COMPILE 两行 | 步骤 1 |
| 41~42 | make uImage LOADADDR=0xC2000040,产物在 arch/arm/boot | 步骤 2 |
| 43 | 设备树:参考 dk1,新增 fsmp1x.dtsi + fsmp1a.dts(老师提供) | 步骤 3 |
| 44 | dts/Makefile 加一行使新设备树被编译 | 步骤 4 |
| 45 | make dtbs,产物 stm32mp157a-fsmp1a.dtb | 步骤 5 |
| 46 | 此刻点火会怎样:无根文件系统的结局 | 步骤 6(认知) |
本篇动作 → 后面谁用 → 现在含糊的后果
| 本篇动作 | 后面哪一篇要用 | 现在含糊的后果 |
|---|---|---|
顶层 Makefile 的ARCH := arm、CROSS_COMPILE := arm-none-linux-gnueabihf-两行 | 实验二十一、二十二每次重编译——写一次管到第 5 章结束 | 不写就得每条 make 命令都带ARCH=arm CROSS_COMPILE=...,长命令更容易错 |
LOADADDR=0xC2000040 | 实验二十三点火时 uImage 落在 0xC2000000、真身在 +0x40(实验十六实测互证) | 写成 0xC2000000,U-Boot 头说好的入口和实际代码错位,点火失败 |
stm32mp157a-fsmp1a.dtb(我们的设备树) | 实验二十一、二十二改的就是它的源文件;实验二十三点火要用它 | 误用出厂mipi050.dtb替代,则后面改驱动的步骤全部白做 |
| 两个产物的字节数记录 | 实验二十三点火后与 tftp 的Bytes transferred对账 | 拷错文件、下错版本都发现不了 |
本篇需要的资料:kernel-初始设备树.zip(2,226 字节,md538190d0400d9504bebc3caaf48ed6fed)——里面是老师提供的两个设备树源文件,步骤 3 解压使用。
四、实验步骤
步骤 1:顶层 Makefile 加两行(Slide 41)
打开内核源码顶层Makefile,定位到第 360 行——ARCH与?=之间隔的是两个 Tab(课件截图里看着像空格):
grep-n'?= $(SUBARCH)'Makefile# 应打出:360:ARCH ?= $(SUBARCH)为什么不能搜
grep -n "ARCH ?=" Makefile?那是在搜"ARCH+空格+?="这个字面串,而第 360 行里ARCH与?=之间是两个Tab字符——字面对不上,grep 会一行不中、无声地回到提示符(本系列实测踩过这一下)。搜?= $(SUBARCH)这段不含 Tab 的尾巴就能绕开,且全文只有第 360 行有它;单引号让$、(都按字面字符处理,不必转义。
用 nano 改 Makefile——四步走:
① 打开(当前目录就在内核源码顶层):
nanoMakefilenano 界面底部两排是快捷键提示,^代表 Ctrl 键(比如^O就是 Ctrl+O)。
② 定位到第 360 行:按Ctrl+W(Where Is,搜索),输入?= $(SUBARCH)后回车——光标落到第 360 行ARCH ?= $(SUBARCH)上(这段字符全文唯一,不会跳错)。想按行号跳也行:Ctrl+_(等价 Alt+G)输入360回车。
③ 插入两行:用方向键把光标移到第 360 行的行尾($(SUBARCH)的右括号后面),按一次回车新起一行,然后逐字敲入下面两行——顶格、不要缩进,:=两侧各一个空格,gnueabihf-结尾的连字符一个都不能丢(必须与实验十九装的那套编译器一字不差):
ARCH := arm CROSS_COMPILE := arm-none-linux-gnueabihf-敲完后 360 行附近应长这样(新旧行之间没有空行):
ARCH ?= $(SUBARCH) ARCH := arm CROSS_COMPILE := arm-none-linux-gnueabihf- # Architecture as present in compile.h④ 保存并退出:
- Ctrl+O(保存)→ 底部提示
File Name to Write: Makefile→直接回车确认文件名; - Ctrl+X(退出)回到终端。
这套 nano 键位(Ctrl+W搜索定位 /Ctrl+O保存回车 /Ctrl+X退出)是本系列的通用手艺——实验二十一、二十二改设备树,实验三十一改 Makefile,实验二十六写 etc 四件套,全是同一套动作,后续各篇不再重复展开。
图:实测(顶替课件 Slide 41)——nano 4.8 里改好的样子:绿框两行就是新增的
ARCH := arm与CROSS_COMPILE := arm-none-linux-gnueabihf-,插在ARCH ?= $(SUBARCH)与# Architecture as present in compile.h之间,与上面"敲完后应长这样"的预期逐行一致。顺手认一眼 nano 的中文底栏:^O 写入、^X 离开、^W 搜索——正是本步骤那套键位(这台 Ubuntu 是中文环境,快捷键含义不变);标题栏"已更改"表示改动尚未保存(截图时还没按 Ctrl+O)。
这两行就是实验十九讲的"前缀"落地点:从此每条 make 命令都自动带上架构与编译器前缀,不用再写ARCH=arm CROSS_COMPILE=...(两种写法等价,课件选择写死在 Makefile 里,我们照做;后面实验十九那些make ARCH=arm xxx_defconfig命令多写一遍ARCH=arm也无害)。
就地验证(改完立刻做):
grep-n"^ARCH := arm"Makefile# 应打出新增那行grep-n"^CROSS_COMPILE := arm-none"Makefile# 应打出新增那行gitdiff--stat# 应只有 Makefile 一处、+2 行步骤 2:编内核——make uImage LOADADDR=0xC2000040(Slide 41~42)
makeuImageLOADADDR=0xC2000040-j4-j4:4 线程并行(第一次编 20~40 分钟,后面的重编只需几分钟——make 只重编改动过的文件)。虚拟机只分了 4GB 内存的话,-j4编译中途可能被杀(终端打出Killed、编译戛然而止)——那是内存耗尽的 OOM,不是源码问题:改用make uImage LOADADDR=0xC2000040 -j2接着编即可,进度保留(第 3 章编 U-Boot 的老经验);LOADADDR=0xC2000040:uImage 头里记录的"内核加载/入口地址"。实验十六实测过:uImage 放在 0xC2000000,头占 0x40,真身从 0xC2000040 开始——这个参数就是把这层关系写死进镜像头里。漏了它会用默认值,点火必挂且难查。
编完验证:
ls-larch/arm/boot/uImage arch/arm/boot/zImage# uImage 应比 zImage 恰好大 64 字节("四兄弟"加工链的现场版)# 两个字节数都记下来——实验二十三点火时与 tftp 的 Bytes transferred 对账实际执行结果:
图:实测——编译收尾与
ls -l产物对账:uImage7,313,872 字节、zImage 7,313,808,恰差 64 字节("内核文件四兄弟"账目的现场版);Image Name: Linux-5.4.31-g77fcad789-dirty兑现实验十九预告的 git 版本串(-dirty= 步骤 1 那两行还没提交);Load Address/Entry Point均为c2000040,与实验十六出厂件互证;(uncompressed)= 负载是自解压的 zImage、mkimage 不做二次压缩。绿箭头指Kernel: arch/arm/boot/uImage is ready收官行。两个字节数已记账,实验二十三点火时与 tftp 的Bytes transferred对账。
步骤 3:放入 FS-MP1A 的设备树源文件(Slide 43)
5.4.31 内核必须配设备树才能跑。ST 官方板的设备树是arch/arm/boot/dts/下的stm32mp15xx-dkx.dtsi+stm32mp157a-dk1.dts(前者也是 0020-DEVICETREE 补丁新建的,实验十九说过);FS-MP1A 的对应文件老师已提供,就是资料包kernel-初始设备树.zip。
zip 的结构先看清:解压出来不是一个光秃秃的文件,而是套了一层
kernel-初始设备树/目录,两个文件在目录里——直接cp zip 里的文件会扑空。
zip 里的文件(在kernel-初始设备树/一层目录下) | 放到内核源码的位置 | 角色 |
|---|---|---|
stm32mp15xx-fsmp1x.dtsi(3,662 字节,177 行) | arch/arm/boot/dts/ | FS-MP1A 的公共外设描述(实验二十一、二十二往它里面加 eMMC 与网卡的节点) |
stm32mp157a-fsmp1a.dts(724 字节,35 行) | arch/arm/boot/dts/ | 板级入口文件(引用 .dtsi) |
复制与验证按"先去到目的地 → 再执行复制 → 再检验"三步走——命令里的<共享目录>是占位符:换成你在虚拟机里放资料包解压内容与工作文件的那个目录(本系列示例~/Desktop/LINUX-gy/Test2,每个人的前缀不同);它后面的长串(stm32mp1-openstlinux-…起)出自同一个资料包,人人一样、照抄即可:
① 去到设备树目标目录:
cd<共享目录>/stm32mp1-openstlinux-5.4-dunfell-mp1-20-06-24/sources/arm-ostl-linux-gnueabi/linux-stm32mp-5.4.31-r0/linux-5.4.31/arch/arm/boot/dts/pwdpwd打出的路径末段应是dts——到了。后面的复制、检验都在这里执行(刚才两个报错——“为同一文件"与"没有那个文件或目录”——都是没先到这里造成的:人在解压目录里,cp的相对目标落空、ls的相对目标也不存在)。
② 执行复制(源用完整路径指向右键提取出的目录;目标.= 当前 dts 目录):
cp<共享目录>/kernel-初始设备树/stm32mp15xx-fsmp1x.dtsi.cp<共享目录>/kernel-初始设备树/stm32mp157a-fsmp1a.dts.(若你的提取目录名/位置与示例不同,把源路径前半段换成你的实际位置。cp成功时一声不吭——没有输出就是成功,成败看下一步的检验。右键"提取"出的kernel-初始设备树/目录完成复制后可留可删。)
③ 检验(就在 dts 目录里用相对路径——人已站在正确的一层,验的就是真货):
ls-lstm32mp15xx-fsmp1x.dtsi stm32mp157a-fsmp1a.dtslsstm32mp157.dtsi stm32mp15xa.dtsi stm32mp15-pinctrl.dtsi stm32mp15xxaa-pinctrl.dtsi第一条应打出 3,662 / 724 两个文件——复制成功的凭据(这条检验只有站在内核树的 dts 目录里才会真正通过;上一版人在解压目录里验,恰好有同名文件会假通过,这就是流程改成"先到目的地再复制再检验"的原因)。第二条四个"新命名"文件是 0020-DEVICETREE 补丁带进来的(实验十九步骤 3.2 说过),四个都在 = 补丁打全了。
就地验证(两条):
ls-lstm32mp15xx-fsmp1x.dtsi stm32mp157a-fsmp1a.dts# 两个新文件都在lsstm32mp157.dtsi stm32mp15xa.dtsi stm32mp15-pinctrl.dtsi stm32mp15xxaa-pinctrl.dtsi# 这四个"新命名"文件是 0020-DEVICETREE 补丁带进来的(实验十九步骤 3.2 说过)# 四个都在 = 补丁打全了,我们文件的 include 才接得上;缺了就回实验十九重打文件内容现在不用看懂,但三个彩蛋先埋好:① 它里头已经写好了v3v3、vdd两路固定电源(后面实验二十一的 eMMC 节点直接引用);② 它的&sdmmc1(SD 卡)节点里cd-gpios用的正是gpioh 3——第 3 章 F-2 在 U-Boot 里手工做的那个改动(PB7→PH3),内核侧老师给的文件原生就是这么写的,同一块板、两个 bootloader 各自印证;③ 它把看门狗&iwdg2设成 32 秒超时并使能——实验十六 panic 后约半分钟自动复位的幕后主使,源码出处就在这儿。实验二十一、二十三会分别再碰到它们。
图:实测——步骤 3 全程:重复执行一次
cd无害(原地踏步);两条cp无声成功;ls -l打出724 / 3,662 字节两个文件(时间戳 21:27/21:28 = 刚复制进来的);ls四个"新命名"文件stm32mp157.dtsi、stm32mp15-pinctrl.dtsi、stm32mp15xa.dtsi、stm32mp15xxaa-pinctrl.dtsi 全部在列——0020-DEVICETREE 补丁打全的凭据,我们两个文件的#include有着落了。
顺手查一下顶层的残留:此前若曾在内核顶层错放过这两个文件(上一轮
cp ... .版),按步骤 4 开头的cd回到内核顶层后执行git status --short——若见?? stm32mp15xx-fsmp1x.dtsi、?? stm32mp157a-fsmp1a.dts两行残留,rm掉它们(dts 目录里已是新副本);没有就跳过本条。
步骤 4:让 dts/Makefile 认识新设备树(Slide 44)
(人在 dts 子目录;下面 grep/nano 用相对路径前先回内核顶层:cd <共享目录>/stm32mp1-openstlinux-5.4-dunfell-mp1-20-06-24/sources/arm-ostl-linux-gnueabi/linux-stm32mp-5.4.31-r0/linux-5.4.31。)
设备树不会自动被编译——要在arch/arm/boot/dts/Makefile的 STM32 那一组里加一行。定位:
grep-n"CONFIG_ARCH_STM32"arch/arm/boot/dts/Makefile# 第 981 行起是它的 dtb 清单打开 dts/Makefile:
nanoarch/arm/boot/dts/MakefileCtrl+W搜stm32mp157a-dk1.dtb回车,光标直落第 991 行;在该行行尾回车新起一行,插入一行:
stm32mp157a-fsmp1a.dtb \图:实测(顶替课件 Slide 44)——nano 4.8 里改好的样子:绿框即新增的
stm32mp157a-fsmp1a.dtb \,插在stm32mp157a-dk1.dtb \之后、stm32mp157d-dk1.dtb \之前(dtb-$(CONFIG_ARCH_STM32) 清单里),绿箭头指向它;底部"已写入 1323 行" = 保存成功。行尾的反斜杠\是续行符,一个都不能少——它告诉 make"清单还没列完"。
就地验证:
grep-n"fsmp1a.dtb"arch/arm/boot/dts/Makefile# 应恰有一行(dtb 清单里那条)加行之前跑这条必然无输出——那行还没加呢,不是坏了;nano 加完再跑,才会打出恰一条。
步骤 5:编设备树——make dtbs(Slide 45)
makedtbs# 步骤 4 开头已回到内核顶层,直接敲make dtbs只编设备树、不重编内核,几秒钟完事(编.dtb用的dtc就是实验十九 apt 装 u-boot-tools 时捎带上的device-tree-compiler)。以后每次改.dtsi都只用敲它——实验二十一、二十二全是这个节奏。
编完验证:
ls-larch/arm/boot/dts/stm32mp157a-fsmp1a.dtb# 几万字节量级(出厂的 mipi050.dtb 是 71,805 字节;我们这份因源文件不同,数值会不同)# 字节数记下来,实验二十三对账用实际执行结果(2026-09-26 实测):
图:实测——
make dtbs首次运行会把清单里所有板子的 dtb 都编一遍(满屏 DTC 行正常,不是失控);绿箭头指收官对账行:ls -l打出arch/arm/boot/dts/stm32mp157a-fsmp1a.dtb——63,250 字节(出厂的 mipi050.dtb 是 71,805;源文件不同,数值不同属预期)。字节数已记账,实验二十三点火时与 tftp 的Bytes transferred对账。
步骤 6:认知——此刻点火会发生什么(Slide 45~46)
本篇不动板子,但要把"零修改内核点火"的预期算清楚,实验二十三全靠它对照。课件 Slide 45~46 给的预告是:缺 eMMC 驱动,内核启动会一直停在:
图:课件 Slide 46——内核启动日志的结尾:驱动探完一轮后,最后一行停在
Waiting for root device /dev/mmcblk1p4...。注意两点:① 课件板的 eMMC 盘号是mmcblk1,与我们板无必然对应(盘号怎么定看实验二十三);② 这屏日志里Kernel command line带了root=...——那是课件板 U-Boot 环境里留着的 bootargs 传进去的,不是内核自带的默认值。
课件说"缺 eMMC 驱动",这话对了一半——源码层面看得更细(实验十九打完补丁的这棵树里可以验证):
- 控制器驱动其实已经在:menuconfig 里的
STMicroelectronics STM32 SDMMC Controller(配置符号CONFIG_MMC_STM32_SDMMC)依赖 ARM AMBA MMC 且default y——实验十九生成的.config里它天生就是=y。实验二十一还会让你开 menuconfig 看一眼,到时它已经是勾上的; - 真正缺的是设备树节点:SoC 级
stm32mp151.dtsi里sdmmc2(eMMC 那条总线)默认status = "disabled",老师给的fsmp1x.dtsi又没写它的板级节点——设备树不描述,驱动再全也没人去接管。SD 卡那条总线(sdmmc1)在fsmp1x.dtsi里节点齐全,所以零修改内核认得出 SD 卡、认不出 eMMC——一出一入,正好是实验二十一要补的对照。
再挂上我们的环境差异:课件板的 U-Boot 环境里留着出厂 bootargs(root=/dev/mmcblk1p4),所以它"等根设备";我们的板从实验九清过环境、bootargs 从没设过——同样点火会走实验十六的老结局:Kernel command line:为空 → 直接Kernel panic - not syncing: VFS: Unable to mount root fs。等还是 panic,差别只在 bootargs;eMMC 认不出来这件事,两边是一样的。
步骤 7:把实验二十的改动提交进 git(选做,推荐)
第 3 章的分层管理(实验二讲的"官方底座 / ST 补丁 / 自己的修改"三层)在内核树同样适用:实验十九提交了基线(new kernel),实验二十的改动值得单独一条提交——出问题时git log/git diff能立刻分清是哪一层干的;而且提交之后,内核版本串的-dirty尾巴会消失(实验十九步骤 3.3 的机制),实验二十一、二十二再改时,"哪次改的"在版本串上一目了然。
提交前先看一眼工作区(2026-09-26 实测,与你的终端应一致):
gitstatus--shortM Makefile M arch/arm/boot/dts/Makefile ?? arch/arm/boot/dts/stm32mp157a-fsmp1a.dts ?? arch/arm/boot/dts/stm32mp15xx-fsmp1x.dtsi ?? arch/arm/configs/stm32_fsmp1a_defconfig五个文件,正是步骤 1~5 的全部改动(顶层没有多余残留——之前错放的两个 dts 文件已清理,.config被 .gitignore 忽略不入列)。显式列出文件提交,不用git add -A(第 3 章实验十一的教训:add -A 容易把不该入库的文件卷进来):
gitaddMakefile arch/arm/boot/dts/Makefile arch/arm/boot/dts/stm32mp15xx-fsmp1x.dtsi arch/arm/boot/dts/stm32mp157a-fsmp1a.dts arch/arm/configs/stm32_fsmp1a_defconfiggitcommit-m"FS-MP1A 设备树与编译配置(实验二十)"就地验证:
gitlog--oneline|head-3# 顶部应是"FS-MP1A 设备树与编译配置(实验二十)"gitstatus--short# 应无输出 = 工作区干净提交后的两个小变化:① 版本串从Linux-5.4.31-g77fcad789-dirty变成Linux-5.4.31-g<新哈希>(-dirty消失——工作区干净了);② 想让账本跟着更新,顺手增量重编一次make uImage dtbs LOADADDR=0xC2000040(几分钟,版本串写进镜像会导致字节数微调)——实验二十三对账以最新一次的字节数为准。实验二十一的改动不单独提交——它与实验二十二同改一个fsmp1x.dtsi、同属"第 5 章驱动移植"一组,两篇一起在实验二十二收官时提交一条(说明与命令见实验二十二)。
实际执行结果(2026-09-26 实测):
图:实测——提交全程:
git add五个文件后git status --short显示M M A A A(两个修改 + 三个新增,全部已暂存);git commit打出[WORKING 381ee3922] FS-MP1A 设备树与编译配置(实验二十)、5 files changed, 6542 insertions(+)(defconfig 一千六百行是大头;create mode ×3 = 两个 dts 文件与 defconfig 首次入库);git log --oneline顶部两条 = 实验二十提交叠在实验十九的new kernel基线之上;收尾git status --short无输出 =工作区干净,版本串的-dirty尾巴已随之消失(下次重编生效)。
五、注意事项
- 第一次
make uImage时间长是正常的(20~40 分钟量级);中途 Ctrl+C 也没关系,重敲会从断点续编(make 的增量特性,第 3 章编 U-Boot 时验证过)。编译里打出Killed是 4GB 虚拟机内存不够(OOM),换-j2接着编。 - LOADADDR 别写成 0xC2000000:差 0x40 就是差一个头。它在头里的
Load Address/Entry Point两栏出现——实验十六 bootm 回显里见过。 stm32mp157a-fsmp1a.dtb与出厂的stm32mp157a-fsmp1a-mipi050.dtb是两份不同的 dtb:前者是我们源码里编的(后面两篇持续改它,model字段是HQYJ STM32MP157 FSMP1A Discovery Board,不带 MIPI),后者是华清出厂 bootfs 里的(...FSMP1A MIPI...)。实验二十三点火用我们自己这份,别拿错。- dts/Makefile 加行注意续行符
\:加错位置或漏\,make dtbs不会编出我们的 dtb,且不报错——grep fsmp1a.dtb与ls产物是唯一判据。 - 改 Makefile 前后用
git diff过一眼(源码已纳管),改坏了好回退。 - 编译报
arm-none-linux-gnueabihf-gcc: command not found→ 回实验十九步骤 1(PATH/重新登录)。 - 在共享文件夹里编译能跑但慢(实验十九已实测解压/打补丁无碍;吃 IO 的是 make)——慢到不能忍或报符号链接/权限类错误时,把源码挪到虚拟机本地磁盘(如
~/kernel/),挪后要make distclean+ 用stm32_fsmp1a_defconfig重做配置,再回到本篇步骤 1。
六、验证点一览
这一节把各步骤里就地该敲的验证汇总成表,方便对照自查(每条的判据都写在对应步骤里):
| 验证点 | 命令 | 通过的样子 | 在哪一步敲 |
|---|---|---|---|
| 顶层 Makefile 两行 | grep -n "^ARCH := arm" Makefile、grep -n "^CROSS_COMPILE := arm-none" Makefile | 两行各打出一条 | 步骤 1 |
| uImage 生成 | ls -l arch/arm/boot/uImage | 实测 7,313,872 字节(2026-09-26);字节数记下与实验二十三对账 | 步骤 2 |
| 四兄弟账目 | ls -l arch/arm/boot/uImage arch/arm/boot/zImage | 实测恰差 64 字节(7,313,872 − 7,313,808) | 步骤 2 |
| 设备树源文件到位 | ls -l stm32mp15xx-fsmp1x.dtsi stm32mp157a-fsmp1a.dts(dts 目录里) | 实测通过(2026-09-26):724 / 3,662 字节两个文件在 dts 目录 | 步骤 3 |
| 补丁带来的依赖齐全 | ls stm32mp157.dtsi stm32mp15xa.dtsi stm32mp15-pinctrl.dtsi stm32mp15xxaa-pinctrl.dtsi | 实测四个全在(0020 补丁的货) | 步骤 3 |
| dts/Makefile 加行 | grep -n "fsmp1a.dtb" arch/arm/boot/dts/Makefile | 实测恰一条,行尾带\(加行前跑必无输出,属正常) | 步骤 4 |
| dtb 生成 | ls -l arch/arm/boot/dts/stm32mp157a-fsmp1a.dtb | 实测 63,250 字节(2026-09-26);字节数记下与实验二十三对账 | 步骤 5 |
| 工作区改动清白 | git status --short | 只有预期项:顶层 Makefile、dts/Makefile、两个新 dts 文件(+.config等忽略项之外无意外文件) | 收尾 |
| git 收官提交 | git log --oneline | head -3、git status --short | 实测通过(2026-09-26):提交哈希381ee3922在列、工作区干净 | 步骤 7 |
不达标时的排查:
| 现象 | 先查什么 |
|---|---|
make uImage报"mkimage" command not found | 实验十九步骤 2 的 u-boot-tools 装了没(mkimage -V) |
| 编译一开始就报架构/编译器相关错误 | 顶层 Makefile 两行的拼写;arm-none-linux-gnueabihf-gcc单独敲一下 |
make dtbs报找不到stm32mp157.dtsi等 include | 0020-DEVICETREE 补丁没打全(实验十九步骤 3.2)——`ls …/*.patch |
make dtbs后找不到我们的 dtb | dts/Makefile 那行的位置与行尾\;grep fsmp1a.dtb核对 |
编译中途Killed | 4GB 内存 OOM——换-j2续编 |
| 磁盘满 | 清理或扩容(源码 + 编译产物约 2~3 GB) |
七、实验完成标志
- 顶层 Makefile 已加
ARCH/CROSS_COMPILE两行,grep两条都能打出(步骤 1 实测,nano 截图入档) make uImage LOADADDR=0xC2000040编译成功(2026-09-26 实测):arch/arm/boot/uImage生成7,313,872 字节、zImage 7,313,808 恰小 64 字节、版本串Linux-5.4.31-g77fcad789-dirty、Load Address/Entry Point均为c2000040(步骤 2 实测,截图入档)stm32mp15xx-fsmp1x.dtsi(3,662 字节)与stm32mp157a-fsmp1a.dts(724 字节)已放入arch/arm/boot/dts/,四个"新命名"依赖文件都在(步骤 3 实测,截图入档)- dts/Makefile 已加
stm32mp157a-fsmp1a.dtb \一行,grep恰一条(步骤 4 实测,截图入档) make dtbs编出arch/arm/boot/dts/stm32mp157a-fsmp1a.dtb,实测 63,250 字节(2026-09-26,步骤 5 实测,截图入档)git status --short只显示预期改动(步骤 1~4 的四个文件)- 步骤 7 实测:实验二十改动已单独提交(哈希381ee3922、5 files changed 6542 insertions,工作区干净);实验二十一的改动按约定不单独提交(见步骤 7 尾)
八、下一步:移植 eMMC 驱动
内核编出来了,但它"看不见"eMMC——缺的是设备树里的 sdmmc2 节点。下一篇(实验二十一)补上它:往fsmp1x.dtsi加一段节点 + 开 menuconfig 确认那个"天生已开"的控制器选项 + 重编译,让内核像出厂那份一样把 eMMC 认出来。