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