news 2026/10/15 8:41:07

芯片Boot流程详解:从ROM Code到Kernel的启动链路与调试

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
芯片Boot流程详解:从ROM Code到Kernel的启动链路与调试

简介:芯片从上电复位到操作系统启动的完整boot过程,以Word文档形式整理为一份底层原理笔记,面向嵌入式开发、Linux驱动调试及芯片底层原理学习者,帮助理解多级引导程序的分工与协作。文档围绕ROM Code、SPL、U-Boot、Kernel四个阶段展开,详细说明ROM Code如何完成CPU与系统初始化、SPL如何将Bootloader分步搬运至SRAM与DDR、U-Boot如何加载内核并提供UART/USB/SD/EMMC等多种启动模式,以及Kernel最终接管系统管理的过程。资源为1个docx文档,包体大小1.41MB,纯文字笔记形式便于阅读与检索,目前已有921人学习下载。内容结合实际SD卡启动场景展开,涵盖启动模式判断、搬运地址、运行阶段划分等底层细节,并涉及UART/USB下载模式、SD/EMMC启动模式及ptset测试模式,可作为芯片启动流程梳理、嵌入式面试准备或驱动开发参考笔记,适合需要系统性理解完整引导链路的开发者。

1. 芯片启动Boot流程:从上电到Kernel的完整链路

芯片的boot过程,说白了就是一段芯片启动接力:ROM Code、SPL、U-Boot、Kernel。芯片启动时最容易遇到的问题是上电后没任何反应,连打印都没有,这时候如果你不理解这条链路的每一级在哪切换,就只能对着原理图发愣。这篇笔记把芯片从上电复位到最终运行系统代码的完整过程拆开讲,覆盖SD卡、eMMC启动和UART/USB下载模式,也讲清楚为什么SPL经常只搬前70KB就够用,以及ptset测试模式怎么绕开正常启动。适合做嵌入式驱动、系统移植和芯片验证的开发者先通读再上板。

2. ROM Code阶段:芯片上电后的第一段固化代码

2.1 Reset中断与handler模式:CPU第一跳为什么不是main

芯片上电复位后,CPU进入handler模式并触发reset中断,这是芯片架构层面的硬约束。CPU从复位向量取到第一条指令,入口就是ROM Code的代码地址。也就是说,CPU真正执行的第一段指令不是来自SD卡、Flash或DDR,而是芯片内部固化的ROM。这块ROM在芯片出厂时就写好了,用户改不了,所以它的代码风格通常非常保守,依赖的外部条件被压到最少。

ROM Code的入口代码先做CPU init,包含几个关键动作:设置CPU工作模式、关闭或配置中断控制器、配置PLL和时钟树、初始化片内SRAM访问属性。CPU init完成不代表系统已经可用,它只是把CPU和最小存储路径准备好。接下来,ROM Code会读取启动模式判定引脚或OTP标志,决定是进ptset测试模式,还是走正常启动流程。

我在实际调板时,习惯先确认ROM Code是否在跑,方法很简单:把芯片复位脚和UART_TX引脚同时挂示波器,上电后抓一段波形。如果ROM Code阶段已经初始化过UART,会在UART_TX上看到波特率对应的电平翻转。如果完全没有,优先怀疑CPU基础电源、复位时序和时钟源。ROM Code固化的代码虽然不会打印很丰富,但只要有串口输出,就说明这条链路基本是通的。

2.2 System Init:UART与键盘模块在早期被初始化的真实原因

文档里明确说,如果不进入ptset模式,ROM Code会开始进行system init操作。这里的system init不是把芯片所有外设都配一遍,它的目标很窄:只把后续判断启动介质、下载程序或输出状态信息所必需的最小外设集合配好。典型对象是UART和键盘控制器。

键盘控制器在这个场合更多是扫描一组GPIO状态,用于检测启动选择或状态配置,不是接外接键盘。它和UART一样,属于启动阶段的基础模块。UART是boot过程中最重要的调试通道,ROM Code往往在早期就把UART的波特率、引脚复用和数据帧格式配好,这样SPL和U-Boot阶段才能直接复用打印日志。我拿到新板子做的第一件事就是把串口终端接上,波特率从115200开始试,多数平台第一版固件用的是这个值。

有个容易忽略的点:system init阶段不会去初始化DDR。原因很简单,DDR初始化和电源稳定、时钟稳定强相关,而这一阶段要保持最小依赖,只做启动介质判断和镜像搬运准备。有的开发者尝试把DDR初始化提前到这个阶段来,这完全没有必要,ROM Code的职责就是尽量少做事,把复杂工作交给后面的SPL。

验证system init是否正常,可以这样操作:先确认UART引脚复用状态,再看波特率寄存器写入的实际分频值,最后观察启动判别引脚在复位释放后的保持时间。如果ROM Code阶段打印了特定字符串,说明system init里UART初始化已经完成。如果打印出来是乱码,先查波特率配置,不要急着怀疑ROM Code跑飞。

表:ROM Code阶段关键检查点

检查项关键参数判断方法
CPU init状态复位时序、PLL锁定时间示波器抓复位脚与UART_TX波形
UART配置波特率、引脚复用、8N1格式串口终端能否收到ROM Code打印
ptset判定判定引脚电平组合、OTP标志对照芯片手册的ptset进入条件
介质判定SD/eMMC优先级、UART/USB使能断开不同介质观察ROM Code行为变化
SRAM访问属性AON SRAM起始地址与可用容量从链接脚本和map文件反查

2.3 介质判断前的准备:ptset测试模式与普通启动的分岔

ptset测试模式是文档单独列出来的一种运行状态。ROM Code完成CPU基础初始化后,会先检查ptset条件,判断依据一般是芯片特定引脚的电平组合或OTP区间的标志位。如果条件成立,ROM Code直接跳进专用测试逻辑,不执行常规system init,也不做正常的介质搬运。这个模式面向量产测试和硬件验证,软件开发阶段基本用不到。

如果ptset不成立,ROM Code走正常分支,执行system init之后开始判断boot方式。文档列出了SD卡、eMMC、UART下载、USB下载四条通道。芯片一般通过配置引脚或OTP里的启动顺序决定优先级。以SD卡启动为例,ROM Code会先初始化SD控制器,再在卡里查找合法镜像。合法镜像通常必须在特定偏移处有魔数或头部结构,不是随便放一个bin文件就能被识别。

我在项目中见过一种误判情况:开发者的启动判别引脚同时配置成SD优先,但卡槽里实际插的是一张eMMC转SD的转接卡。ROM Code按SD流程初始化后发现卡响应异常,一直卡在重试逻辑里,看起来就像死机。这不是芯片bug,而是介质优先级和实际硬件不匹配。建议拿到新板子后,先把boot模式对应的引脚表格和优先级关系摘出来,对照实际接线画一张状态表,再开始调试。

注意:查ptset和介质判定问题时,先把原理图上相关引脚的上下拉电阻检查一遍,引脚悬空导致的启动不稳定案例比想象中多。

3. SD卡启动与SPL搬运:AON SRAM容量和70KB分段策略

3.1 启动介质是怎么判定的:SD、eMMC、UART/USB的优先级关系

ROM Code完成system init之后,要决定这次从哪里取程序。文档里的SD卡、eMMC、UART下载、USB下载四条通道,对应不同使用场景。SD卡和eMMC属于量产启动通道,UART和USB更多用于开发调试和产线烧录。

介质判定过程可以拆成三步:第一步看配置位选的是哪个介质,第二步看介质控制器初始化是否成功,第三步看介质头部镜像描述是否合法。三步里任何一步不满足,ROM Code都会回到重试逻辑。实际表现就是同一个镜像在A卡上能启动,换到B卡完全无反应。原因常常不是容量或速度等级差异,而是B卡的启动分区布局和A卡不一样,ROM Code在预设偏移处找不到头部魔数。

开发调试阶段,UART/USB下载模式比SD卡更常用。进入这两种模式后,ROM Code等待上位机发送镜像数据,然后把数据按协议写入SRAM,写完再跳转执行。下载模式的握手阶段通常有固定的命令序列,比如先发同步字符、再发长度和校验值。有的平台下载前还需要先擦除目标区域,有的则直接覆盖写。这些细节在不同芯片间差异很大,不要假设所有平台都一样。

3.2 70KB分段加载为什么存在:AON SRAM容量与DDR初始化顺序

文档中的70KB是一个非常关键的数字。ROM Code通过SD控制器读取SD卡内容到AON RAM运行,但AON RAM是片内常供电SRAM,容量很小,一般只有几十KB到一两百KB。SD卡上的bootloader镜像只要超过这个容量,就没法一次性载入。

所以设计上采用分段策略:先搬运SD卡前70KB内容到AON SRAM,让这段程序先跑起来。这段程序的任务很明确,一是初始化DDR控制器,二是等DDR可用后,再把SD卡剩余内容搬运到DDR里执行。注意这里的"剩余内容"在文档里被称作kernel,实际包含U-Boot镜像和内核镜像,统称kernel是因为内核在整体镜像中占大头。

在使用这个策略时,我一般会把SPL镜像的链接脚本单独做一遍检查。SPL在SRAM中的加载地址和运行地址,必须严格落在AON SRAM有效范围内。如果SPL镜像的text段或数据段跨越了SRAM边界,链接过程大概率能过,但运行时会出现总线错误。还有一类错误是DMA搬运时目标地址没按对齐要求设置,比如SD读卡按512字节块读,目标地址却是非对齐的,搬运结果就会错位。

3.3 SPL的加载参数:SD控制器、起始块、镜像大小怎么定

SPL阶段涉及的关键参数集中在SD控制器和搬运配置里:

  • 起始块地址:指向SD卡上bootloader镜像所在的首块,一般不是0;
  • 块数量:对应前70KB镜像所需块数,按512字节块向上取整;
  • 目标地址:AON SRAM内预留给SPL运行的内存基址;
  • 总线模式:SD 1-bit还是4-bit,直接决定搬运速度和引脚占用;
  • 镜像长度字段:SPL头部里记录的镜像大小,用于校验实际搬运长度。

我在调试SPL加载时遇到过一种很隐蔽的情况:前70KB能正常跑,但把剩余镜像搬到DDR后一执行就异常。定位了很长时间,最后发现是DDR控制器初始化时,把CAS延迟和tRCD参数配错了。这个案例说明一个道理:SPL阶段最核心的代码不是搬运本身,而是搬运之前对DDR控制器的初始化配置。DMA搬运只是把数据从一个地方挪到另一个地方,如果DDR参数不对,搬运是否成功没有意义。

还有一点需要注意:如果镜像头部带校验,SPL搬运完成后会做一次头部解析和CRC校验。如果工具生成的镜像长度字段与实际大小对不上,SPL会在校验环节直接停下,表现就是打印停在"loading"之类的提示后不再继续。遇到这种问题,不要先怀疑代码逻辑,先检查生成镜像时有没有人为修改过头部长度字段。

表:SD卡SPL阶段常用参数参考

参数典型值作用
SD起始块地址按镜像偏移计算定位bootloader起始位置
单次读取块数按70KB/512B向上取整控制单次DMA传输长度
SPL在AON SRAM运行地址低于SRAM容量上限决定链接脚本的加载地址
DDR目标地址由U-Boot链接地址决定剩余镜像的最终运行位置
总线模式SD 1-bit或4-bit影响搬运速度和引脚占用

4. 从SPL到Kernel:DDR初始化、U-Boot接力与内存布局

4.1 SPL的运行边界:它只负责DDR初始化和搬运

SPL全称Secondary Program Loader,是ROM Code和完整Bootloader之间的桥梁。ROM Code本身不理解文件系统、分区布局,它只是把前70KB读进SRAM,然后交给SPL。SPL带着这段bootloader内容在SRAM里运行,核心任务就两件:初始化DDR、把剩余镜像从SD卡搬运到DDR。

这两件事做完,SPL的使命就结束了。在代码组织上,我会把SPL的入口函数写得很短,主流程就是时钟、DDR控制器、串口打印、SD读卡、跳转。不要试图在SPL里堆业务逻辑,AON SRAM空间有限,SPL阶段的中断处理也弱,一旦出现异常几乎没有调试信息。开发时建议在SPL入口和跳转前各放一个打印点,如果入口有打印而跳转前没有,说明卡在DDR初始化或搬运环节。

SPL跳转到U-Boot的方式因平台而异,有的是直接跳绝对地址,有的是通过函数指针跳转。跳转前要确保栈指针指向一个有效区域,并且关闭中断。有的平台要求SPL在跳转前把D-Cache清干净,否则U-Boot在DDR里读到的是cache里残留的旧数据,这种问题表现出来就是随机性死机,非常难受。

4.2 U-Boot阶段的参数:bootargs、loadaddr和常见启动命令

镜像搬进DDR后,U-Boot开始执行。U-Boot是一个功能完整的引导程序,它可以从DDR里已经放好的镜像继续加载,也可以重新从SD或eMMC读取内核和设备树。U-Boot阶段的启动参数集中在环境变量里,我调试时一般先执行几条命令确认状态:

# 查看当前环境变量 printenv bootargs bootcmd loadaddr fdt_addr # 从MMC设备0分区0读取内核镜像到内存 mmc dev 0 mmc read ${loadaddr} 0x800 0x4000 # 启动内核,-表示跳过ramdisk bootm ${loadaddr} - ${fdt_addr}

这里loadaddr常见值是0x40008000一类地址,fdt_addr指向设备树在DDR中的位置。如果镜像不是U-Boot格式的uImage,bootm会报错,这时改用booti命令加载原始内核镜像。还有一个细节:mmc read的起始块和块数,必须和SD卡上实际写入的位置一致。之前SPL阶段搬运剩余镜像时,目标地址要和这里U-Boot读取的地址错开,不能重叠。

U-Boot阶段最容易踩的坑有三个:一是bootargs里root=参数和根文件系统分区对不上;二是设备树地址和内核加载地址重叠;三是malloc区域配置过小导致环境变量加载失败。我一般会先把loadaddr、fdt_addr、bootargs三个变量打印出来,在纸上排一遍地址关系,再决定怎么调。

4.3 Kernel接管前的最后几步:在DDR中跳转和内存约束

U-Boot通过bootm或booti启动内核时,会做一次带参数跳转。跳转前要确保中断关闭、栈指针设置正确、设备树物理地址传给内核参数。在这个时刻,CPU已经运行在DDR里,之前SRAM中的SPL数据区和栈已经不重要。如果U-Boot在跳转前还访问SRAM里的全局变量,内核启动后那部分地址被新数据覆盖,就会出现随机死机。

实践上,我建议在跳转前做一份检查清单:设备树地址在DDR有效范围内;内核加载地址和U-Boot自身镜像不重叠;bootargs里mem=大小不超过实际DDR容量;内核DTS里的reg属性和当前DDR控制器配置一致。这些检查项每一条都可以写脚本验证,但最直接的方式还是先printenv把所有地址打印出来,人工确认一遍。U-Boot阶段还有安全启动的概念,如果芯片使能了安全启动链,SPL和U-Boot的镜像头部会带签名和证书,没有正确签名的镜像会在校验环节被拒绝。这个机制对开发阶段是个障碍,但对量产产品是必要的保护,做方案选型时要把这条链路提前考虑进去。

表:DDR启动阶段常用地址约束

项目检查点
内核加载地址必须与DDR起始地址加偏移匹配
设备树地址与内核镜像不重叠,建议错开4MB以上
U-Boot自身位置不能被内核镜像覆盖
bootargs内存大小与DDR控制器实际配置一致
栈和堆区域跳转前由U-Boot接管,确认无越界

5. 避坑:Boot流程中最常踩的五个现场问题

5.1 现象:上电完全无打印

这是最让人头疼的一种情况。串口终端什么都收不到,示波器抓UART引脚也看不到电平翻转。原因可能出在几个方面:芯片根本没有跑起来,复位引脚一直被拉低;电源时序不满足要求;ROM Code的介质判定卡在死循环里等待某个引脚;UART引脚复用错了方向,打印发到了别的引脚上。

解决思路是逐层确认。先查复位脚波形是否符合手册要求的上电时序,再确认晶振或时钟源是否起振,然后把示波器挂在UART_TX引脚看有没有电平翻转。如果确实没有任何打印,优先检查boot模式选择引脚。有些芯片在这些引脚悬空时会持续等待介质,表现就和无启动完全一样。检查原理图时,要把相关引脚上的上下拉电阻画清楚,特别是状态保持到ROM Code采样完成之前,否则会出现上电能启动、下一次又不能的间歇性故障。

5.2 现象:SD卡启动卡在SPL阶段,串口无输出或极短乱码

SD卡上的镜像格式不对,或者镜像头部校验失败时,ROM Code可能根本不会进入SPL代码,表现就是完全没有输出。输出极短乱码多半是UART波特率不匹配,ROM Code配的和SPL配的不一致,两段代码各自用了不同的打印配置。

调试办法是先确认ROM Code打印能正常收到,再确认SPL入口打印是否出现。如果ROM Code有打印但SPL没有,用读卡器把SD卡镜像倒出来,检查前70KB位置的头部魔数和校验字段。另一个常见原因是用烧录工具写卡时,起始块地址被工具默认设置偏移了,镜像没有写在ROM Code预期的位置。

5.3 现象:SPL正常但跳到DDR后死机

SPL在SRAM里跑得好好的,搬运完成跳出后一进DDR就死。这种问题最早我在项目里排查了很久,原因是DDR初始化参数与实际硬件不匹配,尤其是内存频率、时序参数或驱动强度配置不对。也有可能是SPL跳转时没有切换栈指针,或者跳转地址和链接脚本不一致。

解决方式分两步:先把DDR控制器的初始化参数和内存颗粒数据手册逐项核对,重点检查CAS延迟、tRCD、tRP这些时序参数。然后写一个简单的DDR读写测试函数,在SPL跳转前对目标地址做写读比较。如果读写测试都不出错,再回头查跳转地址。这类问题优先用内存读写脚本定位,不要一开始就怀疑跳转代码写错。

5.4 现象:UART/USB下载模式能握手但下载完起不来

下载模式是开发期最常用的调试手段,但有时握手正常、传输也显示成功,跳转后却起不来。原因通常在于下载工具传给ROM Code的镜像长度、校验值和实际文件不一致,或者下载目标地址和运行地址不一致。还有一种情况是协议里带校验头,长度字段写错,ROM Code把有效镜像截断了。

解决办法是核对下载工具输出日志里的下载长度、起始地址和CRC,与本地生成镜像的工具链配置保持一致。如果用了加载地址重定向,要确保链接脚本里的链接地址和下载地址一致。我把镜像生成命令和下载命令写到一个脚本里,自动计算长度和CRC,不手工填值,从根上避免这类错误。

5.5 现象:eMMC与SD卡启动行为不一致

eMMC和SD在电气协议上相近,但细节差异很大。eMMC支持boot分区,SD没有这个概念。eMMC初始化通常需要CMD1获取OCR寄存器,总线宽度切换的方式也和SD不同。直接拿SD版本的SPL放到eMMC上,经常出现能识别容量但读取超时的问题。

解决方式是在SPL或ROM Code的eMMC分支里单独确认boot分区的使能状态和总线宽度配置。有的芯片需要在初始化阶段显式写boot bus width寄存器,没设置的话后续读取全部失败。另外,eMMC如果上一次写入的是非boot分区,ROM Code按boot分区查镜像查不到,表现同样为启动失败。重新烧写时要用烧录工具把镜像写到boot分区而不是普通用户分区,这一步经常被忽略。

注意:遇到启动问题先按介质、地址、参数三条线排查,不要先怀疑是芯片本身有问题。绝大多数boot失败是配置问题或镜像布局问题。

6. 用GPIO翻转和串口时间戳给Boot各阶段做性能画像

Boot过程不只是功能问题,很多产品对启动时间有硬指标。拿到新板子后,我习惯先给boot流程做一次性能画像,看每个阶段花了多少时间,再决定优化方向。

最简单的打点方案是:在ROM Code、SPL、U-Boot、Kernel每段的入口和完成点各翻转一次GPIO。选一个空闲GPIO做标志位,进入阶段时拉高,离开阶段时拉低。逻辑分析仪挂在这个GPIO上,上电后抓一段波形,每一段的持续时间一目了然。需要提醒的是,GPIO在这个阶段能不能用,取决于芯片是否允许ROM Code阶段操作GPIO控制器。有些芯片要在system init之后GPIO才可用,这种情况把第一个打点放在SPL入口更现实。

串口时间戳可以辅助精度要求不高的测量:在启动代码里用系统定时器打印当前计数,换算成毫秒。比如SPL入口打印t=10ms,U-Boot入口打印t=35ms,Kernel入口打印t=120ms,这样各阶段耗时清晰可见。我在几个平台测下来,最耗时的通常是DDR初始化和SD/eMMC的大块镜像搬运。优化方向一般是减少DDR初始化时的稳定等待时间,以及调整总线速度和DMA burst大小。

从那以后,我每次拿到新芯片或者改过启动配置,都会强制自己先做一遍GPIO打点,把各阶段时长记录存档。后续改任何启动代码,都能立刻看出哪一段变慢了、哪一段时序变了,不用等整机功能异常才回头排查。串口日志加GPIO波形,这两个工具配合起来,比仿真器打断点更接近启动过程的真实状态。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/15 8:40:43

CDH集群中Presto部署实战:轻量SQL引擎与现有生态深度集成

1. 项目概述:为什么在CDH集群里单独部署Presto,而不是直接用Impala或HiveServer2?“七十、CDH集群中部署Presto”——这个标题看似平实,但背后藏着一个在某金融类数据平台实际落地时反复被问到的核心问题:我们已经有CD…

作者头像 李华
网站建设 2026/10/15 8:40:32

UVa 12860:星系碰撞问题的二分图算法解析

1. 问题背景与理解UVa 12860 "Galaxy Collision" 是ICPC世界总决赛级别的经典计算几何题目。题目描述了两个星系碰撞的场景,其中每个星系由若干恒星组成。当两个星系碰撞时,它们的恒星会相互混合。题目要求我们根据混合后的恒星位置&#xff0…

作者头像 李华
网站建设 2026/10/15 8:40:31

SpringBoot+Vue全栈项目实战:从架构设计到部署上线完整指南

每个人做全栈项目,基本都会经历过这样的阶段:需求看着明白,代码也能写,但一问“前后端怎么配合”“部署到服务器上怎么跑起来”就卡壳。这篇文章我拿一个之前做过的社区医疗服务系统当例子,把从架构设计、核心模块实现…

作者头像 李华
网站建设 2026/10/15 8:40:06

自演化具身智能:从感知行动闭环到技能自组织的工程实践

1. 自演化具身智能到底在解决什么问题第一次听到“自演化具身人工智能”这个词,很多人会把它和“具身智能”画等号。实际上两者差着一个关键维度。具身智能解决的是“有身体的智能体如何在物理世界里感知和行动”,比如机械臂抓杯子、四足机器人走碎石路。…

作者头像 李华
网站建设 2026/10/15 8:39:52

Lazada多站点团队怎么分权限,才能少登错店?

Lazada员工负责不同站点时,平台账号权限和浏览器环境要分工处理。权限决定员工能进入哪些店铺、执行哪些操作,浏览器环境则帮助团队区分站点、店铺、成员和登录入口。老梁观察到,很多团队的问题不是店铺太多,而是“谁负责哪家店”…

作者头像 李华
网站建设 2026/10/15 8:39:02

AnyPS5 跨平台串流方案:PS5 远程游玩与手柄映射实战

1. 项目缘起与核心定位AnyPS5 这个名字,第一次看到的时候我愣了一下。PS5 是索尼那台次世代主机,Any 这个前缀通常意味着“任意、通用、跨平台”。把这两个词拼在一起,直觉告诉我这是一个跟 PlayStation 5 相关的工具类项目,而且大…

作者头像 李华