summaryrefslogtreecommitdiffstats
path: root/sys/boot/fdt/fdt_loader_cmd.c
diff options
context:
space:
mode:
authorgonzo <gonzo@FreeBSD.org>2012-11-30 03:15:50 +0000
committergonzo <gonzo@FreeBSD.org>2012-11-30 03:15:50 +0000
commite9a6dd0099d4e0e6f29bd9acfdba4596e6cff8c0 (patch)
tree8badf4cffd59109679f8f867ce307dc34e2d830f /sys/boot/fdt/fdt_loader_cmd.c
parentc099a6d04f3ab2d73a3a47a0feddc48a3645a076 (diff)
downloadFreeBSD-src-e9a6dd0099d4e0e6f29bd9acfdba4596e6cff8c0.zip
FreeBSD-src-e9a6dd0099d4e0e6f29bd9acfdba4596e6cff8c0.tar.gz
- 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.
Diffstat (limited to 'sys/boot/fdt/fdt_loader_cmd.c')
-rw-r--r--sys/boot/fdt/fdt_loader_cmd.c262
1 files changed, 206 insertions, 56 deletions
diff --git a/sys/boot/fdt/fdt_loader_cmd.c b/sys/boot/fdt/fdt_loader_cmd.c
index b52d92f..c7297f4 100644
--- a/sys/boot/fdt/fdt_loader_cmd.c
+++ b/sys/boot/fdt/fdt_loader_cmd.c
@@ -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 *argv[]);
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 *argv[])
}
/*
- * 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 *argv[])
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 *argv[])
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 *argv[])
}
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[])
{
OpenPOWER on IntegriCloud