- 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.
This commit is contained in:
gonzo 2012-11-30 03:15:50 +00:00
parent c099a6d04f
commit e9a6dd0099
2 changed files with 222 additions and 61 deletions

View File

@ -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,41 +194,13 @@ 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;
/*
* Find the device tree 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;
}
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);
}
COPYOUT(fdtp_va, fdtp, fdtp_size);
/*
* Validate the blob.
*/
err = fdt_check_header(fdtp);
COPYOUT(va, &header, sizeof(header));
err = fdt_check_header(&header);
if (err < 0) {
if (err == -FDT_ERR_BADVERSION)
sprintf(command_errbuf,
@ -232,9 +210,51 @@ fdt_setup_fdtp()
else
sprintf(command_errbuf, "error validating blob: %s",
fdt_strerror(err));
return (CMD_ERROR);
return (1);
}
return (CMD_OK);
/*
* Release previous blob
*/
if (fdtp)
free(fdtp);
fdtp_size = fdt_totalsize(&header);
fdtp = malloc(fdtp_size);
if (fdtp == NULL) {
command_errmsg = "can't allocate memory for device tree copy";
return (1);
}
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);
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;
}
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;
@ -652,12 +750,6 @@ command_fdt_internal(int argc, char *argv[])
return (CMD_ERROR);
}
/*
* Check if uboot env vars were parsed already. If not, do it now.
*/
if (fdt_fixup() == 0)
return (CMD_ERROR);
/*
* Validate fdt <command>.
*/
@ -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.
*/
@ -685,6 +786,31 @@ command_fdt_internal(int argc, char *argv[])
return (err);
}
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[])
{
@ -1444,6 +1570,30 @@ fdt_cmd_pwd(int argc, char *argv[])
return (CMD_OK);
}
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[])
{

View File

@ -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 "