Module Name: src Committed By: jmcneill Date: Thu Nov 1 00:43:38 UTC 2018
Modified Files: src/sys/stand/efiboot: efiblock.c efiblock.h efiboot.c efifdt.c version Log Message: Add GPT support. To generate a diff of this commit: cvs rdiff -u -r1.3 -r1.4 src/sys/stand/efiboot/efiblock.c cvs rdiff -u -r1.2 -r1.3 src/sys/stand/efiboot/efiblock.h cvs rdiff -u -r1.11 -r1.12 src/sys/stand/efiboot/efiboot.c \ src/sys/stand/efiboot/efifdt.c cvs rdiff -u -r1.6 -r1.7 src/sys/stand/efiboot/version Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/stand/efiboot/efiblock.c diff -u src/sys/stand/efiboot/efiblock.c:1.3 src/sys/stand/efiboot/efiblock.c:1.4 --- src/sys/stand/efiboot/efiblock.c:1.3 Fri Sep 14 21:37:03 2018 +++ src/sys/stand/efiboot/efiblock.c Thu Nov 1 00:43:38 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: efiblock.c,v 1.3 2018/09/14 21:37:03 jakllsch Exp $ */ +/* $NetBSD: efiblock.c,v 1.4 2018/11/01 00:43:38 jmcneill Exp $ */ /*- * Copyright (c) 2016 Kimihiro Nonaka <non...@netbsd.org> @@ -31,6 +31,7 @@ #include <sys/param.h> #include <sys/md5.h> +#include <sys/uuid.h> #include "efiboot.h" #include "efiblock.h" @@ -192,16 +193,114 @@ efi_block_find_partitions_mbr(struct efi return 0; } +static const struct { + struct uuid guid; + uint8_t fstype; +} gpt_guid_to_str[] = { + { GPT_ENT_TYPE_NETBSD_FFS, FS_BSDFFS }, + { GPT_ENT_TYPE_NETBSD_LFS, FS_BSDLFS }, + { GPT_ENT_TYPE_NETBSD_RAIDFRAME, FS_RAID }, + { GPT_ENT_TYPE_NETBSD_CCD, FS_CCD }, + { GPT_ENT_TYPE_NETBSD_CGD, FS_CGD }, + { GPT_ENT_TYPE_MS_BASIC_DATA, FS_MSDOS }, /* or NTFS? ambiguous */ +}; + +static int +efi_block_find_partitions_gpt_entry(struct efi_block_dev *bdev, struct gpt_hdr *hdr, struct gpt_ent *ent, UINT32 index) +{ + struct efi_block_part *bpart; + uint8_t fstype = FS_UNUSED; + struct uuid uuid; + int n; + + memcpy(&uuid, ent->ent_type, sizeof(uuid)); + for (n = 0; n < __arraycount(gpt_guid_to_str); n++) + if (memcmp(ent->ent_type, &gpt_guid_to_str[n].guid, sizeof(ent->ent_type)) == 0) { + fstype = gpt_guid_to_str[n].fstype; + break; + } + if (fstype == FS_UNUSED) + return 0; + + bpart = alloc(sizeof(*bpart)); + bpart->index = index; + bpart->bdev = bdev; + bpart->type = EFI_BLOCK_PART_GPT; + bpart->gpt.fstype = fstype; + bpart->gpt.ent = *ent; + memcpy(bpart->hash, ent->ent_guid, sizeof(bpart->hash)); + TAILQ_INSERT_TAIL(&bdev->partitions, bpart, entries); + + return 0; +} + +static int +efi_block_find_partitions_gpt(struct efi_block_dev *bdev) +{ + struct gpt_hdr hdr; + struct gpt_ent ent; + EFI_STATUS status; + UINT32 sz, entry; + uint8_t *buf; + + sz = __MAX(sizeof(hdr), bdev->bio->Media->BlockSize); + sz = roundup(sz, bdev->bio->Media->BlockSize); + buf = AllocatePool(sz); + if (!buf) + return ENOMEM; + + status = uefi_call_wrapper(bdev->bio->ReadBlocks, 5, bdev->bio, bdev->media_id, GPT_HDR_BLKNO, sz, buf); + if (EFI_ERROR(status)) { + FreePool(buf); + return EIO; + } + memcpy(&hdr, buf, sizeof(hdr)); + FreePool(buf); + + if (memcmp(hdr.hdr_sig, GPT_HDR_SIG, sizeof(hdr.hdr_sig)) != 0) + return ENOENT; + if (le32toh(hdr.hdr_entsz) < sizeof(ent)) + return EINVAL; + + sz = __MAX(le32toh(hdr.hdr_entsz) * le32toh(hdr.hdr_entries), bdev->bio->Media->BlockSize); + sz = roundup(sz, bdev->bio->Media->BlockSize); + buf = AllocatePool(sz); + if (!buf) + return ENOMEM; + + status = uefi_call_wrapper(bdev->bio->ReadBlocks, 5, bdev->bio, bdev->media_id, le64toh(hdr.hdr_lba_table), sz, buf); + if (EFI_ERROR(status)) { + FreePool(buf); + return EIO; + } + + for (entry = 0; entry < le32toh(hdr.hdr_entries); entry++) { + memcpy(&ent, buf + (entry * le32toh(hdr.hdr_entsz)), sizeof(ent)); + efi_block_find_partitions_gpt_entry(bdev, &hdr, &ent, entry); + } + + FreePool(buf); + + return 0; +} + static int efi_block_find_partitions(struct efi_block_dev *bdev) { - return efi_block_find_partitions_mbr(bdev); + int error; + + error = efi_block_find_partitions_gpt(bdev); + if (error) + error = efi_block_find_partitions_mbr(bdev); + + return error; } void efi_block_probe(void) { struct efi_block_dev *bdev; + struct efi_block_part *bpart; EFI_BLOCK_IO *bio; EFI_STATUS status; uint16_t devindex = 0; @@ -234,13 +333,40 @@ efi_block_probe(void) TAILQ_INIT(&bdev->partitions); TAILQ_INSERT_TAIL(&efi_block_devs, bdev, entries); + efi_block_find_partitions(bdev); + if (depth > 0 && efi_device_path_ncmp(efi_bootdp, DevicePathFromHandle(efi_block[n]), depth) == 0) { - char devname[9]; - snprintf(devname, sizeof(devname), "hd%ua", bdev->index); - set_default_device(devname); + TAILQ_FOREACH(bpart, &bdev->partitions, entries) { + uint8_t fstype = FS_UNUSED; + switch (bpart->type) { + case EFI_BLOCK_PART_DISKLABEL: + fstype = bpart->disklabel.part.p_fstype; + break; + case EFI_BLOCK_PART_GPT: + fstype = bpart->gpt.fstype; + break; + } + if (fstype == FS_BSDFFS) { + char devname[9]; + snprintf(devname, sizeof(devname), "hd%u%c", bdev->index, bpart->index + 'a'); + set_default_device(devname); + break; + } + } } + } +} - efi_block_find_partitions(bdev); +static void +print_guid(const uint8_t *guid) +{ + const int index[] = { 3, 2, 1, 0, 5, 4, 7, 6, 8, 9, 10, 11, 12, 13, 14, 15 }; + int i; + + for (i = 0; i < 16; i++) { + printf("%02x", guid[index[i]]); + if (i == 3 || i == 5 || i == 7 || i == 9) + printf("-"); } } @@ -284,6 +410,27 @@ efi_block_show(void) printf("%s\n", fstypenames[bpart->disklabel.part.p_fstype]); break; + case EFI_BLOCK_PART_GPT: + printf(" hd%u%c ", bdev->index, bpart->index + 'a'); + + if (bpart->gpt.ent.ent_name[0] == 0x0000) { + printf("\""); + print_guid(bpart->gpt.ent.ent_guid); + printf("\""); + } else { + Print(L"\"%s\"", bpart->gpt.ent.ent_name); + } + + /* Size in MB */ + size = (le64toh(bpart->gpt.ent.ent_lba_end) - le64toh(bpart->gpt.ent.ent_lba_start)) * bdev->bio->Media->BlockSize; + size /= (1024 * 1024); + if (size >= 10000) + printf(" (%"PRIu64" GB): ", size / 1024); + else + printf(" (%"PRIu64" MB): ", size); + + printf("%s\n", fstypenames[bpart->gpt.fstype]); + break; default: break; } @@ -357,6 +504,14 @@ efi_block_strategy(void *devdata, int rw } dblk += bpart->disklabel.part.p_offset; break; + case EFI_BLOCK_PART_GPT: + if (bpart->bdev->bio->Media->BlockSize != DEV_BSIZE) { + printf("%s: unsupported block size %d (expected %d)\n", __func__, + bpart->bdev->bio->Media->BlockSize, DEV_BSIZE); + return EIO; + } + dblk += le64toh(bpart->gpt.ent.ent_lba_start); + break; default: return EINVAL; } Index: src/sys/stand/efiboot/efiblock.h diff -u src/sys/stand/efiboot/efiblock.h:1.2 src/sys/stand/efiboot/efiblock.h:1.3 --- src/sys/stand/efiboot/efiblock.h:1.2 Mon Aug 27 09:51:32 2018 +++ src/sys/stand/efiboot/efiblock.h Thu Nov 1 00:43:38 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: efiblock.h,v 1.2 2018/08/27 09:51:32 jmcneill Exp $ */ +/* $NetBSD: efiblock.h,v 1.3 2018/11/01 00:43:38 jmcneill Exp $ */ /*- * Copyright (c) 2018 Jared McNeill <jmcne...@invisible.ca> @@ -29,6 +29,7 @@ #include <sys/queue.h> #include <sys/bootblock.h> #include <sys/disklabel.h> +#include <sys/disklabel_gpt.h> enum efi_block_part_type { EFI_BLOCK_PART_DISKLABEL, @@ -52,12 +53,18 @@ struct efi_block_part_disklabel { struct partition part; }; +struct efi_block_part_gpt { + uint8_t fstype; + struct gpt_ent ent; +}; + struct efi_block_part { uint32_t index; struct efi_block_dev *bdev; enum efi_block_part_type type; union { struct efi_block_part_disklabel disklabel; + struct efi_block_part_gpt gpt; }; uint8_t hash[16]; Index: src/sys/stand/efiboot/efiboot.c diff -u src/sys/stand/efiboot/efiboot.c:1.11 src/sys/stand/efiboot/efiboot.c:1.12 --- src/sys/stand/efiboot/efiboot.c:1.11 Wed Oct 31 13:00:35 2018 +++ src/sys/stand/efiboot/efiboot.c Thu Nov 1 00:43:38 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: efiboot.c,v 1.11 2018/10/31 13:00:35 jmcneill Exp $ */ +/* $NetBSD: efiboot.c,v 1.12 2018/11/01 00:43:38 jmcneill Exp $ */ /*- * Copyright (c) 2018 Jared McNeill <jmcne...@invisible.ca> @@ -84,10 +84,10 @@ efi_main(EFI_HANDLE imageHandle, EFI_SYS efi_acpi_probe(); efi_fdt_probe(); - efi_file_system_probe(); - efi_block_probe(); efi_pxe_probe(); efi_net_probe(); + efi_file_system_probe(); + efi_block_probe(); boot(); Index: src/sys/stand/efiboot/efifdt.c diff -u src/sys/stand/efiboot/efifdt.c:1.11 src/sys/stand/efiboot/efifdt.c:1.12 --- src/sys/stand/efiboot/efifdt.c:1.11 Wed Oct 31 12:59:43 2018 +++ src/sys/stand/efiboot/efifdt.c Thu Nov 1 00:43:38 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: efifdt.c,v 1.11 2018/10/31 12:59:43 jmcneill Exp $ */ +/* $NetBSD: efifdt.c,v 1.12 2018/11/01 00:43:38 jmcneill Exp $ */ /*- * Copyright (c) 2018 Jared McNeill <jmcne...@invisible.ca> @@ -219,6 +219,19 @@ efi_fdt_bootargs(const char *bootargs) fdt_setprop_u32(fdt_data, chosen, "netbsd,partition", bpart->index); break; + case EFI_BLOCK_PART_GPT: + if (bpart->gpt.ent.ent_name[0] == 0x0000) { + fdt_setprop(fdt_data, chosen, "netbsd,gpt-guid", + bpart->hash, sizeof(bpart->hash)); + } else { + char *label = NULL; + int rv = ucs2_to_utf8(bpart->gpt.ent.ent_name, &label); + if (rv == 0) { + fdt_setprop_string(fdt_data, chosen, "netbsd,gpt-label", label); + FreePool(label); + } + } + break; default: break; } Index: src/sys/stand/efiboot/version diff -u src/sys/stand/efiboot/version:1.6 src/sys/stand/efiboot/version:1.7 --- src/sys/stand/efiboot/version:1.6 Sun Oct 28 10:17:47 2018 +++ src/sys/stand/efiboot/version Thu Nov 1 00:43:38 2018 @@ -1,4 +1,4 @@ -$NetBSD: version,v 1.6 2018/10/28 10:17:47 jmcneill Exp $ +$NetBSD: version,v 1.7 2018/11/01 00:43:38 jmcneill Exp $ NOTE ANY CHANGES YOU MAKE TO THE EFI BOOTLOADER HERE. The format of this file is important - make sure the entries are appended on end, last item @@ -10,3 +10,4 @@ is taken as the current. 1.3: Add ACPI support. 1.4: Add bootfile support. 1.5: EFI runtime support. +1.6: Add GPT support.