From 35b93e247fbe3a76f656c4975f54a771f5d609fa Mon Sep 17 00:00:00 2001 From: Mark Date: Sat, 4 Jan 2020 20:11:40 +0200 Subject: [PATCH] Add support for GPT partitions --- sys/blk.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) diff --git a/sys/blk.c b/sys/blk.c index 9b2ae52..8f1028c 100644 --- a/sys/blk.c +++ b/sys/blk.c @@ -29,6 +29,7 @@ ssize_t blk_write(struct blkdev *blk, const void *buf, size_t off, size_t lim) { } } +const char GUID_EMPTY[16] = {0}; // TODO: guess this would better be in blk_part.c or something like that struct mbr { @@ -46,6 +47,32 @@ struct mbr { uint16_t sign; } __attribute__((packed)); +struct gpt_header { + char signature[8]; + uint32_t revision; + uint32_t header_size; + uint32_t header_crc32; + uint32_t __res0; + uint64_t my_lba; + uint64_t alt_lba; + uint64_t first_lba; + uint64_t last_lba; + char disk_guid[16]; + uint64_t partition_entry_lba; + uint32_t partition_count; + uint32_t partition_entry_size; + uint32_t partition_array_crc32; +} __attribute__((packed)); + +struct gpt_part_entry { + char type_guid[16]; + char part_guid[16]; + uint64_t start_lba; + uint64_t end_lba; + uint64_t attr; + char part_name[72]; +}; + struct blk_part { struct blkdev *device; uint64_t lba_start; @@ -119,6 +146,56 @@ static int blk_enumerate_mbr(struct blkdev *dev, uint8_t *head) { return 0; } +static int blk_enumerate_gpt(struct blkdev *dev, uint8_t *head) { + // LBA1 - GPT header + struct gpt_header *hdr = (struct gpt_header *) &head[512]; + // Read a single block for partition table entries + char buf[512]; + + _assert(blk_read(dev, buf, hdr->partition_entry_lba * 512, 512) >= 0); + + size_t offset = 0; + size_t part_n = 0; + for (size_t i = 0; i < hdr->partition_count; ++i) { + struct gpt_part_entry *ent = (struct gpt_part_entry *) &buf[offset]; + + if (strncmp(ent->type_guid, GUID_EMPTY, 16)) { + // Maybe some known filesystem here, ignore partition type guid + + struct blk_part *part = (struct blk_part *) kmalloc(sizeof(struct blk_part)); + part->device = dev; + part->lba_start = ent->start_lba; + part->lba_size = ent->end_lba - ent->start_lba; + + void *buf = kmalloc(sizeof(struct blkdev) + sizeof(struct dev_entry)); + struct dev_entry *ent = (struct dev_entry *) buf; + struct blkdev *blk = (struct blkdev *) ((uintptr_t) buf + sizeof(struct dev_entry)); + _assert(ent); + + blk->dev_data = part; + blk->read = blk_part_read; + blk->ent_parent = dev->ent; + + ent->dev = blk; + ent->dev_class = DEV_CLASS_BLOCK; + ent->dev_subclass = DEV_BLOCK_PART; + // XXX: This is ugly + strcpy(ent->dev_name, dev->ent->dev_name); + char digit[2] = { '1' + part_n++, 0 }; + strcat(ent->dev_name, digit); + + dev_entry_add(ent); + } + + offset += hdr->partition_entry_size; + if (offset >= 512) { + break; + } + } + + return 0; +} + struct blkdev *blk_by_name(const char *name) { struct dev_entry *it = dev_iter(); @@ -133,13 +210,14 @@ struct blkdev *blk_by_name(const char *name) { int blk_enumerate_partitions(struct blkdev *dev) { kdebug("Enumerating partitions of %s\n", dev->ent->dev_name); + // TODO: handle stuff where block size is not 512 uint8_t buf[1024]; _assert(blk_read(dev, buf, 0, 1024) >= 0); if (!strncmp((const char *) (buf + 512), "EFI PART", 8)) { // Found GPT - panic("Found GPT: not supported\n"); + return blk_enumerate_gpt(dev, buf); } else if (buf[510] == 0x55 && buf[511] == 0xAA) { // Found MBR return blk_enumerate_mbr(dev, buf);