summaryrefslogtreecommitdiffstats
path: root/sys/boot
diff options
context:
space:
mode:
authorraj <raj@FreeBSD.org>2009-05-05 16:29:08 +0000
committerraj <raj@FreeBSD.org>2009-05-05 16:29:08 +0000
commit25b538c6a6349c10d9df14fd79f4a238f0e6067d (patch)
treead95f0fba7df9d61056ba4253bb4c25009ade29f /sys/boot
parentd41e64fb3b4dc3c516438f8b15afea2c95bf4be2 (diff)
downloadFreeBSD-src-25b538c6a6349c10d9df14fd79f4a238f0e6067d.zip
FreeBSD-src-25b538c6a6349c10d9df14fd79f4a238f0e6067d.tar.gz
GPT style partitioning for loader(8) with U-Boot support library (tested on
ARM). Submitted by: Piotr Ziecik kosmo ! semihalf dot com
Diffstat (limited to 'sys/boot')
-rw-r--r--sys/boot/uboot/lib/devicename.c39
-rw-r--r--sys/boot/uboot/lib/disk.c225
-rw-r--r--sys/boot/uboot/lib/libuboot.h6
3 files changed, 243 insertions, 27 deletions
diff --git a/sys/boot/uboot/lib/devicename.c b/sys/boot/uboot/lib/devicename.c
index 5d91550..27ea5cc 100644
--- a/sys/boot/uboot/lib/devicename.c
+++ b/sys/boot/uboot/lib/devicename.c
@@ -90,7 +90,7 @@ uboot_parsedev(struct uboot_devdesc **dev, const char *devspec,
struct devsw *dv;
char *cp;
const char *np;
- int i, unit, partition, err;
+ int i, unit, pnum, ptype, err;
/* minimum length check */
if (strlen(devspec) < 2)
@@ -116,7 +116,8 @@ uboot_parsedev(struct uboot_devdesc **dev, const char *devspec,
case DEVT_DISK:
unit = -1;
- partition = -1;
+ pnum = -1;
+ ptype = -1;
if (*np && (*np != ':')) {
/* next comes the unit number */
unit = strtol(np, &cp, 10);
@@ -126,13 +127,20 @@ uboot_parsedev(struct uboot_devdesc **dev, const char *devspec,
}
if (*cp && (*cp != ':')) {
/* get partition */
- partition = *cp - 'a';
- if ((partition < 0) ||
- (partition >= MAXPARTITIONS)) {
- err = EPART;
- goto fail;
+ if (*cp == 'p' && *(cp + 1) &&
+ *(cp + 1) != ':') {
+ pnum = strtol(cp + 1, &cp, 10);
+ ptype = PTYPE_GPT;
+ } else {
+ pnum = *cp - 'a';
+ ptype = PTYPE_BSDLABEL;
+ if ((pnum < 0) ||
+ (pnum >= MAXPARTITIONS)) {
+ err = EPART;
+ goto fail;
+ }
+ cp++;
}
- cp++;
}
}
if (*cp && (*cp != ':')) {
@@ -141,7 +149,8 @@ uboot_parsedev(struct uboot_devdesc **dev, const char *devspec,
}
idev->d_unit = unit;
- idev->d_disk.partition = partition;
+ idev->d_disk.pnum = pnum;
+ idev->d_disk.ptype = ptype;
idev->d_disk.data = NULL;
if (path != NULL)
*path = (*cp == 0) ? cp : cp + 1;
@@ -202,9 +211,15 @@ uboot_fmtdev(void *vdev)
case DEVT_DISK:
cp = buf;
cp += sprintf(cp, "%s%d", dev->d_dev->dv_name, dev->d_unit);
- if (dev->d_kind.disk.partition >= 0)
- cp += sprintf(cp, "%c", dev->d_kind.disk.partition +
- 'a');
+ if (dev->d_kind.disk.pnum >= 0) {
+ if (dev->d_kind.disk.ptype == PTYPE_BSDLABEL)
+ cp += sprintf(cp, "%c",
+ dev->d_kind.disk.pnum + 'a');
+ else if (dev->d_kind.disk.ptype == PTYPE_GPT)
+ cp += sprintf(cp, "p%i",
+ dev->d_kind.disk.pnum);
+ }
+
strcat(cp, ":");
break;
diff --git a/sys/boot/uboot/lib/disk.c b/sys/boot/uboot/lib/disk.c
index 4570ceb..1725d07 100644
--- a/sys/boot/uboot/lib/disk.c
+++ b/sys/boot/uboot/lib/disk.c
@@ -1,5 +1,6 @@
/*-
* Copyright (c) 2008 Semihalf, Rafal Jaworowski
+ * Copyright (c) 2009 Semihalf, Piotr Ziecik
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -41,6 +42,8 @@ __FBSDID("$FreeBSD$");
#define FSTYPENAMES
#include <sys/disklabel.h>
+#include <sys/diskmbr.h>
+#include <sys/gpt.h>
#include "api_public.h"
#include "bootstrap.h"
@@ -72,9 +75,6 @@ struct gpt_part {
struct open_dev {
int od_bsize; /* block size */
int od_bstart; /* start block offset from beginning of disk */
- int od_type;
-#define OD_BSDLABEL 0x0001
-#define OD_GPT 0x0002
union {
struct {
struct disklabel bsdlabel;
@@ -90,6 +90,13 @@ struct open_dev {
#define od_nparts _data._gpt.gpt_nparts
#define od_partitions _data._gpt.gpt_partitions
+static uuid_t efi = GPT_ENT_TYPE_EFI;
+static uuid_t freebsd_boot = GPT_ENT_TYPE_FREEBSD_BOOT;
+static uuid_t freebsd_ufs = GPT_ENT_TYPE_FREEBSD_UFS;
+static uuid_t freebsd_swap = GPT_ENT_TYPE_FREEBSD_SWAP;
+static uuid_t freebsd_zfs = GPT_ENT_TYPE_FREEBSD_ZFS;
+static uuid_t ms_basic_data = GPT_ENT_TYPE_MS_BASIC_DATA;
+
static int stor_info[UB_MAX_DEV];
static int stor_info_no = 0;
static int stor_opendev(struct open_dev **, struct uboot_devdesc *);
@@ -213,9 +220,158 @@ stor_close(struct open_file *f)
static int
stor_open_gpt(struct open_dev *od, struct uboot_devdesc *dev)
{
+ char *buf;
+ struct dos_partition *dp;
+ struct gpt_hdr *hdr;
+ struct gpt_ent *ent;
+ daddr_t slba, lba, elba;
+ int eps, part, i;
+ int err = 0;
+
+ od->od_nparts = 0;
+ od->od_partitions = NULL;
+
+ /* Devices with block size smaller than 512 bytes cannot use GPT */
+ if (od->od_bsize < 512)
+ return (ENXIO);
+
+ /* Allocate 1 block */
+ buf = malloc(od->od_bsize);
+ if (!buf) {
+ stor_printf("could not allocate memory for GPT\n");
+ return (ENOMEM);
+ }
+
+ /* Read MBR */
+ err = stor_readdev(dev, 0, 1, buf);
+ if (err) {
+ stor_printf("GPT read error=%d\n", err);
+ err = EIO;
+ goto out;
+ }
+
+ /* Check the slice table magic. */
+ if (*((uint16_t *)(buf + DOSMAGICOFFSET)) != DOSMAGIC) {
+ err = ENXIO;
+ goto out;
+ }
+
+ /* Check GPT slice */
+ dp = (struct dos_partition *)(buf + DOSPARTOFF);
+ part = 0;
+
+ for (i = 0; i < NDOSPART; i++) {
+ if (dp[i].dp_typ == 0xee)
+ part += 1;
+ else if (dp[i].dp_typ != 0x00) {
+ err = EINVAL;
+ goto out;
+ }
+ }
+
+ if (part != 1) {
+ err = EINVAL;
+ goto out;
+ }
+
+ /* Read primary GPT header */
+ err = stor_readdev(dev, 1, 1, buf);
+ if (err) {
+ stor_printf("GPT read error=%d\n", err);
+ err = EIO;
+ goto out;
+ }
+
+ hdr = (struct gpt_hdr *)buf;
+
+ /* Check GPT header */
+ if (bcmp(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig)) != 0 ||
+ hdr->hdr_lba_self != 1 || hdr->hdr_revision < 0x00010000 ||
+ hdr->hdr_entsz < sizeof(*ent) ||
+ od->od_bsize % hdr->hdr_entsz != 0) {
+ debugf("Invalid GPT header!\n");
+ err = EINVAL;
+ goto out;
+ }
+
+ /* Count number of valid partitions */
+ part = 0;
+ eps = od->od_bsize / hdr->hdr_entsz;
+ slba = hdr->hdr_lba_table;
+ elba = slba + hdr->hdr_entries / eps;
+
+ for (lba = slba; lba < elba; lba++) {
+ err = stor_readdev(dev, lba, 1, buf);
+ if (err) {
+ stor_printf("GPT read error=%d\n", err);
+ err = EIO;
+ goto out;
+ }
+
+ ent = (struct gpt_ent *)buf;
+
+ for (i = 0; i < eps; i++) {
+ if (uuid_is_nil(&ent[i].ent_type, NULL) ||
+ ent[i].ent_lba_start == 0 ||
+ ent[i].ent_lba_end < ent[i].ent_lba_start)
+ continue;
+
+ part += 1;
+ }
+ }
+
+ /* Save information about partitions */
+ if (part != 0) {
+ od->od_nparts = part;
+ od->od_partitions = malloc(part * sizeof(struct gpt_part));
+ if (!od->od_partitions) {
+ stor_printf("could not allocate memory for GPT\n");
+ err = ENOMEM;
+ goto out;
+ }
+
+ part = 0;
+ for (lba = slba; lba < elba; lba++) {
+ err = stor_readdev(dev, lba, 1, buf);
+ if (err) {
+ stor_printf("GPT read error=%d\n", err);
+ err = EIO;
+ goto out;
+ }
+
+ ent = (struct gpt_ent *)buf;
+
+ for (i = 0; i < eps; i++) {
+ if (uuid_is_nil(&ent[i].ent_type, NULL) ||
+ ent[i].ent_lba_start == 0 ||
+ ent[i].ent_lba_end < ent[i].ent_lba_start)
+ continue;
+
+ od->od_partitions[part].gp_index = (lba - slba)
+ * eps + i + 1;
+ od->od_partitions[part].gp_type =
+ ent[i].ent_type;
+ od->od_partitions[part].gp_start =
+ ent[i].ent_lba_start;
+ od->od_partitions[part].gp_end =
+ ent[i].ent_lba_end;
+ part += 1;
+ }
+ }
+ }
+
+ dev->d_disk.ptype = PTYPE_GPT;
+
+ for (i = 0; i < od->od_nparts; i++)
+ if (od->od_partitions[i].gp_index == dev->d_disk.pnum)
+ od->od_bstart = od->od_partitions[i].gp_start;
+
+out:
+ if (err && od->od_partitions)
+ free(od->od_partitions);
- /* TODO */
- return (ENXIO);
+ free(buf);
+ return (err);
}
static int
@@ -247,8 +403,9 @@ stor_open_bsdlabel(struct open_dev *od, struct uboot_devdesc *dev)
err = EUNLAB;
goto out;
}
- od->od_type = OD_BSDLABEL;
- od->od_bstart = dl->d_partitions[dev->d_disk.partition].p_offset;
+
+ od->od_bstart = dl->d_partitions[dev->d_disk.pnum].p_offset;
+ dev->d_disk.ptype = PTYPE_BSDLABEL;
debugf("bstart=%d\n", od->od_bstart);
@@ -314,7 +471,6 @@ stor_opendev(struct open_dev **odp, struct uboot_devdesc *dev)
}
od->od_bsize = di->di_stor.block_size;
od->od_bstart = 0;
- od->od_type = 0;
if ((err = stor_open_gpt(od, dev)) != 0)
err = stor_open_bsdlabel(od, dev);
@@ -332,9 +488,14 @@ stor_opendev(struct open_dev **odp, struct uboot_devdesc *dev)
static int
stor_closedev(struct uboot_devdesc *dev)
{
+ struct open_dev *od;
int err, h;
- free((struct open_dev *)dev->d_disk.data);
+ od = (struct open_dev *)dev->d_disk.data;
+ if (dev->d_disk.ptype == PTYPE_GPT && od->od_nparts != 0)
+ free(od->od_partitions);
+
+ free(od);
dev->d_disk.data = NULL;
if (--stor_open_count == 0) {
@@ -420,6 +581,42 @@ stor_print_bsdlabel(struct uboot_devdesc *dev, char *prefix, int verbose)
}
static void
+stor_print_gpt(struct uboot_devdesc *dev, char *prefix, int verbose)
+{
+ struct open_dev *od = (struct open_dev *)dev->d_disk.data;
+ struct gpt_part *gp;
+ char line[80];
+ char *fs;
+ int i;
+
+ for (i = 0; i < od->od_nparts; i++) {
+ gp = &od->od_partitions[i];
+
+ if (uuid_equal(&gp->gp_type, &efi, NULL))
+ fs = "EFI";
+ else if (uuid_equal(&gp->gp_type, &ms_basic_data, NULL))
+ fs = "FAT/NTFS";
+ else if (uuid_equal(&gp->gp_type, &freebsd_boot, NULL))
+ fs = "FreeBSD Boot";
+ else if (uuid_equal(&gp->gp_type, &freebsd_ufs, NULL))
+ fs = "FreeBSD UFS";
+ else if (uuid_equal(&gp->gp_type, &freebsd_swap, NULL))
+ fs = "FreeBSD Swap";
+ else if (uuid_equal(&gp->gp_type, &freebsd_zfs, NULL))
+ fs = "FreeBSD ZFS";
+ else
+ fs = "unknown";
+
+ sprintf(line, " %sp%u: %s %s (%lld - %lld)\n", prefix,
+ gp->gp_index, fs,
+ display_size(gp->gp_end + 1 - gp->gp_start), gp->gp_start,
+ gp->gp_end);
+
+ pager_output(line);
+ }
+}
+
+static void
stor_print_one(int i, struct device_info *di, int verbose)
{
struct uboot_devdesc dev;
@@ -431,16 +628,16 @@ stor_print_one(int i, struct device_info *di, int verbose)
dev.d_dev = &uboot_storage;
dev.d_unit = i;
- dev.d_disk.partition = -1;
+ dev.d_disk.pnum = -1;
dev.d_disk.data = NULL;
if (stor_opendev(&od, &dev) == 0) {
dev.d_disk.data = od;
- if (od->od_type == OD_GPT) {
- /* TODO */
-
- } else if (od->od_type == OD_BSDLABEL) {
+ if (dev.d_disk.ptype == PTYPE_GPT) {
+ sprintf(line, "\t\tdisk%d", i);
+ stor_print_gpt(&dev, line, verbose);
+ } else if (dev.d_disk.ptype == PTYPE_BSDLABEL) {
sprintf(line, "\t\tdisk%d", i);
stor_print_bsdlabel(&dev, line, verbose);
}
diff --git a/sys/boot/uboot/lib/libuboot.h b/sys/boot/uboot/lib/libuboot.h
index 346409c..7c8050c 100644
--- a/sys/boot/uboot/lib/libuboot.h
+++ b/sys/boot/uboot/lib/libuboot.h
@@ -35,13 +35,17 @@ struct uboot_devdesc
union {
struct {
void *data;
- int partition;
+ int pnum;
+ int ptype;
} disk;
} d_kind;
};
#define d_disk d_kind.disk
+#define PTYPE_BSDLABEL 1
+#define PTYPE_GPT 2
+
/*
* Default network packet alignment in memory
*/
OpenPOWER on IntegriCloud