告别迷茫!手把手教你用fdisk和dd命令分析RK3399的GPT分区表
深入解析RK3399的GPT分区表:从命令行工具到实战排查
当你第一次拿到一块预装系统的RK3399开发板时,可能会对eMMC或SD卡的分区结构感到困惑。官方文档往往语焉不详,而图形化工具又无法满足深度调试需求。本文将带你使用最基础的Linux命令行工具,一步步揭开GPT分区表的神秘面纱。
1. 准备工作与环境搭建
在开始分析之前,我们需要确保开发环境准备就绪。首先通过USB转串口工具连接RK3399开发板的调试串口,使用终端工具(如minicom或screen)建立串口连接。启动开发板后,登录Linux系统。
确认系统识别到的存储设备:
lsblk
这个命令会列出所有块设备,通常eMMC会显示为/dev/mmcblk0,而SD卡可能是/dev/mmcblk1。
安装必要的工具链:
sudo apt update
sudo apt install fdisk hexdump util-linux
关键检查点:
- 确认当前用户有访问块设备的权限(通常需要root)
- 确保不会对存储设备进行写操作,避免意外损坏分区表
- 准备备用存储设备以防万一需要恢复数据
警告:直接操作块设备存在风险,建议在操作前先完整备份重要数据
2. 初步探查:使用fdisk分析分区结构
fdisk是最基础也是最强大的分区表分析工具之一。让我们首先查看设备的分区信息:
fdisk -l /dev/mmcblk0
典型输出可能如下:
Disk /dev/mmcblk0: 14.6 GiB, 15634268160 bytes, 30535680 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 7D3A0000-0000-4F4C-8000-4940000036C4
Device Start End Sectors Size Name
/dev/mmcblk0p1 16384 24575 8192 4M uboot
/dev/mmcblk0p2 24576 32767 8192 4M trust
/dev/mmcblk0p3 40960 106495 65536 32M boot
/dev/mmcblk0p4 172032 237567 65536 32M backup
/dev/mmcblk0p5 368640 30535646 30167007 14.3G rootfs
从输出中我们可以获取以下关键信息:
- 磁盘使用GPT分区表(Disklabel type: gpt)
- 磁盘总大小和扇区信息
- 各分区的起始/结束扇区、大小和名称
常见问题排查:
- 如果fdisk报告"无效的GPT签名",可能是分区表损坏
- 某些嵌入式系统可能使用混合MBR/GPT布局,需要特别注意
3. 深入GPT结构:使用dd和hexdump
GPT分区表的结构远比表面看到的复杂。让我们用底层工具直接读取和分析磁盘的原始数据。
3.1 保护性MBR分析
GPT分区表在LBA0(第一个扇区)保留了传统的MBR结构,主要用于兼容性:
dd if=/dev/mmcblk0 bs=512 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 ff ff ff 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
保护性MBR的关键特征:
- 0x1BE-0x1FD:分区表项(通常只有一个类型为0xEE的分区)
- 0x1FE-0x1FF:MBR签名(0x55AA)
3.2 GPT头分析
GPT头位于LBA1,包含分区表的元信息:
dd if=/dev/mmcblk0 bs=512 skip=1 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
GPT头的重要字段解析:
| 偏移量 | 长度 | 描述 | 示例值 |
|---|---|---|---|
| 0x00 | 8 | 签名 ("EFI PART") | 45 46 49 20 50 41 52 54 |
| 0x08 | 4 | 版本 (1.0) | 00 00 01 00 |
| 0x20 | 8 | 分区区域起始LBA | 22 00 00 00 00 00 00 00 (LBA34) |
| 0x28 | 8 | 分区区域结束LBA | de ef d1 01 00 00 00 00 |
| 0x48 | 8 | 分区表起始LBA | 02 00 00 00 00 00 00 00 (LBA2) |
| 0x50 | 4 | 分区表项数量 | 80 00 00 00 (128) |
| 0x54 | 4 | 分区表项大小 | 80 00 00 00 (128字节) |
3.3 分区表项分析
分区表从LBA2开始,通常占用32个扇区(LBA2-33)。每个分区表项128字节,因此每个扇区可以存放4个分区表项。
读取第一个分区表项:
dd if=/dev/mmcblk0 bs=512 skip=2 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...............|
分区表项结构解析:
| 偏移量 | 长度 | 描述 | 示例值 |
|---|---|---|---|
| 0x00 | 16 | 分区类型GUID | 00 00 60 3b ... 58 ca |
| 0x10 | 16 | 分区唯一GUID | 00 00 7b 72 ... 5d ea |
| 0x20 | 8 | 起始LBA | 00 40 00 00 00 00 00 00 (0x4000) |
| 0x28 | 8 | 结束LBA | ff 5f 00 00 00 00 00 00 (0x5fff) |
| 0x30 | 8 | 属性标志 | 00 00 00 00 00 00 00 00 |
| 0x38 | 72 | 分区名(UTF-16LE) | 75 00 62 00 ... (uboot) |
4. 实战案例:分区表问题排查
在实际开发中,你可能会遇到各种分区表相关的问题。以下是几个常见场景及其解决方法。
4.1 分区表损坏恢复
当系统无法启动且怀疑分区表损坏时,可以尝试以下步骤:
- 检查GPT头签名:
dd if=/dev/mmcblk0 bs=512 skip=1 count=1 | hexdump -C | head -n 1
应该显示"EFI PART"签名(45 46 49 20 50 41 52 54)
- 如果主GPT头损坏,尝试使用备份GPT头:
# 首先获取磁盘最后LBA
total_sectors=$(blockdev --getsz /dev/mmcblk0)
# 读取备份GPT头(位于最后一个扇区)
dd if=/dev/mmcblk0 bs=512 skip=$(($total_sectors-1)) count=1 | hexdump -C
- 如果备份GPT头完好,可以尝试恢复:
# 将备份GPT头恢复到主位置
dd if=/dev/mmcblk0 bs=512 skip=$(($total_sectors-1)) count=1 of=/dev/mmcblk0 seek=1
4.2 分区与parameter.txt不一致
RK3399平台通常使用parameter.txt文件定义分区布局,但实际分区表可能与之不一致。验证步骤:
- 提取parameter.txt中的分区信息:
grep "CMDLINE" parameter.txt
示例输出:
CMDLINE: mtdparts=rk29xxnand:0x00002000@0x00004000(uboot),0x00002000@0x00006000(trust),0x00010000@0x0000a000(boot),0x00010000@0x0002a000(backup),-@0x0005a000(rootfs:grow)
- 与实际分区表对比:
fdisk -l /dev/mmcblk0
- 使用以下命令将parameter.txt中的分区信息转换为fdisk可识别的格式:
# 简易转换脚本示例
def convert_param_to_sectors(param):
parts = param.split('@')
start = int(parts[0].split(':')[-1], 16) // 512
size = int(parts[1].split('(')[0], 16) // 512
return start, size
4.3 分区扩容实战
当rootfs分区空间不足时,可以按照以下步骤扩容:
- 使用parted工具调整分区表:
parted /dev/mmcblk0
(parted) resizepart 5 100%
(parted) quit
- 调整文件系统大小:
resize2fs /dev/mmcblk0p5
- 验证调整结果:
df -h
注意:分区调整操作有风险,务必先备份重要数据
5. 高级技巧与自动化工具
对于需要频繁分析分区表的开发者,可以创建一些便捷的工具和脚本。
5.1 自定义GPT分析脚本
以下是一个简单的bash脚本,用于快速显示GPT关键信息:
#!/bin/bash
DEVICE=${1:-/dev/mmcblk0}
# 读取保护性MBR
echo "=== Protective MBR ==="
dd if=$DEVICE bs=512 count=1 2>/dev/null | hexdump -C | grep -A1 -B1 "55 aa"
# 读取GPT头
echo -e "\n=== GPT Header ==="
HEADER=$(dd if=$DEVICE bs=512 skip=1 count=1 2>/dev/null | hexdump -C)
echo "$HEADER" | head -n 8
# 读取分区表项
echo -e "\n=== Partition Entries ==="
ENTRIES=$(dd if=$DEVICE bs=512 skip=2 count=32 2>/dev/null | hexdump -C)
echo "$ENTRIES" | grep -A3 -B3 "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"
5.2 分区表备份与恢复
定期备份分区表是良好的实践:
# 备份GPT分区表
dd if=/dev/mmcblk0 bs=512 count=34 of=gpt_backup.bin
# 恢复GPT分区表
dd if=gpt_backup.bin of=/dev/mmcblk0 bs=512
5.3 与uboot交互
在uboot环境中也可以分析分区表:
=> mmc part
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
6. 性能优化与最佳实践
在处理大容量存储设备时,直接使用dd可能会很慢。以下是一些优化技巧:
- 使用更大的块大小提高读取效率:
dd if=/dev/mmcblk0 bs=1M count=1 | hexdump -C
- 仅读取必要的部分数据:
# 只读取GPT头和相关分区表项
dd if=/dev/mmcblk0 bs=512 skip=1 count=33 | hexdump -C
- 使用更专业的工具替代dd:
hdparm --read-sector 0 /dev/mmcblk0 # 读取单个扇区
- 在内存中进行分析,减少I/O操作:
# 将分区表读入内存文件系统
mkdir -p /mnt/tmpfs
mount -t tmpfs tmpfs /mnt/tmpfs
dd if=/dev/mmcblk0 of=/mnt/tmpfs/gpt_dump.bin bs=512 count=34
对于嵌入式开发者来说,理解GPT分区表的底层结构不仅能帮助解决实际问题,还能在系统设计和优化时做出更明智的决策。记住,每次操作前做好备份,谨慎对待每一个写操作命令。
更多推荐



所有评论(0)