MBR vs GPT Partition Table Structures in Ventoy: Key Differences Explained

The key difference is that Ventoy detects MBR disks by reading a simple 512-byte sector with four 16-byte partition entries, while GPT disks require a protective MBR flag (0xEE) followed by a 512-byte GPT header with a signature of "EFI PART" and a 128-entry partition array.

Ventoy supports both legacy BIOS (MBR) and modern UEFI (GPT) boot schemes, handling each through distinct code paths in the ventoy/Ventoy repository. Understanding these partition table structures is essential for developers working with Ventoy's disk management utilities or debugging boot loader interactions across different firmware types.

Structural Layout Differences

MBR (Master Boot Record) Structure

The MBR layout occupies exactly 512 bytes in sector 0. According to vtoycli/vtoycli.h, this sector contains 446 bytes of boot code, followed by four 16-byte partition entries (PART_TABLE), and ends with the magic bytes 0x55AA.

Each PART_TABLE entry (lines 46-62) contains:

  • Active – boot indicator flag
  • FsFlag – filesystem type identifier
  • StartSectorId – starting sector number
  • SectorCount – partition size in sectors

Ventoy limits MBR to 4 primary partitions (or extended partitions via chaining), accessing the EFI partition through the second entry MBR.PartTbl[1].

GPT (GUID Partition Table) Structure

GPT uses a protective MBR in sector 0 (with FsFlag == 0xEE) followed by a dedicated GPT header and partition array. As defined in vtoycli/vtoycli.h (lines 80-108), the structure includes:

  • Header (VTOY_GPT_HDR): 512-byte sector containing an 8-byte ASCII signature "EFI PART", version info, CRC checksums, and the backup header location (EfiBackupLBA)
  • Partition Array: 128 entries (VTOY_GPT_PART_TBL), each 128 bytes, storing GUIDs for partition type and unique ID, 64-bit LBA ranges (StartLBA, LastLBA), attributes, and UTF-16 names

Ventoy stores a backup copy of the GPT header and partition array at the end of the disk, unlike MBR which maintains no redundant table.

Detection Logic in Ventoy Source Code

Protective MBR Flag Check

Ventoy branches its disk-handling logic early by checking the first partition entry's filesystem flag. In vtoyjump/vtoyjump.c (lines 973-996), the code reads sector 0 into an MBR_HEAD structure and tests:

if (MBR.PartTbl[0].FsFlag == 0xEE) {
    // GPT handling path
} else {
    // MBR handling path
}

This 0xEE flag indicates a protective MBR that reserves the entire disk for GPT usage, preventing legacy tools from accidentally destroying the partition table.

GPT Signature Verification

After detecting the protective flag, Ventoy validates the GPT header by reading the VTOY_GPT_INFO structure and verifying the signature. In vtoycli/partresize.c (lines 84-90), the detection logic confirms:

if (pGPT->MBR.PartTbl[0].FsFlag == 0xEE &&
    memcmp(pGPT->Head.Signature, "EFI PART", 8) == 0) {
    // Valid GPT disk confirmed
}

Only when both conditions pass does Ventoy proceed with GPT-specific calculations using 64-bit LBA addressing.

Data Structure Definitions in vtoycli.h

MBR Structures

The legacy structure uses simple 32-bit sector addressing. From vtoycli/vtoycli.h:

typedef struct {
    UINT8   Active;         // 0x80 = active
    UINT8   StartHead;
    UINT16  StartSector;    // bits 0-5
    UINT8   StartCylinder;  // bits 6-15
    UINT8   FsFlag;         // 0xEE for protective MBR
    UINT8   EndHead;
    UINT16  EndSector;
    UINT8   EndCylinder;
    UINT32  StartSectorId;  // 32-bit LBA
    UINT32  SectorCount;    // 32-bit size
} PART_TABLE;

typedef struct {
    UINT8       BootCode[446];
    PART_TABLE  PartTbl[4]; // Four primary entries
    UINT8       Signature[2]; // 0x55 0xAA
} MBR_HEAD;

GPT Structures

Modern GUID-based addressing uses 128-bit identifiers and 64-bit LBAs:

typedef struct {
    CHAR8   Signature[8];   // "EFI PART"
    UINT32  Version;
    UINT32  HeaderSize;
    UINT32  Crc32;
    UINT32  Reserved;
    UINT64  EfiStartLBA;    // My LBA (always 1)
    UINT64  EfiBackupLBA;   // Backup header location
    UINT64  PartAreaStartLBA; // First usable sector
    UINT64  PartAreaEndLBA;
    CHAR8   DiskGuid[16];
    UINT64  PartTblStartLBA; // Usually 2
    UINT32  PartTblTotCnt;   // 128 entries
    UINT32  PartTblSize;     // 128 bytes each
    UINT8   Reserved2[420];
} VTOY_GPT_HDR;

typedef struct {
    CHAR8   PartType[16];   // GUID type identifier
    CHAR8   PartGuid[16];   // Unique partition GUID
    UINT64  StartLBA;       // 64-bit start address
    UINT64  LastLBA;        // 64-bit end address
    UINT64  Attr;
    CHAR16  Name[36];       // UTF-16 partition name
} VTOY_GPT_PART_TBL;

Practical Implementation Examples

Reading the EFI Partition Start Sector

The cross-platform function GetVentoyEfiPartStartSector in vtoyjump/vtoyjump.c (lines 955-1002) handles both layouts:

UINT64 GetVentoyEfiPartStartSector(HANDLE hDrive) {
    MBR_HEAD MBR;
    VTOY_GPT_INFO *pGpt = NULL;
    UINT64 StartSector = 0;
    DWORD dwSize;

    SetFilePointer(hDrive, 0, NULL, FILE_BEGIN);
    ReadFile(hDrive, &MBR, sizeof(MBR), &dwSize, NULL);

    if (MBR.PartTbl[0].FsFlag == 0xEE) {          // GPT path
        pGpt = malloc(sizeof(VTOY_GPT_INFO));
        SetFilePointer(hDrive, 0, NULL, FILE_BEGIN);
        ReadFile(hDrive, pGpt, sizeof(VTOY_GPT_INFO), &dwSize, NULL);
        StartSector = pGpt->PartTbl[1].StartLBA;   // EFI partition
        free(pGpt);
    } else {                                      // MBR path
        StartSector = MBR.PartTbl[1].StartSectorId;
    }
    return StartSector;
}

Creating Protective MBR Entries

When Ventoy CLI detects a GPT disk, it marks the drive info structure accordingly in Ventoy2Disk/ventoy_cli.c (line 269):

if (MBR.PartTbl[0].FsFlag == 0xEE) {
    pDrvInfo->PartStyle = 1;   // 1 = GPT, 0 = MBR
    memcpy(&(pDrvInfo->MBR), &MBR, sizeof(MBR));
}

Dumping GPT Header Information

For debugging and validation, vtoycli/vtoygpt.c (lines 143-226) provides dump utilities:

void DumpHead(VTOY_GPT_HDR *pHead) {
    // Prints signature, version, and CRC validation
}

void DumpPartTable(VTOY_GPT_PART_TBL *Tbl) {
    // Iterates all 128 entries displaying GUIDs and LBA ranges
}

Key Source Files

Summary

  • MBR uses 512-byte sectors with four primary partition entries and 32-bit sector addressing; Ventoy identifies it when FsFlag != 0xEE.
  • GPT uses protective MBR + header + array, supporting 128 partitions with 64-bit LBA addressing and GUID identifiers; detected via FsFlag == 0xEE and "EFI PART" signature.
  • Backup redundancy exists only in GPT, with primary and backup headers at opposite ends of the disk.
  • EFI partition location is read from PartTbl[1].StartSectorId (MBR) or PartTbl[1].StartLBA (GPT) depending on the detected layout.
  • All detection branches on the protective flag before parsing the appropriate VTOY_GPT_INFO or MBR_HEAD structure.

Frequently Asked Questions

How does Ventoy detect whether a disk uses MBR or GPT?

Ventoy reads the first 512 bytes of the drive into an MBR_HEAD structure and checks if MBR.PartTbl[0].FsFlag == 0xEE. If true, it reads the subsequent GPT header and verifies the "EFI PART" signature; otherwise, it processes the legacy MBR layout directly.

What is the protective MBR in GPT disks used by Ventoy?

The protective MBR is a dummy MBR structure with a single partition entry marked 0xEE that covers the entire disk. This prevents legacy partitioning tools from treating the disk as unpartitioned or creating conflicting MBR entries that would destroy the GPT data.

How many partition entries does Ventoy allocate for GPT disks?

According to vtoycli/vtoycli.h, Ventoy allocates the full 128-entry array specified by the GPT standard, with each entry consuming 128 bytes. This provides space for multiple OS installations and utility partitions beyond MBR's four-entry limit.

Where does Ventoy store the EFI partition in MBR vs GPT layouts?

In MBR disks, Ventoy places the EFI partition at the location specified by MBR.PartTbl[1].StartSectorId. In GPT disks, it uses the second partition entry pGpt->PartTbl[1].StartLBA, which typically resides immediately after the GPT header and partition array sectors.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →