Source-Changes-HG archive

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

[src/trunk]: src/sys/arch/i386/stand/lib Teach BIOS disk driver about GPT par...



details:   https://anonhg.NetBSD.org/src/rev/2e4bcee1c5cd
branches:  trunk
changeset: 760480:2e4bcee1c5cd
user:      jakllsch <jakllsch%NetBSD.org@localhost>
date:      Wed Jan 05 22:06:59 2011 +0000

description:
Teach BIOS disk driver about GPT partition tables.
Inspired by Mike Volokhov's GPT booting GSoC project.

diffstat:

 sys/arch/i386/stand/lib/Makefile   |    3 +-
 sys/arch/i386/stand/lib/biosdisk.c |  352 ++++++++++++++++++++++++++++++------
 2 files changed, 295 insertions(+), 60 deletions(-)

diffs (truncated from 524 to 300 lines):

diff -r 8c46246cf44a -r 2e4bcee1c5cd sys/arch/i386/stand/lib/Makefile
--- a/sys/arch/i386/stand/lib/Makefile  Wed Jan 05 21:44:23 2011 +0000
+++ b/sys/arch/i386/stand/lib/Makefile  Wed Jan 05 22:06:59 2011 +0000
@@ -1,4 +1,4 @@
-#      $NetBSD: Makefile,v 1.30 2010/12/20 01:12:44 jakllsch Exp $
+#      $NetBSD: Makefile,v 1.31 2011/01/05 22:06:59 jakllsch Exp $
 
 S?=    ${.CURDIR}/../../../..
 
@@ -14,6 +14,7 @@
 CPPFLAGS= -I$S/lib/libsa ${I386CPPFLAGS} ${I386MISCCPPFLAGS}
 #CPPFLAGS+= -DDISK_DEBUG
 #CPPFLAGS+= -DNO_DISKLABEL
+#CPPFLAGS+= -DNO_GPT
 #CPPFLAGS+= -DSAVE_MEMORY
 
 SRCS= pcio.c conio.S comio.S comio_direct.c biosvideomode.S
diff -r 8c46246cf44a -r 2e4bcee1c5cd sys/arch/i386/stand/lib/biosdisk.c
--- a/sys/arch/i386/stand/lib/biosdisk.c        Wed Jan 05 21:44:23 2011 +0000
+++ b/sys/arch/i386/stand/lib/biosdisk.c        Wed Jan 05 22:06:59 2011 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: biosdisk.c,v 1.35 2011/01/05 21:44:23 jakllsch Exp $   */
+/*     $NetBSD: biosdisk.c,v 1.36 2011/01/05 22:06:59 jakllsch Exp $   */
 
 /*
  * Copyright (c) 1996, 1998
@@ -63,18 +63,22 @@
  * the rights to redistribute these changes.
  */
 
-#ifndef NO_DISKLABEL
+#if !defined(NO_DISKLABEL) || !defined(NO_GPT)
 #define FSTYPENAMES
 #endif
 
+#include <lib/libkern/libkern.h>
+#include <lib/libsa/stand.h>
+
 #include <sys/types.h>
 #include <sys/md5.h>
 #include <sys/param.h>
 #include <sys/disklabel.h>
+#include <sys/disklabel_gpt.h>
+#include <sys/uuid.h>
 
 #include <fs/cd9660/iso.h>
 
-#include <lib/libsa/stand.h>
 #include <lib/libsa/saerrno.h>
 #include <machine/stdarg.h>
 #include <machine/cpu.h>
@@ -88,12 +92,28 @@
 
 #define BUFSIZE        2048    /* must be large enough for a CD sector */
 
+#define BIOSDISKNPART 26
+
 struct biosdisk {
        struct biosdisk_ll ll;
        daddr_t         boff;
        char            buf[BUFSIZE];
+#if !defined(NO_DISKLABEL) || !defined(NO_GPT)
+       struct {
+               daddr_t offset;
+               daddr_t size;
+               int     fstype;
+       } part[BIOSDISKNPART];
+#endif
 };
 
+#ifndef NO_GPT
+const struct uuid GET_nbsd_raid = GPT_ENT_TYPE_NETBSD_RAIDFRAME;
+const struct uuid GET_nbsd_ffs = GPT_ENT_TYPE_NETBSD_FFS;
+const struct uuid GET_nbsd_lfs = GPT_ENT_TYPE_NETBSD_LFS;
+const struct uuid GET_nbsd_swap = GPT_ENT_TYPE_NETBSD_SWAP;
+#endif /* NO_GPT */
+
 #ifdef _STANDALONE
 static struct btinfo_bootdisk bi_disk;
 static struct btinfo_bootwedge bi_wedge;
@@ -162,11 +182,174 @@
        return d;
 }
 
+#if !defined(NO_DISKLABEL) || !defined(NO_GPT)
+static void
+md5(void *hash, const void *data, size_t len)
+{
+       MD5_CTX ctx;
+
+       MD5Init(&ctx);
+       MD5Update(&ctx, data, len);
+       MD5Final(hash, &ctx);
+
+       return;
+}
+#endif
+
+#ifndef NO_GPT
+static bool
+guid_is_nil(const struct uuid *u)
+{
+       static const struct uuid nil = { .time_low = 0 };
+       return (memcmp(u, &nil, sizeof(*u)) == 0 ? true : false);
+}
+
+static bool
+guid_is_equal(const struct uuid *a, const struct uuid *b)
+{
+       return (memcmp(a, b, sizeof(*a)) == 0 ? true : false);
+}
+
+static int
+check_gpt(struct biosdisk *d, daddr_t sector)
+{
+       struct gpt_hdr gpth;
+       const struct gpt_ent *ep;
+       const struct uuid *u;
+       daddr_t entblk;
+       size_t size;
+       uint32_t crc;
+       int sectors;
+       int entries;
+       int entry;
+       int i, j;
+
+       /* read in gpt_hdr sector */
+       if (readsects(&d->ll, sector, 1, d->buf, 1)) {
+#ifdef DISK_DEBUG
+               printf("Error reading GPT header at %"PRId64"\n", sector);
+#endif
+               return EIO;
+       }
+
+       gpth = *(const struct gpt_hdr *)d->buf;
+
+       if (memcmp(GPT_HDR_SIG, gpth.hdr_sig, sizeof(gpth.hdr_sig)))
+               return -1;
+
+       crc = gpth.hdr_crc_self;
+       gpth.hdr_crc_self = 0;
+       gpth.hdr_crc_self = crc32(0, (const void *)&gpth, GPT_HDR_SIZE);
+       if (gpth.hdr_crc_self != crc) {
+               return -1;
+       }
+
+       if (gpth.hdr_lba_self != sector)
+               return -1;
+
+#ifdef _STANDALONE
+       bi_wedge.matchblk = sector;
+       bi_wedge.matchnblks = 1;
+
+       md5(bi_wedge.matchhash, d->buf, d->ll.secsize);
+#endif
+
+       sectors = sizeof(d->buf)/d->ll.secsize; /* sectors per buffer */
+       entries = sizeof(d->buf)/gpth.hdr_entsz; /* entries per buffer */
+       entblk = gpth.hdr_lba_table;
+       crc = crc32(0, NULL, 0);
+
+       j = 0;
+       ep = (const struct gpt_ent *)d->buf;
+
+       for (entry = 0; entry < gpth.hdr_entries; entry += entries) {
+               size = MIN(sizeof(d->buf),
+                   (gpth.hdr_entries - entry) * gpth.hdr_entsz);
+               entries = size / gpth.hdr_entsz;
+               sectors = roundup(size, d->ll.secsize) / d->ll.secsize;
+               if (readsects(&d->ll, entblk, sectors, d->buf, 1))
+                       return -1;
+               entblk += sectors;
+               crc = crc32(crc, (const void *)d->buf, size);
+
+               for (i = 0; j < BIOSDISKNPART && i < entries; i++, j++) {
+                       u = (const struct uuid *)ep[i].ent_type;
+                       if (!guid_is_nil(u)) {
+                               d->part[j].offset = ep[i].ent_lba_start;
+                               d->part[j].size = ep[i].ent_lba_end -
+                                   ep[i].ent_lba_start + 1;
+                               if (guid_is_equal(u, &GET_nbsd_ffs))
+                                       d->part[j].fstype = FS_BSDFFS;
+                               else if (guid_is_equal(u, &GET_nbsd_lfs))
+                                       d->part[j].fstype = FS_BSDLFS;
+                               else if (guid_is_equal(u, &GET_nbsd_raid))
+                                       d->part[j].fstype = FS_RAID;
+                               else if (guid_is_equal(u, &GET_nbsd_swap))
+                                       d->part[j].fstype = FS_SWAP;
+                               else
+                                       d->part[j].fstype = FS_OTHER;
+                       }
+               }
+
+       }
+
+       if (crc != gpth.hdr_crc_table) {
+#ifdef DISK_DEBUG      
+               printf("GPT table CRC invalid\n");
+#endif
+               return -1;
+       }
+
+       return 0;
+}
+
+static int
+read_gpt(struct biosdisk *d)
+{
+       struct biosdisk_extinfo ed;
+       daddr_t gptsector[2];
+       int i, error;
+
+       gptsector[0] = GPT_HDR_BLKNO;
+       if (set_geometry(&d->ll, &ed) == 0 && d->ll.flags & BIOSDISK_INT13EXT) {
+               gptsector[1] = ed.totsec - 1;
+               d->ll.secsize = ed.sbytes;
+       } else {
+#ifdef DISK_DEBUG
+               printf("Unable to determine extended disk geometry - "
+                       "using CHS\n");
+#endif
+               /* at least try some other reasonable values then */
+               gptsector[1] = d->ll.chs_sectors - 1;
+       }
+
+       /*
+        * Use any valid GPT available, do not require both GPTs to be valid
+        */
+       for (i = 0; i < __arraycount(gptsector); i++) {
+               error = check_gpt(d, gptsector[i]);
+               if (error == 0)
+                       break;
+       }
+
+       if (i >= __arraycount(gptsector)) {
+               memset(d->part, 0, sizeof(d->part));
+               return -1;
+       }
+
+#ifdef DISK_DEBUG
+       printf("using %s GPT\n", (i == 0) ? "primary" : "secondary");
+#endif
+       return 0;
+}
+#endif /* !NO_GPT */
+
 #ifndef NO_DISKLABEL
 static int
 check_label(struct biosdisk *d, daddr_t sector)
 {
        struct disklabel *lp;
+       int part;
 
        /* find partition in NetBSD disklabel */
        if (readsects(&d->ll, sector + LABELSECTOR, 1, d->buf, 0)) {
@@ -183,7 +366,31 @@
                return -1;
        }
 
+       memset(d->part, 0, sizeof(d->part));
+       for (part = 0; part < lp->d_npartitions; part++) {
+               if (lp->d_partitions[part].p_size == 0)
+                       continue;
+               if (lp->d_partitions[part].p_fstype == FS_UNUSED)
+                       continue;
+               d->part[part].fstype = lp->d_partitions[part].p_fstype;
+               d->part[part].offset = lp->d_partitions[part].p_offset;
+               d->part[part].size = lp->d_partitions[part].p_size;
+       }
+       
        d->boff = sector;
+
+#ifdef _STANDALONE
+       bi_disk.labelsector = d->boff + LABELSECTOR;
+       bi_disk.label.type = lp->d_type;
+       memcpy(bi_disk.label.packname, lp->d_packname, 16);
+       bi_disk.label.checksum = lp->d_checksum;
+
+       bi_wedge.matchblk = d->boff + LABELSECTOR;
+       bi_wedge.matchnblks = 1;
+
+       md5(bi_wedge.matchhash, d->buf, d->ll.secsize);
+#endif
+
        return 0;
 }
 
@@ -297,17 +504,39 @@
 }
 #endif /* NO_DISKLABEL */
 
+#if !defined(NO_DISKLABEL) || !defined(NO_GPT)
+static int
+read_partitions(struct biosdisk *d)
+{
+       int error;
+
+       error = -1;
+
+#ifndef NO_GPT



Home | Main Index | Thread Index | Old Index