Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 29 Apr 2014 00:45:43 +0000 (UTC)
From:      Ian Lepore <ian@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org
Subject:   svn commit: r265071 - in stable/10/sys/boot/uboot: common lib
Message-ID:  <201404290045.s3T0jhxD032973@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: ian
Date: Tue Apr 29 00:45:42 2014
New Revision: 265071
URL: http://svnweb.freebsd.org/changeset/base/265071

Log:
  MFC r263052, r263124, r263265, r263267...  Enhance loaderdev env var.
  
  Enhance the mechanism that lets you configure the ubldr boot device by
  setting the u-boot environment variable loaderdev=.  It used to accept only
  'disk' or 'net'.  Now it allows specification of unit, slice, and partition
  as well.  In addition to the generic 'disk' it also accepts specific
  storage device types such as 'mmc' or 'sata'.
  
  If there isn't a loaderdev env var, the historical behavior is maintained.
  It will use the first storage device it finds, or a network device if
  no working storage device exists.
  
  99% of the work on this was done by Patrick Kelsey, but I made some
  changes, so if anything goes wrong, blame me.
  
  (Indeed, the 3 followup commits fixed things I got wrong on the first.)

Modified:
  stable/10/sys/boot/uboot/common/main.c
  stable/10/sys/boot/uboot/lib/api_public.h
  stable/10/sys/boot/uboot/lib/disk.c
  stable/10/sys/boot/uboot/lib/glue.c
  stable/10/sys/boot/uboot/lib/libuboot.h
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/boot/uboot/common/main.c
==============================================================================
--- stable/10/sys/boot/uboot/common/main.c	Tue Apr 29 00:38:46 2014	(r265070)
+++ stable/10/sys/boot/uboot/common/main.c	Tue Apr 29 00:45:42 2014	(r265071)
@@ -36,10 +36,27 @@ __FBSDID("$FreeBSD$");
 #include "glue.h"
 #include "libuboot.h"
 
+#ifndef nitems
+#define	nitems(x)	(sizeof((x)) / sizeof((x)[0]))
+#endif
+
 struct uboot_devdesc currdev;
 struct arch_switch archsw;		/* MI/MD interface boundary */
 int devs_no;
 
+struct device_type { 
+	const char *name;
+	int type;
+} device_types[] = {
+	{ "disk", DEV_TYP_STOR },
+	{ "ide",  DEV_TYP_STOR | DT_STOR_IDE },
+	{ "mmc",  DEV_TYP_STOR | DT_STOR_MMC },
+	{ "sata", DEV_TYP_STOR | DT_STOR_SATA },
+	{ "scsi", DEV_TYP_STOR | DT_STOR_SCSI },
+	{ "usb",  DEV_TYP_STOR | DT_STOR_USB },
+	{ "net",  DEV_TYP_NET }
+};
+
 extern char end[];
 extern char bootprog_name[];
 extern char bootprog_rev[];
@@ -111,17 +128,265 @@ meminfo(void)
 	for (i = 0; i < 3; i++) {
 		size = memsize(si, t[i]);
 		if (size > 0)
-			printf("%s:\t %lldMB\n", ub_mem_type(t[i]),
+			printf("%s: %lldMB\n", ub_mem_type(t[i]),
 			    size / 1024 / 1024);
 	}
 }
 
+static const char *
+get_device_type(const char *devstr, int *devtype)
+{
+	int i;
+	int namelen;
+	struct device_type *dt;
+
+	if (devstr) {
+		for (i = 0; i < nitems(device_types); i++) {
+			dt = &device_types[i];
+			namelen = strlen(dt->name);
+			if (strncmp(dt->name, devstr, namelen) == 0) {
+				*devtype = dt->type;
+				return (devstr + namelen);
+			}
+		}
+		printf("Unknown device type '%s'\n", devstr);
+	}
+
+	*devtype = -1;
+	return (NULL);
+}
+
+static const char *
+device_typename(int type)
+{
+	int i;
+
+	for (i = 0; i < nitems(device_types); i++)
+		if (device_types[i].type == type)
+			return (device_types[i].name);
+
+	return ("<unknown>");
+}
+
+/*
+ * Parse a device string into type, unit, slice and partition numbers. A
+ * returned value of -1 for type indicates a search should be done for the
+ * first loadable device, otherwise a returned value of -1 for unit
+ * indicates a search should be done for the first loadable device of the
+ * given type.
+ *
+ * The returned values for slice and partition are interpreted by
+ * disk_open().
+ *
+ * Valid device strings:                     For device types:
+ *
+ * <type_name>                               DEV_TYP_STOR, DEV_TYP_NET
+ * <type_name><unit>                         DEV_TYP_STOR, DEV_TYP_NET
+ * <type_name><unit>:                        DEV_TYP_STOR, DEV_TYP_NET
+ * <type_name><unit>:<slice>                 DEV_TYP_STOR
+ * <type_name><unit>:<slice>.                DEV_TYP_STOR
+ * <type_name><unit>:<slice>.<partition>     DEV_TYP_STOR
+ *
+ * For valid type names, see the device_types array, above.
+ *
+ * Slice numbers are 1-based.  0 is a wildcard.
+ */
+static void
+get_load_device(int *type, int *unit, int *slice, int *partition)
+{
+	char *devstr;
+	const char *p;
+	char *endp;
+
+	*type = -1;
+	*unit = -1;
+	*slice = 0;
+	*partition = -1;
+
+	devstr = ub_env_get("loaderdev");
+	if (devstr == NULL) {
+		printf("U-Boot env: loaderdev not set, will probe all devices.\n");
+		return;
+	}
+	printf("U-Boot env: loaderdev='%s'\n", devstr);
+
+	p = get_device_type(devstr, type);
+
+	/*
+	 * Empty device string, or unknown device name, or a bare, known 
+	 * device name. 
+	 */
+	if ((*type == -1) || (*p == '\0')) {
+		return;
+	}
+
+	/* Malformed unit number. */
+	if (!isdigit(*p)) {
+		*type = -1;
+		return;
+	}
+
+	/* Guaranteed to extract a number from the string, as *p is a digit. */
+	*unit = strtol(p, &endp, 10);
+	p = endp;
+
+	/* Known device name with unit number and nothing else. */
+	if (*p == '\0') {
+		return;
+	}
+
+	/* Device string is malformed beyond unit number. */
+	if (*p != ':') {
+		*type = -1;
+		*unit = -1;
+		return;
+	}
+
+	p++;
+
+	/* No slice and partition specification. */
+	if ('\0' == *p )
+		return;
+
+	/* Only DEV_TYP_STOR devices can have a slice specification. */
+	if (!(*type & DEV_TYP_STOR)) {
+		*type = -1;
+		*unit = -1;
+		return;
+	}
+
+	*slice = strtoul(p, &endp, 10);
+
+	/* Malformed slice number. */
+	if (p == endp) {
+		*type = -1;
+		*unit = -1;
+		*slice = 0;
+		return;
+	}
+
+	p = endp;
+	
+	/* No partition specification. */
+	if (*p == '\0')
+		return;
+
+	/* Device string is malformed beyond slice number. */
+	if (*p != '.') {
+		*type = -1;
+		*unit = -1;
+		*slice = 0;
+		return;
+	}
+
+	p++;
+
+	/* No partition specification. */
+	if (*p == '\0')
+		return;
+
+	*partition = strtol(p, &endp, 10);
+	p = endp;
+
+	/*  Full, valid device string. */
+	if (*endp == '\0')
+		return;
+
+	/* Junk beyond partition number. */
+	*type = -1;
+	*unit = -1;
+	*slice = 0;
+	*partition = -1;
+} 
+
+static void
+print_disk_probe_info()
+{
+	char slice[32];
+	char partition[32];
+
+	if (currdev.d_disk.slice > 0)
+		sprintf(slice, "%d", currdev.d_disk.slice);
+	else
+		strcpy(slice, "<auto>");
+
+	if (currdev.d_disk.partition > 0)
+		sprintf(partition, "%d", currdev.d_disk.partition);
+	else
+		strcpy(partition, "<auto>");
+
+	printf("  Checking unit=%d slice=%s partition=%s...",
+	    currdev.d_unit, slice, partition);
+
+}
+
+static int
+probe_disks(int devidx, int load_type, int load_unit, int load_slice, 
+    int load_partition)
+{
+	int open_result, unit;
+	struct open_file f;
+
+	currdev.d_disk.slice = load_slice;
+	currdev.d_disk.partition = load_partition;
+
+	f.f_devdata = &currdev;
+	open_result = -1;
+
+	if (load_type == -1) {
+		printf("  Probing all disk devices...\n");
+		/* Try each disk in succession until one works.  */
+		for (currdev.d_unit = 0; currdev.d_unit < UB_MAX_DEV;
+		     currdev.d_unit++) {
+			print_disk_probe_info();
+			open_result = devsw[devidx]->dv_open(&f, &currdev);
+			if (open_result == 0) {
+				printf(" good.\n");
+				return (0);
+			}
+			printf("\n");
+		}
+		return (-1);
+	}
+
+	if (load_unit == -1) {
+		printf("  Probing all %s devices...\n", device_typename(load_type));
+		/* Try each disk of given type in succession until one works. */
+		for (unit = 0; unit < UB_MAX_DEV; unit++) {
+			currdev.d_unit = uboot_diskgetunit(load_type, unit);
+			if (currdev.d_unit == -1)
+				break;
+			print_disk_probe_info();
+			open_result = devsw[devidx]->dv_open(&f, &currdev);
+			if (open_result == 0) {
+				printf(" good.\n");
+				return (0);
+			}
+			printf("\n");
+		}
+		return (-1);
+	}
+
+	if ((currdev.d_unit = uboot_diskgetunit(load_type, load_unit)) != -1) {
+		print_disk_probe_info();
+		open_result = devsw[devidx]->dv_open(&f,&currdev);
+		if (open_result == 0) {
+			printf(" good.\n");
+			return (0);
+		}
+		printf("\n");
+	}
+
+	printf("  Requested disk type/unit not found\n");
+	return (-1);
+}
+
 int
 main(void)
 {
 	struct api_signature *sig = NULL;
-	int diskdev, i, netdev, usedev;
-	struct open_file f;
+	int load_type, load_unit, load_slice, load_partition;
+	int i;
 	const char * loaderdev;
 
 	/*
@@ -145,21 +410,26 @@ main(void)
 	bzero(__bss_start, _end - __bss_start);
 
 	/*
-         * Set up console.
-         */
+	 * Initialise the heap as early as possible.  Once this is done,
+	 * alloc() is usable. The stack is buried inside us, so this is safe.
+	 */
+	setheap((void *)end, (void *)(end + 512 * 1024));
+
+	/*
+	 * Set up console.
+	 */
 	cons_probe();
+	printf("Compatible U-Boot API signature found @%x\n", (uint32_t)sig);
 
-	printf("Compatible API signature found @%x\n", (uint32_t)sig);
+	printf("\n");
+	printf("%s, Revision %s\n", bootprog_name, bootprog_rev);
+	printf("(%s, %s)\n", bootprog_maker, bootprog_date);
+	printf("\n");
 
 	dump_sig(sig);
 	dump_addr_info();
 
-	/*
-	 * Initialise the heap as early as possible.  Once this is done,
-	 * alloc() is usable. The stack is buried inside us, so this is
-	 * safe.
-	 */
-	setheap((void *)end, (void *)(end + 512 * 1024));
+	meminfo();
 
 	/*
 	 * Enumerate U-Boot devices
@@ -168,55 +438,11 @@ main(void)
 		panic("no U-Boot devices found");
 	printf("Number of U-Boot devices: %d\n", devs_no);
 
-	printf("\n");
-	printf("%s, Revision %s\n", bootprog_name, bootprog_rev);
-	printf("(%s, %s)\n", bootprog_maker, bootprog_date);
-	meminfo();
+	get_load_device(&load_type, &load_unit, &load_slice, &load_partition);
 
 	/*
-	 * March through the device switch probing for things -- sort of.
-	 *
-	 * The devsw array will have one or two items in it. If
-	 * LOADER_DISK_SUPPORT is defined the first item will be a disk (which
-	 * may not actually work if u-boot didn't supply one). If
-	 * LOADER_NET_SUPPORT is defined the next item will be a network
-	 * interface.  Again it may not actually work at the u-boot level.
-	 *
-	 * The original logic was to always use a disk if it could be
-	 * successfully opened, otherwise use the network interface.  Now that
-	 * logic is amended to first check whether the u-boot environment
-	 * contains a loaderdev variable which tells us which device to use.  If
-	 * it does, we use it and skip the original (second) loop which "probes"
-	 * for a device. We still loop over the devsw just in case it ever gets
-	 * expanded to hold more than 2 devices (but then unit numbers, which
-	 * don't currently exist, may come into play).  If the device named by
-	 * loaderdev isn't found, fall back using to the old "probe" loop.
-	 *
-	 * The original probe loop still effectively behaves as it always has:
-	 * the first usable disk device is choosen, and a network device is used
-	 * only if no disk device is found.  The logic has been reworked so that
-	 * it examines (and thus lists) every potential device along the way
-	 * instead of breaking out of the loop when the first device is found.
+	 * March through the device switch probing for things.
 	 */
-	loaderdev = ub_env_get("loaderdev");
-	usedev = -1;
-	if (loaderdev != NULL) {
-		for (i = 0; devsw[i] != NULL; i++) {
-			if (strcmp(loaderdev, devsw[i]->dv_name) == 0) {
-				if (devsw[i]->dv_init == NULL)
-					continue;
-				if ((devsw[i]->dv_init)() != 0)
-					continue;
-				usedev = i;
-				goto have_device;
-			}
-		}
-		printf("U-Boot env contains 'loaderdev=%s', "
-		    "device not found.\n", loaderdev);
-	}
-	printf("Probing for bootable devices...\n");
-	diskdev = -1;
-	netdev = -1;
 	for (i = 0; devsw[i] != NULL; i++) {
 
 		if (devsw[i]->dv_init == NULL)
@@ -224,43 +450,33 @@ main(void)
 		if ((devsw[i]->dv_init)() != 0)
 			continue;
 
-		printf("Bootable device: %s\n", devsw[i]->dv_name);
+		printf("Found U-Boot device: %s\n", devsw[i]->dv_name);
 
-		if (strncmp(devsw[i]->dv_name, "disk",
-		    strlen(devsw[i]->dv_name)) == 0) {
-			f.f_devdata = &currdev;
-			currdev.d_dev = devsw[i];
-			currdev.d_type = currdev.d_dev->dv_type;
-			currdev.d_unit = 0;
-			currdev.d_disk.slice = 0;
-			if (devsw[i]->dv_open(&f, &currdev) == 0) {
-				devsw[i]->dv_close(&f);
-				if (diskdev == -1)
-					diskdev = i;
-			}
-		} else if (strncmp(devsw[i]->dv_name, "net",
-		    strlen(devsw[i]->dv_name)) == 0) {
-			if (netdev == -1)
-				netdev = i;
+		currdev.d_dev = devsw[i];
+		currdev.d_type = currdev.d_dev->dv_type;
+		currdev.d_unit = 0;
+
+		if ((load_type == -1 || (load_type & DEV_TYP_STOR)) &&
+		    strcmp(devsw[i]->dv_name, "disk") == 0) {
+			if (probe_disks(i, load_type, load_unit, load_slice, 
+			    load_partition) == 0)
+				break;
 		}
-	}
 
-	if (diskdev != -1)
-		usedev = diskdev;
-	else if (netdev != -1)
-		usedev = netdev;
-	else
-		panic("No bootable devices found!\n");
-
-have_device:
-
-	currdev.d_dev = devsw[usedev];
-	currdev.d_type = devsw[usedev]->dv_type;
-	currdev.d_unit = 0;
-	if (currdev.d_type == DEV_TYP_STOR)
-		currdev.d_disk.slice = 0;
+		if ((load_type == -1 || (load_type & DEV_TYP_NET)) &&
+		    strcmp(devsw[i]->dv_name, "net") == 0)
+			break;
+	}
 
-	printf("Current device: %s\n", currdev.d_dev->dv_name);
+	/*
+	 * If we couldn't find a boot device, return an error to u-boot.
+	 * U-boot may be running a boot script that can try something different
+	 * so returning an error is better than forcing a reboot.
+	 */
+	if (devsw[i] == NULL) {
+		printf("No boot device found!\n");
+		return (0xbadef1ce);
+	}
 
 	env_setenv("currdev", EV_VOLATILE, uboot_fmtdev(&currdev),
 	    uboot_setcurrdev, env_nounset);

Modified: stable/10/sys/boot/uboot/lib/api_public.h
==============================================================================
--- stable/10/sys/boot/uboot/lib/api_public.h	Tue Apr 29 00:38:46 2014	(r265070)
+++ stable/10/sys/boot/uboot/lib/api_public.h	Tue Apr 29 00:45:42 2014	(r265071)
@@ -132,7 +132,7 @@ typedef unsigned long lbastart_t;
 #define	DT_STOR_SCSI	0x0020
 #define	DT_STOR_USB	0x0040
 #define	DT_STOR_MMC	0x0080
-#define	DT_STOR_NAND	0x0100
+#define	DT_STOR_SATA	0x0100
 
 #define	DEV_STA_CLOSED	0x0000		/* invalid, closed */
 #define	DEV_STA_OPEN	0x0001		/* open i.e. active */

Modified: stable/10/sys/boot/uboot/lib/disk.c
==============================================================================
--- stable/10/sys/boot/uboot/lib/disk.c	Tue Apr 29 00:38:46 2014	(r265070)
+++ stable/10/sys/boot/uboot/lib/disk.c	Tue Apr 29 00:45:42 2014	(r265071)
@@ -278,3 +278,26 @@ stor_ioctl(struct open_file *f, u_long c
 	return (0);
 }
 
+
+/*
+ * Return the device unit number for the given type and type-relative unit
+ * number.
+ */
+int
+uboot_diskgetunit(int type, int type_unit)
+{
+	int local_type_unit;
+	int i;
+
+	local_type_unit = 0;
+	for (i = 0; i < stor_info_no; i++) {
+		if ((stor_info[i].type & type) == type) {
+			if (local_type_unit == type_unit) {
+				return (i);
+			}
+			local_type_unit++;
+		}
+	}
+
+	return (-1);
+}

Modified: stable/10/sys/boot/uboot/lib/glue.c
==============================================================================
--- stable/10/sys/boot/uboot/lib/glue.c	Tue Apr 29 00:38:46 2014	(r265070)
+++ stable/10/sys/boot/uboot/lib/glue.c	Tue Apr 29 00:45:42 2014	(r265071)
@@ -404,8 +404,8 @@ ub_stor_type(int type)
 	if (type & DT_STOR_MMC)
 		return ("MMC");
 
-	if (type & DT_STOR_NAND)
-		return ("NAND");
+	if (type & DT_STOR_SATA)
+		return ("SATA");
 
 	return ("Unknown");
 }

Modified: stable/10/sys/boot/uboot/lib/libuboot.h
==============================================================================
--- stable/10/sys/boot/uboot/lib/libuboot.h	Tue Apr 29 00:38:46 2014	(r265070)
+++ stable/10/sys/boot/uboot/lib/libuboot.h	Tue Apr 29 00:45:42 2014	(r265071)
@@ -32,9 +32,9 @@ struct uboot_devdesc
 	struct devsw	*d_dev;
 	int		d_type;
 	int		d_unit;
+	void		*d_opendata;
 	union {
 		struct {
-			void	*data;
 			int	slice;
 			int	partition;
 			off_t	offset;
@@ -70,6 +70,8 @@ extern struct file_format uboot_elf;
 
 void reboot(void);
 
+int uboot_diskgetunit(int type, int type_unit);
+
 #if defined(LOADER_FDT_SUPPORT)
 extern int fdt_setup_fdtp();
 extern int fdt_copy(vm_offset_t);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201404290045.s3T0jhxD032973>