9、自定义Bootloader:Little Kernel简介、U-Boot在Android中的应用、编译与烧录自定义Bootloader
好,咱们进入第九章。这一章我打算聊聊自定义Bootloader。说实话,做Android底层开发这么多年,Bootloader一直是个“既熟悉又陌生”的东西。熟悉是因为每次开机它都在跑,陌生是因为大部分时候我们直接用厂商提供的就完事了。但如果你想深入理解Android启动流程,或者想给设备做深度定制,那自定义Bootloader就是绕不开的一关。
今天咱们重点聊两个东西:Little Kernel(LK)和U-Boot。嗯,这两个在Android生态里是最常见的开源Bootloader。
9.1 Little Kernel(LK)简介
Little Kernel,简称LK。名字里带个“Little”,但它干的事可不小。它是Google在Android早期阶段就开始使用的Bootloader,很多高通平台的设备默认就是它。
我个人习惯把LK看作一个“轻量级的小型操作系统”。它有自己的线程管理、内存管理、甚至还有简单的设备驱动框架。你想想看,一个Bootloader能做到这个程度,已经很不简单了。
核心特点:
- 代码量小,结构清晰,适合嵌入式环境
- 支持ABL(Android Bootloader)规范
- 内置Fastboot协议支持
- 支持多种启动设备:eMMC、UFS、SD卡等
我在项目中遇到过一个问题:某款高通平台的设备,在低温环境下偶尔无法正常启动。排查到最后,发现是LK阶段对eMMC的初始化时序不够稳健。说白了,就是Bootloader在低温下读eMMC时,时序参数没适配好。后来我们在LK的板级配置里调整了时钟延迟参数,问题就解决了。所以你看,Bootloader虽然小,但硬件相关的坑一个都不少。
LK的启动流程
LK的启动流程其实不复杂,我简单梳理一下:
- CPU复位:从ROM代码跳转到LK入口
- 早期初始化:设置栈、清零BSS段
- 平台初始化:时钟、GPIO、UART等
- 设备探测:检测eMMC、显示屏、按键等
- 启动模式判断:正常启动还是进入Fastboot
- 加载并跳转:读取boot.img并跳转到kernel
这里有个细节我想提一下:LK的启动模式判断,通常是通过检测按键组合来实现的。比如音量减+电源键进入Fastboot。我曾经调试过一个设备,按键检测的GPIO配置错了,导致怎么按都进不了Fastboot模式。嗯,这种问题排查起来其实挺费时间的。
9.2 U-Boot在Android中的应用
U-Boot,全称是Das U-Boot。它比LK更老牌,在嵌入式Linux领域几乎是标配。Android早期也有不少设备用U-Boot,现在主要在一些非高通平台(比如瑞芯微、全志、MTK部分平台)上还能看到它的身影。
U-Boot和LK最大的区别是什么?我个人觉得有两点:
- U-Boot更“重”:功能更丰富,支持更多文件系统、网络协议、命令行工具
- U-Boot更“开放”:它的驱动模型和配置系统非常灵活,适配新板子相对容易
我的建议:如果你是在做基于Linux的嵌入式产品(非Android),U-Boot几乎是首选。但如果是做Android手机/平板,尤其是高通平台,LK更常见。当然,现在Google也在推ABL(基于UEFI的Bootloader),那是另一个话题了。
U-Boot在Android中的典型用法
U-Boot在Android设备上,通常承担以下职责:
| 功能 | 说明 |
|---|---|
| 加载内核 | 从boot分区读取kernel并跳转 |
| Fastboot支持 | 通过fastboot协议刷写分区 |
| 环境变量管理 | 存储启动参数、分区表等 |
| 多系统启动 | 支持Android + Linux双系统 |
| OTA升级辅助 | 在升级失败时提供恢复机制 |
我记得有一次帮客户调试一个基于RK3399的Android平板,U-Boot阶段死活加载不了内核。最后发现是环境变量里的bootargs参数写错了,少了一个关键的dma参数。你想想看,就一个字符串的差异,导致整个系统起不来。所以我说,做底层开发,细节决定成败。
9.3 编译与烧录自定义Bootloader
好,到了实操环节。咱们聊聊怎么编译和烧录自定义Bootloader。这里我以LK为例,因为它的编译系统相对简单,适合入门。
编译LK
LK的编译系统基于Makefile,没有复杂的Kconfig。你只需要配置好交叉编译工具链,然后指定目标平台即可。
# 设置交叉编译工具链
export PATH=/path/to/your/toolchain/bin:$PATH
export CROSS_COMPILE=aarch64-linux-android-
# 编译LK
make -j4 PROJECT=<your_project_name>
这里的PROJECT变量指定了目标平台。LK的源码里有一个project目录,里面存放了各个平台的板级配置。比如高通某平台的配置可能是msm8998或sm8250。
注意:编译LK时,一定要确保你的交叉编译工具链版本与目标平台匹配。我曾经用了一个太新的GCC版本编译LK,结果链接出来的二进制在目标板上跑不起来。后来换回厂商推荐的GCC版本,问题就解决了。工具链版本这事,真的不能马虎。
烧录自定义Bootloader
编译完成后,你会得到一个lk.bin或bootloader.img文件。烧录方式取决于你的设备:
- 通过Fastboot烧录:
fastboot flash bootloader lk.bin - 通过下载工具烧录: 比如高通的QFIL、瑞芯微的RKDevTool
- 通过JTAG/SWD烧录: 用于变砖后的救砖场景
我个人最常用的是Fastboot方式。前提是你的设备当前还能正常进入Fastboot模式。如果Bootloader已经刷坏了,那就只能上JTAG或者拆机用SPI Flash编程器了。
避坑指南:我曾经在调试阶段频繁刷写Bootloader,结果有一次不小心把分区表也擦掉了。设备直接变砖,只能拆机用编程器恢复。从那以后,我每次刷Bootloader之前都会先备份原始分区表。嗯,这个习惯救过我很多次。
9.4 知识体系结构图
下面这张图是我整理的本章知识体系,方便你理解各个概念之间的关系:
这张图把本章的三个核心内容串起来了。左边是LK,右边是U-Boot,下面是编译烧录的实操要点。你可以把它当作一个快速索引,复习的时候瞄一眼就能想起来。
9.5 小结
这一章我们聊了LK和U-Boot这两个主流的开源Bootloader。LK轻量、简洁,适合高通平台;U-Boot功能丰富,适合非高通平台和嵌入式Linux场景。编译和烧录方面,我分享了一些实际项目中的经验和教训,希望能帮你少走弯路。
自定义Bootloader这件事,说难不难,说简单也不简单。关键是要理解它的启动流程、熟悉编译工具链、以及掌握烧录和救砖的方法。嗯,这些都需要在实际项目中慢慢积累。
一句话总结:Bootloader是Android启动的第一道关卡,自定义它需要你对硬件、编译系统和启动流程都有足够的理解。别怕踩坑,每个坑都是成长的机会。
公众号:蓝海资料掘金营,微信deep3321