博通机顶盒平台GPT分区和制作工具

0. 前言

本文基于Broadcom机顶盒平台,介绍GPT分区的特点,并重点描述了如何通过开源的sgdisk工具和博通Android包自带的makegpt工具在博通机顶盒平台上进行GPT分区设置。

内容较长,以下为直通车:

  • 只想了解GPT的特点,请参考1.2 GPT设备的特点
  • 只想通过sgdisk进行分区划分,请参考2.2 sgdisk分区实例
  • 只想通过makegpt生成GPT数据,请参考3.2 makegpt分区实例

1. GPT介绍

1.1 GPT介绍

本文略过GPT的各种细节,详细资料可以参考以下页面:

1.2 GPT设备的特点

总体上GPT分区的布局如下:

GPT 布局

归结起来,GPT设备有以下特点:

  1. 设备由若干的逻辑块LBA (Logic Block Addressing)组成,单个LBA大小为512字节
  2. LBA 0用于兼容传统的MBR,也称作”Protective MBR
  3. 设备有两个GPT镜像数据,每个占用33个LBA
    • LBA 1开始的Primary GPT
      • LBA 1存放Primary GPT Header
      • LBA 2 - LBA 33,总计32块用于存放分区信息
    • LBA - 1结束的Secondary GPT
      • LBA-33 - LBA-2,总计32块用于存放分区信息
      • LBA-1存放Secondary GPT Header
  4. 数据存放到设备中间的LBA 34 - LBA-34区域

1.3 GPT Header的格式

GPT Header占用一个完整的LBA,以Primary GPT Header为例,在LBA 1中的格式如下:

OffsetLengthContents
0 (0x00)8 bytesSignature (“EFI PART”, 45h 46h 49h 20h 50h 41h 52h 54h on little-endian machines)
8 (0x08)4 bytesRevision (for GPT version 1.0, the value is 00h 00h 01h 00h)
12 (0x0C)4 bytesHeader size in little endian (in bytes, usually 5Ch 00h 00h 00h or 92 bytes)
16 (0x10)4 bytesCRC32 of header (offset +0 up to header size), with this field zeroed during calculation
20 (0x14)4 bytesReserved; must be zero
24 (0x18)8 bytesCurrent LBA (location of this header copy)
32 (0x20)8 bytesBackup LBA (location of the other header copy)
40 (0x28)8 bytesFirst usable LBA for partitions (primary partition table last LBA + 1)
48 (0x30)8 bytesLast usable LBA (secondary partition table first LBA - 1)
56 (0x38)16 bytesDisk GUID (also referred as UUID on UNIXes)
72 (0x48)8 bytesStarting LBA of array of partition entries (always 2 in primary copy)
80 (0x50)4 bytesNumber of partition entries in array
84 (0x54)4 bytesSize of a single partition entry (usually 80h or 128)
88 (0x58)4 bytesCRC32 of partition array
92 (0x5C)*Reserved; must be zeroes for the rest of the block

以下是一个实际的Primary GPT Header例子:

GPT Header Example

这里从第二个LBALBA 1开始,其偏移地址为0x200,每个字段解释如下:

  1. 0x200-0x207GPT头签名, "45 46 49 20 50 41 52 54"(ASCII: "EFI PART")
  2. 0x208-0x20B, 版本号, 00 00 01 00,表示1.0
  3. 0x20C-0x20FGPT头大小, 5C 00 00 00 ,(小端)表示0x5C (92)字节
  4. 0x210-0x203GPTCRC校验和(计算时把这个字段本身看做零值),“
  5. 0x214-0x217, 预留,00 00 00 00
  6. 0x218-0x21F, 当前GPT头的起始扇区号,01 00 00 00 00 00 00 00,即LBA 1
  7. 0x220-0x227, 备份GPT头的起始扇区号,FF FF E8 00 00 00 00 00
  8. 0x228-0x22F,分区起始扇区号,06 00 00 00 00 00 00 00,即LBA 6,通常会从LBA 34开始
  9. 0x230-0x237,分区结束扇区号,FA FF E8 00 00 00 00 00
  10. 0x238-0x247,设备GUID33 C4 B9 43 06 A1 BF 68 AF F4 89 04 16 FC 87 D7
  11. 0x248-0x24F,分区表起始扇区号,02 00 00 00 00 00 00 00,即LBA 2
  12. 0x250-0x253,分区表总项数,0D 00 00 00,即13项,通常为128项
  13. 0x254-0x257,单个分区表占用字节数,80 00 00 00,即128字节
  14. 0x248-0x25B,分区表CRC校验和,D4 6A D8 FB
  15. 0x25C-0x39F,预留,填充全0

从上面的第12,13项看,一个LBA可以存放4个分区项,13个分区项总共占用4个LBA,再加上LBA 0和用于存放GPT HeaderLBA 1,因此这里设备开始处整个GPT占用6个LBA,即LBA 0 - LBA 5,所以第8项指出分区的起始扇区号为LBA 6

从主GPT反推备份GPT,显然备份GPT只占用尾部的5个LBA(1个LBA存放GPT头,4个LBA存放13个分区项),而并非预期的33个。

1.4 Partition Entry的格式

GPT Header中定义了Partition Entry的数目(0x50)和大小(0x54),单个Partition Entry的大小通常为128字节,所以一个LBA可以存放4项。

GUID partition entry format

OffsetLengthContents
0 (0x00)16 bytesPartition type GUID
16 (0x10)16 bytesUnique partition GUID
32 (0x20)8 bytesFirst LBA (little endian)
40 (0x28)8 bytesLast LBA (inclusive, usually odd)
48 (0x30)8 bytesAttribute flags (e.g. bit 60 denotes read-only)
56 (0x38)72 bytesPartition name (36 UTF-16LE code units)

对于分区属性,Microsoft定义的基本分区属性有:

Basic data partition attributes

BitValueContent
600x0001000000000000Read-only
610x0002000000000000Shadow copy (of another partition)
620x0004000000000000Hidden
630x0008000000000000No drive letter (i.e. do not automount)

以上Partition Entry的描述中,比较直观的有:

  • offset 0x20, 起始LBA
  • offset 0x28, 结束LBA
  • offset 0x30, 分区属性
  • offset 0x38, 分区名称

这几个属性在工具sgdiskmakegpt的参数中都有体现。

以下是一个Partition Entry的例子:
<code>Partition Entry Exmaple</code>

这里从第三个LBALBA 2开始,其偏移地址为0x400,每个字段解释如下:

  1. 0x400-0x40F,分区类型GUID"A2 A0 D0 EB E5 B9 33 44 87 C0 68 B6 B7 26 99 C7",转换为GUIDEBD0A0A2-B9E5-4433-87C0-68B6B72699C7,相应的分区类型为“基本数据分区”
  2. 0x410-0x41F,分区的GUID1F 29 CA 94 2B 2A FE DE 0D 52 7D 9C 5C 91 55 8A
  3. 0x420-0x427,分区起始扇区号,22 00 00 00 00 00 00 00,表示从第0x22个LBALBA 34开始
  4. 0x428-0x42F,分区结束扇区号,22 00 00 00 00 00 00 00,表示分区在第0x22个LBA结束,即该分区只占用了1个LBA
  5. 0x430-0x437,分区属性,00 00 00 00 00 00 00 00
  6. 0x438-0x47F,分区名称,这里为"macadr"

从上图可见,在LBA 2上(区域0x400-0x5FF),共存放了4个分区项,分区类型都是“基本数据分区”,其名称分别为"macadr","nvram","bsu"和"misc"

2. sgdisk工具

sgdiskLinux上用于创建GPT分区的工具,官方网站GPT fdisk Tutorial

2.1 sgdisk的参数

sgdisk的参数非常多,可以在命令行运行sgdisk --help获得详细信息。
也可以参考sgdisk的帮助页面:sgdisk man page,该页面对每一个选项都有详细的描述。

简单讲,sgdisk的使用如下:

sgdisk [ options ] device`

如:sgdisk -p /dev/mmcblk0,显示eMMC设备/dev/mmcblk0上的分区信息。

2.1.1 sgdisk常用的选项
  • -c, --change-name=partnum:name,设置分区partnum的名字
  • -d, --delete=partnum,删除指定编号partnum的分区
  • -E, --end-of-largest,显示设备最大的可用sector值,由于GPT在设备顶端还有一个镜像数据,所以该值为Secondary GPT的下边界,即LBA - 34
  • -n, --new=partnum:start:end,创建指定编号为partnum的分区,且该分区的起始LBA分别为startend
  • -p, --print,摘要显示GPT分区信息,包括设备和分区的信息
  • -o, --clear,清除设备的分区数据
2.1.2 sgdisk的一些其它选项
  • -a, --set-alignment=value,设置分区对齐的方式,以sector为单位,默认为2048(2048 x 512 = 1MB),即1MB边界对齐
  • -A, --attributes=list|[partnum:show|or|nand|xor|=|set|clear|toggle|get[:bitnum|hexbitmask]],设置分区partnum的属性
  • -b, --backup=file,备份分区数据到文件file
  • -i, --info=partnum,显示指定分区partnum的详细信息
  • -l, --load-backup=file,从文件file加载分区数据
  • -v, --verify,校验GPT数据,该命令可以检查发现较多问题,如CRC不正确,Primary GPTSecondary GPT不匹配等。

2.2 sgdisk的实例

以下是在一个4G的eMMC上创建分区的例子:

2.2.1 待分区数据
分区号起始LBA号结束LBA号分区大小名称
134545256.0 KiBmacadr
25461057256.0 KiBnvram
310581569256.0 KiBbsu
4157036171024.0 KiBmisc
536186651024.0 KiBhwcfg
656667120132.0 MiBboot
77120213673732.0 MiBrecovery
813673822338891024.0 MiBcache
9223389043310411024.0 MiBsystem
10433104264281931024.0 MiBuserdata
1164289147733214636.9 MiBstorage
2.2.2 分区命令
sgdisk -o /dev/mmcblk0
sgdisk -a 1 -n 1:34:545 -c 1:"macadr" /dev/mmcblk0
sgdisk -a 1 -n 2:546:1057 -c 2:"nvram" /dev/mmcblk0
sgdisk -a 1 -n 3:1058:1569 -c 3:"bsu" /dev/mmcblk0
sgdisk -a 1 -n 4:1570:3617 -c 4:"misc" /dev/mmcblk0
sgdisk -a 1 -n 5:3618:5665 -c 5:"hwcfg" /dev/mmcblk0
sgdisk -a 1 -n 6:5666:71201 -c 6:"boot" /dev/mmcblk0
sgdisk -a 1 -n 7:71202:136737 -c 7:"recovery" /dev/mmcblk0
sgdisk -a 1 -n 8:136738:2233889 -c 8:"cache" /dev/mmcblk0
sgdisk -a 1 -n 9:2233890:4331041 -c 9:"system" /dev/mmcblk0
sgdisk -a 1 -n 10:4331042:6428193 -c 10:"userdata" /dev/mmcblk0
sgdisk -n 11:6428914:`sgdisk -E /dev/mmcblk0` -c 11:"storage" /dev/mmcblk0

以上命令中,

  • 先用sgdisk -o /dev/mmcblk0选项清空设备上的分区数据,
  • 然后再用sgdisk -n -c选项逐个划分了编号为1-11的分区,
  • 其中最后一个分区的结束位置通过命令sgdisk -E /dev/mmcblk0来取得。
2.2.3 显示分区

执行完成后,用sgdisk -p命令查看刚才划分的分区:

# sgdisk -p /dev/mmcblk0
Disk /dev/mmcblk0: 7733248 sectors, 3.7 GiB
Logical sector size: 512 bytes
Disk identifier (GUID): 782D35FD-F9E9-45F1-85FF-AD5E25034F86
Partition table holds up to 128 entries
First usable sector is 34, last usable sector is 7733214
Partitions will be aligned on 2-sector boundaries
Total free space is 720 sectors (360.0 KiB)

Number  Start (sector)    End (sector)  Size       Code  Name
   1              34             545   256.0 KiB   8300  macadr
   2             546            1057   256.0 KiB   8300  nvram
   3            1058            1569   256.0 KiB   8300  bsu
   4            1570            3617   1024.0 KiB  8300  misc
   5            3618            5665   1024.0 KiB  8300  hwcfg
   6            5666           71201   32.0 MiB    8300  boot
   7           71202          136737   32.0 MiB    8300  recovery
   8          136738         2233889   1024.0 MiB  8300  cache
   9         2233890         4331041   1024.0 MiB  8300  system
  10         4331042         6428193   1024.0 MiB  8300  userdata
  11         6428914         7733214   636.9 MiB   8300  storage

使用sgdisk进行划分时,需要提供start:end参数,对于每个分区都需要进行计算才能得到这个参数,分区数量多的情况下还容易出错,操作起来不太方便。

2.3 sgdisk的其它实例

  • 打印分区信息

    # sgdisk -p /dev/mmcblk0

  • 清除分区信息

    # sgdisk -o /dev/mmcblk0

  • 设置分区属性

    将partition 9设置为只读(属性 bit 60置1):

    # sgdisk -A 9:set:60 /dev/mmcblk0

  • 备份GPT数据

    将GPT数据备份到文件gpt.bin:

    # sgdisk -b gpt.bin /dev/mmcblk0

  • 加载GPT数据

    从文件gpt.bin恢复GPT数据:
    # sgdisk -l gpt.bin /dev/mmcblk0

  • 校验GPT数据

    # sgdisk -v /dev/mmcblk0

3. makegpt工具

sgdisk进行划分需要精确计算每个分区的起始和结束位置,不太方便;另外,生产线上运行sgdisk命令创建分区会影响流水线效率,如果能预先制作好GPT数据,生产时直接写入设备的相应位置就更好了。

博通机顶盒平台的Android系统提供了一个makegpt工具,该工具通过读取一个比较直观的配置文件来生成GPT数据,然后只需要将生成的gpt.bin写到eMMC设备的起始位置即可,解决了sgdisk运行不方便的问题。

Android 7.1release包为例,工具makegpt相关的文件有:

  • makegpt源码:vendor\broadcom\bcm_platform\tools\makegpt
  • GPT分区的配置数据:device\broadcom\common\gpts\default.conf
  • 编译后生成的makegpt工具:out\host\linux-x86\bin\makegpt
  • 编译后生成的gpt.bin数据:out\target\product\bcm{board}\gpt.bin

3.1 makegpt的参数

Android根目录下执行makegpt --help得到的用法如下:

$ out/host/linux-x86/bin/makegpt -help 
Usage: makegpt [options] partitionName,startaddr,size,attr [...]...
where options may be one of:
  -b base_address     base address of partition table (mandatory)
  -s total_disk_size  total disk size in bytes (mandatory)
  -a                  generate alternate GPT table instead
  -o  outputfile      output file (mandatory)
  -v  level           turns on verbose mode. 0=off, 1=normal, 2=debug, 3=noisy
  -h                  prints this help

  startaddr can be '-' to guess based on previous startaddr+size.
  size can be '-' to guess based on next startaddr.
  startaddr and size can be a hex value or a value with suffix K, M, or G.

Example: makegpt -a -b 0x60000 -o gpt_alt.bin -s 0x1e0000000 -- image1,0x10000,0x10000,0 image2,-,64k,0 image3,0x30000,0x30000,0 image4,0x90000,-,0

从上面的help信息可见,makegpt的使用方式为:

makegpt [options] partitionName,startaddr,size,attr [...]...

其中,对每个分区的设置如下:

  • partitionName,指定分区名字
  • startaddr,指定分区起始地址,如果为“-”,则基于上一分区的起始地址和大小进行计算,即 previous startaddr + size
  • size,指定分区的大小,如果为“-”,则基于下一分区的起始地址进行计算
  • attr,指定分区的属性,例如Androidsystem分区指定属性0x0001000000000000(bit 48置1)

3.2 GPT分区配置文件

这里的GPT分区配置文件default.conf默认的内容为:

-s 7818182656 -b 0 -v 3
macadr,17K,512,0
nvram,-,64K,0
bsu,-,256K,0
misc,1M,1M,0
hwcfg,-,1M,0
boot,-,32M,0
recovery,-,32M,0
cache,-,256M,0x0001000000000000
splash,-,12M,0
metadata,-,12M,0
tee,-,8M,0
system,-,1224M,0x0001000000000000
userdata,-,-,0x0001000000000000

根据3.1节对makegpt参数的分析,这里主要指定了以下参数:

  • -s total_disk_size,指定设备的大小(按字节Byte计算),为7818182656字节
  • -b base_address,指定分区起始位置,为0,从偏移为0的地址开始
  • -o outputfile,指定生成的gpt数据,没有设置,因为已经在调用makegpt的命令行中指定
  • -v levelmakegpt执行时输出log的level开关(0=off, 1=normal, 2=debug, 3=noisy),这里设置为3,会显示较多的log信息
  • partitionName,startaddr,size,attr,指定分区参数,这里指定了13个分区:
    1. macadr,17K,512,0,从17K(第34个LBA)开始,大小为512B,属性为0;
    2. nvram,-,64K,0,从macadr分区结束地址(即17K+512)开始,大小为64KB,属性为0;
    3. bsu,-,256K,0,从nvram分区结束地址开始,大小为256KB,属性为0;
    4. misc,1M,1M,0,从绝对地址1MB处开始,大小为1MB,属性为0;
    5. hwcfg,-,1M,0,从misc分区结束地址开始,大小为1MB,属性为0;
    6. boot,-,32M,0,从hwcfg分区结束地址开始,大小为32MB,属性为0;
    7. recovery,-,32M,0,从boot分区结束地址开始,大小为32MB,属性为0;
    8. cache,-,256M,0x0001000000000000,从recovery分区结束地址开始,大小为256MB,指定属性为0x0001000000000000
    9. splash,-,12M,0,从cache分区结束地址开始,大小为12MB,属性为0;
    10. metadata,-,12M,0,从splash分区结束地址开始,大小为12MB,属性为0;
    11. tee,-,8M,0,从metadata分区结束地址开始,大小为8MB,属性为0;
    12. system,-,1224M,0x0001000000000000,从tee分区结束地址开始,大小为1224MB,指定属性为0x0001000000000000
    13. userdata,-,-,0x0001000000000000,从system分区结束地址开始,包含剩余空间,指定属性为0x0001000000000000

注意:

  1. 预留了LBA 0 - LBA 33用于存放GPT数据,所以第一个分区macadrLBA 34(即17K)开始
  2. 分区划分中,由于bsumisc不连续,分区之间会有未使用空间构成的空白区域

在编译Android时,调用makegpt生成gpt.bin的命令为:

out/host/linux-x86/bin/makegpt -o out/target/product/bcm7252ssffdr4/gpt.bin `paste -sd " " device/broadcom/common/gpts/default.conf`

这里通过命令paste -sd " " device/broadcom/common/gpts/default.conf,将文件default.conf输出到命令行作为makegpt的调用参数,因此makegpt执行的完整命令如下:

$ out/host/linux-x86/bin/makegpt \
    -o out/target/product/bcm7252ssffdr4/gpt.bin \
    -s 7818182656 \
    -b 0 \
    -v 3 \
    macadr,17K,512,0 \
    nvram,-,64K,0 \
    bsu,-,256K,0 \
    misc,1M,1M,0 \
    hwcfg,-,1M,0 \
    boot,-,32M,0 \
    recovery,-,32M,0 \
    cache,-,256M,0x0001000000000000 \
    splash,-,12M,0 \
    metadata,-,12M,0 \
    tee,-,8M,0 \
    system,-,1224M,0x0001000000000000 \
    userdata,-,-,0x0001000000000000

4. 操作eMMC的boot分区

eMMC默认出厂时用户可见的分区有4个:

  1. BOOT Area Partition 1
  2. BOOT Area Partition 2
  3. User Data Area
  4. RPMB (Replay Protected Memory Block)

通常boot1分区用于存放启动代码,boot2分区用于存放备份代码或配置数据,更多的厂家将boot2分区闲置浪费了,因此可以将boot2分区利用起来。

boot分区默认是raw格式,可以在boot2分区上写入GPT数据创建GPT分区。

以下通过GPT工具将boot2分区设置为GPT设备。

4.1 用makegpt设置boot2分区

  • boot2分区划分

    分区配置文件boot.conf:

    -s 4194304 -b 0 -v 3
    data1,17K,512,0
    data2,-,64K,0
    data3,-,256K,0
    data4,-,-,0
    
  • 生成Primary GPT

    ``$ makegpt -o gpt-primary.binpaste -sd ” ” boot.conf““

  • 生成Secondary GPT

    ``$ makegpt -a -o gpt-secondary.binpaste -sd ” ” boot.conf““

    将上面生成的gpt-primary.bingpt-secondary.bin分别写入boot2分区的LBA 0LBA - 34(对于4MB的boot2分区,总共有8192个LBA, LBA - 34对应为LBA 8158)即可。

  • BOLT命令行向boot2分区写入GPT数据

    • 写入Primary GPT:

      BOLT> flash 192.168.1.100:gpt-primary.bin flash2

    • 写入Secondary GPTLBA 8158 (偏移地址:0x3FBC00):

      BOLT> flash -offset=0x3FBC00 192.168.1.100:gpt-secondary.bin flash2

      写入后启动提示说备份GPT无效,打开gpt-secondary.bin发现只占用了2个LBA,所以将数据重新写到LBA - 2的位置,即LBA 8190(偏移地址:0x3FFC00),系统启动正常,写入命令如下:

      BOLT> flash -offset=0x3FFC00 192.168.1.100:gpt-secondary.bin flash2

5. 总结

  • sgdisk可以在命令行通过命令或脚本任意创建、修改和删除分区,比较灵活;
  • makegpt根据传入的配置,直接生成所需的GPT数据,比较方便,但不灵活;
  • 4
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
GPT(GUID Partition Table)是一种磁盘分区表的格式,用于替代传统的MBR(Master Boot Record)分区表。GPT分区表支持更大的磁盘容量和更多的分区,并提供了更好的数据保护机制。下面是在Linux系统中使用GPT分区和挂载的步骤: 1. 确认磁盘设备:使用以下命令之一确认要分区的磁盘设备: ```shell sudo fdisk -l sudo lsblk ``` 2. 创建GPT分区:使用`gdisk`命令创建GPT分区。例如,创建一个新的GPT分区表并添加一个主分区: ```shell sudo gdisk /dev/sdX n # 创建新分区 <Enter> # 默认分区编号 <Enter> # 默认起始扇区 <Enter> # 默认结束扇区 <Enter> # 默认分区类型 w # 保存并退出 ``` 请将`/dev/sdX`替换为实际的磁盘设备名称,例如`/dev/sda`。 3. 格式化分区:使用`mkfs`命令格式化新创建的分区。例如,格式化为ext4文件系统: ```shell sudo mkfs.ext4 /dev/sdX1 ``` 请将`/dev/sdX1`替换为实际的分区设备名称。 4. 创建挂载点:选择一个目录作为挂载点,用于将分区挂载到文件系统中。例如,创建一个名为`/mnt/mydisk`的挂载点: ```shell sudo mkdir /mnt/mydisk ``` 5. 挂载分区:使用`mount`命令将分区挂载到挂载点。例如,将分区`/dev/sdX1`挂载到`/mnt/mydisk`: ```shell sudo mount /dev/sdX1 /mnt/mydisk ``` 请将`/dev/sdX1`替换为实际的分区设备名称。 6. 配置自动挂载:如果希望在系统启动时自动挂载分区,需要将分区信息添加到`/etc/fstab`文件中。打开`/etc/fstab`文件并添加以下行: ```shell /dev/sdX1 /mnt/mydisk ext4 defaults 0 2 ``` 请将`/dev/sdX1`和`/mnt/mydisk`替换为实际的分区设备名称和挂载点。 现在,您已经了解了如何在Linux系统中使用GPT分区和挂载。如果您有任何进一步的问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

洛奇看世界

一分也是爱~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值