GPT全称是GUID Partition Table,它是一个分区表,用于描述系统内分区信息情况。通常的,机器在上电启动后,首先加载自己芯片本身的romcode,或者BIOS代码,然后由这些代码直接读取存储器上的gpt或mbr分区信息。在有了分区信息之后,代码就能正常的跳转到存储器的分区地址进行真正的引导(因为romcode会实现对gpt的解析),跳到存储器上运行的第一个程序,也就是bootloader或者grub。然后再由bootloader引导Linux内核再到系统上。
查看原始数据
root@kylin:~# dd if=/dev/mmcblk1 count=1 2>/dev/zero | 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.|
GPT的第一个逻辑块叫做保护MBR,用于防止基于 MBR 的引导程序的错误识别。也就是说,一些引导程序还是通过首先检查MBR分区来识别分区类型。
MBR的主要分布如下:
可以看到下面数据属于第一个分区条目
00 00 00 00 ee 00 00 00 01 00 00 00 ff ff ff ff
关于分区条目如下描述
由上可以知道,第一个0xee实际上就是分区种类,在《https://en.wikipedia.org/wiki/Partition_type#PID_EEh》
可以查到
也就是说,GPT会被MBR识别程序通过0x1c2地址上的值为0xee识别为GPT的保护MBR
同样,01 00 00 00 是分区中第一个绝对扇区的LBA。ff ff ff ff 是该分区的扇区数目,55 aa 是MBR的最后签名。
查看原始数据
root@kylin:~# dd if=/dev/mmcblk1 count=1 skip=1 2>/dev/zero | hexdump -C 00000000 45 46 49 20 50 41 52 54 00 00 01 00 5c 00 00 00 |EFI PART....\...| 00000010 63 0f bd fd 00 00 00 00 01 00 00 00 00 00 00 00 |c...............| 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 47 f9 00 00 53 41 |..........G...SA| 00000040 80 00 24 75 00 00 12 a2 02 00 00 00 00 00 00 00 |..$u............| 00000050 80 00 00 00 80 00 00 00 fa d0 f2 c2 00 00 00 00 |................| 00000060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
需要留意:
备份分区地址: ff ef d1 01 00 00 00 00 也就是0x01d1efff,而最后一个可用LBA是 de ef d1 01 00 00 00 00 也就是 0x01d1efde。把这两者相减可得,最后留了34个扇区
root@kylin:~# echo $((0x01d1efff-0x01d1efde+1)) 34
dd可以查看备份LBA的GPT头如下
root@kylin:~# dd if=/dev/mmcblk1 skip=$((0x01d1efff)) count=1 2>/dev/null| hexdump -C 00000000 45 46 49 20 50 41 52 54 00 00 01 00 5c 00 00 00 |EFI PART....\...| 00000010 8d 9a 64 6b 00 00 00 00 ff ef d1 01 00 00 00 00 |..dk............| 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 47 f9 00 00 53 41 |..........G...SA| 00000040 80 00 24 75 00 00 12 a2 df ef d1 01 00 00 00 00 |..$u............| 00000050 80 00 00 00 80 00 00 00 fa d0 f2 c2 00 00 00 00 |................| 00000060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
结合GPT分区的分布如下:
也就是说,最后从-1到-34个扇区,是备份的GPT分区。
磁盘UUID在0x38-0x48。也就是如下数据
00 00 47 f9 00 00 53 41 80 00 24 75 00 00 12 a2
在上层可以通过命令对应起来
root@kylin:~# gdisk /dev/mmcblk1 -l 2>/dev/zero| grep GUID | awk -F : '{print $2}' | sed "s/ //g" F9470000-0000-4153-8000-2475000012A2
查看原始数据
root@kylin:~# dd if=/dev/mmcblk1 skip=2 count=32 2>/dev/null | hexdump -C 00000000 00 00 23 6e 00 00 42 49 80 00 37 43 00 00 53 af |..#n..BI..7C..S.| 00000010 00 00 7f 46 00 00 28 4f 80 00 35 3d 00 00 04 d9 |...F..(O..5=....| 00000020 00 80 00 00 00 00 00 00 ff 7f 02 00 00 00 00 00 |................| 00000030 00 00 00 00 00 00 00 00 62 00 6f 00 6f 00 74 00 |........b.o.o.t.| 00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 00000080 00 00 1c e2 00 00 08 43 80 00 0e 64 00 00 41 73 |.......C...d..As| 00000090 00 00 4e 61 00 00 53 4b 80 00 1d 28 00 00 54 a9 |..Na..SK...(..T.| 000000a0 00 80 03 00 00 00 00 00 de ef d1 01 00 00 00 00 |................| 000000b0 00 00 00 00 00 00 00 00 72 00 6f 00 6f 00 74 00 |........r.o.o.t.| 000000c0 66 00 73 00 00 00 00 00 00 00 00 00 00 00 00 00 |f.s.............| 000000d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
相信从右边的ascii可以大概猜得出来了,这就是真正的具体分区内容了。其中具体信息解析如下:
首先的16字节是分区的GUID,这个是用来标识分区类型的ID,是标准分配的。
第二个16字节是分区存在于系统中的GUID,可以与如下命令对应
root@kylin:~# ls -lh /dev/disk/by-partuuid/ | grep mmcblk1p1 | awk '{print $9}' 467f0000-0000-4f28-8000-353d000004d9
接下来16字节是 LBA的开始和结束地址
00 80 00 00 00 00 00 00 ff 7f 02 00 00 00 00 00
这里可以看到起始地址为0x00008000,结束地址为0x00027fff
root@kylin:~# gdisk -l /dev/mmcblk1 2>/dev/null | grep Number -A2 | tail -n 2 1 32768 163839 64.0 MiB FFFF boot 2 229376 30535646 14.5 GiB FFFF rootfs
这里boot分区的起始扇区和结束扇区是对应的。
root@kylin:~# echo $((0x8000)) $((0x00027fff)) 32768 163839
最后从0x38开始的72字节为分区的名字。这里可以直接通过ascii查看到。
env set partitions "name=boot,size=64M,start=16M;name=rootfs,start=112M,size=-,uuid=614e0000-0000-4b53-8000-1d28000054a9;" gpt write mmc 0 $partitions gpt verify mmc 0 $partitions
设置两个分区,boot分区从16M开始大小为64M,rootfs分区从112M开始,大小为分区的所有空间,uuid为614e0000-0000
修改后,uboot读取gpt分区信息如下。
=> 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 0x00008000 0x00027fff "boot" attrs: 0x0000000000000000 type: ebd0a0a2-b9e5-4433-87c0-68b6b72699c7 guid: da6ed6e6-16f0-415f-95bf-e0721f8721ea 2 0x00038000 0x01d1efde "rootfs" attrs: 0x0000000000000000 type: ebd0a0a2-b9e5-4433-87c0-68b6b72699c7 guid: 614e0000-0000-4b53-8000-1d28000054a9
上述操作对应的RK paramter分区表为如下:
CMDLINE:mtdparts=rk29xxnand:0x0020000@0x00008000(boot),-@0x00038000(rootfs:grow) uuid:rootfs=614e0000-0000-4b53-8000-1d28000054a9
cat /proc/cmdline storagemedia=emmc androidboot.storagemedia=emmc androidboot.mode=normal androidboot.verifiedbootstate=orange androidboot.slot_suffix= androidboot.serialno=42036bf58040a13f rw rootwait earlycon=uart8250,mmio32,0xff1a0000 swiotlb=1 console=tty0 console=ttyFIQ0 root=PARTUUID=614e0000-0000 rootfstype=ext4 coherent_pool=1m
可以发现系统启动通过root=PARTUUID=614e0000-0000,所以修改分区名字不会导致系统无法正常启动
gdisk /dev/mmcblk1 Command (? for help): c Partition number (1-2): 2 Enter name: test_rootfs Command (? for help): p Disk /dev/mmcblk1: 30535680 sectors, 14.6 GiB Sector size (logical/physical): 512/512 bytes Disk identifier (GUID): E3550000-0000-443E-8000-27FC000002AA Partition table holds up to 128 entries Main partition table begins at sector 2 and ends at sector 33 First usable sector is 34, last usable sector is 30535646 Partitions will be aligned on 2048-sector boundaries Total free space is 98270 sectors (48.0 MiB) Number Start (sector) End (sector) Size Code Name 1 32768 163839 64.0 MiB FFFF boot 2 229376 30535646 14.5 GiB FFFF test_rootfs Command (? for help): w Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING PARTITIONS!! Do you want to proceed? (Y/N): y OK; writing new GUID partition table (GPT) to /dev/mmcblk1. Warning: The kernel is still using the old partition table. The new table will be used at the next reboot or after you run partprobe(8) or kpartx(8) The operation has completed successfully. partprobe /dev/mmcblk1
重启后,查看分区名字信息
root@kylin:/home/kylin# gdisk -l /dev/mmcblk1 GPT fdisk (gdisk) version 1.0.5 Partition table scan: MBR: protective BSD: not present APM: not present GPT: present Found valid GPT with protective MBR; using GPT. Disk /dev/mmcblk1: 30535680 sectors, 14.6 GiB Sector size (logical/physical): 512/512 bytes Disk identifier (GUID): E3550000-0000-443E-8000-27FC000002AA Partition table holds up to 128 entries Main partition table begins at sector 2 and ends at sector 33 First usable sector is 34, last usable sector is 30535646 Partitions will be aligned on 2048-sector boundaries Total free space is 98270 sectors (48.0 MiB) Number Start (sector) End (sector) Size Code Name 1 32768 163839 64.0 MiB FFFF boot 2 229376 30535646 14.5 GiB FFFF test_rootfs
除了可以修改名字之外,实际上还可以修改,分区大小,分区UUID等各种处理。但这些处理并不能保证系统在修改之后仍可以无故障的启动。这里不做演示了。
GPT的wiki:https://en.wikipedia.org/wiki/GUID_Partition_Table
Uboot中对gpt的描述:https://github.com/u-boot/u-boot/blob/master/doc/README.gpt
RK平台本身的GPT描述:http://opensource.rock-chips.com/wiki_Partitions
MBR格式介绍:https://wiki.osdev.org/MBR_(x86)