RK3399 GPT分区

RK3399 GPT分区

  • 前言
  • 一、RK3399烧写分区
  • 二、GPT分区
    • 1. MBR分区
    • 2. GPT分区
  • 总结
  • 参考资料

前言

之前学习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

一、RK3399烧写分区

  1. 将RK3399的升级包update.img解包后,发现有 parameter.txt 一个文件,内容如下:
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 文件中个字段的作用。

  1. 使用AndroidTool.exe烧写工具可以按分区烧写镜像,如下图:
    RK3399 GPT分区_第1张图片

通过上图推断 parameter.txt 会烧写到emmc的0地址处, LOADER 也烧写在0地址出。这2个东西都烧写在emmc的0地址处,这个也太奇怪了吧。
我猜测:软件中可能设置了一个偏移量,其中的一个没有烧写在0地址处。

  1. 阅读《Rockchip-Parameter-File-Format-Version1.4.pdf》文档,发现了一些奇怪的东西:
    RK3399 GPT分区_第2张图片
    这句话的意思是说, parameter.txt 不会烧录存储器件里面?
    还是 parameter.txt 中的 CMDLINE 不会烧录存储器件里面?
    RK3399 GPT分区_第3张图片(所有数值的单位是sector,1个sector为512Bytes)

从上表可以看出: GPT 烧写下 emmc 的 0 地址,LOADER 烧写下 emmc 的 0x40 * 512 地址。可以说明(2)中我的猜测是正确的。

  1. 在uboot中读取emmc中的内容,验证上面的内容。

(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

RK3399 GPT分区_第4张图片
RK3399 GPT分区_第5张图片
(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入手继续分析

二、GPT分区

1. MBR分区

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”。

2. GPT分区

GPT磁盘分区结构解决了MBR只能分4个主分区的的缺点,理论上说,GPT磁盘分区结构对分区的数量好像是没有限制的。但某些操作系统可能会对此有限制。GPT磁盘分区结构由6部分组成,与MBR对比如下图:
RK3399 GPT分区_第6张图片
LBA地址和GPT分区结构的对应关系:
RK3399 GPT分区_第7张图片
其中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

对比结果:一模一样
RK3399 GPT分区_第8张图片
(4)分区区域
uboot分区 : 0x00004000 ~ 0x00005fff
trust分区 : 0x00006000 ~ 0x00007fff
boot分区 :0x0000a000 ~ 0x00019fff
backup分区 :0x0002a000 ~ 0x00039fff
rootfs分区 :0x0005a000 ~ 0x01d1efde

(5)备份GPT分区表
(6)备份GPT分区表头

总结

  1. 采用GPT分区的方式,不是将 parameter.txt 文件保存在emmc的0地址处,而是将其中的CMDLINE信息解析为标准的GPT分区结构,保存在emmc的0地址处。
  2. 通过上面的分析,GPT分区结构占用了1(MBR)+ 1(GPT Header) + 32(GPT Entry) = 34个扇区,从LBA34~LBA63读取的数据都是0,从LBA64开始有数据,与文档中的)LOADER位置一致,但是为什么读出的数据与MiniLoaderAll.bin不一致,我也不知道,请知道高手指教下,谢谢。

参考资料

  1. Rockchip-Parameter-File-Format-Version1.4.pdf
  2. GPT 分区详解
  3. GPT分区表的备份与恢复

你可能感兴趣的:(RK3399,linux,分区表,uboot)