1*ca987d46SWarner Losh /*- 2*ca987d46SWarner Losh * Copyright (c) 2009-2010 The FreeBSD Foundation 3*ca987d46SWarner Losh * All rights reserved. 4*ca987d46SWarner Losh * 5*ca987d46SWarner Losh * This software was developed by Semihalf under sponsorship from 6*ca987d46SWarner Losh * the FreeBSD Foundation. 7*ca987d46SWarner Losh * 8*ca987d46SWarner Losh * Redistribution and use in source and binary forms, with or without 9*ca987d46SWarner Losh * modification, are permitted provided that the following conditions 10*ca987d46SWarner Losh * are met: 11*ca987d46SWarner Losh * 1. Redistributions of source code must retain the above copyright 12*ca987d46SWarner Losh * notice, this list of conditions and the following disclaimer. 13*ca987d46SWarner Losh * 2. Redistributions in binary form must reproduce the above copyright 14*ca987d46SWarner Losh * notice, this list of conditions and the following disclaimer in the 15*ca987d46SWarner Losh * documentation and/or other materials provided with the distribution. 16*ca987d46SWarner Losh * 17*ca987d46SWarner Losh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18*ca987d46SWarner Losh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19*ca987d46SWarner Losh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20*ca987d46SWarner Losh * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21*ca987d46SWarner Losh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22*ca987d46SWarner Losh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23*ca987d46SWarner Losh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24*ca987d46SWarner Losh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25*ca987d46SWarner Losh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26*ca987d46SWarner Losh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27*ca987d46SWarner Losh * SUCH DAMAGE. 28*ca987d46SWarner Losh */ 29*ca987d46SWarner Losh 30*ca987d46SWarner Losh #include <sys/cdefs.h> 31*ca987d46SWarner Losh __FBSDID("$FreeBSD$"); 32*ca987d46SWarner Losh 33*ca987d46SWarner Losh #include <stand.h> 34*ca987d46SWarner Losh #include <fdt.h> 35*ca987d46SWarner Losh #include <libfdt.h> 36*ca987d46SWarner Losh #include <sys/param.h> 37*ca987d46SWarner Losh #include <sys/linker.h> 38*ca987d46SWarner Losh #include <machine/elf.h> 39*ca987d46SWarner Losh 40*ca987d46SWarner Losh #include "bootstrap.h" 41*ca987d46SWarner Losh #include "fdt_platform.h" 42*ca987d46SWarner Losh #include "fdt_overlay.h" 43*ca987d46SWarner Losh 44*ca987d46SWarner Losh #ifdef DEBUG 45*ca987d46SWarner Losh #define debugf(fmt, args...) do { printf("%s(): ", __func__); \ 46*ca987d46SWarner Losh printf(fmt,##args); } while (0) 47*ca987d46SWarner Losh #else 48*ca987d46SWarner Losh #define debugf(fmt, args...) 49*ca987d46SWarner Losh #endif 50*ca987d46SWarner Losh 51*ca987d46SWarner Losh #define FDT_CWD_LEN 256 52*ca987d46SWarner Losh #define FDT_MAX_DEPTH 12 53*ca987d46SWarner Losh 54*ca987d46SWarner Losh #define FDT_PROP_SEP " = " 55*ca987d46SWarner Losh 56*ca987d46SWarner Losh #define COPYOUT(s,d,l) archsw.arch_copyout(s, d, l) 57*ca987d46SWarner Losh #define COPYIN(s,d,l) archsw.arch_copyin(s, d, l) 58*ca987d46SWarner Losh 59*ca987d46SWarner Losh #define FDT_STATIC_DTB_SYMBOL "fdt_static_dtb" 60*ca987d46SWarner Losh 61*ca987d46SWarner Losh #define CMD_REQUIRES_BLOB 0x01 62*ca987d46SWarner Losh 63*ca987d46SWarner Losh /* Location of FDT yet to be loaded. */ 64*ca987d46SWarner Losh /* This may be in read-only memory, so can't be manipulated directly. */ 65*ca987d46SWarner Losh static struct fdt_header *fdt_to_load = NULL; 66*ca987d46SWarner Losh /* Location of FDT on heap. */ 67*ca987d46SWarner Losh /* This is the copy we actually manipulate. */ 68*ca987d46SWarner Losh static struct fdt_header *fdtp = NULL; 69*ca987d46SWarner Losh /* Size of FDT blob */ 70*ca987d46SWarner Losh static size_t fdtp_size = 0; 71*ca987d46SWarner Losh /* Location of FDT in kernel or module. */ 72*ca987d46SWarner Losh /* This won't be set if FDT is loaded from disk or memory. */ 73*ca987d46SWarner Losh /* If it is set, we'll update it when fdt_copy() gets called. */ 74*ca987d46SWarner Losh static vm_offset_t fdtp_va = 0; 75*ca987d46SWarner Losh 76*ca987d46SWarner Losh static int fdt_load_dtb(vm_offset_t va); 77*ca987d46SWarner Losh 78*ca987d46SWarner Losh static int fdt_cmd_nyi(int argc, char *argv[]); 79*ca987d46SWarner Losh 80*ca987d46SWarner Losh static int fdt_cmd_addr(int argc, char *argv[]); 81*ca987d46SWarner Losh static int fdt_cmd_mkprop(int argc, char *argv[]); 82*ca987d46SWarner Losh static int fdt_cmd_cd(int argc, char *argv[]); 83*ca987d46SWarner Losh static int fdt_cmd_hdr(int argc, char *argv[]); 84*ca987d46SWarner Losh static int fdt_cmd_ls(int argc, char *argv[]); 85*ca987d46SWarner Losh static int fdt_cmd_prop(int argc, char *argv[]); 86*ca987d46SWarner Losh static int fdt_cmd_pwd(int argc, char *argv[]); 87*ca987d46SWarner Losh static int fdt_cmd_rm(int argc, char *argv[]); 88*ca987d46SWarner Losh static int fdt_cmd_mknode(int argc, char *argv[]); 89*ca987d46SWarner Losh static int fdt_cmd_mres(int argc, char *argv[]); 90*ca987d46SWarner Losh 91*ca987d46SWarner Losh typedef int cmdf_t(int, char *[]); 92*ca987d46SWarner Losh 93*ca987d46SWarner Losh struct cmdtab { 94*ca987d46SWarner Losh const char *name; 95*ca987d46SWarner Losh cmdf_t *handler; 96*ca987d46SWarner Losh int flags; 97*ca987d46SWarner Losh }; 98*ca987d46SWarner Losh 99*ca987d46SWarner Losh static const struct cmdtab commands[] = { 100*ca987d46SWarner Losh { "addr", &fdt_cmd_addr, 0 }, 101*ca987d46SWarner Losh { "alias", &fdt_cmd_nyi, 0 }, 102*ca987d46SWarner Losh { "cd", &fdt_cmd_cd, CMD_REQUIRES_BLOB }, 103*ca987d46SWarner Losh { "header", &fdt_cmd_hdr, CMD_REQUIRES_BLOB }, 104*ca987d46SWarner Losh { "ls", &fdt_cmd_ls, CMD_REQUIRES_BLOB }, 105*ca987d46SWarner Losh { "mknode", &fdt_cmd_mknode, CMD_REQUIRES_BLOB }, 106*ca987d46SWarner Losh { "mkprop", &fdt_cmd_mkprop, CMD_REQUIRES_BLOB }, 107*ca987d46SWarner Losh { "mres", &fdt_cmd_mres, CMD_REQUIRES_BLOB }, 108*ca987d46SWarner Losh { "prop", &fdt_cmd_prop, CMD_REQUIRES_BLOB }, 109*ca987d46SWarner Losh { "pwd", &fdt_cmd_pwd, CMD_REQUIRES_BLOB }, 110*ca987d46SWarner Losh { "rm", &fdt_cmd_rm, CMD_REQUIRES_BLOB }, 111*ca987d46SWarner Losh { NULL, NULL } 112*ca987d46SWarner Losh }; 113*ca987d46SWarner Losh 114*ca987d46SWarner Losh static char cwd[FDT_CWD_LEN] = "/"; 115*ca987d46SWarner Losh 116*ca987d46SWarner Losh static vm_offset_t 117*ca987d46SWarner Losh fdt_find_static_dtb() 118*ca987d46SWarner Losh { 119*ca987d46SWarner Losh Elf_Ehdr *ehdr; 120*ca987d46SWarner Losh Elf_Shdr *shdr; 121*ca987d46SWarner Losh Elf_Sym sym; 122*ca987d46SWarner Losh vm_offset_t strtab, symtab, fdt_start; 123*ca987d46SWarner Losh uint64_t offs; 124*ca987d46SWarner Losh struct preloaded_file *kfp; 125*ca987d46SWarner Losh struct file_metadata *md; 126*ca987d46SWarner Losh char *strp; 127*ca987d46SWarner Losh int i, sym_count; 128*ca987d46SWarner Losh 129*ca987d46SWarner Losh debugf("fdt_find_static_dtb()\n"); 130*ca987d46SWarner Losh 131*ca987d46SWarner Losh sym_count = symtab = strtab = 0; 132*ca987d46SWarner Losh strp = NULL; 133*ca987d46SWarner Losh 134*ca987d46SWarner Losh offs = __elfN(relocation_offset); 135*ca987d46SWarner Losh 136*ca987d46SWarner Losh kfp = file_findfile(NULL, NULL); 137*ca987d46SWarner Losh if (kfp == NULL) 138*ca987d46SWarner Losh return (0); 139*ca987d46SWarner Losh 140*ca987d46SWarner Losh /* Locate the dynamic symbols and strtab. */ 141*ca987d46SWarner Losh md = file_findmetadata(kfp, MODINFOMD_ELFHDR); 142*ca987d46SWarner Losh if (md == NULL) 143*ca987d46SWarner Losh return (0); 144*ca987d46SWarner Losh ehdr = (Elf_Ehdr *)md->md_data; 145*ca987d46SWarner Losh 146*ca987d46SWarner Losh md = file_findmetadata(kfp, MODINFOMD_SHDR); 147*ca987d46SWarner Losh if (md == NULL) 148*ca987d46SWarner Losh return (0); 149*ca987d46SWarner Losh shdr = (Elf_Shdr *)md->md_data; 150*ca987d46SWarner Losh 151*ca987d46SWarner Losh for (i = 0; i < ehdr->e_shnum; ++i) { 152*ca987d46SWarner Losh if (shdr[i].sh_type == SHT_DYNSYM && symtab == 0) { 153*ca987d46SWarner Losh symtab = shdr[i].sh_addr + offs; 154*ca987d46SWarner Losh sym_count = shdr[i].sh_size / sizeof(Elf_Sym); 155*ca987d46SWarner Losh } else if (shdr[i].sh_type == SHT_STRTAB && strtab == 0) { 156*ca987d46SWarner Losh strtab = shdr[i].sh_addr + offs; 157*ca987d46SWarner Losh } 158*ca987d46SWarner Losh } 159*ca987d46SWarner Losh 160*ca987d46SWarner Losh /* 161*ca987d46SWarner Losh * The most efficient way to find a symbol would be to calculate a 162*ca987d46SWarner Losh * hash, find proper bucket and chain, and thus find a symbol. 163*ca987d46SWarner Losh * However, that would involve code duplication (e.g. for hash 164*ca987d46SWarner Losh * function). So we're using simpler and a bit slower way: we're 165*ca987d46SWarner Losh * iterating through symbols, searching for the one which name is 166*ca987d46SWarner Losh * 'equal' to 'fdt_static_dtb'. To speed up the process a little bit, 167*ca987d46SWarner Losh * we are eliminating symbols type of which is not STT_NOTYPE, or(and) 168*ca987d46SWarner Losh * those which binding attribute is not STB_GLOBAL. 169*ca987d46SWarner Losh */ 170*ca987d46SWarner Losh fdt_start = 0; 171*ca987d46SWarner Losh while (sym_count > 0 && fdt_start == 0) { 172*ca987d46SWarner Losh COPYOUT(symtab, &sym, sizeof(sym)); 173*ca987d46SWarner Losh symtab += sizeof(sym); 174*ca987d46SWarner Losh --sym_count; 175*ca987d46SWarner Losh if (ELF_ST_BIND(sym.st_info) != STB_GLOBAL || 176*ca987d46SWarner Losh ELF_ST_TYPE(sym.st_info) != STT_NOTYPE) 177*ca987d46SWarner Losh continue; 178*ca987d46SWarner Losh strp = strdupout(strtab + sym.st_name); 179*ca987d46SWarner Losh if (strcmp(strp, FDT_STATIC_DTB_SYMBOL) == 0) 180*ca987d46SWarner Losh fdt_start = (vm_offset_t)sym.st_value + offs; 181*ca987d46SWarner Losh free(strp); 182*ca987d46SWarner Losh } 183*ca987d46SWarner Losh return (fdt_start); 184*ca987d46SWarner Losh } 185*ca987d46SWarner Losh 186*ca987d46SWarner Losh static int 187*ca987d46SWarner Losh fdt_load_dtb(vm_offset_t va) 188*ca987d46SWarner Losh { 189*ca987d46SWarner Losh struct fdt_header header; 190*ca987d46SWarner Losh int err; 191*ca987d46SWarner Losh 192*ca987d46SWarner Losh debugf("fdt_load_dtb(0x%08jx)\n", (uintmax_t)va); 193*ca987d46SWarner Losh 194*ca987d46SWarner Losh COPYOUT(va, &header, sizeof(header)); 195*ca987d46SWarner Losh err = fdt_check_header(&header); 196*ca987d46SWarner Losh if (err < 0) { 197*ca987d46SWarner Losh if (err == -FDT_ERR_BADVERSION) { 198*ca987d46SWarner Losh snprintf(command_errbuf, sizeof(command_errbuf), 199*ca987d46SWarner Losh "incompatible blob version: %d, should be: %d", 200*ca987d46SWarner Losh fdt_version(fdtp), FDT_LAST_SUPPORTED_VERSION); 201*ca987d46SWarner Losh } else { 202*ca987d46SWarner Losh snprintf(command_errbuf, sizeof(command_errbuf), 203*ca987d46SWarner Losh "error validating blob: %s", fdt_strerror(err)); 204*ca987d46SWarner Losh } 205*ca987d46SWarner Losh return (1); 206*ca987d46SWarner Losh } 207*ca987d46SWarner Losh 208*ca987d46SWarner Losh /* 209*ca987d46SWarner Losh * Release previous blob 210*ca987d46SWarner Losh */ 211*ca987d46SWarner Losh if (fdtp) 212*ca987d46SWarner Losh free(fdtp); 213*ca987d46SWarner Losh 214*ca987d46SWarner Losh fdtp_size = fdt_totalsize(&header); 215*ca987d46SWarner Losh fdtp = malloc(fdtp_size); 216*ca987d46SWarner Losh 217*ca987d46SWarner Losh if (fdtp == NULL) { 218*ca987d46SWarner Losh command_errmsg = "can't allocate memory for device tree copy"; 219*ca987d46SWarner Losh return (1); 220*ca987d46SWarner Losh } 221*ca987d46SWarner Losh 222*ca987d46SWarner Losh fdtp_va = va; 223*ca987d46SWarner Losh COPYOUT(va, fdtp, fdtp_size); 224*ca987d46SWarner Losh debugf("DTB blob found at 0x%jx, size: 0x%jx\n", (uintmax_t)va, (uintmax_t)fdtp_size); 225*ca987d46SWarner Losh 226*ca987d46SWarner Losh return (0); 227*ca987d46SWarner Losh } 228*ca987d46SWarner Losh 229*ca987d46SWarner Losh int 230*ca987d46SWarner Losh fdt_load_dtb_addr(struct fdt_header *header) 231*ca987d46SWarner Losh { 232*ca987d46SWarner Losh int err; 233*ca987d46SWarner Losh 234*ca987d46SWarner Losh debugf("fdt_load_dtb_addr(%p)\n", header); 235*ca987d46SWarner Losh 236*ca987d46SWarner Losh fdtp_size = fdt_totalsize(header); 237*ca987d46SWarner Losh err = fdt_check_header(header); 238*ca987d46SWarner Losh if (err < 0) { 239*ca987d46SWarner Losh snprintf(command_errbuf, sizeof(command_errbuf), 240*ca987d46SWarner Losh "error validating blob: %s", fdt_strerror(err)); 241*ca987d46SWarner Losh return (err); 242*ca987d46SWarner Losh } 243*ca987d46SWarner Losh free(fdtp); 244*ca987d46SWarner Losh if ((fdtp = malloc(fdtp_size)) == NULL) { 245*ca987d46SWarner Losh command_errmsg = "can't allocate memory for device tree copy"; 246*ca987d46SWarner Losh return (1); 247*ca987d46SWarner Losh } 248*ca987d46SWarner Losh 249*ca987d46SWarner Losh fdtp_va = 0; // Don't write this back into module or kernel. 250*ca987d46SWarner Losh bcopy(header, fdtp, fdtp_size); 251*ca987d46SWarner Losh return (0); 252*ca987d46SWarner Losh } 253*ca987d46SWarner Losh 254*ca987d46SWarner Losh int 255*ca987d46SWarner Losh fdt_load_dtb_file(const char * filename) 256*ca987d46SWarner Losh { 257*ca987d46SWarner Losh struct preloaded_file *bfp, *oldbfp; 258*ca987d46SWarner Losh int err; 259*ca987d46SWarner Losh 260*ca987d46SWarner Losh debugf("fdt_load_dtb_file(%s)\n", filename); 261*ca987d46SWarner Losh 262*ca987d46SWarner Losh oldbfp = file_findfile(NULL, "dtb"); 263*ca987d46SWarner Losh 264*ca987d46SWarner Losh /* Attempt to load and validate a new dtb from a file. */ 265*ca987d46SWarner Losh if ((bfp = file_loadraw(filename, "dtb", 1)) == NULL) { 266*ca987d46SWarner Losh snprintf(command_errbuf, sizeof(command_errbuf), 267*ca987d46SWarner Losh "failed to load file '%s'", filename); 268*ca987d46SWarner Losh return (1); 269*ca987d46SWarner Losh } 270*ca987d46SWarner Losh if ((err = fdt_load_dtb(bfp->f_addr)) != 0) { 271*ca987d46SWarner Losh file_discard(bfp); 272*ca987d46SWarner Losh return (err); 273*ca987d46SWarner Losh } 274*ca987d46SWarner Losh 275*ca987d46SWarner Losh /* A new dtb was validated, discard any previous file. */ 276*ca987d46SWarner Losh if (oldbfp) 277*ca987d46SWarner Losh file_discard(oldbfp); 278*ca987d46SWarner Losh return (0); 279*ca987d46SWarner Losh } 280*ca987d46SWarner Losh 281*ca987d46SWarner Losh static int 282*ca987d46SWarner Losh fdt_load_dtb_overlay(const char * filename) 283*ca987d46SWarner Losh { 284*ca987d46SWarner Losh struct preloaded_file *bfp, *oldbfp; 285*ca987d46SWarner Losh struct fdt_header header; 286*ca987d46SWarner Losh int err; 287*ca987d46SWarner Losh 288*ca987d46SWarner Losh debugf("fdt_load_dtb_overlay(%s)\n", filename); 289*ca987d46SWarner Losh 290*ca987d46SWarner Losh oldbfp = file_findfile(filename, "dtbo"); 291*ca987d46SWarner Losh 292*ca987d46SWarner Losh /* Attempt to load and validate a new dtb from a file. */ 293*ca987d46SWarner Losh if ((bfp = file_loadraw(filename, "dtbo", 1)) == NULL) { 294*ca987d46SWarner Losh printf("failed to load file '%s'\n", filename); 295*ca987d46SWarner Losh return (1); 296*ca987d46SWarner Losh } 297*ca987d46SWarner Losh 298*ca987d46SWarner Losh COPYOUT(bfp->f_addr, &header, sizeof(header)); 299*ca987d46SWarner Losh err = fdt_check_header(&header); 300*ca987d46SWarner Losh 301*ca987d46SWarner Losh if (err < 0) { 302*ca987d46SWarner Losh file_discard(bfp); 303*ca987d46SWarner Losh if (err == -FDT_ERR_BADVERSION) 304*ca987d46SWarner Losh printf("incompatible blob version: %d, should be: %d\n", 305*ca987d46SWarner Losh fdt_version(fdtp), FDT_LAST_SUPPORTED_VERSION); 306*ca987d46SWarner Losh 307*ca987d46SWarner Losh else 308*ca987d46SWarner Losh printf("error validating blob: %s\n", 309*ca987d46SWarner Losh fdt_strerror(err)); 310*ca987d46SWarner Losh return (1); 311*ca987d46SWarner Losh } 312*ca987d46SWarner Losh 313*ca987d46SWarner Losh /* A new dtb was validated, discard any previous file. */ 314*ca987d46SWarner Losh if (oldbfp) 315*ca987d46SWarner Losh file_discard(oldbfp); 316*ca987d46SWarner Losh 317*ca987d46SWarner Losh return (0); 318*ca987d46SWarner Losh } 319*ca987d46SWarner Losh 320*ca987d46SWarner Losh int 321*ca987d46SWarner Losh fdt_load_dtb_overlays(const char * filenames) 322*ca987d46SWarner Losh { 323*ca987d46SWarner Losh char *names; 324*ca987d46SWarner Losh char *name; 325*ca987d46SWarner Losh char *comaptr; 326*ca987d46SWarner Losh 327*ca987d46SWarner Losh debugf("fdt_load_dtb_overlay(%s)\n", filenames); 328*ca987d46SWarner Losh 329*ca987d46SWarner Losh names = strdup(filenames); 330*ca987d46SWarner Losh if (names == NULL) 331*ca987d46SWarner Losh return (1); 332*ca987d46SWarner Losh name = names; 333*ca987d46SWarner Losh do { 334*ca987d46SWarner Losh comaptr = strchr(name, ','); 335*ca987d46SWarner Losh if (comaptr) 336*ca987d46SWarner Losh *comaptr = '\0'; 337*ca987d46SWarner Losh fdt_load_dtb_overlay(name); 338*ca987d46SWarner Losh name = comaptr + 1; 339*ca987d46SWarner Losh } while(comaptr); 340*ca987d46SWarner Losh 341*ca987d46SWarner Losh free(names); 342*ca987d46SWarner Losh return (0); 343*ca987d46SWarner Losh } 344*ca987d46SWarner Losh 345*ca987d46SWarner Losh void 346*ca987d46SWarner Losh fdt_apply_overlays() 347*ca987d46SWarner Losh { 348*ca987d46SWarner Losh struct preloaded_file *fp; 349*ca987d46SWarner Losh size_t overlays_size, max_overlay_size, new_fdtp_size; 350*ca987d46SWarner Losh void *new_fdtp; 351*ca987d46SWarner Losh void *overlay; 352*ca987d46SWarner Losh int rv; 353*ca987d46SWarner Losh 354*ca987d46SWarner Losh if ((fdtp == NULL) || (fdtp_size == 0)) 355*ca987d46SWarner Losh return; 356*ca987d46SWarner Losh 357*ca987d46SWarner Losh overlays_size = 0; 358*ca987d46SWarner Losh max_overlay_size = 0; 359*ca987d46SWarner Losh for (fp = file_findfile(NULL, "dtbo"); fp != NULL; fp = fp->f_next) { 360*ca987d46SWarner Losh if (max_overlay_size < fp->f_size) 361*ca987d46SWarner Losh max_overlay_size = fp->f_size; 362*ca987d46SWarner Losh overlays_size += fp->f_size; 363*ca987d46SWarner Losh } 364*ca987d46SWarner Losh 365*ca987d46SWarner Losh /* Nothing to apply */ 366*ca987d46SWarner Losh if (overlays_size == 0) 367*ca987d46SWarner Losh return; 368*ca987d46SWarner Losh 369*ca987d46SWarner Losh /* It's actually more than enough */ 370*ca987d46SWarner Losh new_fdtp_size = fdtp_size + overlays_size; 371*ca987d46SWarner Losh new_fdtp = malloc(new_fdtp_size); 372*ca987d46SWarner Losh if (new_fdtp == NULL) { 373*ca987d46SWarner Losh printf("failed to allocate memory for DTB blob with overlays\n"); 374*ca987d46SWarner Losh return; 375*ca987d46SWarner Losh } 376*ca987d46SWarner Losh 377*ca987d46SWarner Losh overlay = malloc(max_overlay_size); 378*ca987d46SWarner Losh if (overlay == NULL) { 379*ca987d46SWarner Losh printf("failed to allocate memory for DTB blob with overlays\n"); 380*ca987d46SWarner Losh free(new_fdtp); 381*ca987d46SWarner Losh return; 382*ca987d46SWarner Losh } 383*ca987d46SWarner Losh 384*ca987d46SWarner Losh rv = fdt_open_into(fdtp, new_fdtp, new_fdtp_size); 385*ca987d46SWarner Losh if (rv != 0) { 386*ca987d46SWarner Losh printf("failed to open DTB blob for applying overlays\n"); 387*ca987d46SWarner Losh free(new_fdtp); 388*ca987d46SWarner Losh free(overlay); 389*ca987d46SWarner Losh return; 390*ca987d46SWarner Losh } 391*ca987d46SWarner Losh 392*ca987d46SWarner Losh for (fp = file_findfile(NULL, "dtbo"); fp != NULL; fp = fp->f_next) { 393*ca987d46SWarner Losh printf("applying DTB overlay '%s'\n", fp->f_name); 394*ca987d46SWarner Losh COPYOUT(fp->f_addr, overlay, fp->f_size); 395*ca987d46SWarner Losh fdt_overlay_apply(new_fdtp, overlay, fp->f_size); 396*ca987d46SWarner Losh } 397*ca987d46SWarner Losh 398*ca987d46SWarner Losh free(fdtp); 399*ca987d46SWarner Losh fdtp = new_fdtp; 400*ca987d46SWarner Losh fdtp_size = new_fdtp_size; 401*ca987d46SWarner Losh 402*ca987d46SWarner Losh free(overlay); 403*ca987d46SWarner Losh } 404*ca987d46SWarner Losh 405*ca987d46SWarner Losh int 406*ca987d46SWarner Losh fdt_setup_fdtp() 407*ca987d46SWarner Losh { 408*ca987d46SWarner Losh struct preloaded_file *bfp; 409*ca987d46SWarner Losh vm_offset_t va; 410*ca987d46SWarner Losh 411*ca987d46SWarner Losh debugf("fdt_setup_fdtp()\n"); 412*ca987d46SWarner Losh 413*ca987d46SWarner Losh /* If we already loaded a file, use it. */ 414*ca987d46SWarner Losh if ((bfp = file_findfile(NULL, "dtb")) != NULL) { 415*ca987d46SWarner Losh if (fdt_load_dtb(bfp->f_addr) == 0) { 416*ca987d46SWarner Losh printf("Using DTB from loaded file '%s'.\n", 417*ca987d46SWarner Losh bfp->f_name); 418*ca987d46SWarner Losh return (0); 419*ca987d46SWarner Losh } 420*ca987d46SWarner Losh } 421*ca987d46SWarner Losh 422*ca987d46SWarner Losh /* If we were given the address of a valid blob in memory, use it. */ 423*ca987d46SWarner Losh if (fdt_to_load != NULL) { 424*ca987d46SWarner Losh if (fdt_load_dtb_addr(fdt_to_load) == 0) { 425*ca987d46SWarner Losh printf("Using DTB from memory address %p.\n", 426*ca987d46SWarner Losh fdt_to_load); 427*ca987d46SWarner Losh return (0); 428*ca987d46SWarner Losh } 429*ca987d46SWarner Losh } 430*ca987d46SWarner Losh 431*ca987d46SWarner Losh if (fdt_platform_load_dtb() == 0) 432*ca987d46SWarner Losh return (0); 433*ca987d46SWarner Losh 434*ca987d46SWarner Losh /* If there is a dtb compiled into the kernel, use it. */ 435*ca987d46SWarner Losh if ((va = fdt_find_static_dtb()) != 0) { 436*ca987d46SWarner Losh if (fdt_load_dtb(va) == 0) { 437*ca987d46SWarner Losh printf("Using DTB compiled into kernel.\n"); 438*ca987d46SWarner Losh return (0); 439*ca987d46SWarner Losh } 440*ca987d46SWarner Losh } 441*ca987d46SWarner Losh 442*ca987d46SWarner Losh command_errmsg = "No device tree blob found!\n"; 443*ca987d46SWarner Losh return (1); 444*ca987d46SWarner Losh } 445*ca987d46SWarner Losh 446*ca987d46SWarner Losh #define fdt_strtovect(str, cellbuf, lim, cellsize) _fdt_strtovect((str), \ 447*ca987d46SWarner Losh (cellbuf), (lim), (cellsize), 0); 448*ca987d46SWarner Losh 449*ca987d46SWarner Losh /* Force using base 16 */ 450*ca987d46SWarner Losh #define fdt_strtovectx(str, cellbuf, lim, cellsize) _fdt_strtovect((str), \ 451*ca987d46SWarner Losh (cellbuf), (lim), (cellsize), 16); 452*ca987d46SWarner Losh 453*ca987d46SWarner Losh static int 454*ca987d46SWarner Losh _fdt_strtovect(const char *str, void *cellbuf, int lim, unsigned char cellsize, 455*ca987d46SWarner Losh uint8_t base) 456*ca987d46SWarner Losh { 457*ca987d46SWarner Losh const char *buf = str; 458*ca987d46SWarner Losh const char *end = str + strlen(str) - 2; 459*ca987d46SWarner Losh uint32_t *u32buf = NULL; 460*ca987d46SWarner Losh uint8_t *u8buf = NULL; 461*ca987d46SWarner Losh int cnt = 0; 462*ca987d46SWarner Losh 463*ca987d46SWarner Losh if (cellsize == sizeof(uint32_t)) 464*ca987d46SWarner Losh u32buf = (uint32_t *)cellbuf; 465*ca987d46SWarner Losh else 466*ca987d46SWarner Losh u8buf = (uint8_t *)cellbuf; 467*ca987d46SWarner Losh 468*ca987d46SWarner Losh if (lim == 0) 469*ca987d46SWarner Losh return (0); 470*ca987d46SWarner Losh 471*ca987d46SWarner Losh while (buf < end) { 472*ca987d46SWarner Losh 473*ca987d46SWarner Losh /* Skip white whitespace(s)/separators */ 474*ca987d46SWarner Losh while (!isxdigit(*buf) && buf < end) 475*ca987d46SWarner Losh buf++; 476*ca987d46SWarner Losh 477*ca987d46SWarner Losh if (u32buf != NULL) 478*ca987d46SWarner Losh u32buf[cnt] = 479*ca987d46SWarner Losh cpu_to_fdt32((uint32_t)strtol(buf, NULL, base)); 480*ca987d46SWarner Losh 481*ca987d46SWarner Losh else 482*ca987d46SWarner Losh u8buf[cnt] = (uint8_t)strtol(buf, NULL, base); 483*ca987d46SWarner Losh 484*ca987d46SWarner Losh if (cnt + 1 <= lim - 1) 485*ca987d46SWarner Losh cnt++; 486*ca987d46SWarner Losh else 487*ca987d46SWarner Losh break; 488*ca987d46SWarner Losh buf++; 489*ca987d46SWarner Losh /* Find another number */ 490*ca987d46SWarner Losh while ((isxdigit(*buf) || *buf == 'x') && buf < end) 491*ca987d46SWarner Losh buf++; 492*ca987d46SWarner Losh } 493*ca987d46SWarner Losh return (cnt); 494*ca987d46SWarner Losh } 495*ca987d46SWarner Losh 496*ca987d46SWarner Losh void 497*ca987d46SWarner Losh fdt_fixup_ethernet(const char *str, char *ethstr, int len) 498*ca987d46SWarner Losh { 499*ca987d46SWarner Losh uint8_t tmp_addr[6]; 500*ca987d46SWarner Losh 501*ca987d46SWarner Losh /* Convert macaddr string into a vector of uints */ 502*ca987d46SWarner Losh fdt_strtovectx(str, &tmp_addr, 6, sizeof(uint8_t)); 503*ca987d46SWarner Losh /* Set actual property to a value from vect */ 504*ca987d46SWarner Losh fdt_setprop(fdtp, fdt_path_offset(fdtp, ethstr), 505*ca987d46SWarner Losh "local-mac-address", &tmp_addr, 6 * sizeof(uint8_t)); 506*ca987d46SWarner Losh } 507*ca987d46SWarner Losh 508*ca987d46SWarner Losh void 509*ca987d46SWarner Losh fdt_fixup_cpubusfreqs(unsigned long cpufreq, unsigned long busfreq) 510*ca987d46SWarner Losh { 511*ca987d46SWarner Losh int lo, o = 0, o2, maxo = 0, depth; 512*ca987d46SWarner Losh const uint32_t zero = 0; 513*ca987d46SWarner Losh 514*ca987d46SWarner Losh /* We want to modify every subnode of /cpus */ 515*ca987d46SWarner Losh o = fdt_path_offset(fdtp, "/cpus"); 516*ca987d46SWarner Losh if (o < 0) 517*ca987d46SWarner Losh return; 518*ca987d46SWarner Losh 519*ca987d46SWarner Losh /* maxo should contain offset of node next to /cpus */ 520*ca987d46SWarner Losh depth = 0; 521*ca987d46SWarner Losh maxo = o; 522*ca987d46SWarner Losh while (depth != -1) 523*ca987d46SWarner Losh maxo = fdt_next_node(fdtp, maxo, &depth); 524*ca987d46SWarner Losh 525*ca987d46SWarner Losh /* Find CPU frequency properties */ 526*ca987d46SWarner Losh o = fdt_node_offset_by_prop_value(fdtp, o, "clock-frequency", 527*ca987d46SWarner Losh &zero, sizeof(uint32_t)); 528*ca987d46SWarner Losh 529*ca987d46SWarner Losh o2 = fdt_node_offset_by_prop_value(fdtp, o, "bus-frequency", &zero, 530*ca987d46SWarner Losh sizeof(uint32_t)); 531*ca987d46SWarner Losh 532*ca987d46SWarner Losh lo = MIN(o, o2); 533*ca987d46SWarner Losh 534*ca987d46SWarner Losh while (o != -FDT_ERR_NOTFOUND && o2 != -FDT_ERR_NOTFOUND) { 535*ca987d46SWarner Losh 536*ca987d46SWarner Losh o = fdt_node_offset_by_prop_value(fdtp, lo, 537*ca987d46SWarner Losh "clock-frequency", &zero, sizeof(uint32_t)); 538*ca987d46SWarner Losh 539*ca987d46SWarner Losh o2 = fdt_node_offset_by_prop_value(fdtp, lo, "bus-frequency", 540*ca987d46SWarner Losh &zero, sizeof(uint32_t)); 541*ca987d46SWarner Losh 542*ca987d46SWarner Losh /* We're only interested in /cpus subnode(s) */ 543*ca987d46SWarner Losh if (lo > maxo) 544*ca987d46SWarner Losh break; 545*ca987d46SWarner Losh 546*ca987d46SWarner Losh fdt_setprop_inplace_cell(fdtp, lo, "clock-frequency", 547*ca987d46SWarner Losh (uint32_t)cpufreq); 548*ca987d46SWarner Losh 549*ca987d46SWarner Losh fdt_setprop_inplace_cell(fdtp, lo, "bus-frequency", 550*ca987d46SWarner Losh (uint32_t)busfreq); 551*ca987d46SWarner Losh 552*ca987d46SWarner Losh lo = MIN(o, o2); 553*ca987d46SWarner Losh } 554*ca987d46SWarner Losh } 555*ca987d46SWarner Losh 556*ca987d46SWarner Losh #ifdef notyet 557*ca987d46SWarner Losh static int 558*ca987d46SWarner Losh fdt_reg_valid(uint32_t *reg, int len, int addr_cells, int size_cells) 559*ca987d46SWarner Losh { 560*ca987d46SWarner Losh int cells_in_tuple, i, tuples, tuple_size; 561*ca987d46SWarner Losh uint32_t cur_start, cur_size; 562*ca987d46SWarner Losh 563*ca987d46SWarner Losh cells_in_tuple = (addr_cells + size_cells); 564*ca987d46SWarner Losh tuple_size = cells_in_tuple * sizeof(uint32_t); 565*ca987d46SWarner Losh tuples = len / tuple_size; 566*ca987d46SWarner Losh if (tuples == 0) 567*ca987d46SWarner Losh return (EINVAL); 568*ca987d46SWarner Losh 569*ca987d46SWarner Losh for (i = 0; i < tuples; i++) { 570*ca987d46SWarner Losh if (addr_cells == 2) 571*ca987d46SWarner Losh cur_start = fdt64_to_cpu(reg[i * cells_in_tuple]); 572*ca987d46SWarner Losh else 573*ca987d46SWarner Losh cur_start = fdt32_to_cpu(reg[i * cells_in_tuple]); 574*ca987d46SWarner Losh 575*ca987d46SWarner Losh if (size_cells == 2) 576*ca987d46SWarner Losh cur_size = fdt64_to_cpu(reg[i * cells_in_tuple + 2]); 577*ca987d46SWarner Losh else 578*ca987d46SWarner Losh cur_size = fdt32_to_cpu(reg[i * cells_in_tuple + 1]); 579*ca987d46SWarner Losh 580*ca987d46SWarner Losh if (cur_size == 0) 581*ca987d46SWarner Losh return (EINVAL); 582*ca987d46SWarner Losh 583*ca987d46SWarner Losh debugf(" reg#%d (start: 0x%0x size: 0x%0x) valid!\n", 584*ca987d46SWarner Losh i, cur_start, cur_size); 585*ca987d46SWarner Losh } 586*ca987d46SWarner Losh return (0); 587*ca987d46SWarner Losh } 588*ca987d46SWarner Losh #endif 589*ca987d46SWarner Losh 590*ca987d46SWarner Losh void 591*ca987d46SWarner Losh fdt_fixup_memory(struct fdt_mem_region *region, size_t num) 592*ca987d46SWarner Losh { 593*ca987d46SWarner Losh struct fdt_mem_region *curmr; 594*ca987d46SWarner Losh uint32_t addr_cells, size_cells; 595*ca987d46SWarner Losh uint32_t *addr_cellsp, *size_cellsp; 596*ca987d46SWarner Losh int err, i, len, memory, root; 597*ca987d46SWarner Losh size_t realmrno; 598*ca987d46SWarner Losh uint8_t *buf, *sb; 599*ca987d46SWarner Losh uint64_t rstart, rsize; 600*ca987d46SWarner Losh int reserved; 601*ca987d46SWarner Losh 602*ca987d46SWarner Losh root = fdt_path_offset(fdtp, "/"); 603*ca987d46SWarner Losh if (root < 0) { 604*ca987d46SWarner Losh sprintf(command_errbuf, "Could not find root node !"); 605*ca987d46SWarner Losh return; 606*ca987d46SWarner Losh } 607*ca987d46SWarner Losh 608*ca987d46SWarner Losh memory = fdt_path_offset(fdtp, "/memory"); 609*ca987d46SWarner Losh if (memory <= 0) { 610*ca987d46SWarner Losh /* Create proper '/memory' node. */ 611*ca987d46SWarner Losh memory = fdt_add_subnode(fdtp, root, "memory"); 612*ca987d46SWarner Losh if (memory <= 0) { 613*ca987d46SWarner Losh snprintf(command_errbuf, sizeof(command_errbuf), 614*ca987d46SWarner Losh "Could not fixup '/memory' " 615*ca987d46SWarner Losh "node, error code : %d!\n", memory); 616*ca987d46SWarner Losh return; 617*ca987d46SWarner Losh } 618*ca987d46SWarner Losh 619*ca987d46SWarner Losh err = fdt_setprop(fdtp, memory, "device_type", "memory", 620*ca987d46SWarner Losh sizeof("memory")); 621*ca987d46SWarner Losh 622*ca987d46SWarner Losh if (err < 0) 623*ca987d46SWarner Losh return; 624*ca987d46SWarner Losh } 625*ca987d46SWarner Losh 626*ca987d46SWarner Losh addr_cellsp = (uint32_t *)fdt_getprop(fdtp, root, "#address-cells", 627*ca987d46SWarner Losh NULL); 628*ca987d46SWarner Losh size_cellsp = (uint32_t *)fdt_getprop(fdtp, root, "#size-cells", NULL); 629*ca987d46SWarner Losh 630*ca987d46SWarner Losh if (addr_cellsp == NULL || size_cellsp == NULL) { 631*ca987d46SWarner Losh snprintf(command_errbuf, sizeof(command_errbuf), 632*ca987d46SWarner Losh "Could not fixup '/memory' node : " 633*ca987d46SWarner Losh "%s %s property not found in root node!\n", 634*ca987d46SWarner Losh (!addr_cellsp) ? "#address-cells" : "", 635*ca987d46SWarner Losh (!size_cellsp) ? "#size-cells" : ""); 636*ca987d46SWarner Losh return; 637*ca987d46SWarner Losh } 638*ca987d46SWarner Losh 639*ca987d46SWarner Losh addr_cells = fdt32_to_cpu(*addr_cellsp); 640*ca987d46SWarner Losh size_cells = fdt32_to_cpu(*size_cellsp); 641*ca987d46SWarner Losh 642*ca987d46SWarner Losh /* 643*ca987d46SWarner Losh * Convert memreserve data to memreserve property 644*ca987d46SWarner Losh * Check if property already exists 645*ca987d46SWarner Losh */ 646*ca987d46SWarner Losh reserved = fdt_num_mem_rsv(fdtp); 647*ca987d46SWarner Losh if (reserved && 648*ca987d46SWarner Losh (fdt_getprop(fdtp, root, "memreserve", NULL) == NULL)) { 649*ca987d46SWarner Losh len = (addr_cells + size_cells) * reserved * sizeof(uint32_t); 650*ca987d46SWarner Losh sb = buf = (uint8_t *)malloc(len); 651*ca987d46SWarner Losh if (!buf) 652*ca987d46SWarner Losh return; 653*ca987d46SWarner Losh 654*ca987d46SWarner Losh bzero(buf, len); 655*ca987d46SWarner Losh 656*ca987d46SWarner Losh for (i = 0; i < reserved; i++) { 657*ca987d46SWarner Losh if (fdt_get_mem_rsv(fdtp, i, &rstart, &rsize)) 658*ca987d46SWarner Losh break; 659*ca987d46SWarner Losh if (rsize) { 660*ca987d46SWarner Losh /* Ensure endianness, and put cells into a buffer */ 661*ca987d46SWarner Losh if (addr_cells == 2) 662*ca987d46SWarner Losh *(uint64_t *)buf = 663*ca987d46SWarner Losh cpu_to_fdt64(rstart); 664*ca987d46SWarner Losh else 665*ca987d46SWarner Losh *(uint32_t *)buf = 666*ca987d46SWarner Losh cpu_to_fdt32(rstart); 667*ca987d46SWarner Losh 668*ca987d46SWarner Losh buf += sizeof(uint32_t) * addr_cells; 669*ca987d46SWarner Losh if (size_cells == 2) 670*ca987d46SWarner Losh *(uint64_t *)buf = 671*ca987d46SWarner Losh cpu_to_fdt64(rsize); 672*ca987d46SWarner Losh else 673*ca987d46SWarner Losh *(uint32_t *)buf = 674*ca987d46SWarner Losh cpu_to_fdt32(rsize); 675*ca987d46SWarner Losh 676*ca987d46SWarner Losh buf += sizeof(uint32_t) * size_cells; 677*ca987d46SWarner Losh } 678*ca987d46SWarner Losh } 679*ca987d46SWarner Losh 680*ca987d46SWarner Losh /* Set property */ 681*ca987d46SWarner Losh if ((err = fdt_setprop(fdtp, root, "memreserve", sb, len)) < 0) 682*ca987d46SWarner Losh printf("Could not fixup 'memreserve' property.\n"); 683*ca987d46SWarner Losh 684*ca987d46SWarner Losh free(sb); 685*ca987d46SWarner Losh } 686*ca987d46SWarner Losh 687*ca987d46SWarner Losh /* Count valid memory regions entries in sysinfo. */ 688*ca987d46SWarner Losh realmrno = num; 689*ca987d46SWarner Losh for (i = 0; i < num; i++) 690*ca987d46SWarner Losh if (region[i].start == 0 && region[i].size == 0) 691*ca987d46SWarner Losh realmrno--; 692*ca987d46SWarner Losh 693*ca987d46SWarner Losh if (realmrno == 0) { 694*ca987d46SWarner Losh sprintf(command_errbuf, "Could not fixup '/memory' node : " 695*ca987d46SWarner Losh "sysinfo doesn't contain valid memory regions info!\n"); 696*ca987d46SWarner Losh return; 697*ca987d46SWarner Losh } 698*ca987d46SWarner Losh 699*ca987d46SWarner Losh len = (addr_cells + size_cells) * realmrno * sizeof(uint32_t); 700*ca987d46SWarner Losh sb = buf = (uint8_t *)malloc(len); 701*ca987d46SWarner Losh if (!buf) 702*ca987d46SWarner Losh return; 703*ca987d46SWarner Losh 704*ca987d46SWarner Losh bzero(buf, len); 705*ca987d46SWarner Losh 706*ca987d46SWarner Losh for (i = 0; i < num; i++) { 707*ca987d46SWarner Losh curmr = ®ion[i]; 708*ca987d46SWarner Losh if (curmr->size != 0) { 709*ca987d46SWarner Losh /* Ensure endianness, and put cells into a buffer */ 710*ca987d46SWarner Losh if (addr_cells == 2) 711*ca987d46SWarner Losh *(uint64_t *)buf = 712*ca987d46SWarner Losh cpu_to_fdt64(curmr->start); 713*ca987d46SWarner Losh else 714*ca987d46SWarner Losh *(uint32_t *)buf = 715*ca987d46SWarner Losh cpu_to_fdt32(curmr->start); 716*ca987d46SWarner Losh 717*ca987d46SWarner Losh buf += sizeof(uint32_t) * addr_cells; 718*ca987d46SWarner Losh if (size_cells == 2) 719*ca987d46SWarner Losh *(uint64_t *)buf = 720*ca987d46SWarner Losh cpu_to_fdt64(curmr->size); 721*ca987d46SWarner Losh else 722*ca987d46SWarner Losh *(uint32_t *)buf = 723*ca987d46SWarner Losh cpu_to_fdt32(curmr->size); 724*ca987d46SWarner Losh 725*ca987d46SWarner Losh buf += sizeof(uint32_t) * size_cells; 726*ca987d46SWarner Losh } 727*ca987d46SWarner Losh } 728*ca987d46SWarner Losh 729*ca987d46SWarner Losh /* Set property */ 730*ca987d46SWarner Losh if ((err = fdt_setprop(fdtp, memory, "reg", sb, len)) < 0) 731*ca987d46SWarner Losh sprintf(command_errbuf, "Could not fixup '/memory' node.\n"); 732*ca987d46SWarner Losh 733*ca987d46SWarner Losh free(sb); 734*ca987d46SWarner Losh } 735*ca987d46SWarner Losh 736*ca987d46SWarner Losh void 737*ca987d46SWarner Losh fdt_fixup_stdout(const char *str) 738*ca987d46SWarner Losh { 739*ca987d46SWarner Losh char *ptr; 740*ca987d46SWarner Losh int serialno; 741*ca987d46SWarner Losh int len, no, sero; 742*ca987d46SWarner Losh const struct fdt_property *prop; 743*ca987d46SWarner Losh char *tmp[10]; 744*ca987d46SWarner Losh 745*ca987d46SWarner Losh ptr = (char *)str + strlen(str) - 1; 746*ca987d46SWarner Losh while (ptr > str && isdigit(*(str - 1))) 747*ca987d46SWarner Losh str--; 748*ca987d46SWarner Losh 749*ca987d46SWarner Losh if (ptr == str) 750*ca987d46SWarner Losh return; 751*ca987d46SWarner Losh 752*ca987d46SWarner Losh serialno = (int)strtol(ptr, NULL, 0); 753*ca987d46SWarner Losh no = fdt_path_offset(fdtp, "/chosen"); 754*ca987d46SWarner Losh if (no < 0) 755*ca987d46SWarner Losh return; 756*ca987d46SWarner Losh 757*ca987d46SWarner Losh prop = fdt_get_property(fdtp, no, "stdout", &len); 758*ca987d46SWarner Losh 759*ca987d46SWarner Losh /* If /chosen/stdout does not extist, create it */ 760*ca987d46SWarner Losh if (prop == NULL || (prop != NULL && len == 0)) { 761*ca987d46SWarner Losh 762*ca987d46SWarner Losh bzero(tmp, 10 * sizeof(char)); 763*ca987d46SWarner Losh strcpy((char *)&tmp, "serial"); 764*ca987d46SWarner Losh if (strlen(ptr) > 3) 765*ca987d46SWarner Losh /* Serial number too long */ 766*ca987d46SWarner Losh return; 767*ca987d46SWarner Losh 768*ca987d46SWarner Losh strncpy((char *)tmp + 6, ptr, 3); 769*ca987d46SWarner Losh sero = fdt_path_offset(fdtp, (const char *)tmp); 770*ca987d46SWarner Losh if (sero < 0) 771*ca987d46SWarner Losh /* 772*ca987d46SWarner Losh * If serial device we're trying to assign 773*ca987d46SWarner Losh * stdout to doesn't exist in DT -- return. 774*ca987d46SWarner Losh */ 775*ca987d46SWarner Losh return; 776*ca987d46SWarner Losh 777*ca987d46SWarner Losh fdt_setprop(fdtp, no, "stdout", &tmp, 778*ca987d46SWarner Losh strlen((char *)&tmp) + 1); 779*ca987d46SWarner Losh fdt_setprop(fdtp, no, "stdin", &tmp, 780*ca987d46SWarner Losh strlen((char *)&tmp) + 1); 781*ca987d46SWarner Losh } 782*ca987d46SWarner Losh } 783*ca987d46SWarner Losh 784*ca987d46SWarner Losh /* 785*ca987d46SWarner Losh * Locate the blob, fix it up and return its location. 786*ca987d46SWarner Losh */ 787*ca987d46SWarner Losh static int 788*ca987d46SWarner Losh fdt_fixup(void) 789*ca987d46SWarner Losh { 790*ca987d46SWarner Losh int chosen, len; 791*ca987d46SWarner Losh 792*ca987d46SWarner Losh len = 0; 793*ca987d46SWarner Losh 794*ca987d46SWarner Losh debugf("fdt_fixup()\n"); 795*ca987d46SWarner Losh 796*ca987d46SWarner Losh if (fdtp == NULL && fdt_setup_fdtp() != 0) 797*ca987d46SWarner Losh return (0); 798*ca987d46SWarner Losh 799*ca987d46SWarner Losh /* Create /chosen node (if not exists) */ 800*ca987d46SWarner Losh if ((chosen = fdt_subnode_offset(fdtp, 0, "chosen")) == 801*ca987d46SWarner Losh -FDT_ERR_NOTFOUND) 802*ca987d46SWarner Losh chosen = fdt_add_subnode(fdtp, 0, "chosen"); 803*ca987d46SWarner Losh 804*ca987d46SWarner Losh /* Value assigned to fixup-applied does not matter. */ 805*ca987d46SWarner Losh if (fdt_getprop(fdtp, chosen, "fixup-applied", NULL)) 806*ca987d46SWarner Losh return (1); 807*ca987d46SWarner Losh 808*ca987d46SWarner Losh fdt_platform_fixups(); 809*ca987d46SWarner Losh 810*ca987d46SWarner Losh fdt_setprop(fdtp, chosen, "fixup-applied", NULL, 0); 811*ca987d46SWarner Losh return (1); 812*ca987d46SWarner Losh } 813*ca987d46SWarner Losh 814*ca987d46SWarner Losh /* 815*ca987d46SWarner Losh * Copy DTB blob to specified location and return size 816*ca987d46SWarner Losh */ 817*ca987d46SWarner Losh int 818*ca987d46SWarner Losh fdt_copy(vm_offset_t va) 819*ca987d46SWarner Losh { 820*ca987d46SWarner Losh int err; 821*ca987d46SWarner Losh debugf("fdt_copy va 0x%08x\n", va); 822*ca987d46SWarner Losh if (fdtp == NULL) { 823*ca987d46SWarner Losh err = fdt_setup_fdtp(); 824*ca987d46SWarner Losh if (err) { 825*ca987d46SWarner Losh printf("No valid device tree blob found!\n"); 826*ca987d46SWarner Losh return (0); 827*ca987d46SWarner Losh } 828*ca987d46SWarner Losh } 829*ca987d46SWarner Losh 830*ca987d46SWarner Losh if (fdt_fixup() == 0) 831*ca987d46SWarner Losh return (0); 832*ca987d46SWarner Losh 833*ca987d46SWarner Losh if (fdtp_va != 0) { 834*ca987d46SWarner Losh /* Overwrite the FDT with the fixed version. */ 835*ca987d46SWarner Losh /* XXX Is this really appropriate? */ 836*ca987d46SWarner Losh COPYIN(fdtp, fdtp_va, fdtp_size); 837*ca987d46SWarner Losh } 838*ca987d46SWarner Losh COPYIN(fdtp, va, fdtp_size); 839*ca987d46SWarner Losh return (fdtp_size); 840*ca987d46SWarner Losh } 841*ca987d46SWarner Losh 842*ca987d46SWarner Losh 843*ca987d46SWarner Losh 844*ca987d46SWarner Losh int 845*ca987d46SWarner Losh command_fdt_internal(int argc, char *argv[]) 846*ca987d46SWarner Losh { 847*ca987d46SWarner Losh cmdf_t *cmdh; 848*ca987d46SWarner Losh int flags; 849*ca987d46SWarner Losh char *cmd; 850*ca987d46SWarner Losh int i, err; 851*ca987d46SWarner Losh 852*ca987d46SWarner Losh if (argc < 2) { 853*ca987d46SWarner Losh command_errmsg = "usage is 'fdt <command> [<args>]"; 854*ca987d46SWarner Losh return (CMD_ERROR); 855*ca987d46SWarner Losh } 856*ca987d46SWarner Losh 857*ca987d46SWarner Losh /* 858*ca987d46SWarner Losh * Validate fdt <command>. 859*ca987d46SWarner Losh */ 860*ca987d46SWarner Losh cmd = strdup(argv[1]); 861*ca987d46SWarner Losh i = 0; 862*ca987d46SWarner Losh cmdh = NULL; 863*ca987d46SWarner Losh while (!(commands[i].name == NULL)) { 864*ca987d46SWarner Losh if (strcmp(cmd, commands[i].name) == 0) { 865*ca987d46SWarner Losh /* found it */ 866*ca987d46SWarner Losh cmdh = commands[i].handler; 867*ca987d46SWarner Losh flags = commands[i].flags; 868*ca987d46SWarner Losh break; 869*ca987d46SWarner Losh } 870*ca987d46SWarner Losh i++; 871*ca987d46SWarner Losh } 872*ca987d46SWarner Losh if (cmdh == NULL) { 873*ca987d46SWarner Losh command_errmsg = "unknown command"; 874*ca987d46SWarner Losh return (CMD_ERROR); 875*ca987d46SWarner Losh } 876*ca987d46SWarner Losh 877*ca987d46SWarner Losh if (flags & CMD_REQUIRES_BLOB) { 878*ca987d46SWarner Losh /* 879*ca987d46SWarner Losh * Check if uboot env vars were parsed already. If not, do it now. 880*ca987d46SWarner Losh */ 881*ca987d46SWarner Losh if (fdt_fixup() == 0) 882*ca987d46SWarner Losh return (CMD_ERROR); 883*ca987d46SWarner Losh } 884*ca987d46SWarner Losh 885*ca987d46SWarner Losh /* 886*ca987d46SWarner Losh * Call command handler. 887*ca987d46SWarner Losh */ 888*ca987d46SWarner Losh err = (*cmdh)(argc, argv); 889*ca987d46SWarner Losh 890*ca987d46SWarner Losh return (err); 891*ca987d46SWarner Losh } 892*ca987d46SWarner Losh 893*ca987d46SWarner Losh static int 894*ca987d46SWarner Losh fdt_cmd_addr(int argc, char *argv[]) 895*ca987d46SWarner Losh { 896*ca987d46SWarner Losh struct preloaded_file *fp; 897*ca987d46SWarner Losh struct fdt_header *hdr; 898*ca987d46SWarner Losh const char *addr; 899*ca987d46SWarner Losh char *cp; 900*ca987d46SWarner Losh 901*ca987d46SWarner Losh fdt_to_load = NULL; 902*ca987d46SWarner Losh 903*ca987d46SWarner Losh if (argc > 2) 904*ca987d46SWarner Losh addr = argv[2]; 905*ca987d46SWarner Losh else { 906*ca987d46SWarner Losh sprintf(command_errbuf, "no address specified"); 907*ca987d46SWarner Losh return (CMD_ERROR); 908*ca987d46SWarner Losh } 909*ca987d46SWarner Losh 910*ca987d46SWarner Losh hdr = (struct fdt_header *)strtoul(addr, &cp, 16); 911*ca987d46SWarner Losh if (cp == addr) { 912*ca987d46SWarner Losh snprintf(command_errbuf, sizeof(command_errbuf), 913*ca987d46SWarner Losh "Invalid address: %s", addr); 914*ca987d46SWarner Losh return (CMD_ERROR); 915*ca987d46SWarner Losh } 916*ca987d46SWarner Losh 917*ca987d46SWarner Losh while ((fp = file_findfile(NULL, "dtb")) != NULL) { 918*ca987d46SWarner Losh file_discard(fp); 919*ca987d46SWarner Losh } 920*ca987d46SWarner Losh 921*ca987d46SWarner Losh fdt_to_load = hdr; 922*ca987d46SWarner Losh return (CMD_OK); 923*ca987d46SWarner Losh } 924*ca987d46SWarner Losh 925*ca987d46SWarner Losh static int 926*ca987d46SWarner Losh fdt_cmd_cd(int argc, char *argv[]) 927*ca987d46SWarner Losh { 928*ca987d46SWarner Losh char *path; 929*ca987d46SWarner Losh char tmp[FDT_CWD_LEN]; 930*ca987d46SWarner Losh int len, o; 931*ca987d46SWarner Losh 932*ca987d46SWarner Losh path = (argc > 2) ? argv[2] : "/"; 933*ca987d46SWarner Losh 934*ca987d46SWarner Losh if (path[0] == '/') { 935*ca987d46SWarner Losh len = strlen(path); 936*ca987d46SWarner Losh if (len >= FDT_CWD_LEN) 937*ca987d46SWarner Losh goto fail; 938*ca987d46SWarner Losh } else { 939*ca987d46SWarner Losh /* Handle path specification relative to cwd */ 940*ca987d46SWarner Losh len = strlen(cwd) + strlen(path) + 1; 941*ca987d46SWarner Losh if (len >= FDT_CWD_LEN) 942*ca987d46SWarner Losh goto fail; 943*ca987d46SWarner Losh 944*ca987d46SWarner Losh strcpy(tmp, cwd); 945*ca987d46SWarner Losh strcat(tmp, "/"); 946*ca987d46SWarner Losh strcat(tmp, path); 947*ca987d46SWarner Losh path = tmp; 948*ca987d46SWarner Losh } 949*ca987d46SWarner Losh 950*ca987d46SWarner Losh o = fdt_path_offset(fdtp, path); 951*ca987d46SWarner Losh if (o < 0) { 952*ca987d46SWarner Losh snprintf(command_errbuf, sizeof(command_errbuf), 953*ca987d46SWarner Losh "could not find node: '%s'", path); 954*ca987d46SWarner Losh return (CMD_ERROR); 955*ca987d46SWarner Losh } 956*ca987d46SWarner Losh 957*ca987d46SWarner Losh strcpy(cwd, path); 958*ca987d46SWarner Losh return (CMD_OK); 959*ca987d46SWarner Losh 960*ca987d46SWarner Losh fail: 961*ca987d46SWarner Losh snprintf(command_errbuf, sizeof(command_errbuf), 962*ca987d46SWarner Losh "path too long: %d, max allowed: %d", len, FDT_CWD_LEN - 1); 963*ca987d46SWarner Losh return (CMD_ERROR); 964*ca987d46SWarner Losh } 965*ca987d46SWarner Losh 966*ca987d46SWarner Losh static int 967*ca987d46SWarner Losh fdt_cmd_hdr(int argc __unused, char *argv[] __unused) 968*ca987d46SWarner Losh { 969*ca987d46SWarner Losh char line[80]; 970*ca987d46SWarner Losh int ver; 971*ca987d46SWarner Losh 972*ca987d46SWarner Losh if (fdtp == NULL) { 973*ca987d46SWarner Losh command_errmsg = "no device tree blob pointer?!"; 974*ca987d46SWarner Losh return (CMD_ERROR); 975*ca987d46SWarner Losh } 976*ca987d46SWarner Losh 977*ca987d46SWarner Losh ver = fdt_version(fdtp); 978*ca987d46SWarner Losh pager_open(); 979*ca987d46SWarner Losh sprintf(line, "\nFlattened device tree header (%p):\n", fdtp); 980*ca987d46SWarner Losh if (pager_output(line)) 981*ca987d46SWarner Losh goto out; 982*ca987d46SWarner Losh sprintf(line, " magic = 0x%08x\n", fdt_magic(fdtp)); 983*ca987d46SWarner Losh if (pager_output(line)) 984*ca987d46SWarner Losh goto out; 985*ca987d46SWarner Losh sprintf(line, " size = %d\n", fdt_totalsize(fdtp)); 986*ca987d46SWarner Losh if (pager_output(line)) 987*ca987d46SWarner Losh goto out; 988*ca987d46SWarner Losh sprintf(line, " off_dt_struct = 0x%08x\n", 989*ca987d46SWarner Losh fdt_off_dt_struct(fdtp)); 990*ca987d46SWarner Losh if (pager_output(line)) 991*ca987d46SWarner Losh goto out; 992*ca987d46SWarner Losh sprintf(line, " off_dt_strings = 0x%08x\n", 993*ca987d46SWarner Losh fdt_off_dt_strings(fdtp)); 994*ca987d46SWarner Losh if (pager_output(line)) 995*ca987d46SWarner Losh goto out; 996*ca987d46SWarner Losh sprintf(line, " off_mem_rsvmap = 0x%08x\n", 997*ca987d46SWarner Losh fdt_off_mem_rsvmap(fdtp)); 998*ca987d46SWarner Losh if (pager_output(line)) 999*ca987d46SWarner Losh goto out; 1000*ca987d46SWarner Losh sprintf(line, " version = %d\n", ver); 1001*ca987d46SWarner Losh if (pager_output(line)) 1002*ca987d46SWarner Losh goto out; 1003*ca987d46SWarner Losh sprintf(line, " last compatible version = %d\n", 1004*ca987d46SWarner Losh fdt_last_comp_version(fdtp)); 1005*ca987d46SWarner Losh if (pager_output(line)) 1006*ca987d46SWarner Losh goto out; 1007*ca987d46SWarner Losh if (ver >= 2) { 1008*ca987d46SWarner Losh sprintf(line, " boot_cpuid = %d\n", 1009*ca987d46SWarner Losh fdt_boot_cpuid_phys(fdtp)); 1010*ca987d46SWarner Losh if (pager_output(line)) 1011*ca987d46SWarner Losh goto out; 1012*ca987d46SWarner Losh } 1013*ca987d46SWarner Losh if (ver >= 3) { 1014*ca987d46SWarner Losh sprintf(line, " size_dt_strings = %d\n", 1015*ca987d46SWarner Losh fdt_size_dt_strings(fdtp)); 1016*ca987d46SWarner Losh if (pager_output(line)) 1017*ca987d46SWarner Losh goto out; 1018*ca987d46SWarner Losh } 1019*ca987d46SWarner Losh if (ver >= 17) { 1020*ca987d46SWarner Losh sprintf(line, " size_dt_struct = %d\n", 1021*ca987d46SWarner Losh fdt_size_dt_struct(fdtp)); 1022*ca987d46SWarner Losh if (pager_output(line)) 1023*ca987d46SWarner Losh goto out; 1024*ca987d46SWarner Losh } 1025*ca987d46SWarner Losh out: 1026*ca987d46SWarner Losh pager_close(); 1027*ca987d46SWarner Losh 1028*ca987d46SWarner Losh return (CMD_OK); 1029*ca987d46SWarner Losh } 1030*ca987d46SWarner Losh 1031*ca987d46SWarner Losh static int 1032*ca987d46SWarner Losh fdt_cmd_ls(int argc, char *argv[]) 1033*ca987d46SWarner Losh { 1034*ca987d46SWarner Losh const char *prevname[FDT_MAX_DEPTH] = { NULL }; 1035*ca987d46SWarner Losh const char *name; 1036*ca987d46SWarner Losh char *path; 1037*ca987d46SWarner Losh int i, o, depth; 1038*ca987d46SWarner Losh 1039*ca987d46SWarner Losh path = (argc > 2) ? argv[2] : NULL; 1040*ca987d46SWarner Losh if (path == NULL) 1041*ca987d46SWarner Losh path = cwd; 1042*ca987d46SWarner Losh 1043*ca987d46SWarner Losh o = fdt_path_offset(fdtp, path); 1044*ca987d46SWarner Losh if (o < 0) { 1045*ca987d46SWarner Losh snprintf(command_errbuf, sizeof(command_errbuf), 1046*ca987d46SWarner Losh "could not find node: '%s'", path); 1047*ca987d46SWarner Losh return (CMD_ERROR); 1048*ca987d46SWarner Losh } 1049*ca987d46SWarner Losh 1050*ca987d46SWarner Losh for (depth = 0; 1051*ca987d46SWarner Losh (o >= 0) && (depth >= 0); 1052*ca987d46SWarner Losh o = fdt_next_node(fdtp, o, &depth)) { 1053*ca987d46SWarner Losh 1054*ca987d46SWarner Losh name = fdt_get_name(fdtp, o, NULL); 1055*ca987d46SWarner Losh 1056*ca987d46SWarner Losh if (depth > FDT_MAX_DEPTH) { 1057*ca987d46SWarner Losh printf("max depth exceeded: %d\n", depth); 1058*ca987d46SWarner Losh continue; 1059*ca987d46SWarner Losh } 1060*ca987d46SWarner Losh 1061*ca987d46SWarner Losh prevname[depth] = name; 1062*ca987d46SWarner Losh 1063*ca987d46SWarner Losh /* Skip root (i = 1) when printing devices */ 1064*ca987d46SWarner Losh for (i = 1; i <= depth; i++) { 1065*ca987d46SWarner Losh if (prevname[i] == NULL) 1066*ca987d46SWarner Losh break; 1067*ca987d46SWarner Losh 1068*ca987d46SWarner Losh if (strcmp(cwd, "/") == 0) 1069*ca987d46SWarner Losh printf("/"); 1070*ca987d46SWarner Losh printf("%s", prevname[i]); 1071*ca987d46SWarner Losh } 1072*ca987d46SWarner Losh printf("\n"); 1073*ca987d46SWarner Losh } 1074*ca987d46SWarner Losh 1075*ca987d46SWarner Losh return (CMD_OK); 1076*ca987d46SWarner Losh } 1077*ca987d46SWarner Losh 1078*ca987d46SWarner Losh static __inline int 1079*ca987d46SWarner Losh isprint(int c) 1080*ca987d46SWarner Losh { 1081*ca987d46SWarner Losh 1082*ca987d46SWarner Losh return (c >= ' ' && c <= 0x7e); 1083*ca987d46SWarner Losh } 1084*ca987d46SWarner Losh 1085*ca987d46SWarner Losh static int 1086*ca987d46SWarner Losh fdt_isprint(const void *data, int len, int *count) 1087*ca987d46SWarner Losh { 1088*ca987d46SWarner Losh const char *d; 1089*ca987d46SWarner Losh char ch; 1090*ca987d46SWarner Losh int yesno, i; 1091*ca987d46SWarner Losh 1092*ca987d46SWarner Losh if (len == 0) 1093*ca987d46SWarner Losh return (0); 1094*ca987d46SWarner Losh 1095*ca987d46SWarner Losh d = (const char *)data; 1096*ca987d46SWarner Losh if (d[len - 1] != '\0') 1097*ca987d46SWarner Losh return (0); 1098*ca987d46SWarner Losh 1099*ca987d46SWarner Losh *count = 0; 1100*ca987d46SWarner Losh yesno = 1; 1101*ca987d46SWarner Losh for (i = 0; i < len; i++) { 1102*ca987d46SWarner Losh ch = *(d + i); 1103*ca987d46SWarner Losh if (isprint(ch) || (ch == '\0' && i > 0)) { 1104*ca987d46SWarner Losh /* Count strings */ 1105*ca987d46SWarner Losh if (ch == '\0') 1106*ca987d46SWarner Losh (*count)++; 1107*ca987d46SWarner Losh continue; 1108*ca987d46SWarner Losh } 1109*ca987d46SWarner Losh 1110*ca987d46SWarner Losh yesno = 0; 1111*ca987d46SWarner Losh break; 1112*ca987d46SWarner Losh } 1113*ca987d46SWarner Losh 1114*ca987d46SWarner Losh return (yesno); 1115*ca987d46SWarner Losh } 1116*ca987d46SWarner Losh 1117*ca987d46SWarner Losh static int 1118*ca987d46SWarner Losh fdt_data_str(const void *data, int len, int count, char **buf) 1119*ca987d46SWarner Losh { 1120*ca987d46SWarner Losh char *b, *tmp; 1121*ca987d46SWarner Losh const char *d; 1122*ca987d46SWarner Losh int buf_len, i, l; 1123*ca987d46SWarner Losh 1124*ca987d46SWarner Losh /* 1125*ca987d46SWarner Losh * Calculate the length for the string and allocate memory. 1126*ca987d46SWarner Losh * 1127*ca987d46SWarner Losh * Note that 'len' already includes at least one terminator. 1128*ca987d46SWarner Losh */ 1129*ca987d46SWarner Losh buf_len = len; 1130*ca987d46SWarner Losh if (count > 1) { 1131*ca987d46SWarner Losh /* 1132*ca987d46SWarner Losh * Each token had already a terminator buried in 'len', but we 1133*ca987d46SWarner Losh * only need one eventually, don't count space for these. 1134*ca987d46SWarner Losh */ 1135*ca987d46SWarner Losh buf_len -= count - 1; 1136*ca987d46SWarner Losh 1137*ca987d46SWarner Losh /* Each consecutive token requires a ", " separator. */ 1138*ca987d46SWarner Losh buf_len += count * 2; 1139*ca987d46SWarner Losh } 1140*ca987d46SWarner Losh 1141*ca987d46SWarner Losh /* Add some space for surrounding double quotes. */ 1142*ca987d46SWarner Losh buf_len += count * 2; 1143*ca987d46SWarner Losh 1144*ca987d46SWarner Losh /* Note that string being put in 'tmp' may be as big as 'buf_len'. */ 1145*ca987d46SWarner Losh b = (char *)malloc(buf_len); 1146*ca987d46SWarner Losh tmp = (char *)malloc(buf_len); 1147*ca987d46SWarner Losh if (b == NULL) 1148*ca987d46SWarner Losh goto error; 1149*ca987d46SWarner Losh 1150*ca987d46SWarner Losh if (tmp == NULL) { 1151*ca987d46SWarner Losh free(b); 1152*ca987d46SWarner Losh goto error; 1153*ca987d46SWarner Losh } 1154*ca987d46SWarner Losh 1155*ca987d46SWarner Losh b[0] = '\0'; 1156*ca987d46SWarner Losh 1157*ca987d46SWarner Losh /* 1158*ca987d46SWarner Losh * Now that we have space, format the string. 1159*ca987d46SWarner Losh */ 1160*ca987d46SWarner Losh i = 0; 1161*ca987d46SWarner Losh do { 1162*ca987d46SWarner Losh d = (const char *)data + i; 1163*ca987d46SWarner Losh l = strlen(d) + 1; 1164*ca987d46SWarner Losh 1165*ca987d46SWarner Losh sprintf(tmp, "\"%s\"%s", d, 1166*ca987d46SWarner Losh (i + l) < len ? ", " : ""); 1167*ca987d46SWarner Losh strcat(b, tmp); 1168*ca987d46SWarner Losh 1169*ca987d46SWarner Losh i += l; 1170*ca987d46SWarner Losh 1171*ca987d46SWarner Losh } while (i < len); 1172*ca987d46SWarner Losh *buf = b; 1173*ca987d46SWarner Losh 1174*ca987d46SWarner Losh free(tmp); 1175*ca987d46SWarner Losh 1176*ca987d46SWarner Losh return (0); 1177*ca987d46SWarner Losh error: 1178*ca987d46SWarner Losh return (1); 1179*ca987d46SWarner Losh } 1180*ca987d46SWarner Losh 1181*ca987d46SWarner Losh static int 1182*ca987d46SWarner Losh fdt_data_cell(const void *data, int len, char **buf) 1183*ca987d46SWarner Losh { 1184*ca987d46SWarner Losh char *b, *tmp; 1185*ca987d46SWarner Losh const uint32_t *c; 1186*ca987d46SWarner Losh int count, i, l; 1187*ca987d46SWarner Losh 1188*ca987d46SWarner Losh /* Number of cells */ 1189*ca987d46SWarner Losh count = len / 4; 1190*ca987d46SWarner Losh 1191*ca987d46SWarner Losh /* 1192*ca987d46SWarner Losh * Calculate the length for the string and allocate memory. 1193*ca987d46SWarner Losh */ 1194*ca987d46SWarner Losh 1195*ca987d46SWarner Losh /* Each byte translates to 2 output characters */ 1196*ca987d46SWarner Losh l = len * 2; 1197*ca987d46SWarner Losh if (count > 1) { 1198*ca987d46SWarner Losh /* Each consecutive cell requires a " " separator. */ 1199*ca987d46SWarner Losh l += (count - 1) * 1; 1200*ca987d46SWarner Losh } 1201*ca987d46SWarner Losh /* Each cell will have a "0x" prefix */ 1202*ca987d46SWarner Losh l += count * 2; 1203*ca987d46SWarner Losh /* Space for surrounding <> and terminator */ 1204*ca987d46SWarner Losh l += 3; 1205*ca987d46SWarner Losh 1206*ca987d46SWarner Losh b = (char *)malloc(l); 1207*ca987d46SWarner Losh tmp = (char *)malloc(l); 1208*ca987d46SWarner Losh if (b == NULL) 1209*ca987d46SWarner Losh goto error; 1210*ca987d46SWarner Losh 1211*ca987d46SWarner Losh if (tmp == NULL) { 1212*ca987d46SWarner Losh free(b); 1213*ca987d46SWarner Losh goto error; 1214*ca987d46SWarner Losh } 1215*ca987d46SWarner Losh 1216*ca987d46SWarner Losh b[0] = '\0'; 1217*ca987d46SWarner Losh strcat(b, "<"); 1218*ca987d46SWarner Losh 1219*ca987d46SWarner Losh for (i = 0; i < len; i += 4) { 1220*ca987d46SWarner Losh c = (const uint32_t *)((const uint8_t *)data + i); 1221*ca987d46SWarner Losh sprintf(tmp, "0x%08x%s", fdt32_to_cpu(*c), 1222*ca987d46SWarner Losh i < (len - 4) ? " " : ""); 1223*ca987d46SWarner Losh strcat(b, tmp); 1224*ca987d46SWarner Losh } 1225*ca987d46SWarner Losh strcat(b, ">"); 1226*ca987d46SWarner Losh *buf = b; 1227*ca987d46SWarner Losh 1228*ca987d46SWarner Losh free(tmp); 1229*ca987d46SWarner Losh 1230*ca987d46SWarner Losh return (0); 1231*ca987d46SWarner Losh error: 1232*ca987d46SWarner Losh return (1); 1233*ca987d46SWarner Losh } 1234*ca987d46SWarner Losh 1235*ca987d46SWarner Losh static int 1236*ca987d46SWarner Losh fdt_data_bytes(const void *data, int len, char **buf) 1237*ca987d46SWarner Losh { 1238*ca987d46SWarner Losh char *b, *tmp; 1239*ca987d46SWarner Losh const char *d; 1240*ca987d46SWarner Losh int i, l; 1241*ca987d46SWarner Losh 1242*ca987d46SWarner Losh /* 1243*ca987d46SWarner Losh * Calculate the length for the string and allocate memory. 1244*ca987d46SWarner Losh */ 1245*ca987d46SWarner Losh 1246*ca987d46SWarner Losh /* Each byte translates to 2 output characters */ 1247*ca987d46SWarner Losh l = len * 2; 1248*ca987d46SWarner Losh if (len > 1) 1249*ca987d46SWarner Losh /* Each consecutive byte requires a " " separator. */ 1250*ca987d46SWarner Losh l += (len - 1) * 1; 1251*ca987d46SWarner Losh /* Each byte will have a "0x" prefix */ 1252*ca987d46SWarner Losh l += len * 2; 1253*ca987d46SWarner Losh /* Space for surrounding [] and terminator. */ 1254*ca987d46SWarner Losh l += 3; 1255*ca987d46SWarner Losh 1256*ca987d46SWarner Losh b = (char *)malloc(l); 1257*ca987d46SWarner Losh tmp = (char *)malloc(l); 1258*ca987d46SWarner Losh if (b == NULL) 1259*ca987d46SWarner Losh goto error; 1260*ca987d46SWarner Losh 1261*ca987d46SWarner Losh if (tmp == NULL) { 1262*ca987d46SWarner Losh free(b); 1263*ca987d46SWarner Losh goto error; 1264*ca987d46SWarner Losh } 1265*ca987d46SWarner Losh 1266*ca987d46SWarner Losh b[0] = '\0'; 1267*ca987d46SWarner Losh strcat(b, "["); 1268*ca987d46SWarner Losh 1269*ca987d46SWarner Losh for (i = 0, d = data; i < len; i++) { 1270*ca987d46SWarner Losh sprintf(tmp, "0x%02x%s", d[i], i < len - 1 ? " " : ""); 1271*ca987d46SWarner Losh strcat(b, tmp); 1272*ca987d46SWarner Losh } 1273*ca987d46SWarner Losh strcat(b, "]"); 1274*ca987d46SWarner Losh *buf = b; 1275*ca987d46SWarner Losh 1276*ca987d46SWarner Losh free(tmp); 1277*ca987d46SWarner Losh 1278*ca987d46SWarner Losh return (0); 1279*ca987d46SWarner Losh error: 1280*ca987d46SWarner Losh return (1); 1281*ca987d46SWarner Losh } 1282*ca987d46SWarner Losh 1283*ca987d46SWarner Losh static int 1284*ca987d46SWarner Losh fdt_data_fmt(const void *data, int len, char **buf) 1285*ca987d46SWarner Losh { 1286*ca987d46SWarner Losh int count; 1287*ca987d46SWarner Losh 1288*ca987d46SWarner Losh if (len == 0) { 1289*ca987d46SWarner Losh *buf = NULL; 1290*ca987d46SWarner Losh return (1); 1291*ca987d46SWarner Losh } 1292*ca987d46SWarner Losh 1293*ca987d46SWarner Losh if (fdt_isprint(data, len, &count)) 1294*ca987d46SWarner Losh return (fdt_data_str(data, len, count, buf)); 1295*ca987d46SWarner Losh 1296*ca987d46SWarner Losh else if ((len % 4) == 0) 1297*ca987d46SWarner Losh return (fdt_data_cell(data, len, buf)); 1298*ca987d46SWarner Losh 1299*ca987d46SWarner Losh else 1300*ca987d46SWarner Losh return (fdt_data_bytes(data, len, buf)); 1301*ca987d46SWarner Losh } 1302*ca987d46SWarner Losh 1303*ca987d46SWarner Losh static int 1304*ca987d46SWarner Losh fdt_prop(int offset) 1305*ca987d46SWarner Losh { 1306*ca987d46SWarner Losh char *line, *buf; 1307*ca987d46SWarner Losh const struct fdt_property *prop; 1308*ca987d46SWarner Losh const char *name; 1309*ca987d46SWarner Losh const void *data; 1310*ca987d46SWarner Losh int len, rv; 1311*ca987d46SWarner Losh 1312*ca987d46SWarner Losh line = NULL; 1313*ca987d46SWarner Losh prop = fdt_offset_ptr(fdtp, offset, sizeof(*prop)); 1314*ca987d46SWarner Losh if (prop == NULL) 1315*ca987d46SWarner Losh return (1); 1316*ca987d46SWarner Losh 1317*ca987d46SWarner Losh name = fdt_string(fdtp, fdt32_to_cpu(prop->nameoff)); 1318*ca987d46SWarner Losh len = fdt32_to_cpu(prop->len); 1319*ca987d46SWarner Losh 1320*ca987d46SWarner Losh rv = 0; 1321*ca987d46SWarner Losh buf = NULL; 1322*ca987d46SWarner Losh if (len == 0) { 1323*ca987d46SWarner Losh /* Property without value */ 1324*ca987d46SWarner Losh line = (char *)malloc(strlen(name) + 2); 1325*ca987d46SWarner Losh if (line == NULL) { 1326*ca987d46SWarner Losh rv = 2; 1327*ca987d46SWarner Losh goto out2; 1328*ca987d46SWarner Losh } 1329*ca987d46SWarner Losh sprintf(line, "%s\n", name); 1330*ca987d46SWarner Losh goto out1; 1331*ca987d46SWarner Losh } 1332*ca987d46SWarner Losh 1333*ca987d46SWarner Losh /* 1334*ca987d46SWarner Losh * Process property with value 1335*ca987d46SWarner Losh */ 1336*ca987d46SWarner Losh data = prop->data; 1337*ca987d46SWarner Losh 1338*ca987d46SWarner Losh if (fdt_data_fmt(data, len, &buf) != 0) { 1339*ca987d46SWarner Losh rv = 3; 1340*ca987d46SWarner Losh goto out2; 1341*ca987d46SWarner Losh } 1342*ca987d46SWarner Losh 1343*ca987d46SWarner Losh line = (char *)malloc(strlen(name) + strlen(FDT_PROP_SEP) + 1344*ca987d46SWarner Losh strlen(buf) + 2); 1345*ca987d46SWarner Losh if (line == NULL) { 1346*ca987d46SWarner Losh sprintf(command_errbuf, "could not allocate space for string"); 1347*ca987d46SWarner Losh rv = 4; 1348*ca987d46SWarner Losh goto out2; 1349*ca987d46SWarner Losh } 1350*ca987d46SWarner Losh 1351*ca987d46SWarner Losh sprintf(line, "%s" FDT_PROP_SEP "%s\n", name, buf); 1352*ca987d46SWarner Losh 1353*ca987d46SWarner Losh out1: 1354*ca987d46SWarner Losh pager_open(); 1355*ca987d46SWarner Losh pager_output(line); 1356*ca987d46SWarner Losh pager_close(); 1357*ca987d46SWarner Losh 1358*ca987d46SWarner Losh out2: 1359*ca987d46SWarner Losh if (buf) 1360*ca987d46SWarner Losh free(buf); 1361*ca987d46SWarner Losh 1362*ca987d46SWarner Losh if (line) 1363*ca987d46SWarner Losh free(line); 1364*ca987d46SWarner Losh 1365*ca987d46SWarner Losh return (rv); 1366*ca987d46SWarner Losh } 1367*ca987d46SWarner Losh 1368*ca987d46SWarner Losh static int 1369*ca987d46SWarner Losh fdt_modprop(int nodeoff, char *propname, void *value, char mode) 1370*ca987d46SWarner Losh { 1371*ca987d46SWarner Losh uint32_t cells[100]; 1372*ca987d46SWarner Losh const char *buf; 1373*ca987d46SWarner Losh int len, rv; 1374*ca987d46SWarner Losh const struct fdt_property *p; 1375*ca987d46SWarner Losh 1376*ca987d46SWarner Losh p = fdt_get_property(fdtp, nodeoff, propname, NULL); 1377*ca987d46SWarner Losh 1378*ca987d46SWarner Losh if (p != NULL) { 1379*ca987d46SWarner Losh if (mode == 1) { 1380*ca987d46SWarner Losh /* Adding inexistant value in mode 1 is forbidden */ 1381*ca987d46SWarner Losh sprintf(command_errbuf, "property already exists!"); 1382*ca987d46SWarner Losh return (CMD_ERROR); 1383*ca987d46SWarner Losh } 1384*ca987d46SWarner Losh } else if (mode == 0) { 1385*ca987d46SWarner Losh sprintf(command_errbuf, "property does not exist!"); 1386*ca987d46SWarner Losh return (CMD_ERROR); 1387*ca987d46SWarner Losh } 1388*ca987d46SWarner Losh len = strlen(value); 1389*ca987d46SWarner Losh rv = 0; 1390*ca987d46SWarner Losh buf = value; 1391*ca987d46SWarner Losh 1392*ca987d46SWarner Losh switch (*buf) { 1393*ca987d46SWarner Losh case '&': 1394*ca987d46SWarner Losh /* phandles */ 1395*ca987d46SWarner Losh break; 1396*ca987d46SWarner Losh case '<': 1397*ca987d46SWarner Losh /* Data cells */ 1398*ca987d46SWarner Losh len = fdt_strtovect(buf, (void *)&cells, 100, 1399*ca987d46SWarner Losh sizeof(uint32_t)); 1400*ca987d46SWarner Losh 1401*ca987d46SWarner Losh rv = fdt_setprop(fdtp, nodeoff, propname, &cells, 1402*ca987d46SWarner Losh len * sizeof(uint32_t)); 1403*ca987d46SWarner Losh break; 1404*ca987d46SWarner Losh case '[': 1405*ca987d46SWarner Losh /* Data bytes */ 1406*ca987d46SWarner Losh len = fdt_strtovect(buf, (void *)&cells, 100, 1407*ca987d46SWarner Losh sizeof(uint8_t)); 1408*ca987d46SWarner Losh 1409*ca987d46SWarner Losh rv = fdt_setprop(fdtp, nodeoff, propname, &cells, 1410*ca987d46SWarner Losh len * sizeof(uint8_t)); 1411*ca987d46SWarner Losh break; 1412*ca987d46SWarner Losh case '"': 1413*ca987d46SWarner Losh default: 1414*ca987d46SWarner Losh /* Default -- string */ 1415*ca987d46SWarner Losh rv = fdt_setprop_string(fdtp, nodeoff, propname, value); 1416*ca987d46SWarner Losh break; 1417*ca987d46SWarner Losh } 1418*ca987d46SWarner Losh 1419*ca987d46SWarner Losh if (rv != 0) { 1420*ca987d46SWarner Losh if (rv == -FDT_ERR_NOSPACE) 1421*ca987d46SWarner Losh sprintf(command_errbuf, 1422*ca987d46SWarner Losh "Device tree blob is too small!\n"); 1423*ca987d46SWarner Losh else 1424*ca987d46SWarner Losh sprintf(command_errbuf, 1425*ca987d46SWarner Losh "Could not add/modify property!\n"); 1426*ca987d46SWarner Losh } 1427*ca987d46SWarner Losh return (rv); 1428*ca987d46SWarner Losh } 1429*ca987d46SWarner Losh 1430*ca987d46SWarner Losh /* Merge strings from argv into a single string */ 1431*ca987d46SWarner Losh static int 1432*ca987d46SWarner Losh fdt_merge_strings(int argc, char *argv[], int start, char **buffer) 1433*ca987d46SWarner Losh { 1434*ca987d46SWarner Losh char *buf; 1435*ca987d46SWarner Losh int i, idx, sz; 1436*ca987d46SWarner Losh 1437*ca987d46SWarner Losh *buffer = NULL; 1438*ca987d46SWarner Losh sz = 0; 1439*ca987d46SWarner Losh 1440*ca987d46SWarner Losh for (i = start; i < argc; i++) 1441*ca987d46SWarner Losh sz += strlen(argv[i]); 1442*ca987d46SWarner Losh 1443*ca987d46SWarner Losh /* Additional bytes for whitespaces between args */ 1444*ca987d46SWarner Losh sz += argc - start; 1445*ca987d46SWarner Losh 1446*ca987d46SWarner Losh buf = (char *)malloc(sizeof(char) * sz); 1447*ca987d46SWarner Losh if (buf == NULL) { 1448*ca987d46SWarner Losh sprintf(command_errbuf, "could not allocate space " 1449*ca987d46SWarner Losh "for string"); 1450*ca987d46SWarner Losh return (1); 1451*ca987d46SWarner Losh } 1452*ca987d46SWarner Losh bzero(buf, sizeof(char) * sz); 1453*ca987d46SWarner Losh 1454*ca987d46SWarner Losh idx = 0; 1455*ca987d46SWarner Losh for (i = start, idx = 0; i < argc; i++) { 1456*ca987d46SWarner Losh strcpy(buf + idx, argv[i]); 1457*ca987d46SWarner Losh idx += strlen(argv[i]); 1458*ca987d46SWarner Losh buf[idx] = ' '; 1459*ca987d46SWarner Losh idx++; 1460*ca987d46SWarner Losh } 1461*ca987d46SWarner Losh buf[sz - 1] = '\0'; 1462*ca987d46SWarner Losh *buffer = buf; 1463*ca987d46SWarner Losh return (0); 1464*ca987d46SWarner Losh } 1465*ca987d46SWarner Losh 1466*ca987d46SWarner Losh /* Extract offset and name of node/property from a given path */ 1467*ca987d46SWarner Losh static int 1468*ca987d46SWarner Losh fdt_extract_nameloc(char **pathp, char **namep, int *nodeoff) 1469*ca987d46SWarner Losh { 1470*ca987d46SWarner Losh int o; 1471*ca987d46SWarner Losh char *path = *pathp, *name = NULL, *subpath = NULL; 1472*ca987d46SWarner Losh 1473*ca987d46SWarner Losh subpath = strrchr(path, '/'); 1474*ca987d46SWarner Losh if (subpath == NULL) { 1475*ca987d46SWarner Losh o = fdt_path_offset(fdtp, cwd); 1476*ca987d46SWarner Losh name = path; 1477*ca987d46SWarner Losh path = (char *)&cwd; 1478*ca987d46SWarner Losh } else { 1479*ca987d46SWarner Losh *subpath = '\0'; 1480*ca987d46SWarner Losh if (strlen(path) == 0) 1481*ca987d46SWarner Losh path = cwd; 1482*ca987d46SWarner Losh 1483*ca987d46SWarner Losh name = subpath + 1; 1484*ca987d46SWarner Losh o = fdt_path_offset(fdtp, path); 1485*ca987d46SWarner Losh } 1486*ca987d46SWarner Losh 1487*ca987d46SWarner Losh if (strlen(name) == 0) { 1488*ca987d46SWarner Losh sprintf(command_errbuf, "name not specified"); 1489*ca987d46SWarner Losh return (1); 1490*ca987d46SWarner Losh } 1491*ca987d46SWarner Losh if (o < 0) { 1492*ca987d46SWarner Losh snprintf(command_errbuf, sizeof(command_errbuf), 1493*ca987d46SWarner Losh "could not find node: '%s'", path); 1494*ca987d46SWarner Losh return (1); 1495*ca987d46SWarner Losh } 1496*ca987d46SWarner Losh *namep = name; 1497*ca987d46SWarner Losh *nodeoff = o; 1498*ca987d46SWarner Losh *pathp = path; 1499*ca987d46SWarner Losh return (0); 1500*ca987d46SWarner Losh } 1501*ca987d46SWarner Losh 1502*ca987d46SWarner Losh static int 1503*ca987d46SWarner Losh fdt_cmd_prop(int argc, char *argv[]) 1504*ca987d46SWarner Losh { 1505*ca987d46SWarner Losh char *path, *propname, *value; 1506*ca987d46SWarner Losh int o, next, depth, rv; 1507*ca987d46SWarner Losh uint32_t tag; 1508*ca987d46SWarner Losh 1509*ca987d46SWarner Losh path = (argc > 2) ? argv[2] : NULL; 1510*ca987d46SWarner Losh 1511*ca987d46SWarner Losh value = NULL; 1512*ca987d46SWarner Losh 1513*ca987d46SWarner Losh if (argc > 3) { 1514*ca987d46SWarner Losh /* Merge property value strings into one */ 1515*ca987d46SWarner Losh if (fdt_merge_strings(argc, argv, 3, &value) != 0) 1516*ca987d46SWarner Losh return (CMD_ERROR); 1517*ca987d46SWarner Losh } else 1518*ca987d46SWarner Losh value = NULL; 1519*ca987d46SWarner Losh 1520*ca987d46SWarner Losh if (path == NULL) 1521*ca987d46SWarner Losh path = cwd; 1522*ca987d46SWarner Losh 1523*ca987d46SWarner Losh rv = CMD_OK; 1524*ca987d46SWarner Losh 1525*ca987d46SWarner Losh if (value) { 1526*ca987d46SWarner Losh /* If value is specified -- try to modify prop. */ 1527*ca987d46SWarner Losh if (fdt_extract_nameloc(&path, &propname, &o) != 0) 1528*ca987d46SWarner Losh return (CMD_ERROR); 1529*ca987d46SWarner Losh 1530*ca987d46SWarner Losh rv = fdt_modprop(o, propname, value, 0); 1531*ca987d46SWarner Losh if (rv) 1532*ca987d46SWarner Losh return (CMD_ERROR); 1533*ca987d46SWarner Losh return (CMD_OK); 1534*ca987d46SWarner Losh 1535*ca987d46SWarner Losh } 1536*ca987d46SWarner Losh /* User wants to display properties */ 1537*ca987d46SWarner Losh o = fdt_path_offset(fdtp, path); 1538*ca987d46SWarner Losh 1539*ca987d46SWarner Losh if (o < 0) { 1540*ca987d46SWarner Losh snprintf(command_errbuf, sizeof(command_errbuf), 1541*ca987d46SWarner Losh "could not find node: '%s'", path); 1542*ca987d46SWarner Losh rv = CMD_ERROR; 1543*ca987d46SWarner Losh goto out; 1544*ca987d46SWarner Losh } 1545*ca987d46SWarner Losh 1546*ca987d46SWarner Losh depth = 0; 1547*ca987d46SWarner Losh while (depth >= 0) { 1548*ca987d46SWarner Losh tag = fdt_next_tag(fdtp, o, &next); 1549*ca987d46SWarner Losh switch (tag) { 1550*ca987d46SWarner Losh case FDT_NOP: 1551*ca987d46SWarner Losh break; 1552*ca987d46SWarner Losh case FDT_PROP: 1553*ca987d46SWarner Losh if (depth > 1) 1554*ca987d46SWarner Losh /* Don't process properties of nested nodes */ 1555*ca987d46SWarner Losh break; 1556*ca987d46SWarner Losh 1557*ca987d46SWarner Losh if (fdt_prop(o) != 0) { 1558*ca987d46SWarner Losh sprintf(command_errbuf, "could not process " 1559*ca987d46SWarner Losh "property"); 1560*ca987d46SWarner Losh rv = CMD_ERROR; 1561*ca987d46SWarner Losh goto out; 1562*ca987d46SWarner Losh } 1563*ca987d46SWarner Losh break; 1564*ca987d46SWarner Losh case FDT_BEGIN_NODE: 1565*ca987d46SWarner Losh depth++; 1566*ca987d46SWarner Losh if (depth > FDT_MAX_DEPTH) { 1567*ca987d46SWarner Losh printf("warning: nesting too deep: %d\n", 1568*ca987d46SWarner Losh depth); 1569*ca987d46SWarner Losh goto out; 1570*ca987d46SWarner Losh } 1571*ca987d46SWarner Losh break; 1572*ca987d46SWarner Losh case FDT_END_NODE: 1573*ca987d46SWarner Losh depth--; 1574*ca987d46SWarner Losh if (depth == 0) 1575*ca987d46SWarner Losh /* 1576*ca987d46SWarner Losh * This is the end of our starting node, force 1577*ca987d46SWarner Losh * the loop finish. 1578*ca987d46SWarner Losh */ 1579*ca987d46SWarner Losh depth--; 1580*ca987d46SWarner Losh break; 1581*ca987d46SWarner Losh } 1582*ca987d46SWarner Losh o = next; 1583*ca987d46SWarner Losh } 1584*ca987d46SWarner Losh out: 1585*ca987d46SWarner Losh return (rv); 1586*ca987d46SWarner Losh } 1587*ca987d46SWarner Losh 1588*ca987d46SWarner Losh static int 1589*ca987d46SWarner Losh fdt_cmd_mkprop(int argc, char *argv[]) 1590*ca987d46SWarner Losh { 1591*ca987d46SWarner Losh int o; 1592*ca987d46SWarner Losh char *path, *propname, *value; 1593*ca987d46SWarner Losh 1594*ca987d46SWarner Losh path = (argc > 2) ? argv[2] : NULL; 1595*ca987d46SWarner Losh 1596*ca987d46SWarner Losh value = NULL; 1597*ca987d46SWarner Losh 1598*ca987d46SWarner Losh if (argc > 3) { 1599*ca987d46SWarner Losh /* Merge property value strings into one */ 1600*ca987d46SWarner Losh if (fdt_merge_strings(argc, argv, 3, &value) != 0) 1601*ca987d46SWarner Losh return (CMD_ERROR); 1602*ca987d46SWarner Losh } else 1603*ca987d46SWarner Losh value = NULL; 1604*ca987d46SWarner Losh 1605*ca987d46SWarner Losh if (fdt_extract_nameloc(&path, &propname, &o) != 0) 1606*ca987d46SWarner Losh return (CMD_ERROR); 1607*ca987d46SWarner Losh 1608*ca987d46SWarner Losh if (fdt_modprop(o, propname, value, 1)) 1609*ca987d46SWarner Losh return (CMD_ERROR); 1610*ca987d46SWarner Losh 1611*ca987d46SWarner Losh return (CMD_OK); 1612*ca987d46SWarner Losh } 1613*ca987d46SWarner Losh 1614*ca987d46SWarner Losh static int 1615*ca987d46SWarner Losh fdt_cmd_rm(int argc, char *argv[]) 1616*ca987d46SWarner Losh { 1617*ca987d46SWarner Losh int o, rv; 1618*ca987d46SWarner Losh char *path = NULL, *propname; 1619*ca987d46SWarner Losh 1620*ca987d46SWarner Losh if (argc > 2) 1621*ca987d46SWarner Losh path = argv[2]; 1622*ca987d46SWarner Losh else { 1623*ca987d46SWarner Losh sprintf(command_errbuf, "no node/property name specified"); 1624*ca987d46SWarner Losh return (CMD_ERROR); 1625*ca987d46SWarner Losh } 1626*ca987d46SWarner Losh 1627*ca987d46SWarner Losh o = fdt_path_offset(fdtp, path); 1628*ca987d46SWarner Losh if (o < 0) { 1629*ca987d46SWarner Losh /* If node not found -- try to find & delete property */ 1630*ca987d46SWarner Losh if (fdt_extract_nameloc(&path, &propname, &o) != 0) 1631*ca987d46SWarner Losh return (CMD_ERROR); 1632*ca987d46SWarner Losh 1633*ca987d46SWarner Losh if ((rv = fdt_delprop(fdtp, o, propname)) != 0) { 1634*ca987d46SWarner Losh snprintf(command_errbuf, sizeof(command_errbuf), 1635*ca987d46SWarner Losh "could not delete %s\n", 1636*ca987d46SWarner Losh (rv == -FDT_ERR_NOTFOUND) ? 1637*ca987d46SWarner Losh "(property/node does not exist)" : ""); 1638*ca987d46SWarner Losh return (CMD_ERROR); 1639*ca987d46SWarner Losh 1640*ca987d46SWarner Losh } else 1641*ca987d46SWarner Losh return (CMD_OK); 1642*ca987d46SWarner Losh } 1643*ca987d46SWarner Losh /* If node exists -- remove node */ 1644*ca987d46SWarner Losh rv = fdt_del_node(fdtp, o); 1645*ca987d46SWarner Losh if (rv) { 1646*ca987d46SWarner Losh sprintf(command_errbuf, "could not delete node"); 1647*ca987d46SWarner Losh return (CMD_ERROR); 1648*ca987d46SWarner Losh } 1649*ca987d46SWarner Losh return (CMD_OK); 1650*ca987d46SWarner Losh } 1651*ca987d46SWarner Losh 1652*ca987d46SWarner Losh static int 1653*ca987d46SWarner Losh fdt_cmd_mknode(int argc, char *argv[]) 1654*ca987d46SWarner Losh { 1655*ca987d46SWarner Losh int o, rv; 1656*ca987d46SWarner Losh char *path = NULL, *nodename = NULL; 1657*ca987d46SWarner Losh 1658*ca987d46SWarner Losh if (argc > 2) 1659*ca987d46SWarner Losh path = argv[2]; 1660*ca987d46SWarner Losh else { 1661*ca987d46SWarner Losh sprintf(command_errbuf, "no node name specified"); 1662*ca987d46SWarner Losh return (CMD_ERROR); 1663*ca987d46SWarner Losh } 1664*ca987d46SWarner Losh 1665*ca987d46SWarner Losh if (fdt_extract_nameloc(&path, &nodename, &o) != 0) 1666*ca987d46SWarner Losh return (CMD_ERROR); 1667*ca987d46SWarner Losh 1668*ca987d46SWarner Losh rv = fdt_add_subnode(fdtp, o, nodename); 1669*ca987d46SWarner Losh 1670*ca987d46SWarner Losh if (rv < 0) { 1671*ca987d46SWarner Losh if (rv == -FDT_ERR_NOSPACE) 1672*ca987d46SWarner Losh sprintf(command_errbuf, 1673*ca987d46SWarner Losh "Device tree blob is too small!\n"); 1674*ca987d46SWarner Losh else 1675*ca987d46SWarner Losh sprintf(command_errbuf, 1676*ca987d46SWarner Losh "Could not add node!\n"); 1677*ca987d46SWarner Losh return (CMD_ERROR); 1678*ca987d46SWarner Losh } 1679*ca987d46SWarner Losh return (CMD_OK); 1680*ca987d46SWarner Losh } 1681*ca987d46SWarner Losh 1682*ca987d46SWarner Losh static int 1683*ca987d46SWarner Losh fdt_cmd_pwd(int argc, char *argv[]) 1684*ca987d46SWarner Losh { 1685*ca987d46SWarner Losh char line[FDT_CWD_LEN]; 1686*ca987d46SWarner Losh 1687*ca987d46SWarner Losh pager_open(); 1688*ca987d46SWarner Losh sprintf(line, "%s\n", cwd); 1689*ca987d46SWarner Losh pager_output(line); 1690*ca987d46SWarner Losh pager_close(); 1691*ca987d46SWarner Losh return (CMD_OK); 1692*ca987d46SWarner Losh } 1693*ca987d46SWarner Losh 1694*ca987d46SWarner Losh static int 1695*ca987d46SWarner Losh fdt_cmd_mres(int argc, char *argv[]) 1696*ca987d46SWarner Losh { 1697*ca987d46SWarner Losh uint64_t start, size; 1698*ca987d46SWarner Losh int i, total; 1699*ca987d46SWarner Losh char line[80]; 1700*ca987d46SWarner Losh 1701*ca987d46SWarner Losh pager_open(); 1702*ca987d46SWarner Losh total = fdt_num_mem_rsv(fdtp); 1703*ca987d46SWarner Losh if (total > 0) { 1704*ca987d46SWarner Losh if (pager_output("Reserved memory regions:\n")) 1705*ca987d46SWarner Losh goto out; 1706*ca987d46SWarner Losh for (i = 0; i < total; i++) { 1707*ca987d46SWarner Losh fdt_get_mem_rsv(fdtp, i, &start, &size); 1708*ca987d46SWarner Losh sprintf(line, "reg#%d: (start: 0x%jx, size: 0x%jx)\n", 1709*ca987d46SWarner Losh i, start, size); 1710*ca987d46SWarner Losh if (pager_output(line)) 1711*ca987d46SWarner Losh goto out; 1712*ca987d46SWarner Losh } 1713*ca987d46SWarner Losh } else 1714*ca987d46SWarner Losh pager_output("No reserved memory regions\n"); 1715*ca987d46SWarner Losh out: 1716*ca987d46SWarner Losh pager_close(); 1717*ca987d46SWarner Losh 1718*ca987d46SWarner Losh return (CMD_OK); 1719*ca987d46SWarner Losh } 1720*ca987d46SWarner Losh 1721*ca987d46SWarner Losh static int 1722*ca987d46SWarner Losh fdt_cmd_nyi(int argc, char *argv[]) 1723*ca987d46SWarner Losh { 1724*ca987d46SWarner Losh 1725*ca987d46SWarner Losh printf("command not yet implemented\n"); 1726*ca987d46SWarner Losh return (CMD_ERROR); 1727*ca987d46SWarner Losh } 1728