Fix GPT protective MBR to start at LBA 1 per UEFI spec#71
Merged
Olof-Lagerkvist merged 1 commit intoJul 4, 2026
Conversation
The protective MBR was created with CreatePrimaryByCylinder, which cylinder-aligns the 0xEE record so its StartingLBA is 63 instead of 1 and its SizeInLBA ends short of the disk end. The UEFI spec (Protective MBR) requires the 0xEE record to have StartingLBA exactly 1 and SizeInLBA equal to the disk size minus one, capped at 0xFFFFFFFF. The Linux kernel enforces this in block/partitions/efi.c pmbr_part_valid() (starting_lba must equal 1) and EDK2 firmware (MdeModulePkg PartitionDxe, UNPACK_UINT32(StartingLBA) == 1) does the same, so disks initialized by DiscUtils were rejected by both and could not be EFI-booted; gdisk also warned the 0xEE partition did not start on sector 1. Replace the cylinder-based call with CreatePrimaryBySector(1, min(sectorCount - 1, uint.MaxValue), ...), which already handles the CHS fields and caps oversized CHS at 1023/254/63. Adds a ProtectiveMbrIsSpecCompliant unit test asserting the record starts at LBA 1 and spans the disk.
937d113
into
LTRData:LTRData.DiscUtils-initial
3 checks passed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
GuidPartitionTable.Initializecreated the GPT protective MBR withCreatePrimaryByCylinder, which cylinder-aligns the 0xEE record. That places itsStartingLBAat 63 (the first head boundary of the fake CHS geometry) and gives it aSizeInLBAthat ends on a cylinder boundary short of the disk end.The UEFI spec ("Protective MBR", table "Protective MBR Partition Record") requires the single 0xEE record to have:
StartingLBAexactly 1 (the LBA of the GPT header), andSizeInLBAequal to the size of the disk minus one, capped at0xFFFFFFFF.Because DiscUtils wrote
StartingLBA = 63, the GPT was rejected outright by:block/partitions/efi.cpmbr_part_valid()returns invalid unlessstarting_lba == 1, so the kernel ignores the GPT completely (losetup -P,blkid, andmountsee zero partitions; the msdos fallback scanner also bails when it sees a 0xEE type).MdeModulePkgPartitionDxehas the same check (UNPACK_UINT32(StartingLBA) == 1), so disks initialized by DiscUtils could never be EFI-booted.Wrong vs. right (bytes at offset
0x1BE, the first MBR partition record)Wrong (before — cylinder aligned,
StartingLBA = 63):Right (after — sector based,
StartingLBA = 1):SizeInLBA(the following 4 bytes) becomesmin(diskSectors - 1, 0xFFFFFFFF).Fix
Replace the cylinder-based call with a sector-based record starting at LBA 1 covering the rest of the disk:
BiosPartitionTable.CreatePrimaryBySectoralready fills in the CHS fields and caps oversized CHS at the1023/254/63tuple.How to reproduce / test
Unit test added (
ProtectiveMbrIsSpecCompliantinTests/LibraryTests/Partitions/GuidPartitionTableTest.cs): initializes a GPT on a 3 MBMemoryStream, reads sector 0, and asserts the boot signature (0x55 0xAA), that exactly one record is type0xEE(the other three0x00), that its status byte is0, thatStartingLBA == 1, and thatSizeInLBA == diskSectors - 1.Manual reproduction with
sgdisk(Linux), before vs. after this patch:Optionally,
losetup -P+blkid/lsblkon the image: before the patch the kernel sees no partitions; after, the GPT partitions appear.