1. 分区烧录基础:理解嵌入式设备的分区表与分区作用
做嵌入式系统这么多年,我见过太多因为分区搞砸的项目。有一次,同事在量产前最后一刻发现系统起不来——查了半天,原来是分区表写错了,boot分区被data分区覆盖了一部分。嗯,从那以后,我每次做烧录方案,第一件事就是先把分区表理清楚。
说白了,分区就是给存储芯片画格子。每个格子装不同的东西:系统内核、用户数据、缓存文件……各有各的地盘,互不干扰。今天我们就从最基础的分区表讲起。
1.1 分区表:MBR 与 GPT
分区表就是一张地图,告诉芯片“哪个区域归谁管”。目前主流的有两种:MBR 和 GPT。
| 对比项 | MBR(主引导记录) | GPT(GUID分区表) |
|---|---|---|
| 诞生时间 | 1983年(DOS时代) | 2000年代(UEFI时代) |
| 最大磁盘容量 | 2TB | 9.4ZB(实际受OS限制) |
| 分区数量 | 最多4个主分区 | 理论上无限制(Windows限制128个) |
| 冗余备份 | 无(只有一份,坏了就完蛋) | 有(主分区表和备份分区表) |
| 校验机制 | 无 | CRC32校验 |
| 适用场景 | 老旧设备、小容量Flash | 新平台、大容量eMMC/UFS |
1.2 嵌入式设备常见分区类型
不管用MBR还是GPT,嵌入式设备里通常都有这几个核心分区。我按启动顺序给你捋一遍。
1.2.1 Boot分区
这是系统的“第一口奶”。芯片上电后,BootROM会从这里加载启动代码。通常包含两个部分:
- Primary Bootloader(PBL):固化在芯片内部,不可修改
- Secondary Bootloader(SBL):存放在Flash上,比如U-Boot、LK
我个人习惯把Boot分区单独放在最前面,并且给它加上写保护。为什么?因为一旦Boot分区坏了,整个系统就彻底废了。你想想看,连启动都做不到,还谈什么恢复?
1.2.2 System分区
这里装的是操作系统内核、驱动、核心库和系统应用。在Android设备上,它就是/system目录;在Linux嵌入式设备上,它通常是rootfs。
System分区一般是只读的(或者挂载为ro)。我建议你永远不要在生产环境里把它挂载成读写——除非你在做开发调试。我在一个项目里见过有人为了省事,把system分区设成可写,结果OTA升级时文件系统损坏,整批设备返厂。
1.2.3 Data分区
用户数据存放区。包括应用安装包、配置文件、数据库、日志等。这个分区是可读写的,也是整个系统里最容易出问题的地方。
- 空间不足导致应用崩溃
- 异常断电导致文件系统损坏
- 恶意软件写入垃圾数据
1.2.4 Cache分区
缓存分区,用来存放临时数据。比如OTA升级包、系统更新缓存、应用缓存等。这个分区可以随时清空,不影响系统运行。
你可能会问:既然可以随时清空,那它重要吗?重要。因为如果Cache分区满了,OTA升级可能失败,系统更新会卡住。我建议给Cache分区预留足够空间,至少是系统固件大小的1.5倍。
1.3 分区布局实战:一个典型的嵌入式Linux设备
下面是我在一个量产项目中用过的分区布局。你可以参考一下。
| 分区名称 | 起始地址 | 大小 | 文件系统 | 作用 |
|---|---|---|---|---|
| boot | 0x00000000 | 2MB | raw | U-Boot引导程序 |
| env | 0x00200000 | 128KB | raw | U-Boot环境变量 |
| boot_a | 0x00400000 | 16MB | ext4 | 内核+dtb(A槽) |
| boot_b | 0x01400000 | 16MB | ext4 | 内核+dtb(B槽,备份) |
| system_a | 0x02400000 | 256MB | ext4 | 系统镜像(A槽) |
| system_b | 0x12400000 | 256MB | ext4 | 系统镜像(B槽,备份) |
| data | 0x22400000 | 剩余空间 | f2fs | 用户数据 |
| cache | 0x80000000 | 64MB | ext4 | 缓存 |
1.4 分区表操作:查看与备份
在实际工作中,你经常需要查看设备的分区表。下面是我常用的几个命令。
查看分区表
# 查看eMMC分区表(Linux环境下)
cat /proc/partitions
# 使用fdisk查看
fdisk -l /dev/mmcblk0
# 使用gdisk查看GPT分区表
gdisk -l /dev/mmcblk0
# 查看分区挂载情况
mount | grep mmcblk0
备份分区表
我建议你在量产前,先把分区表完整备份一份。万一哪天分区表损坏,这就是救命稻草。
# 备份MBR(前512字节)
dd if=/dev/mmcblk0 of=mbr_backup.bin bs=512 count=1
# 备份GPT(前34个LBA)
dd if=/dev/mmcblk0 of=gpt_primary.bin bs=512 count=34
# 备份GPT备份分区表(最后33个LBA)
dd if=/dev/mmcblk0 of=gpt_backup.bin bs=512 skip=$(($(blockdev --getsz /dev/mmcblk0) - 33)) count=33
1.5 分区烧录的核心流程
理解了分区表和分区类型,烧录就简单了。核心流程就三步:
- 擦除分区:把目标分区清空,避免旧数据干扰
- 写入镜像:把固件镜像写到指定分区
- 校验数据:读回来比对,确保写入正确
我习惯在烧录脚本里加上CRC校验。虽然会多花几秒钟,但能避免99%的烧录失败问题。有一次量产时,烧录器接触不良,数据写了一半就断了。如果没有校验,这批设备出厂后全都会变砖。
dd命令把分区内容读出来,和原始镜像做md5sum比对。这是最笨但最可靠的方法。
1.6 本章知识结构图
下面这张图帮你梳理了本章的核心知识点。你可以把它当作一个快速索引。
这张图把分区表、分区类型和烧录流程串在了一起。你可以把它当作一个快速参考。在实际项目中,我经常把这张图打印出来贴在工位上——每次做分区方案时看一眼,能避免很多低级错误。