The GUID Partition Table (GPT) is a partitioning scheme that has become the modern standard for disk layout, offering significant advantages over the older Master Boot Record (MBR) system. This article provides a detailed overview of the GPT disk layout, exploring its structure, components, and benefits, particularly in the context of contemporary computing and UEFI (Unified Extensible Firmware Interface) systems.
GPT Overview
The GPT partitioning scheme, as illustrated in Figure 5.4, fundamentally structures disk space to overcome limitations inherent in MBR. At the heart of GPT is the GPT Header, a critical component containing a signature and revision number that dictates the data format within the partition header. Importantly, the GPT Header includes a header size field, crucial for the CRC32 checksum calculation which verifies the integrity of the GPT Header itself. While the size of the GPT Header is designed to be adaptable for future expansions, it is restricted to a single logical block on the storage device.
Logical Block Address (LBA) 0, the very first block on the disk, is reserved for a protective MBR. This protective MBR is a key element for backward compatibility, ensuring that legacy BIOS-based systems can still recognize the disk, albeit as a single, non-bootable partition, thus preventing them from misinterpreting and potentially damaging the GPT structure.
For redundancy and robustness, GPT employs a dual header system: a primary GPT Header and a backup GPT Header. The primary header is always located at LBA 1, the second logical block of the device. Conversely, the backup GPT Header is positioned at the very last LBA of the device. Within each GPT Header, the “My LBA” field denotes the LBA of the header itself, while the “Alternate LBA” field specifies the location of its counterpart header. For instance, in the primary GPT Header, “My LBA” would be 1, and “Alternate LBA” would point to the last LBA of the device. These values are reversed in the backup GPT Header, ensuring bidirectional referencing for recovery and integrity checks.
Figure 5.4: Diagram illustrating the GUID Partition Table (GPT) layout, highlighting the positions of the Protective MBR, Primary GPT Header, Partition Entry Array, and Backup GPT structures on a disk.
The GPT Header plays a pivotal role in defining the range of Logical Block Addresses (LBAs) available for GPT Partition Entries. This range spans inclusively from the “First Usable LBA” to the “Last Usable LBA” of the logical device. All data stored on the volume must reside within this defined usable space. Only UEFI-defined data structures essential for partition management are permitted to exist outside this usable area. The “Disk GUID” field within the GPT Header is a globally unique identifier (GUID) that distinguishes the entire GPT structure and its associated storage. This Disk GUID serves as a unique fingerprint for the disk itself.
The GPT Partition Entry Array, which contains the descriptions of individual partitions, begins at the LBA specified by the “Partition Entry LBA” field in the GPT Header. The size of each individual GUID Partition Entry is defined by the “Size Of Partition Entry” field. The total size of the GPT Partition Entry Array is calculated by multiplying “Size Of Partition Entry” by the “Number Of Partition Entries,” also found in the GPT Header. A 32-bit CRC checksum of the entire GPT Partition Entry Array is stored in the “Partition Entry Array CRC32” field within the GPT Header. If the GPT Partition Entry Array size is not a precise multiple of the logical block size, any remaining space in the final logical block is marked as Reserved and is not included in the “Partition Entry Array CRC32” calculation. Critically, any update to a GUID Partition Entry necessitates recalculating and updating the “Partition Entry Array CRC32.” Furthermore, because the “Partition Entry Array CRC32” is embedded within the GPT Header, updating the array CRC also requires updating the GPT Header CRC to maintain data integrity.
The primary GPT Partition Entry Array must be located immediately after the primary GPT Header, concluding before the “First Usable LBA.” Conversely, the backup GPT Partition Entry Array is situated after the “Last Usable LBA,” ending just before the backup GPT Header. This spatial arrangement ensures that the primary and backup GPT Partition Entry Arrays are physically separated on the disk, enhancing data redundancy and fault tolerance.
Each GPT Partition Entry within the array defines a partition that resides within the usable space declared by the GPT Header. The GPT Partition Entry Array can contain zero or more active entries. Defined partitions must not overlap with each other. A GUID Partition Entry with all fields set to zero is considered unused and does not represent an active partition. A minimum space of 16,384 bytes is mandated to be reserved for the GPT Partition Entry Array, ensuring sufficient capacity for partition definitions.
For devices with a 512-byte block size, the “First Usable LBA” must be at least 34. This allocation accounts for 1 block for the Protective MBR, 1 block for the GPT Header, and 32 blocks for the GPT Partition Entry Array. For devices with a larger 4096-byte logical block size, the “First Useable LBA” requirement is reduced to a minimum of 6 blocks, allocating 1 block for the Protective MBR, 1 for the GPT Header, and 4 for the GPT Partition Entry Array, reflecting the efficiency of larger block sizes in accommodating the GPT structure.
It’s important to note that storage devices can present logical block sizes that differ from the physical block size. In ATA (Advanced Technology Attachment) specifications, the “Long Logical Sector” feature allows devices to report support for logical sectors larger than 512 bytes. Similarly, SCSI (Small Computer System Interface) devices report their logical block size in the READ CAPACITY parameter data. Devices may also implement “Long Physical Sector” features, where the physical block size is larger than the logical block size, for example, presenting 512-byte logical blocks on a 4096-byte physical block device. Understanding these distinctions is crucial for optimizing partition alignment and performance, particularly in advanced storage configurations and RAID (Redundant Array of Independent Disks) systems.
GPT partitions should be aligned to the larger of the physical block boundary and the optimal transfer length granularity, if specified by the device. For instance, if a device has a logical block size of 512 bytes and a physical block size of 4,096 bytes (8 logical blocks per physical block), and no optimal transfer length granularity is specified, GPT partitions should start at an LBA that is a multiple of 8. If the optimal transfer length granularity is 65,536 bytes (128 logical blocks), partitions should be aligned to LBAs that are multiples of 128. To simplify partition alignment and accommodate diverse storage configurations, software often aligns GPT partitions to significantly larger boundaries, such as 1 MiB (1,048,576 bytes) boundaries, corresponding to LBAs that are multiples of 2,048 (assuming logical block 0 is aligned). This 1 MiB alignment strategy is broadly compatible with common physical block sizes and RAID stripe sizes, minimizing potential performance issues related to misaligned I/O operations.
References:
- ISO/IEC 24739-200 [ANSI INCITS 452-2008] AT Attachment 8 – ATA/ATAPI Command Set (ATA8-ACS).
- ISO/IEC 14776-323 [T10/1799-D] SCSI Block Commands – 3 (SBC-3).
GPT Header
The GPT Header is a crucial data structure that defines the parameters and integrity of the GUID Partition Table. Table 5.5 details the fields within the GPT Header.
Table 5.5: GPT Header
Mnemonic | Byte Offset | Byte Length | Description |
---|---|---|---|
Signature | 0 | 8 | Identifies an EFI-compatible partition table header. Must contain the ASCII string “EFI PART”, encoded as the 64-bit constant 0x54 52415020494645. |
Revision | 8 | 4 | Header revision number (version 1.0 is 0x00010000). |
HeaderSize | 12 | 4 | Size in bytes of the GPT Header (must be >= 92 bytes and <= logical block size). |
HeaderCRC32 | 16 | 4 | CRC32 checksum of the GPT Header (calculated with this field set to 0). |
Reserved | 20 | 4 | Must be zero. |
MyLBA | 24 | 8 | LBA of this GPT Header. |
AlternateLBA | 32 | 8 | LBA of the alternate GPT Header. |
FirstUsableLBA | 40 | 8 | First usable LBA for partitions. |
LastUsableLBA | 48 | 8 | Last usable LBA for partitions. |
DiskGUID | 56 | 16 | Unique GUID identifying the disk. |
PartitionEntryLBA | 72 | 8 | Starting LBA of the GPT Partition Entry array. |
NumberOfPartitionEntries | 80 | 4 | Number of Partition Entries in the array. |
SizeOfPartitionEntry | 84 | 4 | Size in bytes of each GPT Partition Entry (e.g., 128, 256, 512). |
PartitionEntryArrayCRC32 | 88 | 4 | CRC32 checksum of the GPT Partition Entry array. |
Reserved | 92 | BlockSize – 92 | Reserved space (must be zero-filled). |
To validate a GPT Header, several checks must be performed:
- Signature Check: Verify the “Signature” field contains the correct “EFI PART” ASCII string.
- Header CRC Check: Compute the CRC32 checksum of the Header (with the HeaderCRC32 field considered zero during calculation) and compare it to the stored HeaderCRC32 value.
- MyLBA Check: Ensure the “MyLBA” field correctly points to the LBA where the GPT Header is located.
- Partition Entry Array CRC Check: Calculate the CRC32 checksum of the GPT Partition Entry Array and compare it to the stored PartitionEntryArrayCRC32 value.
For the primary GPT (located at LBA 1), an additional check is needed:
- AlternateLBA Check: Examine the “AlternateLBA” field to ensure it points to a valid backup GPT.
If the primary GPT is found to be corrupt, the system should then inspect the last LBA of the device for a valid GPT Header, indicating the presence of a backup GPT. If a valid backup GPT and its associated Partition Entry Array are found, the system should attempt to restore the primary GPT, contingent on platform policies and potentially requiring user confirmation. It is crucial for software to report any instance where it automatically or manually restores a GPT, ensuring system administrators are aware of such recovery actions.
Software should prompt for user confirmation before restoring the primary GPT, especially as it involves modifying the storage media. A potential issue arises when a GPT-formatted disk is reformatted to the legacy MBR format by older software. In such cases, the last logical block might not be overwritten and could still contain a stale GPT. If GPT-aware software subsequently accesses this disk and mistakenly honors the outdated GPT, it can misinterpret the disk’s contents, leading to data corruption or system instability. Software can detect this scenario by checking if the MBR contains valid partitions instead of the expected protective MBR, signaling a potential GPT/MBR conflict.
Any software that modifies the primary GPT must also concurrently update the backup GPT to maintain data consistency and redundancy. While the order of updating the GPT Header and GPT Partition Entry Array is flexible due to the CRC mechanisms, it is best practice to update the backup GPT before the primary GPT. This order is particularly important when the device size has changed (e.g., volume expansion). If an update process is interrupted, ensuring the backup GPT is updated first minimizes the risk of data loss or corruption, as a valid backup GPT remains available.
In GPT recovery scenarios, if the primary GPT is invalid, the backup GPT, located at the last logical block, is utilized. If the backup GPT is valid, it should be used to restore the primary GPT. Conversely, if the primary GPT is valid but the backup GPT is invalid, software should restore the backup GPT from the primary. If both the primary and backup GPTs are corrupted, the block device is considered to have an invalid GUID Partition Table, indicating a severe data integrity issue.
Before attempting to expand the size of a physical volume, both the primary and backup GPTs must be valid. This requirement stems from the GPT recovery mechanism, which relies on the backup GPT being located at the end of the device. Volume expansion, often encountered in RAID configurations when disks are added, necessitates relocating the backup GPT to the new end of the expanded volume. Simultaneously, both primary and backup GPT Headers must be updated to reflect the new volume size, ensuring the GPT structure remains consistent and valid across the expanded storage space.
GPT Partition Entry Array
The GPT Partition Entry Array is a fundamental component of the GPT scheme, housing an array of GPT Partition Entries. Each entry in this array defines a single partition on the disk. Table 5.6 details the structure of a GPT Partition Entry.
Table 5.6: GPT Partition Entry
Mnemonic | Byte Offset | Byte Length | Description |
---|---|---|---|
PartitionTypeGUID | 0 | 16 | Unique GUID defining the partition type (zero GUID indicates an unused entry). |
UniquePartitionGUID | 16 | 16 | Unique GUID for each partition entry, generated upon creation. |
StartingLBA | 32 | 8 | Starting LBA of the partition. |
EndingLBA | 40 | 8 | Ending LBA of the partition. |
Attributes | 48 | 8 | Attribute bits (UEFI reserved). |
PartitionName | 56 | 72 | Null-terminated UTF-16 string for the partition name. |
Reserved | 128 | SizeOfPartitionEntry – 128 | Reserved space (must be zero-filled). |
The “SizeOfPartitionEntry” field in the GPT Header determines the size of each GUID Partition Entry. Every partition entry includes a “Unique Partition GUID,” ensuring that each partition ever created has a distinct identifier. This GUID is generated when a new partition entry is created, guaranteeing uniqueness across all partitions. A partition is defined by all logical blocks inclusively between the “StartingLBA” and “EndingLBA.”
The “PartitionTypeGUID” field specifies the content type of the partition, analogous to the “OS Type” field in MBR. Each filesystem or operating system can define and publish its own unique Partition Type GUID. The “Attributes” field provides additional flags for utilities to infer partition usage, as defined in Table 5.7.
UEFI firmware is required to add the “PartitionTypeGuid” to the device handle of every active GPT partition using EFI_BOOT_SERVICES.InstallProtocolInterface()
. This facilitates easy discovery of specific partition types, such as EFI System Partitions or vendor-specific partitions, by drivers and applications, including OS loaders.
Software that duplicates GPT-formatted disks or partitions must generate new “Disk GUID” values for the GPT Headers and new “Unique Partition GUID” values for each GPT Partition Entry. Using identical GUIDs across different disks or partitions can lead to unpredictable and erroneous behavior.
Table 5.7: Defined GPT Partition Entry — Partition Type GUIDs
Description | GUID Value |
---|---|
Unused Entry | 00000000-0000-0000-0000-000000000000 |
EFI System Partition | C12A7328-F81F-11D2-BA4B-00A0C93EC93B |
Partition containing a legacy MBR | 024DEE41-33E7-11D3-9D69-0008C781F39F |
OS vendors are responsible for generating and registering their own Partition Type GUIDs to identify their specific partition types.
Table 5.8: Defined GPT Partition Entry – Attributes
Bits | Name | Description |
---|---|---|
Bit 0 | Required Partition | Indicates a critical partition for platform functionality. Modification or deletion can cause platform failure. |
Bit 1 | No Block IO Protocol | Firmware must not produce an EFI_BLOCK_IO_PROTOCOL for this partition, preventing filesystem mapping in UEFI. |
Bit 2 | Legacy BIOS Bootable | Reserved for legacy BIOS systems to indicate potential bootability of a GPT partition (ignored by UEFI boot manager). |
Bits 3-47 | Undefined and must be zero. Reserved for future UEFI specification expansion. | |
Bits 48-63 | Reserved for GUID specific use. Usage depends on the PartitionTypeGUID . Must be preserved if Bits 0-47 are modified. |
Related Definitions:
#pragma pack(1)
///
/// GPT Partition Entry.
///
typedef struct {
EFI_GUID PartitionTypeGUID;
EFI_GUID UniquePartitionGUID;
EFI_LBA StartingLBA;
EFI_LBA EndingLBA;
UINT64 Attributes;
CHAR16 PartitionName[36];
} EFI_PARTITION_ENTRY;
#pragma pack()