svn commit: r191829 - head/sys/boot/uboot/lib

Rafal Jaworowski raj at FreeBSD.org
Tue May 5 16:29:09 UTC 2009


Author: raj
Date: Tue May  5 16:29:08 2009
New Revision: 191829
URL: http://svn.freebsd.org/changeset/base/191829

Log:
  GPT style partitioning for loader(8) with U-Boot support library (tested on
  ARM).
  
  Submitted by:	Piotr Ziecik kosmo ! semihalf dot com

Modified:
  head/sys/boot/uboot/lib/devicename.c
  head/sys/boot/uboot/lib/disk.c
  head/sys/boot/uboot/lib/libuboot.h

Modified: head/sys/boot/uboot/lib/devicename.c
==============================================================================
--- head/sys/boot/uboot/lib/devicename.c	Tue May  5 16:27:45 2009	(r191828)
+++ head/sys/boot/uboot/lib/devicename.c	Tue May  5 16:29:08 2009	(r191829)
@@ -90,7 +90,7 @@ uboot_parsedev(struct uboot_devdesc **de
 	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 **de
 
 	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 **de
 			}
 			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 **de
 		}
 
 		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;
 

Modified: head/sys/boot/uboot/lib/disk.c
==============================================================================
--- head/sys/boot/uboot/lib/disk.c	Tue May  5 16:27:45 2009	(r191828)
+++ head/sys/boot/uboot/lib/disk.c	Tue May  5 16:29:08 2009	(r191829)
@@ -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;
 
-	/* TODO */
-	return (ENXIO);
+		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);
+
+	free(buf);
+	return (err);
 }
 
 static int
@@ -247,8 +403,9 @@ stor_open_bsdlabel(struct open_dev *od, 
 		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, stru
 	}
 	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, stru
 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
 }
 
 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
 
 	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);
 		}

Modified: head/sys/boot/uboot/lib/libuboot.h
==============================================================================
--- head/sys/boot/uboot/lib/libuboot.h	Tue May  5 16:27:45 2009	(r191828)
+++ head/sys/boot/uboot/lib/libuboot.h	Tue May  5 16:29:08 2009	(r191829)
@@ -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
  */


More information about the svn-src-all mailing list