之前学习s3c2440时,分区信息是保存在uboot的环境变量中。通过uboot的内核命令行给MTD层传递MTD分区信息, 内核读取到的分区信息始终和u-boot中的保持一致。
如: s3c2440分区信息
/* uboot */
$printenv
bootargs=console=ttySAC0 root=/dev/mtdblock3 rootfstype=jffs2 mtdparts=nand_flash:128k(u-boot)ro,64k(u-boot envs),3m(kernel),30m(root.jffs2),30m(root.yaffs)
/* kernel*/
$cat /proc/cmdline
console=ttySAC0 root=/dev/mtdblock3 rootfstype=jffs2 mtdparts=nand_flash:128k(u-boot)ro,64k(u-boot envs),3m(kernel),30m(root.jffs2),30m(root.yaffs)
查看了RK3399的 uboot 环境变量、cmdline、dts,没有发现分区信息
/* uboot */
=> printenv
bootargs=storagemedia=emmc androidboot.storagemedia=emmc androidboot.mode=normal
/* kernel */
cat /proc/cmdline
storagemedia=emmc androidboot.storagemedia=emmc androidboot.mode=normal androidboot.verifiedbootstate=orange androidboot.slot_suffix= androidboot.serialno=12f68f4f2233d049 rw rootwait earlycon=uart8250,mmio32,0xff1a0000 swiotlb=1 console=ttyFIQ0 root=PARTUUID=614e0000-0000 rootfstype=ext4 coherent_pool=1m
/* dts */
chosen {
bootargs = "earlycon=uart8250,mmio32,0xff1a0000 swiotlb=1 console=ttyFIQ0 rw root=PARTUUID=614e0000-0000 rootfstype=ext4 rootwait coherent_pool=1m";
};
通过fdisk发现了一些蛛丝马迹,看到了分区信息。并且发现了一些眼熟的单词:GPT 和 MBR。装过系统的人,应该不陌生。
# fdisk -l
Found valid GPT with protective MBR; using GPT
Disk /dev/mmcblk0: 30535680 sectors, 2622M
Logical sector size: 512
Disk identifier (GUID): 7d3a0000-0000-4f4c-8000-4940000036c4
Partition table holds up to 128 entries
First usable sector is 34, last usable sector is 30535646
Number Start (sector) End (sector) Size Name
1 16384 24575 4096K uboot
2 24576 32767 4096K trust
3 40960 106495 32.0M boot
4 172032 237567 32.0M backup
5 368640 30535646 14.3G rootfs
Disk /dev/mmcblk0boot1: 4 MB, 4194304 bytes, 8192 sectors
128 cylinders, 4 heads, 16 sectors/track
Units: cylinders of 64 * 512 = 32768 bytes
Disk /dev/mmcblk0boot1 doesn't contain a valid partition table
Disk /dev/mmcblk0boot0: 4 MB, 4194304 bytes, 8192 sectors
128 cylinders, 4 heads, 16 sectors/track
Units: cylinders of 64 * 512 = 32768 bytes
Disk /dev/mmcblk0boot0 doesn't contain a valid partition table
FIRMWARE_VER: 8.1
MACHINE_MODEL: RK3399
MACHINE_ID: 007
MANUFACTURER: RK3399
MAGIC: 0x5041524B
ATAG: 0x00200800
MACHINE: 3399
CHECK_MASK: 0x80
PWR_HLD: 0,0,A,0,1
TYPE: GPT
CMDLINE: mtdparts=rk29xxnand:0x00002000@0x00004000(uboot),0x00002000@0x00006000(trust),0x00010000@0x0000a000(boot),0x00010000@0x0002a000(backup),-@0x0005a000(rootfs:grow)
uuid:rootfs=614e0000-0000-4b53-8000-1d28000054a9
发现了熟悉的 CMDLINE,其中的确包含了分区信息。既然这个文件在升级包中,他应该会被烧入emmc中。
可以阅读《Rockchip-Parameter-File-Format-Version1.4.pdf》文档,了解parameter.txt 文件中个字段的作用。
通过上图推断 parameter.txt 会烧写到emmc的0地址处, LOADER 也烧写在0地址出。这2个东西都烧写在emmc的0地址处,这个也太奇怪了吧。
我猜测:软件中可能设置了一个偏移量,其中的一个没有烧写在0地址处。
从上表可以看出: GPT 烧写下 emmc 的 0 地址,LOADER 烧写下 emmc 的 0x40 * 512 地址。可以说明(2)中我的猜测是正确的。
(1)读取emmc 0地址,读出的内容与 parameter.txt 不一致。
=> mmc read 0x0a200000 0 0x40
MMC read: dev # 0, block # 0, count 64 ... 64 blocks read: OK
=> md.b 0x0a200000 0x8000
(2) 读取 emmc 0x40 * 512 地址的内容,与 MiniLoaderAll.bin 不一致。
/* 从 0x40 * 512 地址,读取1K */
=> mmc read 0x0a200000 40 2
MMC read: dev # 0, block # 64, count 2 ... 2 blocks read: OK
=> md.b 0x0a200000 0x8000
(3) 我再测试读取了 emmc 0x4000 * 512 地址出的uboot,读取的内容是一致的。
结论: 我在uboot下读取emmc的数据是没有问题的,但是 parameter.txt 和 MiniLoaderAll.bin 却不一样,到底是为什么呢?继续往下看。
百度中也没有找到关于 parameter.txt 烧写位置的详细资料。想到了2点可以继续入手分析的地方。
(1)在uboot命令行中可以解析到分区信息,所以分析uboot源码,从 part list … 命令入手。大概看了下流程,涉及的函数调用也不少,暂未详细分析。
=> part list mmc 0
Partition Map for MMC device 0 -- Partition Type: EFI
Part Start LBA End LBA Name
Attributes
Type GUID
Partition GUID
1 0x00004000 0x00005fff "uboot"
attrs: 0x0000000000000000
type: 3b600000-0000-423e-8000-128b000058ca
guid: 727b0000-0000-4069-8000-68d500005dea
2 0x00006000 0x00007fff "trust"
attrs: 0x0000000000000000
type: bf570000-0000-440f-8000-42dc000079ef
guid: ff3c0000-0000-4d3a-8000-5e9c00006be6
3 0x0000a000 0x00019fff "boot"
attrs: 0x0000000000000000
type: 4f030000-0000-4744-8000-545300000e1e
guid: 0c240000-0000-4f6a-8000-207e00006722
4 0x0002a000 0x00039fff "backup"
attrs: 0x0000000000000000
type: d3460000-0000-4360-8000-37d9000037c0
guid: 81500000-0000-4f59-8000-166100000c05
5 0x0005a000 0x01d1efde "rootfs"
attrs: 0x0000000000000000
type: 33770000-0000-401d-8000-505400004c3e
guid: 614e0000-0000-4b53-8000-1d28000054a9
(2)分区信息中提到了GPT,GPT分区的资料网上一大把,所以考虑从GPT入手继续分析
MBR磁盘分区是一种使用最为广泛的分区结构,它也被称为DOS分区结构,但它并不仅仅应用于Windows系统平台,也应用于Linux,基于X86的UNIX等系统平台。它位于磁盘的0号扇区(一扇区等于512字节),是一个重要的扇区(简称MBR扇区)。
MBR扇区由以下四部分组成:
(1)引导代码:引导代码占MBR分区的前440字节,负责整个系统启动。如果引导代码被破坏,系统将无法启动。
(2)Windows磁盘签名:占引导代码后面的4字节,是Windows初始化磁盘写入的磁盘标签,如果此标签被破坏,则系统会提示“初始化磁盘”。
(3)MBR分区表:占Windows磁盘标签后面的64个字节,是整个硬盘的分区表。
(4)MBR结束标志:占MBR扇区最后2个字节,一直为“55 AA”。
GPT磁盘分区结构解决了MBR只能分4个主分区的的缺点,理论上说,GPT磁盘分区结构对分区的数量好像是没有限制的。但某些操作系统可能会对此有限制。GPT磁盘分区结构由6部分组成,与MBR对比如下图:
LBA地址和GPT分区结构的对应关系:
其中LBA0表示第一个扇区,占512字节。LBA1表示第二个扇区,以此类推。
(1)保护MBR
在GPT分区表的最开头(LBA0),处于兼容性考虑仍然存储了一份传统的MBR,用来防止不支持GPT的硬盘管理工具错误识别并破坏硬盘中的数据,这个MBR也叫做叫做保护MBR。
在linux系统中直接读取LBA0的数据进行分析:
# dd if=/dev/mmcblk0 skip=$((0x0)) count=1 | hexdump -C
00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
000001c0 00 00 ee 00 00 00 01 00 00 00 ff ff ff ff 00 00 |................|
000001d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
000001f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa |..............U.|
00000200
0x000001c0 - 2 地址是第一个主分区的分区表项开始地址.
在这个MBR中,只有一个标识为0xEE的分区,以此来表示这块硬盘使用GPT分区表。
MBR结束标志:占MBR扇区最后2个字节,一直为“55 AA”
(2)GPT分区表头
GPT分区表头(也称EFI信息)位于磁盘的1号扇区(LBA1),GPT分区表头会定义分区表的起始位置,分区表的结束位置、每个分区表项的大小、分区表项的个数及分区表的校验等信息。其具体结构如下表所示:
相对字节偏移量 (十六进制) | 字节数 | 说明[整数皆以little endian方式表示] |
---|---|---|
00~07 | 8 | GPT头签名“45 46 49 20 50 41 52 54”(ASCII码为“EFI PART”) |
08~0B | 4 | 版本号,目前是1.0版,其值是“00 00 01 00” |
0C~0F | 4 | GPT头的大小(字节数),通常为“5C 00 00 00”(0x5C),也就是92字节。 |
10~13 | 4 | GPT头CRC校验和(计算时把这个字段本身看做零值) |
14~17 | 4 | 保留,必须为“00 00 00 00” |
18~1F | 8 | EFI信息区(GPT头)的起始扇区号,通常为“01 00 00 00 00 00 00 00”,也就是LBA1。 |
20~27 | 8 | EFI信息区(GPT头)备份位置的扇区号,也就是EFI区域结束扇区号。通常是整个磁盘最末一个扇区。 |
28~2F | 8 | GPT分区区域的起始扇区号,通常为“22 00 00 00 00 00 00 00”(0x22),也即是LBA34。 |
30~37 | 8 | GPT分区区域的结束扇区号,通常是倒数第34扇区。 |
38~47 | 16 | 磁盘GUID(全球唯一标识符,与UUID是同义词) |
48~4F | 8 | 分区表起始扇区号,通常为“02 00 00 00 00 00 00 00”(0x02),也就是LBA2。 |
50~53 | 4 | 分区表总项数,通常限定为“80 00 00 00”(0x80),也就是128个。 |
54~57 | 4 | 每个分区表项占用字节数,通常限定为“80 00 00 00”(0x80),也就是128字节。 |
58~5B | 4 | 分区表CRC校验和 |
5C~* | * | 保留,通常是全零填充 |
在linux系统中直接读取LBA1的数据进行分析:
# dd if=/dev/mmcblk0 skip=$((0x1)) count=1 | hexdump -C
00000000 45 46 49 20 50 41 52 54 00 00 01 00 5c 00 00 00 |EFI PART....\...|
00000010 8d 7f 41 a7 00 00 00 00 01 00 00 00 00 00 00 00 |..A.............|
00000020 ff ef d1 01 00 00 00 00 22 00 00 00 00 00 00 00 |........".......|
00000030 de ef d1 01 00 00 00 00 00 00 3a 7d 00 00 4c 4f |..........:}..LO|
00000040 80 00 49 40 00 00 36 c4 02 00 00 00 00 00 00 00 |..I@..6.........|
00000050 80 00 00 00 80 00 00 00 5a 07 ba 30 00 00 00 00 |........Z..0....|
00000060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000200
a. GPT头的起始扇区号: 01
b. GPT头的备份位置的扇区号: 0x01d1efff
c. GPT分区区域的起始扇区号: 0x22,也即是LBA34
d. GPT分区区域的结束扇区号,通常是倒数第34扇区:0x01d1efde
e. GUID = 00 00 3a 7d 00 00 4c 4f 80 00 49 40 00 00 36 c4
f. 分区表起始扇区号:02
g. 分区表总项数: 128
h. 每个分区表项占用字节数: 128
i. 分区表CRC校验和: 5a 07 ba 30
查看写备份GPT头:
# dd if=/dev/mmcblk0 skip=$((0x1d1efff)) count=1 | hexdump -C
00000000 45 46 49 20 50 41 52 54 00 00 01 00 5c 00 00 00 |EFI PART....\...|
00000010 63 ea 98 31 00 00 00 00 ff ef d1 01 00 00 00 00 |c..1............|
00000020 01 00 00 00 00 00 00 00 22 00 00 00 00 00 00 00 |........".......|
00000030 de ef d1 01 00 00 00 00 00 00 3a 7d 00 00 4c 4f |..........:}..LO|
00000040 80 00 49 40 00 00 36 c4 df ef d1 01 00 00 00 00 |..I@..6.........|
00000050 80 00 00 00 80 00 00 00 5a 07 ba 30 00 00 00 00 |........Z..0....|
00000060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000200
对比结果:
a. 10~13Bytes:GPT头CRC校验和不一样,因为两个分区表不一样;
b. GPT头的起始、备份扇区号互换了,这个没有问题;
c. 分区表起始扇区号不一样,备份GPT头保存的是备份分区表起始扇区号。
(3)GPT分区表
GPT分区表位于磁盘的2-33号扇区(LBA2~32),一共占用32个扇区,能够容纳128个分区表项。每个分区表项大小为128字节。 每个分区表项中记录着分区的起始,结束地址,分区类型的GUID,分区的名字,分区属性和分区GUID。其具体结构如下表所示:
相对字节偏移量(十六进制) | 字节数 | 说明[整数皆以little endian方式表示] |
---|---|---|
00~0F | 16 | 用GUID表示的分区类型 |
10~1F | 16 | 用GUID表示的分区唯一标示符 |
20~27 | 8 | 该分区的起始扇区,用LBA值表示。 |
28~2F | 8 | 该分区的结束扇区(包含),用LBA值表示,通常是奇数。 |
30~37 | 8 | 该分区的属性标志 |
38~7F | 72 | UTF-16LE编码的人类可读的分区名称,最大32个字符。 |
注意: 扇区尺寸不能假定为512字节,也就是说,一个扇区内可能存放4个以上的分区项,也可能只存放一个分区项的一部分。也就是说,除了头两个扇区(LBA 0 和 LBA 1)之外,GPT规范仅定义了数据结构的尺寸,而不关心使用多少个扇区进行存储。
在linux系统中直接读取LBA2的数据进行分析:
#dd if=/dev/mmcblk0 skip=$((0x2)) count=1 | hexdump -C
00000000 00 00 60 3b 00 00 3e 42 80 00 12 8b 00 00 58 ca |..`;..>B......X.|
00000010 00 00 7b 72 00 00 69 40 80 00 68 d5 00 00 5d ea |..{r..i@..h...].|
00000020 00 40 00 00 00 00 00 00 ff 5f 00 00 00 00 00 00 |.@......._......|
00000030 00 00 00 00 00 00 00 00 75 00 62 00 6f 00 6f 00 |........u.b.o.o.|
00000040 74 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |t...............|
00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000080 00 00 57 bf 00 00 0f 44 80 00 42 dc 00 00 79 ef |..W....D..B...y.|
00000090 00 00 3c ff 00 00 3a 4d 80 00 5e 9c 00 00 6b e6 |..<...:M..^...k.|
000000a0 00 60 00 00 00 00 00 00 ff 7f 00 00 00 00 00 00 |.`..............|
000000b0 00 00 00 00 00 00 00 00 74 00 72 00 75 00 73 00 |........t.r.u.s.|
000000c0 74 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |t...............|
000000d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000100 00 00 03 4f 00 00 44 47 80 00 54 53 00 00 0e 1e |...O..DG..TS....|
00000110 00 00 24 0c 00 00 6a 4f 80 00 20 7e 00 00 67 22 |..$...jO.. ~..g"|
00000120 00 a0 00 00 00 00 00 00 ff 9f 01 00 00 00 00 00 |................|
00000130 00 00 00 00 00 00 00 00 62 00 6f 00 6f 00 74 00 |........b.o.o.t.|
00000140 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000180 00 00 46 d3 00 00 60 43 80 00 37 d9 00 00 37 c0 |..F...`C..7...7.|
00000190 00 00 50 81 00 00 59 4f 80 00 16 61 00 00 0c 05 |..P...YO...a....|
000001a0 00 a0 02 00 00 00 00 00 ff 9f 03 00 00 00 00 00 |................|
000001b0 00 00 00 00 00 00 00 00 62 00 61 00 63 00 6b 00 |........b.a.c.k.|
000001c0 75 00 70 00 00 00 00 00 00 00 00 00 00 00 00 00 |u.p.............|
000001d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000200
可以粗略的看出,LBA2中有4个分区表,uboot、trust、boot、backup。就其中的第一个分区uboot,进行分析:
a. GUID分区类型:00 00 60 3b 00 00 3e 42 80 00 12 8b 00 00 58 ca
b. GUID分区唯一标示符:00 00 7b 72 00 00 69 40 80 00 68 d5 00 00 5d ea
c. 分区的起始扇区:0x4000
d. 分区的结束扇区:0x5fff
e. 分区的属性标志:0x00
f. 分区名称(UTF-16LE编码):uboot
uboot分区的起始地址和大小与 parameter.txt 中的定义是一样的。
查看写备份GPT分区表:
# dd if=/dev/mmcblk0 skip=$((0x1d1efdf)) count=1 | hexdump -C
00000000 00 00 60 3b 00 00 3e 42 80 00 12 8b 00 00 58 ca |..`;..>B......X.|
00000010 00 00 7b 72 00 00 69 40 80 00 68 d5 00 00 5d ea |..{r..i@..h...].|
00000020 00 40 00 00 00 00 00 00 ff 5f 00 00 00 00 00 00 |.@......._......|
00000030 00 00 00 00 00 00 00 00 75 00 62 00 6f 00 6f 00 |........u.b.o.o.|
00000040 74 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |t...............|
00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000080 00 00 57 bf 00 00 0f 44 80 00 42 dc 00 00 79 ef |..W....D..B...y.|
00000090 00 00 3c ff 00 00 3a 4d 80 00 5e 9c 00 00 6b e6 |..<...:M..^...k.|
000000a0 00 60 00 00 00 00 00 00 ff 7f 00 00 00 00 00 00 |.`..............|
000000b0 00 00 00 00 00 00 00 00 74 00 72 00 75 00 73 00 |........t.r.u.s.|
000000c0 74 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |t...............|
000000d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000100 00 00 03 4f 00 00 44 47 80 00 54 53 00 00 0e 1e |...O..DG..TS....|
00000110 00 00 24 0c 00 00 6a 4f 80 00 20 7e 00 00 67 22 |..$...jO.. ~..g"|
00000120 00 a0 00 00 00 00 00 00 ff 9f 01 00 00 00 00 00 |................|
00000130 00 00 00 00 00 00 00 00 62 00 6f 00 6f 00 74 00 |........b.o.o.t.|
00000140 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000180 00 00 46 d3 00 00 60 43 80 00 37 d9 00 00 37 c0 |..F...`C..7...7.|
00000190 00 00 50 81 00 00 59 4f 80 00 16 61 00 00 0c 05 |..P...YO...a....|
000001a0 00 a0 02 00 00 00 00 00 ff 9f 03 00 00 00 00 00 |................|
000001b0 00 00 00 00 00 00 00 00 62 00 61 00 63 00 6b 00 |........b.a.c.k.|
000001c0 75 00 70 00 00 00 00 00 00 00 00 00 00 00 00 00 |u.p.............|
000001d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000200
对比结果:一模一样
(4)分区区域
uboot分区 : 0x00004000 ~ 0x00005fff
trust分区 : 0x00006000 ~ 0x00007fff
boot分区 :0x0000a000 ~ 0x00019fff
backup分区 :0x0002a000 ~ 0x00039fff
rootfs分区 :0x0005a000 ~ 0x01d1efde
(5)备份GPT分区表
(6)备份GPT分区表头