diff --git a/fusee/fusee-secondary/src/gpt.c b/fusee/fusee-secondary/src/gpt.c new file mode 100644 index 000000000..d6025e8da --- /dev/null +++ b/fusee/fusee-secondary/src/gpt.c @@ -0,0 +1,91 @@ +#include +#include +#include "gpt.h" + +int gpt_get_header(efi_header_t *out, FILE *disk) { + union { + uint8_t sector[512]; + efi_header_t hdr; + } d; + + if (disk == NULL || out == NULL) { + errno = EINVAL; + return -1; + } + + /* Read and check the protective MBR. */ + if (fread(d.sector, 512, 1, disk) == 0) { + return -1; + } + if (d.sector[0x1FE] != 0x55 || d.sector[0x1FF] != 0xAA) { + errno = EILSEQ; + return -1; + } + + /* We only allow for the GPT header to be at sector 1 (like nx-bootloader). */ + if (fread(d.sector, 512, 1, disk) == 0) { + return -1; + } + /* Check for "EFI PART". */ + if (memcmp(d.hdr.magic, "EFI PART", 8) != 0) { + errno = EILSEQ; + return -1; + } + /* Check whether we're really at sector 1, etc. (we won't check backup_lba). */ + if (d.hdr.header_lba != 1 || d.hdr.entries_first_lba < 2 || d.hdr.partitions_last_lba < d.hdr.partitions_first_lba) { + errno = EILSEQ; + return -1; + } + if (d.hdr.header_size < sizeof(efi_header_t) || d.hdr.entry_size < sizeof(efi_entry_t)) { + errno = EILSEQ; + return -1; + } + /* Some more checks: */ + if(d.hdr.header_size > 512 || d.hdr.revision != 0x10000) { + errno = ENOTSUP; + return -1; + } + + memcpy(out, &d.hdr, sizeof(efi_header_t)); + + return 0; +} + +int gpt_iterate_through_entries(FILE *disk, gpt_entry_iterator_t callback) { + efi_header_t hdr; + efi_entry_t entry; + size_t offset = 2 * 512; /* Sector #2. */ + size_t delta; + + /* Get the header. */ + if (gpt_get_header(&hdr, disk) == -1) { + return -1; + } + + /* Seek to the entry table. */ + if (fseek(disk, 512 * hdr.entries_first_lba - offset, SEEK_CUR) != 0) { + return -1; + } + + offset = 512 * hdr.entries_first_lba; + delta = hdr.entry_size - sizeof(efi_entry_t); + + /* Iterate through the entries. */ + for (uint32_t i = 0; i < hdr.entry_count; i++) { + if (fread(&entry, sizeof(efi_entry_t), 1, disk) == 0) { + return -1; + } + + if (callback(&entry, offset, disk) != 0) { + return -1; + } + + if (delta != 0 && fseek(disk, delta, SEEK_CUR) != 0) { + return -1; + } + + offset += hdr.entry_size; + } + + return 0; +} diff --git a/fusee/fusee-secondary/src/gpt.h b/fusee/fusee-secondary/src/gpt.h new file mode 100644 index 000000000..1ab5c537d --- /dev/null +++ b/fusee/fusee-secondary/src/gpt.h @@ -0,0 +1,43 @@ +#ifndef FUSEE_GPT_H +#define FUSEE_GPT_H + +#include + +#include + +typedef struct efi_entry_t { + uint8_t type_uuid[16]; + uint8_t unique_uuid[16]; + uint64_t first_lba; + uint64_t last_lba; /* Inclusive */ + uint64_t attributes; + uint16_t name[36]; +} efi_entry_t; + +typedef struct efi_header { + uint8_t magic[8]; /* Must be "EFI PART" */ + uint32_t revision; + + uint32_t header_size; /* Usually and at most 92 bytes. */ + uint32_t header_crc32; /* 0 during the computation */ + uint32_t reserved; /* Must be 0. */ + + uint64_t header_lba; + uint64_t backup_lba; + uint64_t partitions_first_lba; + uint64_t partitions_last_lba; + + uint8_t disk_guid[16]; + + uint64_t entries_first_lba; + uint32_t entry_count; + uint32_t entry_size; + uint32_t entries_crc32; +} __attribute__((packed, aligned(4))) efi_header_t; + +typedef int (*gpt_entry_iterator_t)(const efi_entry_t *entry, size_t entry_offset, FILE *disk); + +int gpt_get_header(efi_header_t *out, FILE *disk); +int gpt_iterate_through_entries(FILE *disk, gpt_entry_iterator_t callback); + +#endif