RK3576启动流程全解析:从BootROM到根文件系统
发布时间:2026/9/26 1:16:58 作者:尧图编辑部 阅读量:1,286

1. 从按下电源键到看见登录提示符RK3576 到底经历了什么搞嵌入式 Linux 的人都有一个共同的体验板子焊好、镜像烧进去、串口线一接看着终端里一行行滚动的启动日志心里才踏实。但真要问一句“从上电到 rootfs 挂载中间到底跑了哪些东西”能完整说清楚的人并不多。RK3576 这颗芯片这两年在边缘计算、工业网关、商显一体机、轻量级 AI 盒子里铺得很开四核 A72 加四核 A53 的大小核架构配上 6TOPS 的 NPU性价比确实能打。可越是这样集成度高的 SoC启动链路就越像一条被封装好的黑盒——厂商 SDK 一打包build.sh一跑镜像出来了至于里面 BootROM 干了什么、SPL 怎么把 DDR 拉起来、U-Boot 又怎么把控制权交给内核很多人是模糊的。这篇东西就是想把这条链路从头到尾捋一遍。我会按 RK3576 的实际启动顺序把BootROM、SPL、U-Boot、Linux 内核、根文件系统这五个阶段拆开讲每个阶段讲清楚三件事它为什么存在、它具体做了什么、出问题的时候怎么定位。中间会穿插一些我在实际调试中踩过的坑比如 DDR 初始化失败导致串口只打印一个字符就死掉、SPL 和 U-Boot 的加载地址冲突、rootfs 挂载参数写错导致 kernel panic 等等。适合正在用 RK3576 做产品开发的嵌入式工程师也适合刚接触 Rockchip 平台、想搞明白启动流程的 Linux 爱好者。不需要你有多深的汇编功底但至少要会用串口工具、看得懂基本的启动日志。先给一个全局的认知框架后面所有细节都挂在这个框架上。RK3576 的启动是一条链式信任的过程每一级负责把下一级从存储介质里搬进内存并跳转过去执行BootROM芯片内部固化→ SPL一级引导通常叫 MiniLoader 或 loader→ U-Boot二级引导完整功能→ Linux Kernel → RootFS这条链上任何一环断了表现都是“板子起不来”但断在哪一环日志给出的信息完全不同。所以第一步不是急着改代码而是学会看日志定位阶段。下面逐层展开。2. BootROM芯片里那段你改不了的代码2.1 BootROM 的本质与启动介质选择逻辑BootROM 是掩膜在 SoC 内部的一块只读存储区出厂就固化好了用户改不了、也擦不掉。RK3576 上电后CPU 的第一条指令就从这里取。它的核心任务其实很朴素找到可启动的存储介质把里面的 SPL 搬到片内 SRAM然后跳过去执行。为什么不能直接从存储介质跑完整系统因为上电瞬间 DDR 还没初始化外部大容量内存不可用芯片能用的只有片内那几十 KB 的 SRAM。BootROM 自己就住在片内所以它能跑但它没能力把几百 KB 甚至几 MB 的 U-Boot 直接拉起来——SRAM 装不下。这就是为什么必须有 SPL 这一级SPL 的首要任务就是初始化 DDR把“大内存”这块地基打好。RK3576 支持的启动介质优先级一般是这样的顺序具体以芯片手册为准不同配置会有差异优先级启动介质典型场景1SPI NOR Flash小容量引导成本敏感型产品2SPI NAND Flash中等容量需要存 rootfs3eMMC主流方案容量大、速度快4SD/TF 卡开发调试、量产烧录5USBMaskROM 模式救砖、首次烧录BootROM 会按这个顺序去“试探”每个介质看头部有没有合法的引导签名Rockchip 用的是 IDB 结构里面包含引导码和校验信息。找到第一个合法的就加载它。这里有个很实用的点如果你把 eMMC 里的引导擦坏了但插着一张可启动的 SD 卡板子会优先从 SD 卡启动。这就是为什么开发阶段大家喜欢用 SD 卡跑系统砖了也不怕换张卡就行。2.2 MaskROM 模式救砖的最后一道防线当所有介质都找不到合法引导或者你主动让芯片进入 MaskROM 模式时BootROM 会停在原地等待 USB 主机通过特定协议把引导代码传进来。这个模式是 Rockchip 平台“救砖”的核心手段。进入 MaskROM 的常见方式按住板子上的 Recovery/MaskROM 按键再上电或者短接 eMMC 的时钟脚让它无法被识别。进入之后用rkdeveloptool或者厂商的烧录工具就能重新写入 loader 和镜像。注意MaskROM 模式下芯片只认 USB 特定端点普通 USB 线可能不行最好用带数据传输功能的线而且有些板子需要 USB 2.0 口而不是 3.0 口才能识别。这个坑我踩过换了三根线才发现是接口的问题。BootROM 阶段能打印的信息非常有限通常只有一行类似BootRom start或者干脆什么都不打。如果你上电后串口一个字符都没有大概率问题出在 BootROM 之前——供电、晶振、复位电路或者串口本身的波特率配置。RK3576 的 BootROM 默认波特率一般是 1500000不是常见的 115200这一点新手特别容易懵。3. SPL真正把 DDR 拉起来的关键一级3.1 SPL 为什么必须存在SPL 全称 Secondary Program Loader在 Rockchip 的语境里也常被叫做 MiniLoader 或者 DDR Loader。它的体积被严格限制在片内 SRAM 能容纳的范围内通常几十 KB 到一百多 KB。麻雀虽小五脏俱全它要干这几件大事初始化时钟树把 CPU、总线、DDR 控制器的时钟配到目标频率。初始化 DDR这是最核心、最容易出问题的一步包括 DDR 颗粒的时序参数、训练training、电压配置。配置引脚复用把存储介质、串口等外设的 IO 复用关系设好。加载 U-Boot从存储介质里把完整的 U-Boot 搬到 DDR 的指定地址。跳转到 U-Boot把控制权交出去。你可以把 SPL 理解成装修房子时的“水电改造”阶段——墙还没刷、家具还没进但地基和管线必须先弄好后面所有活才能干。DDR 就是这套房子的地基地基没打好U-Boot 和内核根本无处安身。3.2 DDR 初始化SPL 里最要命的部分DDR 初始化之所以难是因为它高度依赖具体的硬件设计用的是哪家的 DDR 颗粒、几片、位宽多少、频率跑多少、PCB 走线如何。这些参数全部体现在一个叫DDR bin的文件里Rockchip 提供工具根据你的硬件配置生成对应的 DDR 初始化代码。RK3576 支持 DDR4、LPDDR4、LPDDR4X、LPDDR5 等多种类型不同颗粒的时序参数差异很大。如果 DDR bin 配错了典型表现是串口打印到DDR相关字样就卡死或者直接乱码。板子反复重启看门狗不断复位。偶尔能起来但跑一会儿就死机时序处于临界状态。我遇到过一次很隐蔽的问题DDR 容量识别正确也能启动但跑内存压力测试时随机报错。最后查出来是 DDR 的 VREF 训练参数在高温下漂移调整了 training 的采样点才稳定。这种问题在常温调试时根本发现不了一定要做高低温测试。实操心得DDR 调试阶段务必先用 Rockchip 提供的 DDR 测试工具单独验证 DDR 稳定性不要等到整个系统跑起来再排查。工具能跑通 memtest 几百轮无错再往下走能省掉大量返工。3.3 SPL 的加载地址与内存布局SPL 被 BootROM 加载到片内 SRAM 执行但它加载 U-Boot 时需要知道把 U-Boot 放到 DDR 的哪个地址。这个地址在编译时就确定好了通常通过配置文件里的CONFIG_SPL_TEXT_BASE或者类似宏定义。RK3576 上常见的 U-Boot 加载地址是0x00200000附近具体以 SDK 为准。这里有个经典的坑SPL 的加载地址和 U-Boot 的运行地址如果重叠或者 U-Boot 的地址和内核的加载地址冲突就会出现“U-Boot 起来了但一加载内核就崩”的现象。排查方法很简单看 U-Boot 启动日志里打印的Loading Kernel Image to ...地址和内核实际期望的运行地址对比不一致就要改配置。4. U-Boot功能最全、也最容易被忽视的一级4.1 U-Boot 在 RK3576 上的职责边界U-Boot 是大家最熟悉的一级但很多人对它的理解停留在“敲几个命令”的层面。在 RK3576 的启动链里U-Boot 承担的工作其实相当繁重完善外设初始化SPL 只初始化了启动必需的外设U-Boot 要把网络、USB、显示、存储等全部拉起来。加载内核从存储介质读取内核镜像Image 或 zImage和设备树DTB搬到 DDR 指定地址。准备启动参数构造 bootargs告诉内核 rootfs 在哪、串口用哪个、内存多大。跳转内核最后执行bootm或booti把控制权交给 Linux。RK3576 的 U-Boot 通常还集成了 Rockchip 自己的很多扩展比如固件加载、安全启动校验、AVBAndroid Verified Boot等。如果你做的是量产产品这些安全机制会直接影响启动流程需要额外关注。4.2 设备树U-Boot 和内核之间的“交接清单”设备树Device Tree是理解 RK3576 启动流程绕不开的概念。它本质上是一份硬件描述文件用文本.dts/.dtsi写好后编译成二进制.dtb告诉软件“这块板子上有什么硬件、地址在哪、怎么配置”。在启动流程里设备树扮演两个角色U-Boot 自己的设备树U-Boot 也需要知道硬件长什么样才能正确初始化外设。传给内核的设备树U-Boot 把内核要用的 DTB 加载到内存并在跳转时把 DTB 地址通过寄存器传给内核。这里最容易出问题的是两份设备树不一致。比如 U-Boot 的设备树里把某个引脚配成了 GPIO内核的设备树里配成了 I2C结果就是 U-Boot 阶段正常一进内核那个外设就失灵。排查这种问题要养成习惯改硬件配置时U-Boot 和内核的设备树同步改。4.3 bootargs内核启动参数的写法与陷阱bootargs是 U-Boot 传给内核的一串字符串决定了内核怎么找根文件系统、怎么配置控制台。RK3576 上常见的写法setenv bootargs consolettyFIQ0,1500000n8 root/dev/mmcblk0p5 rootwait rw rootfstypeext4逐个拆解consolettyFIQ0,1500000n8指定串口控制台和波特率。RK3576 的调试串口通常是ttyFIQ0不是ttyS0这个和很多其他平台不一样写错了就没有内核日志。root/dev/mmcblk0p5根文件系统所在的分区。eMMC 一般是mmcblk0SD 卡是mmcblk1分区号要对上。rootwait等待存储设备就绪再挂载 rootfs对于 eMMC 这种初始化稍慢的设备很关键。rw以读写方式挂载。rootfstypeext4文件系统类型。注意root后面的设备名一定要和实际分区对应。我见过有人把 eMMC 的分区号写成了 SD 卡的结果内核一直报VFS: Cannot open root device查了半天才发现是启动介质搞混了。5. Linux 内核从解压到挂载 rootfs5.1 内核启动的四个阶段U-Boot 跳转之后内核开始执行。RK3576 上跑的是 ARM64 内核启动过程大致分四步解压与自解压如果用的是压缩内核Image.gz先解压成 Image。早期初始化建立页表、初始化内存管理、解析设备树。驱动初始化按设备树的描述逐个初始化外设驱动。挂载 rootfs 并启动 init找到根文件系统执行第一个用户空间程序。内核启动日志是排查问题的金矿。看到Booting Linux on physical CPU说明内核已经跑起来了看到Uncompressing Linux... done说明解压成功看到VFS: Mounted root说明 rootfs 挂载成功。如果卡在某一步日志会停在对应的位置。5.2 内核命令行参数的传递链路内核启动参数从哪来链路是这样的U-Boot 的 bootargs 环境变量 → 跳转时写入设备树 chosen 节点 → 内核解析 chosen 节点所以如果你在 U-Boot 里改了bootargs但内核没生效可能是设备树里的chosen节点覆盖了它。RK3576 的 SDK 里有些配置会把 bootargs 直接写死在 DTS 里这时候改 U-Boot 环境变量是没用的得去改 DTS。5.3 根文件系统挂载失败的典型原因rootfs 挂载失败是新手最常遇到的问题内核会直接 panic。常见原因和排查方向现象可能原因排查方法Cannot open root device设备名写错确认启动介质和分区号VFS: Unable to mount root fs文件系统类型不对检查 rootfstype 和实际格式No filesystem could mount root分区里没有有效文件系统用工具检查分区内容挂载成功但卡在 initinit 程序缺失或权限不对检查 /sbin/init 是否存在我个人的经验是先把 rootfs 挂载问题定位到“设备名、文件系统类型、分区内容”这三个维度基本能覆盖 90% 的情况。剩下的 10% 往往是硬件层面的比如 eMMC 某个分区读写出错那就得回到 SPL 阶段查 DDR 和存储控制器了。6. 根文件系统启动链的终点也是应用的起点6.1 rootfs 的几种形态与选择RK3576 上常见的 rootfs 形态ext4最通用读写方便适合开发阶段。squashfs只读压缩省空间适合量产固件。ubifs用于 NAND Flash带磨损均衡。overlayfs squashfs只读基础系统加可写覆盖层兼顾稳定和可修改。选哪种取决于你的产品需求。开发阶段用 ext4 最省事量产时如果追求稳定和防篡改squashfs 加 overlay 是主流方案。6.2 init 进程与启动脚本rootfs 挂载成功后内核会执行/sbin/init或通过init参数指定的程序。init 负责拉起整个用户空间挂载其他分区、启动服务、配置网络、最后给你一个登录提示符。RK3576 的 SDK 一般用 BusyBox init 或者 systemd。BusyBox 轻量启动快适合资源受限的场景systemd 功能全但体积大、启动慢。如果你发现系统启动到一半卡住可以看 init 脚本里哪一步没走完通常是某个服务在等一个不存在的硬件。6.3 从串口日志反推启动阶段把整个启动链的日志特征整理成一张表方便对照定位日志特征所处阶段说明BootRom startBootROM芯片开始启动DDR相关打印SPLDDR 初始化中U-Boot 20xx.xxU-BootU-Boot 已运行Loading KernelU-Boot正在加载内核Booting LinuxKernel内核已启动Mounted rootKernelrootfs 挂载成功登录提示符RootFS系统完全启动这张表建议存下来调试时对着看能快速判断问题出在哪一级。7. 常见问题与排查技巧实录7.1 串口无输出从硬件查起串口一个字符都没有先别怀疑软件。按这个顺序查供电核心电压、DDR 电压、IO 电压是否正常。晶振主晶振有没有起振频率对不对。复位复位引脚电平是否正确有没有被一直拉低。串口线TX/RX 有没有接反波特率是不是 1500000。BootROM 模式是不是意外进了 MaskROM导致不打印正常启动日志。我遇到过一块板子串口死活没输出最后发现是串口线的 TX 和 RX 接反了。这种低级错误在赶工期的时候特别容易犯建议养成“先查线、再查电、最后查代码”的习惯。7.2 DDR 初始化失败看训练日志DDR 初始化失败时SPL 通常会打印训练结果。如果看到DDR training failed或者类似的错误说明时序参数不对。解决办法用 Rockchip 的 DDR 配置工具重新生成 bin 文件。确认 DDR 颗粒型号和工具里选的一致。适当降低 DDR 频率先保证能起来再逐步往上调。提示DDR 频率不是越高越好稳定优先。量产产品建议留 10% 到 20% 的余量别把频率拉到极限。7.3 内核 panic抓关键日志内核 panic 时日志最后几行最关键。常见的 panic 原因Unable to mount root fsrootfs 问题回到第 5 章排查。Kernel panic - not syncing: No init foundinit 程序缺失。Unable to handle kernel NULL pointer驱动 bug需要看调用栈。抓 panic 日志时建议把串口日志完整保存下来用grep过滤关键字比一行行看效率高得多。7.4 启动慢定位耗时环节如果系统能起来但启动很慢可以在 U-Boot 里打开bootstage功能或者在 init 脚本里加时间戳看哪个环节耗时最长。常见耗时点DDR 训练时间长正常但可以通过优化参数缩短。内核驱动初始化慢某个驱动在等硬件超时。init 脚本里某个服务启动慢。8. 一些实操中的个人体会调 RK3576 的启动流程最深的体会是日志比代码重要硬件比软件优先。很多时候问题不在你改的那行代码而在你忽略的那根线、那个电压、那个时序参数。养成“先看日志定位阶段再查对应环节”的习惯比盲目改代码高效得多。另外DDR 和存储这两块一定要在项目早期就验证充分。它们是启动链的地基地基不稳后面所有调试都是白费功夫。我一般会在硬件打样回来后先用 Rockchip 的工具把 DDR 和 eMMC 单独测一遍确认没问题再烧完整系统。最后分享一个小技巧把每次调试的串口日志按日期存好标注当时的硬件配置和软件版本。RK3576 的启动问题有时候是偶发的过几天再遇到翻出当时的日志对比能省掉大量重复排查的时间。这个习惯看起来笨但真的管用。