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

> Explore MBR vs GPT partition table differences in Ventoy. Learn how Ventoy detects MBR's simple entries and GPT's protective MBR, header, and array for efficient disk management.

- Repository: [longpanda/Ventoy](https://github.com/ventoy/Ventoy)
- Tags: deep-dive
- Published: 2026-03-01

---

**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`](https://github.com/ventoy/Ventoy/blob/main/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`](https://github.com/ventoy/Ventoy/blob/main/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`](https://github.com/ventoy/Ventoy/blob/main/vtoyjump/vtoyjump.c) (lines 973-996), the code reads sector 0 into an `MBR_HEAD` structure and tests:

```c
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`](https://github.com/ventoy/Ventoy/blob/main/vtoycli/partresize.c) (lines 84-90), the detection logic confirms:

```c
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`](https://github.com/ventoy/Ventoy/blob/main/vtoycli/vtoycli.h):

```c
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:

```c
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`](https://github.com/ventoy/Ventoy/blob/main/vtoyjump/vtoyjump.c) (lines 955-1002) handles both layouts:

```c
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`](https://github.com/ventoy/Ventoy/blob/main/Ventoy2Disk/ventoy_cli.c) (line 269):

```c
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`](https://github.com/ventoy/Ventoy/blob/main/vtoycli/vtoygpt.c) (lines 143-226) provides dump utilities:

```c
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

- **[`vtoycli/vtoycli.h`](https://github.com/ventoy/Ventoy/blob/main/vtoycli/vtoycli.h)** – Core structure definitions for `MBR_HEAD`, `VTOY_GPT_HDR`, and `VTOY_GPT_PART_TBL`
- **[`vtoyjump/vtoyjump/vtoyjump.c`](https://github.com/ventoy/Ventoy/blob/main/vtoyjump/vtoyjump/vtoyjump.c)** – Runtime detection logic and EFI partition location retrieval
- **[`vtoycli/partresize.c`](https://github.com/ventoy/Ventoy/blob/main/vtoycli/partresize.c)** – Linux-side GPT/MBR detection and partition resizing operations
- **[`vtoycli/vtoygpt.c`](https://github.com/ventoy/Ventoy/blob/main/vtoycli/vtoygpt.c)** – GPT header dumping and manipulation utilities
- **[`Ventoy2Disk/ventoy_cli.c`](https://github.com/ventoy/Ventoy/blob/main/Ventoy2Disk/ventoy_cli.c)** – CLI entry point for drive classification
- **[`Ventoy2Disk/Ventoy2Disk/ff14/source/ff.c`](https://github.com/ventoy/Ventoy/blob/main/Ventoy2Disk/Ventoy2Disk/ff14/source/ff.c)** – Low-level filesystem checks for protective MBR flags

## 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`](https://github.com/ventoy/Ventoy/blob/main/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.