190 lines
6.9 KiB
C
190 lines
6.9 KiB
C
//
|
|
// GPT (GUID Partition Table) declarations.
|
|
//
|
|
|
|
|
|
//
|
|
// DO WE EVER ALLOW GPT_TABLEs TO NOT BE PACKED UP AGAINST THEIR HEADER?
|
|
// IF NOT, DO WE ALLOW PEOPLE TO MAKE ASSUMPTIONS ABOUT THEIR LOCATION?
|
|
// DO WE NEED THE POINTER?
|
|
//
|
|
|
|
//
|
|
// Rules:
|
|
// None of these structures ever appear at LBA 0, because
|
|
// we put a "fake" MBR there (the legacy defense MBR).
|
|
// Therefore, LBA of 0 is useable as NULL.
|
|
//
|
|
// For All Entry's, StartingLBA must be >= FirstUsableLBA.
|
|
// For All Entry's, EndingLBA must be <= LastUsableLBA.
|
|
//
|
|
// 0 is not a valid GUID. Therefore, emtpy GPT_ENTRY's will
|
|
// have a PartitionType of 0.
|
|
// However, if an entry is otherwise valid, but has a PartitionID
|
|
// of 0, this means a GUID needs to be generated and placed there.
|
|
//
|
|
// LBA = Logical Block Address == Sector Number. Always count from 0.
|
|
//
|
|
// Block size (sector size) could be any number >= sizeof(GPT_ENTRY)
|
|
// AND >= sizeof(GPT_HEADER). In practice, always >= 512 bytes.
|
|
//
|
|
// A block, B, is free for allocation to a partition if and only if
|
|
// it is in the range FirstUsableLBA <= B <= LastUsableLBA AND it
|
|
// is not already allocated to some other parition.
|
|
//
|
|
// GPT partitions are always contiguous arrays of blocks. however,
|
|
// they need NOT be packed on the disk, their order in the GPT need
|
|
// NOT match their order on the disk, there may be blank entries
|
|
// in the GPT table, etc. Building an accurate view of the parititon
|
|
// *requires* reading the entire GPT_TABLE into memory. In practice,
|
|
// it will always be small enough for this to be easy.
|
|
//
|
|
|
|
#pragma pack (4)
|
|
|
|
//
|
|
// Each partition is described by a GPT_ENTRY.
|
|
//
|
|
#define PART_NAME_LEN 36
|
|
|
|
typedef struct {
|
|
EFI_GUID PartitionType; // declartion of this partition's type
|
|
EFI_GUID PartitionID; // Unique ID for this particular partition
|
|
// (unique to this instance)
|
|
EFI_LBA StartingLBA; // 0 based block (sector) address of the
|
|
// first block included in the partition.
|
|
EFI_LBA EndingLBA; // 0 based block (sector) address of the
|
|
// last block included in the partition.
|
|
// If StartingLBA == EndingLBA then the
|
|
// partition is 1 block long. this is legal.
|
|
UINT64 Attributes; // Always ZERO for now
|
|
CHAR16 PartitionName[PART_NAME_LEN]; // 36 unicode characters of name
|
|
} GPT_ENTRY, *PGPT_ENTRY;
|
|
|
|
C_ASSERT (sizeof (GPT_ENTRY) == 128);
|
|
//
|
|
// All of the GPT_ENTRY's are gathered into a GPT_TABLE, which
|
|
// is stored as a linear array of blocks on the disk.
|
|
//
|
|
typedef struct {
|
|
GPT_ENTRY Entry[1]; // Always an integer number of Entry's
|
|
// per sector. Always at least 1 sector.
|
|
// Can be any number of sectors...
|
|
} GPT_TABLE, *PGPT_TABLE;
|
|
|
|
//
|
|
// A main and a backup header each describe the disk, and each points
|
|
// to it's own copy of the GPT_TABLE...
|
|
//
|
|
typedef struct {
|
|
UINT64 Signature; // GPT PART
|
|
UINT32 Revision;
|
|
UINT32 HeaderSize;
|
|
UINT32 HeaderCRC32; // computed using 0 for own init value
|
|
UINT32 Reserved0;
|
|
EFI_LBA MyLBA; // 0 based sector number of the first
|
|
// sector of this structure
|
|
EFI_LBA AlternateLBA; // 0 based sector (block) number of the
|
|
// first sector of the secondary
|
|
// GPT_HEADER, or 0 if this is the
|
|
// secondary.
|
|
EFI_LBA FirstUsableLBA; // 0 based sector number of the first
|
|
// sector that may be included in a partition.
|
|
EFI_LBA LastUsableLBA; // last legal LBA, inclusive.
|
|
EFI_GUID DiskGUID; // The unique ID of this LUN/spindle/disk
|
|
EFI_LBA TableLBA; // The start of the table of entries...
|
|
UINT32 EntriesAllocated; // Number of entries in the table, this is
|
|
// how many allocated, NOT how many used.
|
|
UINT32 SizeOfGPT_ENTRY; // sizeof(GPT_ENTRY) always mult. of 8
|
|
UINT32 TableCRC32; // CRC32 of the table.
|
|
// Reserved and zeros to the end of the block
|
|
// Don't declare an array or sizeof() gives a nonsense answer..
|
|
} GPT_HEADER, *PGPT_HEADER;
|
|
|
|
C_ASSERT (sizeof (GPT_HEADER) == 92);
|
|
|
|
#define GPT_HEADER_SIGNATURE 0x5452415020494645
|
|
#define GPT_REVISION_1_0 0x00010000
|
|
|
|
#define ENTRY_DEFAULT 128
|
|
//#define ENTRY_DEFAULT 8 // TESTING ONLY
|
|
#define ENTRY_SANITY_LIMIT 1024
|
|
|
|
|
|
//
|
|
// GPT Disk Layout
|
|
//
|
|
/*
|
|
|
|
+---------------------------------------------------+
|
|
LBA=0 | "Fake" MBR to ward off legacy parition apps |
|
|
+---------------------------------------------------+
|
|
LBA=1 | Primary GPT_HEADER |
|
|
+---------------------------------------------------+
|
|
LBA=2 | Primary GPT_TABLE starts |
|
|
... ... ...
|
|
LBA=n | Primary GPT_TABLE ends |
|
|
+---------------------------------------------------+
|
|
LBA=n+1 | FirstUsableLBA = this block |
|
|
... ... ...
|
|
LBA=x | LastUsableLBA = this block |
|
|
+---------------------------------------------------+
|
|
LBA=x+1 | Secondary GPT_TABLE starts |
|
|
... ... ...
|
|
LBA=z | Secondary GPT_TABLE ends |
|
|
+---------------------------------------------------+
|
|
LBA=z+n | Secondary GPT_HEADER starts |
|
|
... ... ...
|
|
LAST | Secondary GPT_HEADER ends at last sector of disk |
|
|
+---------------------------------------------------+
|
|
|
|
SO:
|
|
Primary GPT_HEADER is always at LBA=1
|
|
Secondary GPT_HEADER is at LBA=Last so long as GPT_HEADER fits
|
|
in 1 sector, which we require.
|
|
|
|
Primary Table is stacked up after the primary header,
|
|
which points to it anyway.
|
|
|
|
Secondary Table is stacked up before the secondary header,
|
|
which points to it anyway.
|
|
|
|
*/
|
|
|
|
|
|
//
|
|
// ------------------ Functions To Manipulate GPT ---------------
|
|
//
|
|
typedef struct _LBA_BLOCK {
|
|
EFI_LBA Header1_LBA;
|
|
EFI_LBA Table1_LBA;
|
|
EFI_LBA Header2_LBA;
|
|
EFI_LBA Table2_LBA;
|
|
} LBA_BLOCK, *PLBA_BLOCK;
|
|
|
|
|
|
EFI_STATUS
|
|
ReadGPT(
|
|
EFI_HANDLE DiskHandle,
|
|
PGPT_HEADER *Header,
|
|
PGPT_TABLE *Table,
|
|
PLBA_BLOCK *LbaBlock,
|
|
UINTN *DiskType
|
|
);
|
|
|
|
EFI_STATUS
|
|
WriteGPT(
|
|
EFI_HANDLE DiskHandle,
|
|
PGPT_HEADER Header,
|
|
PGPT_TABLE Table,
|
|
PLBA_BLOCK LbaBlock
|
|
);
|
|
|
|
EFI_STATUS
|
|
CreateGPT(
|
|
EFI_HANDLE DiskHandle,
|
|
UINTN EntryRequest
|
|
);
|
|
|
|
#pragma pack ()
|