Initial support to read GPT partition tables in the kernel, if option GPT.
authormiod <miod@openbsd.org>
Sun, 13 Jul 2014 15:32:28 +0000 (15:32 +0000)
committermiod <miod@openbsd.org>
Sun, 13 Jul 2014 15:32:28 +0000 (15:32 +0000)
Contributed by Markus Mueller; code based upon Bitrig's GPT support, with
stricter GPT structures validation and support for alternate header places.

ok deraadt@ jsing@ krw@

sys/arch/amd64/amd64/disksubr.c
sys/arch/amd64/conf/GENERIC
sys/arch/i386/conf/GENERIC
sys/arch/i386/i386/disksubr.c
sys/conf/files
sys/kern/kern_uuid.c [new file with mode: 0644]
sys/kern/subr_disk.c
sys/sys/disklabel.h
sys/sys/uuid.h [new file with mode: 0644]

index e2f1c1a..ae83a2c 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: disksubr.c,v 1.66 2014/06/15 11:43:24 sf Exp $        */
+/*     $OpenBSD: disksubr.c,v 1.67 2014/07/13 15:32:28 miod Exp $      */
 /*     $NetBSD: disksubr.c,v 1.21 1996/05/03 19:42:03 christos Exp $   */
 
 /*
@@ -91,6 +91,12 @@ readdisklabel(dev_t dev, void (*strat)(struct buf *),
        bp = geteblk((int)lp->d_secsize);
        bp->b_dev = dev;
 
+#if defined(GPT)
+       error = readgptlabel(bp, strat, lp, NULL, spoofonly);
+       if (error == 0)
+               goto done;
+#endif
+
        error = readdoslabel(bp, strat, lp, NULL, spoofonly);
        if (error == 0)
                goto done;
index bff331e..901af9e 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: GENERIC,v 1.371 2014/07/12 21:56:56 tedu Exp $
+#      $OpenBSD: GENERIC,v 1.372 2014/07/13 15:32:28 miod Exp $
 #
 # For further information on compiling OpenBSD kernels, see the config(8)
 # man page.
@@ -22,6 +22,7 @@ option                MTRR            # CPU memory range attributes control
 #option                KGDB            # Remote debugger support; exclusive of DDB
 #option                "KGDB_DEVNAME=\"com\"",KGDBADDR=0x2f8,KGDBRATE=9600
 
+option         GPT             # GPT partition table support
 option         NTFS            # NTFS support
 option         HIBERNATE       # Hibernate support
 
index 8730027..7655679 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: GENERIC,v 1.780 2014/07/12 21:56:56 tedu Exp $
+#      $OpenBSD: GENERIC,v 1.781 2014/07/13 15:32:28 miod Exp $
 #
 # For further information on compiling OpenBSD kernels, see the config(8)
 # man page.
@@ -27,6 +27,7 @@ option                MTRR            # CPU memory range attributes control
 option         COMPAT_LINUX    # binary compatibility with Linux
 
 #option                PROCFS          # /proc, currently broken
+option         GPT             # GPT partition table support
 option         NTFS            # NTFS support
 option         HIBERNATE       # Hibernate support
 
index 6da9f77..a8bf13d 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: disksubr.c,v 1.106 2014/06/15 11:43:24 sf Exp $       */
+/*     $OpenBSD: disksubr.c,v 1.107 2014/07/13 15:32:28 miod Exp $     */
 /*     $NetBSD: disksubr.c,v 1.21 1996/05/03 19:42:03 christos Exp $   */
 
 /*
@@ -93,6 +93,12 @@ readdisklabel(dev_t dev, void (*strat)(struct buf *),
        bp = geteblk((int)lp->d_secsize);
        bp->b_dev = dev;
 
+#if defined(GPT)
+       error = readgptlabel(bp, strat, lp, NULL, spoofonly);
+       if (error == 0)
+               goto done;
+#endif
+
        error = readdoslabel(bp, strat, lp, NULL, spoofonly);
        if (error == 0)
                goto done;
index 2ba37e0..3941639 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: files,v 1.574 2014/07/13 13:28:26 pelikan Exp $
+#      $OpenBSD: files,v 1.575 2014/07/13 15:32:28 miod Exp $
 #      $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $
 
 #      @(#)files.newconf       7.5 (Berkeley) 5/10/93
@@ -693,6 +693,7 @@ file kern/kern_synch.c
 file kern/kern_tc.c
 file kern/kern_time.c
 file kern/kern_timeout.c
+file kern/kern_uuid.c                  gpt
 file kern/kern_watchdog.c              !small_kernel
 file kern/kern_workq.c
 file kern/kern_task.c
@@ -1042,7 +1043,7 @@ file lib/libkern/arch/${MACHINE_ARCH}/htons.S | lib/libkern/htons.c
 file lib/libkern/arch/${MACHINE_ARCH}/strncasecmp.S | lib/libkern/strncasecmp.c
 
 file lib/libz/adler32.c                        ppp_deflate | ipsec | crypto | bios
-file lib/libz/crc32.c                  ppp_deflate | ipsec | crypto
+file lib/libz/crc32.c                  ppp_deflate | ipsec | crypto | gpt
 file lib/libz/infback.c                        ppp_deflate | ipsec | crypto
 file lib/libz/inffast.c                        ppp_deflate | ipsec | crypto
 file lib/libz/inflate.c                        ppp_deflate | ipsec | crypto
diff --git a/sys/kern/kern_uuid.c b/sys/kern/kern_uuid.c
new file mode 100644 (file)
index 0000000..7505bf4
--- /dev/null
@@ -0,0 +1,151 @@
+/*     $OpenBSD: kern_uuid.c,v 1.1 2014/07/13 15:32:28 miod Exp $      */
+/*     $NetBSD: kern_uuid.c,v 1.18 2011/11/19 22:51:25 tls Exp $       */
+
+/*
+ * Copyright (c) 2002 Marcel Moolenaar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD: /repoman/r/ncvs/src/sys/kern/kern_uuid.c,v 1.7 2004/01/12 
+13:34:11 rse Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/endian.h>
+#include <sys/systm.h>
+#include <sys/uuid.h>
+
+/*
+ * For a description of UUIDs see RFC 4122.
+ */
+
+struct uuid_private {
+       struct {
+               uint32_t low;
+               uint16_t mid;
+               uint16_t hi;
+       } time;
+       uint16_t seq;
+       uint16_t node[UUID_NODE_LEN>>1];
+};
+
+#ifdef DEBUG
+int
+uuid_snprintf(char *buf, size_t sz, const struct uuid *uuid)
+{
+       const struct uuid_private *id;
+       int cnt;
+
+       id = (const struct uuid_private *)uuid;
+       cnt = snprintf(buf, sz, "%08x-%04x-%04x-%04x-%04x%04x%04x",
+           id->time.low, id->time.mid, id->time.hi, betoh16(id->seq),
+           betoh16(id->node[0]), betoh16(id->node[1]), betoh16(id->node[2]));
+       return (cnt);
+}
+
+int
+uuid_printf(const struct uuid *uuid)
+{
+       char buf[_UUID_BUF_LEN];
+
+       (void) uuid_snprintf(buf, sizeof(buf), uuid);
+       printf("%s", buf);
+       return (0);
+}
+#endif
+
+/*
+ * Encode/Decode UUID into octet-stream.
+ *
+ * 0                   1                   2                   3
+ *   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |                          time_low                             |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |       time_mid                |         time_hi_and_version   |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |clk_seq_hi_res |  clk_seq_low  |         node (0-1)            |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |                         node (2-5)                            |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+void
+uuid_enc_le(void *buf, const struct uuid *uuid)
+{
+       uint8_t *p = buf;
+       int i;
+
+       p[0] = htole32(uuid->time_low);
+       p[4] = htole16(uuid->time_mid);
+       p[6] = htole16(uuid->time_hi_and_version);
+       p[8] = uuid->clock_seq_hi_and_reserved;
+       p[9] = uuid->clock_seq_low;
+       for (i = 0; i < UUID_NODE_LEN; i++)
+               p[10 + i] = uuid->node[i];
+}
+
+void
+uuid_dec_le(void const *buf, struct uuid *uuid)
+{
+       const uint8_t *p = buf;
+       int i;
+
+       uuid->time_low = letoh32(*(uint32_t*)p);
+       uuid->time_mid = letoh16(*(uint16_t*)(p + 4));
+       uuid->time_hi_and_version = letoh16(*(uint16_t*)(p + 6));
+       uuid->clock_seq_hi_and_reserved = p[8];
+       uuid->clock_seq_low = p[9];
+       for (i = 0; i < UUID_NODE_LEN; i++)
+               uuid->node[i] = p[10 + i];
+}
+
+void
+uuid_enc_be(void *buf, const struct uuid *uuid)
+{
+       uint8_t *p = buf;
+       int i;
+
+       p[0] = htobe32(uuid->time_low);
+       p[4] = htobe16(uuid->time_mid);
+       p[6] = htobe16(uuid->time_hi_and_version);
+       p[8] = uuid->clock_seq_hi_and_reserved;
+       p[9] = uuid->clock_seq_low;
+       for (i = 0; i < UUID_NODE_LEN; i++)
+               p[10 + i] = uuid->node[i];
+}
+
+void
+uuid_dec_be(void const *buf, struct uuid *uuid)
+{
+       const uint8_t *p = buf;
+       int i;
+
+       uuid->time_low = betoh32(*(uint32_t*)p);
+       uuid->time_mid = betoh16(*(uint16_t*)(p + 4));
+       uuid->time_hi_and_version = betoh16(*(uint16_t*)(p + 6));
+       uuid->clock_seq_hi_and_reserved = p[8];
+       uuid->clock_seq_low = p[9];
+       for (i = 0; i < UUID_NODE_LEN; i++)
+               uuid->node[i] = p[10 + i];
+}
index 95fc03e..3262da5 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: subr_disk.c,v 1.167 2014/07/12 18:43:32 tedu Exp $    */
+/*     $OpenBSD: subr_disk.c,v 1.168 2014/07/13 15:32:28 miod Exp $    */
 /*     $NetBSD: subr_disk.c,v 1.17 1996/03/16 23:17:08 christos Exp $  */
 
 /*
 #include <dev/rndvar.h>
 #include <dev/cons.h>
 
+#include <lib/libz/zlib.h>
+
 #include "softraid.h"
 
+#ifdef DEBUG
+#define DPRINTF(x...)  printf(x)
+#else
+#define DPRINTF(x...)
+#endif
+
 /*
  * A global list of all disks attached to the system.  May grow or
  * shrink over time.
@@ -530,6 +538,320 @@ notfat:
        return (error);
 }
 
+#ifdef GPT
+
+int gpt_chk_hdr(struct gpt_header *);
+int gpt_chk_parts(struct gpt_header *, struct gpt_partition *);
+int get_fstype(struct uuid *);
+
+int
+gpt_chk_hdr(struct gpt_header *gh)
+{
+       u_int32_t orig_gh_csum = gh->gh_csum;
+       gh->gh_csum = 0;
+       gh->gh_csum = crc32(0, (unsigned char *)gh, gh->gh_size);
+
+       if (orig_gh_csum != gh->gh_csum)
+               return (EINVAL);
+
+       return 0;
+}
+
+int
+gpt_chk_parts(struct gpt_header *gh, struct gpt_partition *gp)
+{
+       u_int32_t checksum;
+       checksum = crc32(0, (unsigned char *)gp,
+           gh->gh_part_num * gh->gh_part_size);
+
+       if (checksum != gh->gh_part_csum)
+               return (EINVAL);
+
+       return 0;
+}
+
+int
+get_fstype(struct uuid *uuid_part)
+{
+       static int init = 0;
+       static struct uuid uuid_openbsd, uuid_msdos, uuid_chromefs,
+           uuid_linux, uuid_hfs, uuid_unused;
+       static const uint8_t gpt_uuid_openbsd[] = GPT_UUID_OPENBSD;
+       static const uint8_t gpt_uuid_msdos[] = GPT_UUID_MSDOS;
+       static const uint8_t gpt_uuid_chromerootfs[] = GPT_UUID_CHROMEROOTFS;
+       static const uint8_t gpt_uuid_linux[] = GPT_UUID_LINUX;
+       static const uint8_t gpt_uuid_hfs[] = GPT_UUID_APPLE_HFS;
+       static const uint8_t gpt_uuid_unused[] = GPT_UUID_UNUSED;
+
+       if (init == 0) {
+               uuid_dec_be(gpt_uuid_openbsd, &uuid_openbsd);
+               uuid_dec_be(gpt_uuid_msdos, &uuid_msdos);
+               uuid_dec_be(gpt_uuid_chromerootfs, &uuid_chromefs);
+               uuid_dec_be(gpt_uuid_linux, &uuid_linux);
+               uuid_dec_be(gpt_uuid_hfs, &uuid_hfs);
+               uuid_dec_be(gpt_uuid_unused, &uuid_unused);
+               init = 1;
+       }
+
+       if (!memcmp(uuid_part, &uuid_unused, sizeof(struct uuid)))
+               return FS_UNUSED;
+       else if (!memcmp(uuid_part, &uuid_openbsd, sizeof(struct uuid)))
+               return FS_BSDFFS;
+       else if (!memcmp(uuid_part, &uuid_msdos, sizeof(struct uuid)))
+               return FS_MSDOS;
+       else if (!memcmp(uuid_part, &uuid_chromefs, sizeof(struct uuid)))
+               return FS_EXT2FS;
+       else if (!memcmp(uuid_part, &uuid_linux, sizeof(struct uuid)))
+               return FS_EXT2FS;
+       else if (!memcmp(uuid_part, &uuid_hfs, sizeof(struct uuid)))
+               return FS_HFS;
+       else
+               return FS_OTHER;
+}
+
+/*
+ * If gpt partition table requested, attempt to load it and
+ * find disklabel inside a GPT partition. Return buffer
+ * for use in signalling errors if requested.
+ * 
+ * XXX: readgptlabel() is based on readdoslabel(), so they should be merged
+ */
+int
+readgptlabel(struct buf *bp, void (*strat)(struct buf *),
+    struct disklabel *lp, daddr_t *partoffp, int spoofonly)
+{
+       struct gpt_header gh;
+       struct gpt_partition *gp, *gp_tmp;
+       size_t gpsz;
+       struct uuid uuid_part, uuid_openbsd;
+       struct partition *pp;
+
+       daddr_t part_blkno;
+       u_int64_t gptpartoff = 0, gptpartend = DL_GETBEND(lp);
+       int i, altheader = 0, error, n=0, ourpart = -1, offset;
+
+       static const u_int8_t gpt_uuid_openbsd[] = GPT_UUID_OPENBSD;
+       u_int8_t fstype;
+
+       uuid_dec_be(gpt_uuid_openbsd, &uuid_openbsd);
+
+       if (lp->d_secpercyl == 0)
+               return (EINVAL);        /* invalid label */
+       if (lp->d_secsize == 0)
+               return (ENOSPC);        /* disk too small */
+
+       /* 
+        * XXX: We should not trust the primary header and instead 
+        * use the last LBA of the disk, as defined in the standard.
+        */
+       for (part_blkno = GPTSECTOR; ; part_blkno = gh.gh_lba_alt, 
+           altheader = 1) {
+               /* read header record */
+               bp->b_blkno = DL_BLKTOSEC(lp, part_blkno) * DL_BLKSPERSEC(lp);
+               offset = DL_BLKOFFSET(lp, part_blkno);
+               bp->b_bcount = lp->d_secsize;
+               bp->b_error = 0; /* B_ERROR and b_error may have stale data. */
+               CLR(bp->b_flags, B_READ | B_WRITE | B_DONE | B_ERROR);
+               SET(bp->b_flags, B_BUSY | B_READ | B_RAW);
+               (*strat)(bp);
+               error = biowait(bp);
+
+               if (error) {
+                       DPRINTF("error reading from disk\n");
+       /*wrong*/       if (partoffp)
+       /*wrong*/               *partoffp = -1;
+                       return (error);
+               }
+
+               bcopy(bp->b_data + offset, &gh, sizeof(gh));
+
+               if (letoh64(gh.gh_sig) != GPTSIGNATURE)
+                       return (EINVAL);
+
+               /* we only support version 1.0 */
+               if (letoh32(gh.gh_rev) != GPTREVISION)
+                       return (EINVAL);
+
+               if (gpt_chk_hdr(&gh)) {
+                       /* header broken, using alternate header */
+                       if (altheader) {
+                               DPRINTF("alternate header also broken\n");
+                               return (EINVAL);
+                       }
+                       
+                       if (gh.gh_lba_alt >= DL_GETDSIZE(lp)) {
+                               DPRINTF("alternate header's position is "
+                                   "bogous\n");
+                               return (EINVAL); 
+                       }
+
+                       continue;
+               }
+
+               /* 
+                * Header size must be greater than or equal to 92 and less
+                * than or equal to the logical block size.
+                */
+               if (letoh32(gh.gh_size) < GPTMINHDRSIZE
+                   && letoh32(gh.gh_size) > DEV_BSIZE)
+                       return (EINVAL);
+
+               if (letoh64(gh.gh_lba_start) >= DL_GETDSIZE(lp) ||
+                   letoh64(gh.gh_lba_end) >= DL_GETDSIZE(lp) ||
+                   letoh64(gh.gh_part_lba) >= DL_GETDSIZE(lp))
+                       return (EINVAL);
+
+               /*
+               * Size per partition entry shall be 128*(2**n) with n >= 0.
+               * We don't support partition entries larger than block size.
+               */
+               if (letoh32(gh.gh_part_size) % GPTMINPARTSIZE
+                   || letoh32(gh.gh_part_size) > DEV_BSIZE
+                   || GPT_PARTSPERSEC(&gh) == 0) {
+                       DPRINTF("invalid partition size\n");
+                       return (EINVAL);
+               }
+               
+               /* XXX: we don't support multiples of GPTMINPARTSIZE yet */
+               if (letoh32(gh.gh_part_size) != GPTMINPARTSIZE) {
+                       DPRINTF("partition sizes larger than %d bytes are not "
+                           "supported", GPTMINPARTSIZE);
+                       return (EINVAL);
+               }
+
+               /* read GPT partition entry array */
+               gpsz = letoh32(gh.gh_part_num) * sizeof(struct gpt_partition);
+               gp = malloc(gpsz, M_DEVBUF, M_NOWAIT|M_ZERO);
+               if (gp == NULL)
+                       return (ENOMEM);
+
+               /*
+               * XXX: Fails if # of partition entries is no multiple of
+               * GPT_PARTSPERSEC(&gh)
+               */
+               for (i = 0; i < letoh32(gh.gh_part_num) / GPT_PARTSPERSEC(&gh);
+                    i++) {
+                       part_blkno = letoh64(gh.gh_part_lba) + i;
+                       /* read partition record */
+                       bp->b_blkno = DL_BLKTOSEC(lp, part_blkno) *
+                           DL_BLKSPERSEC(lp);
+                       offset = DL_BLKOFFSET(lp, part_blkno);
+                       bp->b_bcount = lp->d_secsize;
+                       /* B_ERROR and b_error may have stale data. */
+                       bp->b_error = 0;
+                       CLR(bp->b_flags, B_READ | B_WRITE | B_DONE | B_ERROR);
+                       SET(bp->b_flags, B_BUSY | B_READ | B_RAW);
+                       (*strat)(bp);
+                       error = biowait(bp);
+                       if (error) {
+       /*wrong*/               if (partoffp)
+       /*wrong*/                       *partoffp = -1;
+                               free(gp, M_DEVBUF, gpsz);
+                               return (error);
+                       }
+
+                       bcopy(bp->b_data + offset, gp +
+                           i * GPT_PARTSPERSEC(&gh), GPT_PARTSPERSEC(&gh) *
+                           sizeof(struct gpt_partition));
+               }
+
+               if (gpt_chk_parts(&gh, gp)) {
+                       DPRINTF("partition entries broken, using alternate "
+                           "header\n");
+                       free(gp, M_DEVBUF, gpsz);
+
+                       if (altheader) {
+                               DPRINTF("alternate partition entries are also "
+                                   "broken\n");
+                               return (EINVAL);
+                       }
+
+                       continue;
+               }
+               break;
+       }
+
+       /* find OpenBSD partition */
+       for (gp_tmp = gp, i = 0; i < letoh32(gh.gh_part_num) && ourpart == -1;
+           gp_tmp++, i++) {
+               if (letoh64(gp_tmp->gp_lba_start) > letoh64(gp_tmp->gp_lba_end)
+                   || letoh64(gp_tmp->gp_lba_start) < letoh64(gh.gh_lba_start)
+                   || letoh64(gp_tmp->gp_lba_end) > letoh64(gh.gh_lba_end))
+                       continue; /* entry invalid */
+
+               uuid_dec_le(&gp_tmp->gp_type, &uuid_part);
+               if (!memcmp(&uuid_part, &uuid_openbsd, sizeof(struct uuid))) {
+                       ourpart = i; /* found it */
+               }
+
+               /*
+                * In case the disklabel read below fails, we want to
+                * provide a fake label in i-p.
+                */
+               fstype = get_fstype(&uuid_part);
+
+               /*
+                * Don't set fstype/offset/size when just looking for
+                * the offset of the OpenBSD partition. It would
+                * invalidate the disklabel checksum!
+                *
+                * Don't try to spoof more than 8 partitions, i.e.
+                * 'i' -'p'.
+                */
+               if (partoffp || n >= 8)
+                       continue;
+
+               pp = &lp->d_partitions[8+n];
+               n++;
+               pp->p_fstype = fstype;
+               DL_SETPOFFSET(pp, letoh64(gp_tmp->gp_lba_start));
+               DL_SETPSIZE(pp, letoh64(gp_tmp->gp_lba_end)
+                   - letoh64(gp_tmp->gp_lba_start) + 1);
+       }
+
+       if (ourpart != -1) {
+               /* found our OpenBSD partition, so use it */
+               gp_tmp = &gp[ourpart];
+               gptpartoff = letoh64(gp_tmp->gp_lba_start);
+               gptpartend = letoh64(gp_tmp->gp_lba_end) + 1;
+       } else
+               spoofonly = 1;  /* No disklabel to read from disk. */
+
+       if (!partoffp)
+               /* Must not modify *lp when partoffp is set. */
+               lp->d_npartitions = MAXPARTITIONS;
+
+       free(gp, M_DEVBUF, gpsz);
+
+       /* record the OpenBSD partition's placement for the caller */
+       if (partoffp)
+               *partoffp = gptpartoff;
+       else {
+               DL_SETBSTART(lp, gptpartoff);
+               DL_SETBEND(lp, (gptpartend < DL_GETDSIZE(lp)) ? gptpartend :
+                   DL_GETDSIZE(lp));
+       }
+
+       /* don't read the on-disk label if we are in spoofed-only mode */
+       if (spoofonly)
+               return (0);
+
+       bp->b_blkno = DL_BLKTOSEC(lp, gptpartoff + DOS_LABELSECTOR) *
+           DL_BLKSPERSEC(lp);
+       offset = DL_BLKOFFSET(lp, gptpartoff + DOS_LABELSECTOR);
+       bp->b_bcount = lp->d_secsize;
+       CLR(bp->b_flags, B_READ | B_WRITE | B_DONE);
+       SET(bp->b_flags, B_BUSY | B_READ | B_RAW);
+       (*strat)(bp);
+       if (biowait(bp))
+               return (bp->b_error);
+
+       /* sub-GPT disklabels are always at a LABELOFFSET of 0 */
+       return checkdisklabel(bp->b_data + offset, lp, gptpartoff, gptpartend);
+}
+
+#endif
+
 /*
  * Check new disk label for sensibility before setting it.
  */
index 98cc01e..00c5c90 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: disklabel.h,v 1.61 2014/07/01 05:22:09 dlg Exp $      */
+/*     $OpenBSD: disklabel.h,v 1.62 2014/07/13 15:32:28 miod Exp $     */
 /*     $NetBSD: disklabel.h,v 1.41 1996/05/10 23:07:37 mark Exp $      */
 
 /*
@@ -47,6 +47,8 @@
  */
 #include <machine/disklabel.h>
 
+#include <sys/uuid.h>
+
 /*
  * The absolute maximum number of disk partitions allowed.
  * This is the maximum value of MAXPARTITIONS for which 'struct disklabel'
@@ -380,6 +382,96 @@ struct partinfo {
        struct partition *part;
 };
 
+/* GUID partition table -- located at sector 1 of some disks. */
+#define        GPTSECTOR               1       /* DOS boot block relative sector # */
+#define        GPTSIGNATURE            0x5452415020494645
+                               /* ASCII string "EFI PART" encoded as 64-bit */
+#define        GPTREVISION             0x10000         /* GPT header version 1.0 */
+#define        NGPTPARTITIONS          128
+#define        GPTDOSACTIVE            0x2
+#define        GPTMINHDRSIZE           92
+#define        GPTMINPARTSIZE          128
+
+/* all values in the GPT need to be little endian as per UEFI specification */
+struct gpt_header {
+       u_int64_t gh_sig;       /* "EFI PART" */
+       u_int32_t gh_rev;       /* GPT Version 1.0: 0x00000100 */
+       u_int32_t gh_size;      /* Little-Endian */
+       u_int32_t gh_csum;      /* CRC32: with this field as 0 */
+       u_int32_t gh_rsvd;      /* always zero */
+       u_int64_t gh_lba_self;  /* LBA of this header */
+       u_int64_t gh_lba_alt;   /* LBA of alternate header */
+       u_int64_t gh_lba_start; /* first usable LBA */
+       u_int64_t gh_lba_end;   /* last usable LBA */
+       struct uuid gh_guid;    /* disk GUID used to identify the disk */
+       u_int64_t gh_part_lba;  /* starting LBA of GPT partition entries */
+       u_int32_t gh_part_num;  /* # of partition entries */
+       u_int32_t gh_part_size; /* size per entry, shall be 128*(2**n)
+                                  with n >= 0 */
+       u_int32_t gh_part_csum; /* CRC32 checksum of all partition entries:
+                                * starts at gh_part_lba and is computed over
+                                * a byte length of gh_part_num*gh_part_size */
+       /* the rest of the block is reserved by UEFI and must be zero */
+};
+
+struct gpt_partition {
+       struct uuid gp_type;    /* partition type GUID */
+       struct uuid gp_guid;    /* unique partition GUID */
+       u_int64_t gp_lba_start; /* starting LBA of this partition */
+       u_int64_t gp_lba_end;   /* ending LBA of this partition, inclusive,
+                                  usually odd */
+       u_int64_t gp_attrs;     /* attribute flags */
+       u_int16_t gp_name[36];  /* partition name, utf-16le */
+       /* the rest of the GPT partition entry, if any, is reserved by UEFI
+          and must be zero */
+};
+
+#define GPT_PARTSPERSEC(gh)    (DEV_BSIZE / letoh32((gh)->gh_part_size))
+#define GPT_SECOFFSET(gh, n)   ((gh)->gh_part_size * n)
+
+#define GPT_UUID_UNUSED \
+    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
+#define GPT_UUID_MSDOS \
+    { 0xeb, 0xd0, 0xa0, 0xa2, 0xb9, 0xe5, 0x44, 0x33, \
+      0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7 }
+#define GPT_UUID_EFI_SYSTEM \
+    { 0xc1, 0x2a, 0x73, 0x28, 0xf8, 0x1f, 0x11, 0xd2, \
+      0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b }
+#define GPT_UUID_LEGACY_MBR \
+    { 0x02, 0x4d, 0xee, 0x41, 0x33, 0x37, 0x11, 0xd3, \
+      0x9d, 0x69, 0x00, 0x08, 0xc7, 0x81, 0xf3, 0x9f }
+#define GPT_UUID_OPENBSD \
+    { 0x82, 0x4c, 0xc7, 0xa0, 0x36, 0xa8, 0x11, 0xe3, \
+      0x89, 0x0a, 0x95, 0x25, 0x19, 0xad, 0x3f, 0x61 }
+#define GPT_UUID_CHROMEROOTFS \
+    { 0x3c, 0xb8, 0xe2, 0x02, 0x3b, 0x7e, 0x47, 0xdd, \
+      0x8a, 0x3c, 0x7f, 0xf2, 0xa1, 0x3c, 0xfc, 0xec }
+#define GPT_UUID_LINUX \
+    { 0x0f, 0xc6, 0x3d, 0xaf, 0x84, 0x83, 0x47, 0x72, \
+      0x8e, 0x79, 0x3d, 0x69, 0xd8, 0x47, 0x7d, 0xe4 }
+#define GPT_UUID_LINUX_HOME \
+    { 0x93, 0x3a, 0xc7, 0xe1, 0x2e, 0xb4, 0x4f, 0x13, \
+      0xb8, 0x44, 0x0e, 0x14, 0xe2, 0xae, 0xf9, 0x15 }
+#define GPT_UUID_LINUX_SRV \
+    { 0x3b, 0x8f, 0x84, 0x25, 0x20, 0xe0, 0x4f, 0x3b, \
+      0x90, 0x7f, 0x1a, 0x25, 0xa7, 0x6f, 0x98, 0xe8 }
+#define GPT_UUID_FBSD_DATA \
+    { 0x51, 0x6e, 0x7c, 0xb4, 0x6e, 0xcf, 0x11, 0xd6, \
+      0x8f, 0xf8, 0x00, 0x02, 0x2d, 0x09, 0x71, 0x2b }
+#define GPT_UUID_FBSD_UFS \
+    { 0x51, 0x6e, 0x7c, 0xb6, 0x6e, 0xcf, 0x11, 0xd6, \
+      0x8f, 0xf8, 0x00, 0x02, 0x2d, 0x09, 0x71, 0x2b }
+#define GPT_UUID_NBSD_UFS \
+    { 0x49, 0xf4, 0x8d, 0x5a, 0xb1, 0x0e, 0x11, 0xdc, \
+      0xb9, 0x9b, 0x00, 0x19, 0xd1, 0x87, 0x96, 0x48 }
+#define GPT_UUID_APPLE_HFS \
+    { 0x48, 0x46, 0x53, 0x00, 0x00, 0x00, 0x11, 0xaa, \
+      0xaa, 0x11, 0x00, 0x30, 0x65, 0x43, 0xec, 0xac }
+#define GPT_UUID_APPLE_UFS \
+    { 0x55, 0x46, 0x53, 0x00, 0x00, 0x00, 0x11, 0xaa, \
+      0xaa, 0x11, 0x00, 0x30, 0x65, 0x43, 0xec, 0xac }
+
 /* DOS partition table -- located at start of some disks. */
 #define        DOS_LABELSECTOR 1
 #define        DOSBBSECTOR     0               /* DOS boot block relative sector # */
@@ -445,6 +537,10 @@ int         writedisklabel(dev_t, void (*)(struct buf *), struct disklabel *);
 int     bounds_check_with_label(struct buf *, struct disklabel *);
 int     readdoslabel(struct buf *, void (*)(struct buf *),
            struct disklabel *, daddr_t *, int);
+#ifdef GPT
+int     readgptlabel(struct buf *, void (*)(struct buf *),
+           struct disklabel *, daddr_t *, int);
+#endif
 #ifdef CD9660
 int iso_disklabelspoof(dev_t dev, void (*strat)(struct buf *),
        struct disklabel *lp);
diff --git a/sys/sys/uuid.h b/sys/sys/uuid.h
new file mode 100644 (file)
index 0000000..4e4b3da
--- /dev/null
@@ -0,0 +1,75 @@
+/*     $OpenBSD: uuid.h,v 1.1 2014/07/13 15:32:28 miod Exp $   */
+/*     $NetBSD: uuid.h,v 1.5 2008/11/18 14:01:03 joerg Exp $   */
+
+/*
+ * Copyright (c) 2002 Marcel Moolenaar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD: /repoman/r/ncvs/src/sys/sys/uuid.h,v 1.3 2003/05/31 16:47:07 phk Exp $
+ */
+
+#ifndef _SYS_UUID_H_
+#define        _SYS_UUID_H_
+
+/* Length of a node address (an IEEE 802 address). */
+#define        _UUID_NODE_LEN          6
+
+/* Length of a printed UUID. */
+#define        _UUID_BUF_LEN           38
+
+/*
+ * See also:
+ *      http://www.opengroup.org/dce/info/draft-leach-uuids-guids-01.txt
+ *      http://www.opengroup.org/onlinepubs/009629399/apdxa.htm
+ *
+ * A DCE 1.1 compatible source representation of UUIDs.
+ */
+struct uuid {
+       uint32_t        time_low;
+       uint16_t        time_mid;
+       uint16_t        time_hi_and_version;
+       uint8_t         clock_seq_hi_and_reserved;
+       uint8_t         clock_seq_low;
+       uint8_t         node[_UUID_NODE_LEN];
+};
+
+#ifdef _KERNEL
+
+#define        UUID_NODE_LEN   _UUID_NODE_LEN
+#define        UUID_BUF_LEN    _UUID_BUF_LEN
+
+int    uuid_snprintf(char *, size_t, const struct uuid *);
+int    uuid_printf(const struct uuid *);
+void   uuid_dec_be(const void *, struct uuid *);
+void   uuid_dec_le(const void *, struct uuid *);
+void   uuid_enc_be(void *, const struct uuid *);
+void   uuid_enc_le(void *, const struct uuid *);
+
+#else  /* _KERNEL */
+
+typedef struct uuid uuid_t;
+
+#endif /* _KERNEL */
+
+#endif /* _SYS_UUID_H_ */