Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 30 Nov 2012 03:15:50 +0000 (UTC)
From:      Oleksandr Tymoshenko <gonzo@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r243693 - in head/sys/boot: fdt uboot/common
Message-ID:  <201211300315.qAU3FoRU006253@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: gonzo
Date: Fri Nov 30 03:15:50 2012
New Revision: 243693
URL: http://svnweb.freebsd.org/changeset/base/243693

Log:
  - Implement "fdt mres" sub-command that prints reserved memory regions
  - Add "fdt addr" subcommand that lets you specify preloaded blob address
  - Do not pre-initialize blob for "fdt addr"
  - Do not try to load dtb every time fdt subcommand is issued,
      do it only once
  - Change the way DTB is passed to kernel. With introduction of "fdt addr"
      actual blob address can be not virtual but physical or reside in
      area higher then 64Mb. ubldr should create copy of it in kernel area
      and pass pointer to this newly allocated buffer which is guaranteed to work
      in kernel after switching on MMU.
  - Convert memreserv FDT info to "memreserv" property of root node
      FDT uses /memreserve/ data to notify OS about reserved memory areas.
      Technically it's not real property, it's just data blob, sequence
      of <start, size> pairs where both start and size are 64-bit integers.
      It doesn't fit nicely with OF API we use in kernel, so in order to unify
      thing ubldr converts this data to "memreserve" property using the same
      format for addresses and sizes as /memory node.

Modified:
  head/sys/boot/fdt/fdt_loader_cmd.c
  head/sys/boot/uboot/common/metadata.c

Modified: head/sys/boot/fdt/fdt_loader_cmd.c
==============================================================================
--- head/sys/boot/fdt/fdt_loader_cmd.c	Fri Nov 30 03:14:11 2012	(r243692)
+++ head/sys/boot/fdt/fdt_loader_cmd.c	Fri Nov 30 03:15:50 2012	(r243693)
@@ -40,8 +40,6 @@ __FBSDID("$FreeBSD$");
 #include "bootstrap.h"
 #include "glue.h"
 
-#define DEBUG
-
 #ifdef DEBUG
 #define debugf(fmt, args...) do { printf("%s(): ", __func__);	\
     printf(fmt,##args); } while (0)
@@ -62,6 +60,8 @@ __FBSDID("$FreeBSD$");
 
 #define FDT_STATIC_DTB_SYMBOL	"fdt_static_dtb"
 
+#define	CMD_REQUIRES_BLOB	0x01
+
 /* Local copy of FDT */
 static struct fdt_header *fdtp = NULL;
 /* Size of FDT blob */
@@ -69,8 +69,11 @@ static size_t fdtp_size = 0;
 /* Location of FDT in kernel or module */
 static vm_offset_t fdtp_va = 0;
 
+static int fdt_load_dtb(vm_offset_t va);
+
 static int fdt_cmd_nyi(int argc, char *argv[]);
 
+static int fdt_cmd_addr(int argc, char *argv[]);
 static int fdt_cmd_mkprop(int argc, char *argv[]);
 static int fdt_cmd_cd(int argc, char *argv[]);
 static int fdt_cmd_hdr(int argc, char *argv[]);
@@ -79,25 +82,28 @@ static int fdt_cmd_prop(int argc, char *
 static int fdt_cmd_pwd(int argc, char *argv[]);
 static int fdt_cmd_rm(int argc, char *argv[]);
 static int fdt_cmd_mknode(int argc, char *argv[]);
+static int fdt_cmd_mres(int argc, char *argv[]);
 
 typedef int cmdf_t(int, char *[]);
 
 struct cmdtab {
 	char	*name;
 	cmdf_t	*handler;
+	int	flags;
 };
 
 static const struct cmdtab commands[] = {
-	{ "alias", &fdt_cmd_nyi },
-	{ "cd", &fdt_cmd_cd },
-	{ "header", &fdt_cmd_hdr },
-	{ "ls", &fdt_cmd_ls },
-	{ "mknode", &fdt_cmd_mknode },
-	{ "mkprop", &fdt_cmd_mkprop },
-	{ "mres", &fdt_cmd_nyi },
-	{ "prop", &fdt_cmd_prop },
-	{ "pwd", &fdt_cmd_pwd },
-	{ "rm", &fdt_cmd_rm },
+	{ "addr", &fdt_cmd_addr,	0 },
+	{ "alias", &fdt_cmd_nyi,	0 },
+	{ "cd", &fdt_cmd_cd,		CMD_REQUIRES_BLOB },
+	{ "header", &fdt_cmd_hdr,	CMD_REQUIRES_BLOB },
+	{ "ls", &fdt_cmd_ls,		CMD_REQUIRES_BLOB },
+	{ "mknode", &fdt_cmd_mknode,	CMD_REQUIRES_BLOB },
+	{ "mkprop", &fdt_cmd_mkprop,	CMD_REQUIRES_BLOB },
+	{ "mres", &fdt_cmd_mres,	CMD_REQUIRES_BLOB },
+	{ "prop", &fdt_cmd_prop,	CMD_REQUIRES_BLOB },
+	{ "pwd", &fdt_cmd_pwd,		CMD_REQUIRES_BLOB },
+	{ "rm", &fdt_cmd_rm,		CMD_REQUIRES_BLOB },
 	{ NULL, NULL }
 };
 
@@ -128,7 +134,7 @@ fdt_find_static_dtb()
 	if (md == NULL)
 		return (0);
 	bcopy(md->md_data, &esym, sizeof(esym));
-	// esym is already offset
+	/* esym is already offset */
 
 	md = file_findmetadata(kfp, MODINFOMD_DYNAMIC);
 	if (md == NULL)
@@ -188,53 +194,67 @@ fdt_find_static_dtb()
 }
 
 static int
-fdt_setup_fdtp()
+fdt_load_dtb(vm_offset_t va)
 {
 	struct fdt_header header;
-	struct preloaded_file *bfp;
 	int err;
 
+	COPYOUT(va, &header, sizeof(header));
+	err = fdt_check_header(&header);
+	if (err < 0) {
+		if (err == -FDT_ERR_BADVERSION)
+			sprintf(command_errbuf,
+			    "incompatible blob version: %d, should be: %d",
+			    fdt_version(fdtp), FDT_LAST_SUPPORTED_VERSION);
+
+		else
+			sprintf(command_errbuf, "error validating blob: %s",
+			    fdt_strerror(err));
+		return (1);
+	}
+
 	/*
-	 * Find the device tree blob.
+	 * Release previous blob
 	 */
-	bfp = file_findfile(NULL, "dtb");
-	if (bfp == NULL) {
-		if ((fdtp_va = fdt_find_static_dtb()) == 0) {
-			command_errmsg = "no device tree blob found!";
-			printf("%s\n", command_errmsg);
-			return (CMD_ERROR);
-		}
-	} else {
-		/* Dynamic blob has precedence over static. */
-		fdtp_va = bfp->f_addr;
-	}
+	if (fdtp)
+		free(fdtp);
 
-	COPYOUT(fdtp_va, &header, sizeof(header));
 	fdtp_size = fdt_totalsize(&header);
 	fdtp = malloc(fdtp_size);
+
 	if (fdtp == NULL) {
 		command_errmsg = "can't allocate memory for device tree copy";
-			printf("%s\n", command_errmsg);
-		return (CMD_ERROR);
+		return (1);
 	}
-	COPYOUT(fdtp_va, fdtp, fdtp_size);
 
-	/*
-	 * Validate the blob.
-	 */
-	err = fdt_check_header(fdtp);
-	if (err < 0) {
-		if (err == -FDT_ERR_BADVERSION)
-			sprintf(command_errbuf,
-			    "incompatible blob version: %d, should be: %d",
-			    fdt_version(fdtp), FDT_LAST_SUPPORTED_VERSION);
+	fdtp_va = va;
+	COPYOUT(va, fdtp, fdtp_size);
+	debugf("DTB blob found at 0x%jx, size: 0x%jx\n", (uintmax_t)va, (uintmax_t)fdtp_size);
 
-		else
-			sprintf(command_errbuf, "error validating blob: %s",
-			    fdt_strerror(err));
-		return (CMD_ERROR);
+	return (0);
+}
+
+static int
+fdt_setup_fdtp()
+{
+	struct preloaded_file *bfp;
+	vm_offset_t va;
+
+	bfp = file_findfile(NULL, "dtb");
+	if (bfp == NULL) {
+		if ((va = fdt_find_static_dtb()) == 0) {
+			command_errmsg = "no device tree blob found!";
+			return (1);
+		}
+	} else {
+		/* Dynamic blob has precedence over static. */
+		va = bfp->f_addr;
 	}
-	return (CMD_OK);
+
+	if (fdt_load_dtb(va) != 0)
+		return (1);
+	
+	return (0);
 }
 
 #define fdt_strtovect(str, cellbuf, lim, cellsize) _fdt_strtovect((str), \
@@ -414,6 +434,8 @@ fixup_memory(struct sys_info *si)
 	uint32_t *addr_cellsp, *reg,  *size_cellsp;
 	int err, i, len, memory, realmrno, root;
 	uint8_t *buf, *sb;
+	uint64_t rstart, rsize;
+	int reserved;
 
 	root = fdt_path_offset(fdtp, "/");
 	if (root < 0) {
@@ -453,6 +475,52 @@ fixup_memory(struct sys_info *si)
 	addr_cells = fdt32_to_cpu(*addr_cellsp);
 	size_cells = fdt32_to_cpu(*size_cellsp);
 
+	/*
+	 * Convert memreserve data to memreserve property
+	 * Check if property already exists
+	 */
+	reserved = fdt_num_mem_rsv(fdtp);
+	if (reserved &&
+	    (fdt_getprop(fdtp, root, "memreserve", NULL) == NULL)) {
+		len = (addr_cells + size_cells) * reserved * sizeof(uint32_t);
+		sb = buf = (uint8_t *)malloc(len);
+		if (!buf)
+			return;
+
+		bzero(buf, len);
+
+		for (i = 0; i < reserved; i++) {
+			curmr = &si->mr[i];
+			if (fdt_get_mem_rsv(fdtp, i, &rstart, &rsize))
+				break;
+			if (rsize) {
+				/* Ensure endianess, and put cells into a buffer */
+				if (addr_cells == 2)
+					*(uint64_t *)buf =
+					    cpu_to_fdt64(rstart);
+				else
+					*(uint32_t *)buf =
+					    cpu_to_fdt32(rstart);
+
+				buf += sizeof(uint32_t) * addr_cells;
+				if (size_cells == 2)
+					*(uint64_t *)buf =
+					    cpu_to_fdt64(rsize);
+				else
+					*(uint32_t *)buf =
+					    cpu_to_fdt32(rsize);
+
+				buf += sizeof(uint32_t) * size_cells;
+			}
+		}
+
+		/* Set property */
+		if ((err = fdt_setprop(fdtp, root, "memreserve", sb, len)) < 0)
+			printf("Could not fixup 'memreserve' property.\n");
+
+		free(sb);
+	} 
+
 	/* Count valid memory regions entries in sysinfo. */
 	realmrno = si->mr_no;
 	for (i = 0; i < si->mr_no; i++)
@@ -509,6 +577,8 @@ fixup_memory(struct sys_info *si)
 	/* Set property */
 	if ((err = fdt_setprop(fdtp, memory, "reg", sb, len)) < 0)
 		sprintf(command_errbuf, "Could not fixup '/memory' node.\n");
+
+	free(sb);
 }
 
 void
@@ -564,7 +634,7 @@ fixup_stdout(const char *env)
 /*
  * Locate the blob, fix it up and return its location.
  */
-vm_offset_t
+static vm_offset_t
 fdt_fixup(void)
 {
 	const char *env;
@@ -577,10 +647,12 @@ fdt_fixup(void)
 	ethstr = NULL;
 	len = 0;
 
-	err = fdt_setup_fdtp();
-	if (err) {
-		sprintf(command_errbuf, "No valid device tree blob found!");
-		return (0);
+	if (fdtp == NULL) {
+		err = fdt_setup_fdtp();
+		if (err) {
+			sprintf(command_errbuf, "No valid device tree blob found!");
+			return (0);
+		}
 	}
 
 	/* Create /chosen node (if not exists) */
@@ -640,10 +712,36 @@ success:
 	return (fdtp_va);
 }
 
+/*
+ * Copy DTB blob to specified location and its return size
+ */
+int
+fdt_copy(vm_offset_t va)
+{
+	int err;
+
+	if (fdtp == NULL) {
+		err = fdt_setup_fdtp();
+		if (err) {
+			printf("No valid device tree blob found!");
+			return (0);
+		}
+	}
+
+	if (fdt_fixup() == 0)
+		return (0);
+
+	COPYIN(fdtp, va, fdtp_size);
+	return (fdtp_size);
+}
+
+
+
 int
 command_fdt_internal(int argc, char *argv[])
 {
 	cmdf_t *cmdh;
+	int flags;
 	char *cmd;
 	int i, err;
 
@@ -653,12 +751,6 @@ command_fdt_internal(int argc, char *arg
 	}
 
 	/*
-	 * Check if uboot env vars were parsed already. If not, do it now.
-	 */
-	if (fdt_fixup() == 0)
-		return (CMD_ERROR);
-
-	/*
 	 * Validate fdt <command>.
 	 */
 	cmd = strdup(argv[1]);
@@ -668,6 +760,7 @@ command_fdt_internal(int argc, char *arg
 		if (strcmp(cmd, commands[i].name) == 0) {
 			/* found it */
 			cmdh = commands[i].handler;
+			flags = commands[i].flags;
 			break;
 		}
 		i++;
@@ -677,6 +770,14 @@ command_fdt_internal(int argc, char *arg
 		return (CMD_ERROR);
 	}
 
+	if (flags & CMD_REQUIRES_BLOB) {
+		/*
+		 * Check if uboot env vars were parsed already. If not, do it now.
+		 */
+		if (fdt_fixup() == 0)
+			return (CMD_ERROR);
+	}
+
 	/*
 	 * Call command handler.
 	 */
@@ -686,6 +787,31 @@ command_fdt_internal(int argc, char *arg
 }
 
 static int
+fdt_cmd_addr(int argc, char *argv[])
+{
+	vm_offset_t va;
+	char *addr, *cp;
+
+	if (argc > 2)
+		addr = argv[2];
+	else {
+		sprintf(command_errbuf, "no address specified");
+		return (CMD_ERROR);
+	}
+
+	va = strtol(addr, &cp, 0);
+	if (cp == addr) {
+		sprintf(command_errbuf, "Invalid address: %s", addr);
+		return (CMD_ERROR);
+	}
+
+	if (fdt_load_dtb(va) != 0)
+		return (CMD_ERROR);
+
+	return (CMD_OK);
+}
+
+static int
 fdt_cmd_cd(int argc, char *argv[])
 {
 	char *path;
@@ -1445,6 +1571,30 @@ fdt_cmd_pwd(int argc, char *argv[])
 }
 
 static int
+fdt_cmd_mres(int argc, char *argv[])
+{
+	uint64_t start, size;
+	int i, total;
+	char line[80];
+
+	pager_open();
+	total = fdt_num_mem_rsv(fdtp);
+	if (total > 0) {
+		pager_output("Reserved memory regions:\n");
+		for (i = 0; i < total; i++) {
+			fdt_get_mem_rsv(fdtp, i, &start, &size);
+			sprintf(line, "reg#%d: (start: 0x%jx, size: 0x%jx)\n", 
+			    i, start, size);
+			pager_output(line);
+		}
+	} else
+		pager_output("No reserved memory regions\n");
+	pager_close();
+
+	return (CMD_OK);
+}
+
+static int
 fdt_cmd_nyi(int argc, char *argv[])
 {
 

Modified: head/sys/boot/uboot/common/metadata.c
==============================================================================
--- head/sys/boot/uboot/common/metadata.c	Fri Nov 30 03:14:11 2012	(r243692)
+++ head/sys/boot/uboot/common/metadata.c	Fri Nov 30 03:15:50 2012	(r243693)
@@ -42,7 +42,7 @@ __FBSDID("$FreeBSD$");
 #include "glue.h"
 
 #if defined(LOADER_FDT_SUPPORT)
-extern vm_offset_t fdt_fixup(void);
+extern int fdt_copy(vm_offset_t);
 #endif
 
 /*
@@ -279,7 +279,10 @@ md_load(char *args, vm_offset_t *modulep
 	vm_offset_t		envp;
 	vm_offset_t		size;
 	vm_offset_t		vaddr;
+#if defined(LOADER_FDT_SUPPORT)
 	vm_offset_t		dtbp;
+	int			dtb_size;
+#endif
 	char			*rootdevname;
 	int			howto;
 	int			i;
@@ -325,6 +328,16 @@ md_load(char *args, vm_offset_t *modulep
 	/* Pad to a page boundary */
 	addr = roundup(addr, PAGE_SIZE);
 
+#if defined(LOADER_FDT_SUPPORT)
+	/* Handle device tree blob */
+	dtbp = addr;
+	dtb_size = fdt_copy(addr);
+		
+	/* Pad to a page boundary */
+	if (dtb_size)
+		addr += roundup(dtb_size, PAGE_SIZE);
+#endif
+
 	kernend = 0;
 	kfp = file_findfile(NULL, "elf32 kernel");
 	if (kfp == NULL)
@@ -335,9 +348,7 @@ md_load(char *args, vm_offset_t *modulep
 	file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp);
 
 #if defined(LOADER_FDT_SUPPORT)
-	/* Handle device tree blob */
-	dtbp = fdt_fixup();
-	if (dtbp != 0)
+	if (dtb_size)
 		file_addmetadata(kfp, MODINFOMD_DTBP, sizeof dtbp, &dtbp);
 	else
 		pager_output("WARNING! Trying to fire up the kernel, but no "



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