Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/stand/efiboot Add GPT support.



details:   https://anonhg.NetBSD.org/src/rev/a5892d676fc4
branches:  trunk
changeset: 994325:a5892d676fc4
user:      jmcneill <jmcneill%NetBSD.org@localhost>
date:      Thu Nov 01 00:43:38 2018 +0000

description:
Add GPT support.

diffstat:

 sys/stand/efiboot/efiblock.c |  167 +++++++++++++++++++++++++++++++++++++++++-
 sys/stand/efiboot/efiblock.h |    9 ++-
 sys/stand/efiboot/efiboot.c  |    6 +-
 sys/stand/efiboot/efifdt.c   |   15 +++-
 sys/stand/efiboot/version    |    3 +-
 5 files changed, 188 insertions(+), 12 deletions(-)

diffs (truncated from 322 to 300 lines):

diff -r 9bac534445b0 -r a5892d676fc4 sys/stand/efiboot/efiblock.c
--- a/sys/stand/efiboot/efiblock.c      Wed Oct 31 23:49:34 2018 +0000
+++ b/sys/stand/efiboot/efiblock.c      Thu Nov 01 00:43:38 2018 +0000
@@ -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 <nonaka%netbsd.org@localhost>
@@ -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 @@
        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 @@
                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 @@
 
                                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 @@
                }
                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;
        }
diff -r 9bac534445b0 -r a5892d676fc4 sys/stand/efiboot/efiblock.h
--- a/sys/stand/efiboot/efiblock.h      Wed Oct 31 23:49:34 2018 +0000
+++ b/sys/stand/efiboot/efiblock.h      Thu Nov 01 00:43:38 2018 +0000
@@ -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 <jmcneill%invisible.ca@localhost>
@@ -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 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];
 
diff -r 9bac534445b0 -r a5892d676fc4 sys/stand/efiboot/efiboot.c
--- a/sys/stand/efiboot/efiboot.c       Wed Oct 31 23:49:34 2018 +0000
+++ b/sys/stand/efiboot/efiboot.c       Thu Nov 01 00:43:38 2018 +0000
@@ -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 <jmcneill%invisible.ca@localhost>
@@ -84,10 +84,10 @@
 
        efi_acpi_probe();
        efi_fdt_probe();
+       efi_pxe_probe();
+       efi_net_probe();
        efi_file_system_probe();
        efi_block_probe();
-       efi_pxe_probe();
-       efi_net_probe();
 
        boot();
 
diff -r 9bac534445b0 -r a5892d676fc4 sys/stand/efiboot/efifdt.c
--- a/sys/stand/efiboot/efifdt.c        Wed Oct 31 23:49:34 2018 +0000
+++ b/sys/stand/efiboot/efifdt.c        Thu Nov 01 00:43:38 2018 +0000
@@ -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 <jmcneill%invisible.ca@localhost>
@@ -219,6 +219,19 @@
                        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) {



Home | Main Index | Thread Index | Old Index