Index: boot/uboot/common/metadata.c =================================================================== --- boot/uboot/common/metadata.c (revision 243358) +++ boot/uboot/common/metadata.c (working copy) @@ -42,7 +42,7 @@ #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 @@ 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 @@ /* 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 @@ 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 " Index: boot/fdt/fdt_loader_cmd.c =================================================================== --- boot/fdt/fdt_loader_cmd.c (revision 243358) +++ boot/fdt/fdt_loader_cmd.c (working copy) @@ -40,8 +40,6 @@ #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 @@ #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 @@ /* 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_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 @@ 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 @@ } 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 @@ 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 @@ 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 @@ /* 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 @@ /* * 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 @@ 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 @@ 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 @@ } /* - * Check if uboot env vars were parsed already. If not, do it now. - */ - if (fdt_fixup() == 0) - return (CMD_ERROR); - - /* * Validate fdt . */ cmd = strdup(argv[1]); @@ -668,6 +760,7 @@ if (strcmp(cmd, commands[i].name) == 0) { /* found it */ cmdh = commands[i].handler; + flags = commands[i].flags; break; } i++; @@ -677,6 +770,14 @@ 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 @@ } 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 @@ } 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[]) { Index: arm/arm/machdep.c =================================================================== --- arm/arm/machdep.c (revision 243358) +++ arm/arm/machdep.c (working copy) @@ -1156,7 +1156,9 @@ void * initarm(struct arm_boot_params *abp) { + struct mem_region memory_regions[FDT_MEM_REGIONS]; struct mem_region availmem_regions[FDT_MEM_REGIONS]; + struct mem_region reserved_regions[FDT_MEM_REGIONS]; struct pv_addr kernel_l1pt; struct pv_addr dpcpu; vm_offset_t dtbp, freemempos, l2_start, lastaddr; @@ -1166,7 +1168,12 @@ void *kmdp; u_int l1pagetable; int i = 0, j = 0, err_devmap = 0; + int memory_regions_sz; int availmem_regions_sz; + int reserved_regions_sz; + vm_offset_t start, end; + vm_offset_t rstart, rend; + int curr; lastaddr = parse_boot_param(abp); memsize = 0; @@ -1197,10 +1204,73 @@ while (1); /* Grab physical memory regions information from device tree. */ - if (fdt_get_mem_regions(availmem_regions, &availmem_regions_sz, + if (fdt_get_mem_regions(memory_regions, &memory_regions_sz, &memsize) != 0) while(1); + /* Grab physical memory regions information from device tree. */ + if (fdt_get_reserved_regions(reserved_regions, &reserved_regions_sz) != 0) + reserved_regions_sz = 0; + + /* + * Now exclude all the reserved regions + */ + curr = 0; + for (i = 0; i < memory_regions_sz; i++) { + start = memory_regions[i].mr_start; + end = start + memory_regions[i].mr_size; + for (j = 0; j < reserved_regions_sz; j++) { + rstart = reserved_regions[j].mr_start; + rend = rstart + reserved_regions[j].mr_size; + /* + * Restricted region is before available + * Skip restricted region + */ + if (rend <= start) + continue; + /* + * Restricted region is behind available + * No further processing required + */ + if (rstart >= end) + break; + /* + * Restricted region includes memory region + * skip availble region + */ + if ((start >= rstart) && (rend >= end)) { + start = rend; + end = rend; + break; + } + /* + * Memory region includes restricted region + */ + if ((rstart > start) && (end > rend)) { + availmem_regions[curr].mr_start = start; + availmem_regions[curr++].mr_size = rstart - start; + start = rend; + break; + } + /* + * Memory region partially overlaps with restricted + */ + if ((rstart >= start) && (rstart <= end)) { + end = rstart; + } + else if ((rend >= start) && (rend <= end)) { + start = rend; + } + } + + if (end > start) { + availmem_regions[curr].mr_start = start; + availmem_regions[curr++].mr_size = end - start; + } + } + + availmem_regions_sz = curr; + /* Platform-specific initialisation */ pmap_bootstrap_lastaddr = initarm_lastaddr(); Index: dev/fdt/fdt_common.c =================================================================== --- dev/fdt/fdt_common.c (revision 243358) +++ dev/fdt/fdt_common.c (working copy) @@ -634,6 +634,66 @@ } int +fdt_get_reserved_regions(struct mem_region *mr, int *mrcnt) +{ + pcell_t reserve[FDT_REG_CELLS * FDT_MEM_REGIONS]; + pcell_t *reservep; + phandle_t memory, root; + uint32_t memory_size; + int addr_cells, size_cells; + int i, max_size, res_len, rv, tuple_size, tuples; + + max_size = sizeof(reserve); + root = OF_finddevice("/"); + memory = OF_finddevice("/memory"); + if (memory == -1) { + rv = ENXIO; + goto out; + } + + if ((rv = fdt_addrsize_cells(OF_parent(memory), &addr_cells, + &size_cells)) != 0) + goto out; + + if (addr_cells > 2) { + rv = ERANGE; + goto out; + } + + tuple_size = sizeof(pcell_t) * (addr_cells + size_cells); + + res_len = OF_getproplen(root, "memreserve"); + if (res_len <= 0 || res_len > sizeof(reserve)) { + rv = ERANGE; + goto out; + } + + if (OF_getprop(root, "memreserve", reserve, res_len) <= 0) { + rv = ENXIO; + goto out; + } + + memory_size = 0; + tuples = res_len / tuple_size; + reservep = (pcell_t *)&reserve; + for (i = 0; i < tuples; i++) { + + rv = fdt_data_to_res(reservep, addr_cells, size_cells, + (u_long *)&mr[i].mr_start, (u_long *)&mr[i].mr_size); + + if (rv != 0) + goto out; + + reservep += addr_cells + size_cells; + } + + *mrcnt = i; + rv = 0; +out: + return (rv); +} + +int fdt_get_mem_regions(struct mem_region *mr, int *mrcnt, uint32_t *memsize) { pcell_t reg[FDT_REG_CELLS * FDT_MEM_REGIONS]; Index: dev/fdt/fdt_common.h =================================================================== --- dev/fdt/fdt_common.h (revision 243358) +++ dev/fdt/fdt_common.h (working copy) @@ -90,6 +90,7 @@ int fdt_data_verify(void *, int); phandle_t fdt_find_compatible(phandle_t, const char *, int); int fdt_get_mem_regions(struct mem_region *, int *, uint32_t *); +int fdt_get_reserved_regions(struct mem_region *, int *); int fdt_get_phyaddr(phandle_t, device_t, int *, void **); int fdt_get_range(phandle_t, int, u_long *, u_long *); int fdt_immr_addr(vm_offset_t);