U-Boot移植实战:fastboot刷机与eMMC启动完整攻略

发布时间:2026/10/15 18:09:39
U-Boot移植实战:fastboot刷机与eMMC启动完整攻略 连续折腾了七篇U-Boot移植板子总算能在SD卡上稳定进U-Boot控制台。但说实话每次改完配置都得拔卡、插卡、再开机一天重复几十次先不说手累光是SD卡座针脚被磨秃的风险就够让人揪心。所以到第八篇我决定一次性解决两个问题让U-Boot支持fastboot刷机协议并且能从板载eMMC直接启动系统。这篇文章就是完整的操作记录——从fastboot的配置开关、USB gadget驱动的适配到分区表设计、EMMC启动链路的校验最后附上我实际踩过的几个坑。如果你手里也是一块Exynos 4412级别核心板、想把U-Boot 2020.07刷进eMMC而不是天天插SD卡这篇应该能帮你少走不少弯路。1. 为什么说EMMC启动和fastboot是一对搭档1.1 前面七篇移植做到哪一步了先快速回顾一下当前状态。到上一篇为止这块核心板上的U-Boot已经实现了DDR初始化、串口输出、网络启动、MMC驱动识别甚至能从SD卡加载内核镜像并启动到控制台。看起来功能挺全但整套流程都建立在一个前提上——SD卡必须插着。这个前提在开发调试阶段勉强能忍但一进入量产测试就露馅了。板子拿到手第一件事是插SD卡测完一批还得回收卡、重新烧写下一批效率低不说SD卡里的环境变量还可能互相污染。更麻烦的是如果哪天调试环境只有网口没有SD卡读卡器整块板子就瘫在那里只能拆机。所以我当时给自己定的目标很明确把U-Boot和内核都固化到eMMC里然后通过fastboot接口来做后续的镜像更新。这样既不用频繁插拔SD卡也方便把镜像直接通过网络或者USB线推给板子。1.2 从iROM到U-Boot的启动链在动手之前必须把这款芯片的启动流程看清楚。Exynos 4412内部有一段固化在片内ROM里的引导代码上电后会根据OM引脚的电平组合决定从哪个设备去读取一级引导BL1。如果配置成eMMC也就是SD0通道启动iROM就会直接在eMMC的用户分区里、按照约定好的偏移地址去读BL1然后由BL1完成DRAM初始化再把主U-Boot镜像从eMMC搬运到DDR里执行。这里最关键的一点是固化的iROM并不会去解析U-Boot的头部信息它只认烧写约定好的偏移位置。也就是说BL1放哪个扇区、U-Boot主镜像放哪个扇区必须在烧写时和板级配置完全对齐。如果偏移差了一格iROM可能读出一堆乱码板子就是黑屏没反应。1.3 fastboot在这个链路里扮演的角色传统做法是用PC端的烧写工具通过SD卡座或者串口去写eMMC。但移植U-Boot的场景里还有一条更顺手的路先把一个最小化的U-Boot跑起来哪怕是SD卡启动然后在这个U-Boot里启用fastboot命令让PC通过USB线直接把分区镜像推进去。fastboot在这里不只是刷机工具它实际承担了三个任务一是烧写带校验头的BL1文件二是在U-Boot主镜像所在的分区写入新版本三是刷新内核分区或文件系统分区。换句话说只要fastboot通了后面所有镜像更新都只需要一根USB线完全不需要再拆机换SD卡。而且fastboot是Android系统时期就被大量验证过的协议兼容性很好windows、linux、macOS下都有现成的主机端工具。把fastboot和EMMC启动放在同一篇文章里讲是因为它们本质上是一条完整链路fastboot负责把镜像写进eMMCEMMC启动负责把镜像跑起来缺一不可。2. 移植fastboot之前先摸清的事配置开关、USB驱动和分区表2.1 menuconfig里的关键开关U-Boot 2020.07本身已经内置了fastboot支持但并不是默认打开的。我当时直接在板级defconfig里追加了下面这一组配置然后重新编译CONFIG_CMD_FASTBOOTy CONFIG_USB_FUNCTION_FASTBOOTy CONFIG_USB_GADGETy CONFIG_USB_GADGET_DWC2_OTGy CONFIG_FASTBOOT_BUF_SIZE0x2000000 CONFIG_FASTBOOT_BUF_ADDR0x40000000 CONFIG_FASTBOOT_FLASHy逐个解释一下。CONFIG_CMD_FASTBOOT是让U-Boot命令行里出现fastboot指令CONFIG_USB_FUNCTION_FASTBOOT是注册USB gadget的fastboot功能描述符CONFIG_USB_GADGET_DWC2_OTG对应Exynos 4412内置的高速OTG控制器这里的DWC2 IP选择不能搞错选成别的gadget控制器驱动会直接编译报错或者枚举失败。CONFIG_FASTBOOT_BUF_SIZE和CONFIG_FASTBOOT_BUF_ADDR决定了接收下载镜像时用的内存缓冲区和它的大小我给的0x2000000也就是32MB对于U-Boot和内核镜像来说完全足够但对整个根文件系统镜像来说就偏小了后面细说。CONFIG_FASTBOOT_FLASH打开之后U-Boot才允许处理fastboot协议里的flash指令否则只能执行download/erase这些操作没法真正把镜像写到存储设备里。如果你是从旧版本迁移过来的还要检查一下和USB gadget相关的时钟、引脚复用配置。4412的OTG控制器需要对应的时钟门控打开引脚mux也要配置成USB模式否则USB枚举时设备侧完全无响应。这些通常放在board_early_init_f里移植时容易漏掉。2.2 4412的USB gadget为什么让人头疼刚把fastboot配置加进去、编译烧到SD卡启动输入fastboot usb 0这个命令之后板子串口确实打印了controller ready但PC端fastboot devices死活看不到设备。我查了半天发现不是fastboot协议的问题而是USB gadget的速率协商失败。DWC2控制器在gadget模式下需要把OTG端口配置成设备模式同时要正确处理VBUS检测。当时板子上OTG口的ID引脚没有正确处理控制器一直认为自己应该当主机自然不会向PC枚举为设备。解决办法是在板级初始化里强制把usb_otg模式切成device并把DWC2的usb_otg时钟和复位配置好。另外U-Boot的DWC2 gadget驱动在一些情况下需要额外的CONFIG_USB_GADGET_DUALSPEED支持如果只配置了全速PC端虽然能看到设备但传输速率会很可怜刷一个几十MB的镜像等到怀疑人生。2.3 分区表设计刷Android和刷自己系统都要兼顾fastboot的flash指令是按逻辑分区名来定位目标地址的。也就是说我不能直接告诉它把镜像写到第12345个扇区而是要让U-Boot把某个逻辑分区名映射到具体的eMMC偏移。我在这块板上规划的eMMC用户分区布局如下分区名起始扇区大小用途bl1164扇区(32KB)BL1含签名头uboot65512扇区(256KB)U-Boot主镜像env57764扇区(32KB)环境变量boot6418192扇区(4MB)内核uImagesystem8833100MB根文件系统data剩余剩余数据区这套布局在移植早期就有意做了对齐每个分区都按eMMC的擦除块大小对齐避免在fastboot erase或flash时出现跨块操作带来的性能问题。实际修改时我在板级配置头文件里定义了分区起始地址、大小然后在fastboot的板级回调里把这个映射关系注册进去让系统自动匹配。提示分区表布局直接决定后续烧写是否顺利也会影响后续要装Android系统还是自己精简的Linux系统。建议一开始就预留system和data分区别只放一个boot分区不然想扩展的时候很可能要重刷整个eMMC。3. fastboot首次烧写实录从识别设备到完整刷机验证3.1 让板子进入fastboot模式编译好新U-Boot烧到SD卡启动之后在U-Boot命令行执行fastboot usb 0串口会打印fastboot相关初始化日志。此时用USB线连接板子的OTG口和PCPC端执行fastboot devices如果一切正常会看到类似于?????? fastboot的输出那个问号串是设备序列号可以不管它。我遇到的第一个问题是执行fastboot usb 0后PC毫无反应。排查链路花了将近一个小时最后发现是板级设备树如果是用设备树适配的话里OTG节点的status没有设为okay导致U-Boot驱动初始化时直接跳过了这个控制器。因为之前一直没用到USB gadget功能这个节点就被忽略了直到这次才暴露出来。3.2 先用最小镜像验证通路第一次烧写时强烈建议不要直接丢一个几百KB的U-Boot镜像过去先用一个几KB的文本文件做通路测试。我当时的做法是用fastboot download一个1KB的env文件再执行fastboot flash env env.txt然后直接在U-Boot里检查env分区内容是否更新。这一步的目的不是省那点时间而是为了快速区分故障边界。如果小文件都传不过去说明协议栈、USB枚举、驱动环节的问题而不是烧写逻辑有问题如果小文件能传过去大文件失败那基本就是缓冲区配置、超时或者eMMC写入的问题。很多人在第一次调试时直接拉个大镜像失败之后完全没有排查思路就是因为测试跨度太大了。验证小文件通过之后再执行fastboot flash uboot u-boot.bin fastboot oem reboot这里有个细节fastboot flash uboot时U-Boot收到的是一整份u-boot.bin它会把镜像从内存缓冲区写入到uboot分区对应的扇区。写入完板子不会自动重启需要手动执行fastboot oem reboot让板子复位。3.3 一次完整烧写与读取验证完整的刷机流程无非是下面这几个命令建议写入自动化脚本fastboot devices fastboot erase boot fastboot flash boot uImage fastboot flash system rootfs.img fastboot oem reboot如果分区之前没写过内容erase可以跳过但保险起见还是擦一下避免旧数据残留造成启动时读到脏数据。有个环节很多人忽略烧写完成后的读取验证。fastboot本身没有提供读回分区内容的命令但U-Boot控制台里可以用mmc read读回扇区、再用crc32比对。我实测后发现U-Boot的fastboot写eMMC时如果镜像大小超过缓冲区32MB最后的部分可能根本没写进去但fastboot工具依然会报success。这种假成功比直接失败更难排查所以大镜像必须做读回校验。4. 从EMMC启动必须处理的启动链细节4.1 eMMC硬件分区vs用户分区先分清分区在哪eMMC颗粒内部其实分了几个区域boot0、boot1、RPMB区和用户数据区user area。BootROM可以从boot0启动也可以从用户区启动取决于芯片固化代码的实现。在这颗4412上iROM实际访问的是用户区指定偏移而不是boot0硬件分区。这一点在移植时必须确认清楚否则你把U-Boot写进boot0结果发现芯片根本不认白白折腾一通。我当时确认的方法很简单先看板级量产烧写脚本它里面明确写了往用户区哪个扇区偏移写BL1再对照芯片手册的启动流程图确认SD0通道的读取偏移。两相对照心里就有底了。4.2 BL1和U-Boot镜像的摆放位置与校验头这块板子的启动布局我整理成了一张表实际使用时要结合你自己的板级烧写脚本来确认内容用户区偏移说明BL1扇区1开始16KB/32KB大小带签名头U-Boot main扇区65开始我编译出来的U-Boot约400KB环境变量扇区577开始独立分区避免刷新U-Boot时被覆盖内核扇区641开始uImage格式BL1文件一定要用带校验头的。芯片的iROM读到BL1后首先校验头部签名如果签名信息缺失启动流程会直接终止表现就是上电后串口没有任何输出连个初始化日志都没有。我之前拿到过一份不带校验头的裸BL1dd进eMMC后板子完全没反应后来换用板厂提供的带签名BL1才正常起来。U-Boot主镜像本身不需要签名头但必须保证它的加载地址和编译时配置一致。我在配置里把CONFIG_SYS_TEXT_BASE设为0x43E00000BL1会把主镜像从eMMC搬运到这个地址再跳转执行如果地址对不上一样跑不起来。4.3 U-Boot环境变量和bootcmd的调整EMMC启动的最后一个环节是环境变量。之前SD卡调试时环境变量默认保存在SD卡的env分区里烧进eMMC后如果不改env的存储位置U-Boot还是会去SD卡找环境变量找不到就用编译时的默认值然后启动命令也会去读SD卡上的内核镜像。我调整后的环境变量关键项如下setenv bootcmd mmc dev 0; mmc read 0x40008000 0x281 0x2000; bootm 0x40008000 setenv bootargs consolettySAC2,115200 root/dev/mmcblk0p3 rw rootwait saveenvbootcmd里先把eMMC切到设备0然后从内核分区起始扇区0x281读出约2MB数据到DDR地址0x40008000最后用bootm引导uImage。bootargs里的root参数指向eMMC的设备节点。如果你的内核分区更靠后或者rootfs在另一个分区按实际映射改就行。这里有个特别容易踩的坑bootcmd里如果忘了先执行mmc dev 0U-Boot可能还停留在SD卡的MMC设备号上mmc read读的其实是SD卡的数据板子表现就是看起来在启动但内核根本不匹配。环境变量折腾半天最后发现只要在bootcmd前加一句设备切换就能解决这个坑我记得很清楚。5. 实测中绕不开的几个坑5.1 坑一BOOT分区容量和U-Boot镜像大小之争先说一个让很多人白忙活的误解。eMMC硬件boot0分区通常只有128KB左右根本塞不下一个完整U-Boot 2020.07镜像——我编译出来的最小配置都有约380KB正常配置超过500KB。所以不要试图把整个U-Boot塞到boot0里这个思路就是错的。正确方案是把BL1放在用户区约定偏移主U-Boot也跟着放用户区。硬件boot0分区留给真正需要从它启动的芯片场景对4412来说不适用。我第一次尝试时确实把U-Boot硬塞进boot0结果自然是启动黑屏后来想明白容量问题就释然了。5.2 坑二fastboot烧写大文件最后几秒失败在刷rootfs.img这种上百MB的镜像时我遇到了最后几秒卡住然后报FAILED的故障。查了缓冲区才知道CONFIG_FASTBOOT_BUF_SIZE设的是32MB镜像超过32MBfastboot只能烧进去一部分后续数据没地方放直接失败。我把缓冲区的地址保持在0x40000000但把CONFIG_FASTBOOT_BUF_SIZE改大到0x10000000256MB足以容纳绝大多数镜像。理论上缓冲区越大越保险但要确认这个地址范围内没有和U-Boot当前执行代码、环境变量栈、内核加载地址冲突。我的DDR是1GBU-Boot运行在高端地址放到0x40000000起始的256MB空间不会和后续bootm加载内核的0x40008000冲突。提示fastboot缓冲区地址和bootm加载地址一定不能重叠。我见过有人把两者设成同一个地址烧写时没问题重启引导到bootm时就随机死机折腾半天才发现是缓冲区把内核镜像覆盖了。5.3 坑三SD卡里的旧环境变量污染EMMC启动从SD卡移植到EMMC时最大的隐藏对手其实是环境变量。SD卡上保存的env里bootcmd可能还指着SD卡上的分区bootargs里root/dev/mmcblk1可能也是SD设备节点。上电后U-Boot按存储介质优先级去找env结果把SD卡里的旧环境变量读出来EMMC启动完全失效。解决方式是在EMMC上启动后先执行env default -f -a然后重新设置bootcmd、bootargs再saveenv到eMMC的env分区。如果你不确定当前环境变量来自哪个介质可以看U-Boot启动日志里Loading Environment from MMC后面跟的是哪个设备号一目了然。5.4 坑四fastboot分区映射的字符串溢出这个坑比较隐蔽。我最初在板级配置里定义fastboot分区映射时直接用了固定大小的字符串数组来存分区名和偏移结果分区名较长、数量又多的时候字符串就溢出了。现象是U-Boot启动时随机死机或者在fastboot devices能识别但fastboot flash时报分区找不到。排查之后发现是分区映射表的条目长度没预留够。解决办法是把映射表结构里的name数组加大并在注册函数里做一次strlen检查超过上限直接返回错误避免静默溢出。嵌入式开发里这种问题最烦人它不报编译错误运行时机率性出现非常考验耐心。6. 回头看看这套流程值不值得折腾从SD卡启动切换到EMMC启动之后最大的感受是开发节奏完全变了。以前每次编译U-Boot都要重新插一次SD卡现在直接在U-Boot里执行fastboot usb 0PC端一条fastboot flash uboot命令就搞定从编译到新固件跑起来不超过两分钟。内核调试也一样uImage直接推到boot分区连网线都不用插。如果你正在做类似的核心板U-Boot移植我建议在完成MMC驱动之后、还没沉迷于各种外设适配之前先把fastboot和EMMC启动这条链路打通。它带来的不只是刷机便利更是一个可以反复使用的封闭调试通道——只要板子能进U-Boot就不会变砖只要能进U-Boot所有后续镜像都可以远程刷入。这套流程稳定之后再去折腾显示、触摸、网卡这些外设心理负担会小非常多。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询