diff options
author | raj <raj@FreeBSD.org> | 2009-05-05 16:29:08 +0000 |
---|---|---|
committer | raj <raj@FreeBSD.org> | 2009-05-05 16:29:08 +0000 |
commit | 25b538c6a6349c10d9df14fd79f4a238f0e6067d (patch) | |
tree | ad95f0fba7df9d61056ba4253bb4c25009ade29f /sys/boot/uboot | |
parent | d41e64fb3b4dc3c516438f8b15afea2c95bf4be2 (diff) | |
download | FreeBSD-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/uboot')
-rw-r--r-- | sys/boot/uboot/lib/devicename.c | 39 | ||||
-rw-r--r-- | sys/boot/uboot/lib/disk.c | 225 | ||||
-rw-r--r-- | sys/boot/uboot/lib/libuboot.h | 6 |
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 */ |