fdt_loader_cmd.c revision 247201
1208538Sraj/*- 2208538Sraj * Copyright (c) 2009-2010 The FreeBSD Foundation 3208538Sraj * All rights reserved. 4208538Sraj * 5208538Sraj * This software was developed by Semihalf under sponsorship from 6208538Sraj * the FreeBSD Foundation. 7208538Sraj * 8208538Sraj * Redistribution and use in source and binary forms, with or without 9208538Sraj * modification, are permitted provided that the following conditions 10208538Sraj * are met: 11208538Sraj * 1. Redistributions of source code must retain the above copyright 12208538Sraj * notice, this list of conditions and the following disclaimer. 13208538Sraj * 2. Redistributions in binary form must reproduce the above copyright 14208538Sraj * notice, this list of conditions and the following disclaimer in the 15208538Sraj * documentation and/or other materials provided with the distribution. 16208538Sraj * 17208538Sraj * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18208538Sraj * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19208538Sraj * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20208538Sraj * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21208538Sraj * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22208538Sraj * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23208538Sraj * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24208538Sraj * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25208538Sraj * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26208538Sraj * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27208538Sraj * SUCH DAMAGE. 28208538Sraj */ 29208538Sraj 30208538Sraj#include <sys/cdefs.h> 31208538Sraj__FBSDID("$FreeBSD: head/sys/boot/fdt/fdt_loader_cmd.c 247201 2013-02-23 20:34:47Z kientzle $"); 32208538Sraj 33208538Sraj#include <stand.h> 34208538Sraj#include <fdt.h> 35208538Sraj#include <libfdt.h> 36233230Sraj#include <sys/param.h> 37233230Sraj#include <sys/linker.h> 38233230Sraj#include <machine/elf.h> 39208538Sraj 40208538Sraj#include "bootstrap.h" 41208538Sraj#include "glue.h" 42208538Sraj 43208538Sraj#ifdef DEBUG 44208538Sraj#define debugf(fmt, args...) do { printf("%s(): ", __func__); \ 45208538Sraj printf(fmt,##args); } while (0) 46208538Sraj#else 47208538Sraj#define debugf(fmt, args...) 48208538Sraj#endif 49208538Sraj 50208538Sraj#define FDT_CWD_LEN 256 51208538Sraj#define FDT_MAX_DEPTH 6 52208538Sraj 53208538Sraj#define FDT_PROP_SEP " = " 54208538Sraj 55208538Sraj#define STR(number) #number 56208538Sraj#define STRINGIFY(number) STR(number) 57208538Sraj 58235529Skientzle#define COPYOUT(s,d,l) archsw.arch_copyout(s, d, l) 59235529Skientzle#define COPYIN(s,d,l) archsw.arch_copyin(s, d, l) 60233230Sraj 61233230Sraj#define FDT_STATIC_DTB_SYMBOL "fdt_static_dtb" 62233230Sraj 63243693Sgonzo#define CMD_REQUIRES_BLOB 0x01 64243693Sgonzo 65247201Skientzle/* Location of FDT yet to be loaded. */ 66247201Skientzlestatic struct fdt_header *fdt_to_load = NULL; 67247201Skientzle/* Local copy of FDT on heap. */ 68208538Srajstatic struct fdt_header *fdtp = NULL; 69235529Skientzle/* Size of FDT blob */ 70235529Skientzlestatic size_t fdtp_size = 0; 71235529Skientzle/* Location of FDT in kernel or module */ 72235529Skientzlestatic vm_offset_t fdtp_va = 0; 73208538Sraj 74243693Sgonzostatic int fdt_load_dtb(vm_offset_t va); 75243693Sgonzo 76208538Srajstatic int fdt_cmd_nyi(int argc, char *argv[]); 77208538Sraj 78243693Sgonzostatic int fdt_cmd_addr(int argc, char *argv[]); 79208538Srajstatic int fdt_cmd_mkprop(int argc, char *argv[]); 80208538Srajstatic int fdt_cmd_cd(int argc, char *argv[]); 81208538Srajstatic int fdt_cmd_hdr(int argc, char *argv[]); 82208538Srajstatic int fdt_cmd_ls(int argc, char *argv[]); 83208538Srajstatic int fdt_cmd_prop(int argc, char *argv[]); 84208538Srajstatic int fdt_cmd_pwd(int argc, char *argv[]); 85208538Srajstatic int fdt_cmd_rm(int argc, char *argv[]); 86208538Srajstatic int fdt_cmd_mknode(int argc, char *argv[]); 87243693Sgonzostatic int fdt_cmd_mres(int argc, char *argv[]); 88208538Sraj 89208538Srajtypedef int cmdf_t(int, char *[]); 90208538Sraj 91208538Srajstruct cmdtab { 92208538Sraj char *name; 93208538Sraj cmdf_t *handler; 94243693Sgonzo int flags; 95208538Sraj}; 96208538Sraj 97208538Srajstatic const struct cmdtab commands[] = { 98243693Sgonzo { "addr", &fdt_cmd_addr, 0 }, 99243693Sgonzo { "alias", &fdt_cmd_nyi, 0 }, 100243693Sgonzo { "cd", &fdt_cmd_cd, CMD_REQUIRES_BLOB }, 101243693Sgonzo { "header", &fdt_cmd_hdr, CMD_REQUIRES_BLOB }, 102243693Sgonzo { "ls", &fdt_cmd_ls, CMD_REQUIRES_BLOB }, 103243693Sgonzo { "mknode", &fdt_cmd_mknode, CMD_REQUIRES_BLOB }, 104243693Sgonzo { "mkprop", &fdt_cmd_mkprop, CMD_REQUIRES_BLOB }, 105243693Sgonzo { "mres", &fdt_cmd_mres, CMD_REQUIRES_BLOB }, 106243693Sgonzo { "prop", &fdt_cmd_prop, CMD_REQUIRES_BLOB }, 107243693Sgonzo { "pwd", &fdt_cmd_pwd, CMD_REQUIRES_BLOB }, 108243693Sgonzo { "rm", &fdt_cmd_rm, CMD_REQUIRES_BLOB }, 109208538Sraj { NULL, NULL } 110208538Sraj}; 111208538Sraj 112208538Srajstatic char cwd[FDT_CWD_LEN] = "/"; 113208538Sraj 114233230Srajstatic vm_offset_t 115235529Skientzlefdt_find_static_dtb() 116233230Sraj{ 117235529Skientzle Elf_Dyn dyn; 118233230Sraj Elf_Sym sym; 119235529Skientzle vm_offset_t dyntab, esym, strtab, symtab, fdt_start; 120233230Sraj uint64_t offs; 121233230Sraj struct preloaded_file *kfp; 122233230Sraj struct file_metadata *md; 123235529Skientzle char *strp; 124235529Skientzle int sym_count; 125233230Sraj 126235529Skientzle symtab = strtab = dyntab = esym = 0; 127235529Skientzle strp = NULL; 128233230Sraj 129233230Sraj offs = __elfN(relocation_offset); 130233230Sraj 131233230Sraj kfp = file_findfile(NULL, NULL); 132233230Sraj if (kfp == NULL) 133233230Sraj return (0); 134233230Sraj 135233230Sraj md = file_findmetadata(kfp, MODINFOMD_ESYM); 136233230Sraj if (md == NULL) 137233230Sraj return (0); 138235529Skientzle bcopy(md->md_data, &esym, sizeof(esym)); 139243693Sgonzo /* esym is already offset */ 140233230Sraj 141233230Sraj md = file_findmetadata(kfp, MODINFOMD_DYNAMIC); 142233230Sraj if (md == NULL) 143233230Sraj return (0); 144235529Skientzle bcopy(md->md_data, &dyntab, sizeof(dyntab)); 145233230Sraj dyntab += offs; 146233230Sraj 147233230Sraj /* Locate STRTAB and DYNTAB */ 148235529Skientzle for (;;) { 149235529Skientzle COPYOUT(dyntab, &dyn, sizeof(dyn)); 150235529Skientzle if (dyn.d_tag == DT_STRTAB) { 151235529Skientzle strtab = (vm_offset_t)(dyn.d_un.d_ptr) + offs; 152235529Skientzle } else if (dyn.d_tag == DT_SYMTAB) { 153235529Skientzle symtab = (vm_offset_t)(dyn.d_un.d_ptr) + offs; 154235529Skientzle } else if (dyn.d_tag == DT_NULL) { 155235529Skientzle break; 156233230Sraj } 157235529Skientzle dyntab += sizeof(dyn); 158233230Sraj } 159233230Sraj 160235529Skientzle if (symtab == 0 || strtab == 0) { 161233230Sraj /* 162233230Sraj * No symtab? No strtab? That should not happen here, 163233230Sraj * and should have been verified during __elfN(loadimage). 164233230Sraj * This must be some kind of a bug. 165233230Sraj */ 166233230Sraj return (0); 167233230Sraj } 168233230Sraj 169235529Skientzle sym_count = (int)(esym - symtab) / sizeof(Elf_Sym); 170233323Sraj 171233230Sraj /* 172233230Sraj * The most efficent way to find a symbol would be to calculate a 173233230Sraj * hash, find proper bucket and chain, and thus find a symbol. 174233230Sraj * However, that would involve code duplication (e.g. for hash 175233230Sraj * function). So we're using simpler and a bit slower way: we're 176233230Sraj * iterating through symbols, searching for the one which name is 177233230Sraj * 'equal' to 'fdt_static_dtb'. To speed up the process a little bit, 178233230Sraj * we are eliminating symbols type of which is not STT_NOTYPE, or(and) 179233230Sraj * those which binding attribute is not STB_GLOBAL. 180233230Sraj */ 181235529Skientzle fdt_start = 0; 182235529Skientzle while (sym_count > 0 && fdt_start == 0) { 183235529Skientzle COPYOUT(symtab, &sym, sizeof(sym)); 184235529Skientzle symtab += sizeof(sym); 185235529Skientzle --sym_count; 186233230Sraj if (ELF_ST_BIND(sym.st_info) != STB_GLOBAL || 187233230Sraj ELF_ST_TYPE(sym.st_info) != STT_NOTYPE) 188233230Sraj continue; 189235529Skientzle strp = strdupout(strtab + sym.st_name); 190235529Skientzle if (strcmp(strp, FDT_STATIC_DTB_SYMBOL) == 0) 191235529Skientzle fdt_start = (vm_offset_t)sym.st_value + offs; 192233230Sraj free(strp); 193233230Sraj } 194235529Skientzle printf("fdt_start: 0x%08jX\n", (intmax_t)fdt_start); 195235529Skientzle return (fdt_start); 196233230Sraj} 197233230Sraj 198208538Srajstatic int 199243693Sgonzofdt_load_dtb(vm_offset_t va) 200208538Sraj{ 201235529Skientzle struct fdt_header header; 202208538Sraj int err; 203208538Sraj 204243693Sgonzo COPYOUT(va, &header, sizeof(header)); 205243693Sgonzo err = fdt_check_header(&header); 206243693Sgonzo if (err < 0) { 207243693Sgonzo if (err == -FDT_ERR_BADVERSION) 208243693Sgonzo sprintf(command_errbuf, 209243693Sgonzo "incompatible blob version: %d, should be: %d", 210243693Sgonzo fdt_version(fdtp), FDT_LAST_SUPPORTED_VERSION); 211243693Sgonzo 212243693Sgonzo else 213243693Sgonzo sprintf(command_errbuf, "error validating blob: %s", 214243693Sgonzo fdt_strerror(err)); 215243693Sgonzo return (1); 216243693Sgonzo } 217243693Sgonzo 218208538Sraj /* 219243693Sgonzo * Release previous blob 220208538Sraj */ 221243693Sgonzo if (fdtp) 222243693Sgonzo free(fdtp); 223208538Sraj 224235529Skientzle fdtp_size = fdt_totalsize(&header); 225235529Skientzle fdtp = malloc(fdtp_size); 226243693Sgonzo 227235529Skientzle if (fdtp == NULL) { 228235529Skientzle command_errmsg = "can't allocate memory for device tree copy"; 229243693Sgonzo return (1); 230235529Skientzle } 231235529Skientzle 232243693Sgonzo fdtp_va = va; 233243693Sgonzo COPYOUT(va, fdtp, fdtp_size); 234243693Sgonzo debugf("DTB blob found at 0x%jx, size: 0x%jx\n", (uintmax_t)va, (uintmax_t)fdtp_size); 235208538Sraj 236243693Sgonzo return (0); 237243693Sgonzo} 238243693Sgonzo 239243693Sgonzostatic int 240247045Skientzlefdt_load_dtb_addr(struct fdt_header *header) 241243693Sgonzo{ 242243693Sgonzo struct preloaded_file *bfp; 243243693Sgonzo 244247045Skientzle bfp = mem_load_raw("dtb", "memory.dtb", header, fdt_totalsize(header)); 245243693Sgonzo if (bfp == NULL) { 246247045Skientzle command_errmsg = "unable to copy DTB into module directory"; 247247045Skientzle return (1); 248208538Sraj } 249247045Skientzle return fdt_load_dtb(bfp->f_addr); 250247045Skientzle} 251243693Sgonzo 252247045Skientzlestatic int 253247045Skientzlefdt_setup_fdtp() 254247045Skientzle{ 255247045Skientzle struct preloaded_file *bfp; 256247045Skientzle struct fdt_header *hdr; 257247201Skientzle const char *s; 258247201Skientzle char *p; 259247045Skientzle vm_offset_t va; 260247045Skientzle 261247045Skientzle if ((bfp = file_findfile(NULL, "dtb")) != NULL) { 262247045Skientzle printf("Using DTB from loaded file.\n"); 263247045Skientzle return fdt_load_dtb(bfp->f_addr); 264247201Skientzle } 265247045Skientzle 266247201Skientzle if (fdt_to_load != NULL) { 267247201Skientzle printf("Using DTB from memory address 0x%08X.\n", 268247201Skientzle (unsigned int)fdt_to_load); 269247201Skientzle return fdt_load_dtb_addr(fdt_to_load); 270247201Skientzle } 271247201Skientzle 272247045Skientzle s = ub_env_get("fdtaddr"); 273247045Skientzle if (s != NULL && *s != '\0') { 274247045Skientzle hdr = (struct fdt_header *)strtoul(s, &p, 16); 275247045Skientzle if (*p == '\0') { 276247045Skientzle printf("Using DTB provided by U-Boot.\n"); 277247045Skientzle return fdt_load_dtb_addr(hdr); 278247045Skientzle } 279247045Skientzle } 280247045Skientzle 281247045Skientzle if ((va = fdt_find_static_dtb()) != 0) { 282247045Skientzle printf("Using DTB compiled into kernel.\n"); 283247045Skientzle return (fdt_load_dtb(va)); 284247045Skientzle } 285247045Skientzle 286247045Skientzle command_errmsg = "no device tree blob found!"; 287247045Skientzle return (1); 288208538Sraj} 289208538Sraj 290208538Sraj#define fdt_strtovect(str, cellbuf, lim, cellsize) _fdt_strtovect((str), \ 291208538Sraj (cellbuf), (lim), (cellsize), 0); 292208538Sraj 293208538Sraj/* Force using base 16 */ 294208538Sraj#define fdt_strtovectx(str, cellbuf, lim, cellsize) _fdt_strtovect((str), \ 295208538Sraj (cellbuf), (lim), (cellsize), 16); 296208538Sraj 297208538Srajstatic int 298208538Sraj_fdt_strtovect(char *str, void *cellbuf, int lim, unsigned char cellsize, 299208538Sraj uint8_t base) 300208538Sraj{ 301208538Sraj char *buf = str; 302208538Sraj char *end = str + strlen(str) - 2; 303208538Sraj uint32_t *u32buf = NULL; 304208538Sraj uint8_t *u8buf = NULL; 305208538Sraj int cnt = 0; 306208538Sraj 307208538Sraj if (cellsize == sizeof(uint32_t)) 308208538Sraj u32buf = (uint32_t *)cellbuf; 309208538Sraj else 310208538Sraj u8buf = (uint8_t *)cellbuf; 311208538Sraj 312208538Sraj if (lim == 0) 313208538Sraj return (0); 314208538Sraj 315208538Sraj while (buf < end) { 316208538Sraj 317208538Sraj /* Skip white whitespace(s)/separators */ 318208538Sraj while (!isxdigit(*buf) && buf < end) 319208538Sraj buf++; 320208538Sraj 321208538Sraj if (u32buf != NULL) 322208538Sraj u32buf[cnt] = 323208538Sraj cpu_to_fdt32((uint32_t)strtol(buf, NULL, base)); 324208538Sraj 325208538Sraj else 326208538Sraj u8buf[cnt] = (uint8_t)strtol(buf, NULL, base); 327208538Sraj 328208538Sraj if (cnt + 1 <= lim - 1) 329208538Sraj cnt++; 330208538Sraj else 331208538Sraj break; 332208538Sraj buf++; 333208538Sraj /* Find another number */ 334208538Sraj while ((isxdigit(*buf) || *buf == 'x') && buf < end) 335208538Sraj buf++; 336208538Sraj } 337208538Sraj return (cnt); 338208538Sraj} 339208538Sraj 340208538Sraj#define TMP_MAX_ETH 8 341208538Sraj 342208538Srajvoid 343208538Srajfixup_ethernet(const char *env, char *ethstr, int *eth_no, int len) 344208538Sraj{ 345208538Sraj char *end, *str; 346208538Sraj uint8_t tmp_addr[6]; 347208538Sraj int i, n; 348208538Sraj 349208538Sraj /* Extract interface number */ 350208538Sraj i = strtol(env + 3, &end, 10); 351208538Sraj if (end == (env + 3)) 352208538Sraj /* 'ethaddr' means interface 0 address */ 353208538Sraj n = 0; 354208538Sraj else 355208538Sraj n = i; 356208538Sraj 357208538Sraj if (n > TMP_MAX_ETH) 358208538Sraj return; 359208538Sraj 360208538Sraj str = ub_env_get(env); 361208538Sraj 362208538Sraj /* Convert macaddr string into a vector of uints */ 363208538Sraj fdt_strtovectx(str, &tmp_addr, 6, sizeof(uint8_t)); 364208538Sraj if (n != 0) { 365208538Sraj i = strlen(env) - 7; 366208538Sraj strncpy(ethstr + 8, env + 3, i); 367208538Sraj } 368208538Sraj /* Set actual property to a value from vect */ 369208538Sraj fdt_setprop(fdtp, fdt_path_offset(fdtp, ethstr), 370208538Sraj "local-mac-address", &tmp_addr, 6 * sizeof(uint8_t)); 371208538Sraj 372208538Sraj /* Clear ethernet..XXXX.. string */ 373208538Sraj bzero(ethstr + 8, len - 8); 374208538Sraj 375208538Sraj if (n + 1 > *eth_no) 376208538Sraj *eth_no = n + 1; 377208538Sraj} 378208538Sraj 379208538Srajvoid 380208538Srajfixup_cpubusfreqs(unsigned long cpufreq, unsigned long busfreq) 381208538Sraj{ 382208538Sraj int lo, o = 0, o2, maxo = 0, depth; 383208538Sraj const uint32_t zero = 0; 384208538Sraj 385208538Sraj /* We want to modify every subnode of /cpus */ 386208538Sraj o = fdt_path_offset(fdtp, "/cpus"); 387235261Skientzle if (o < 0) 388235261Skientzle return; 389208538Sraj 390208538Sraj /* maxo should contain offset of node next to /cpus */ 391208538Sraj depth = 0; 392208538Sraj maxo = o; 393208538Sraj while (depth != -1) 394208538Sraj maxo = fdt_next_node(fdtp, maxo, &depth); 395208538Sraj 396208538Sraj /* Find CPU frequency properties */ 397208538Sraj o = fdt_node_offset_by_prop_value(fdtp, o, "clock-frequency", 398208538Sraj &zero, sizeof(uint32_t)); 399208538Sraj 400208538Sraj o2 = fdt_node_offset_by_prop_value(fdtp, o, "bus-frequency", &zero, 401208538Sraj sizeof(uint32_t)); 402208538Sraj 403208538Sraj lo = MIN(o, o2); 404208538Sraj 405208538Sraj while (o != -FDT_ERR_NOTFOUND && o2 != -FDT_ERR_NOTFOUND) { 406208538Sraj 407208538Sraj o = fdt_node_offset_by_prop_value(fdtp, lo, 408208538Sraj "clock-frequency", &zero, sizeof(uint32_t)); 409208538Sraj 410208538Sraj o2 = fdt_node_offset_by_prop_value(fdtp, lo, "bus-frequency", 411208538Sraj &zero, sizeof(uint32_t)); 412208538Sraj 413208538Sraj /* We're only interested in /cpus subnode(s) */ 414208538Sraj if (lo > maxo) 415208538Sraj break; 416208538Sraj 417208538Sraj fdt_setprop_inplace_cell(fdtp, lo, "clock-frequency", 418208538Sraj (uint32_t)cpufreq); 419208538Sraj 420208538Sraj fdt_setprop_inplace_cell(fdtp, lo, "bus-frequency", 421208538Sraj (uint32_t)busfreq); 422208538Sraj 423208538Sraj lo = MIN(o, o2); 424208538Sraj } 425208538Sraj} 426208538Sraj 427208538Srajint 428208538Srajfdt_reg_valid(uint32_t *reg, int len, int addr_cells, int size_cells) 429208538Sraj{ 430208538Sraj int cells_in_tuple, i, tuples, tuple_size; 431208538Sraj uint32_t cur_start, cur_size; 432208538Sraj 433208538Sraj cells_in_tuple = (addr_cells + size_cells); 434208538Sraj tuple_size = cells_in_tuple * sizeof(uint32_t); 435208538Sraj tuples = len / tuple_size; 436208538Sraj if (tuples == 0) 437208538Sraj return (EINVAL); 438208538Sraj 439208538Sraj for (i = 0; i < tuples; i++) { 440208538Sraj if (addr_cells == 2) 441208538Sraj cur_start = fdt64_to_cpu(reg[i * cells_in_tuple]); 442208538Sraj else 443208538Sraj cur_start = fdt32_to_cpu(reg[i * cells_in_tuple]); 444208538Sraj 445208538Sraj if (size_cells == 2) 446208538Sraj cur_size = fdt64_to_cpu(reg[i * cells_in_tuple + 2]); 447208538Sraj else 448208538Sraj cur_size = fdt32_to_cpu(reg[i * cells_in_tuple + 1]); 449208538Sraj 450208538Sraj if (cur_size == 0) 451208538Sraj return (EINVAL); 452208538Sraj 453208538Sraj debugf(" reg#%d (start: 0x%0x size: 0x%0x) valid!\n", 454208538Sraj i, cur_start, cur_size); 455208538Sraj } 456208538Sraj return (0); 457208538Sraj} 458208538Sraj 459208538Srajvoid 460208538Srajfixup_memory(struct sys_info *si) 461208538Sraj{ 462208538Sraj struct mem_region *curmr; 463208538Sraj uint32_t addr_cells, size_cells; 464208538Sraj uint32_t *addr_cellsp, *reg, *size_cellsp; 465208538Sraj int err, i, len, memory, realmrno, root; 466208538Sraj uint8_t *buf, *sb; 467243693Sgonzo uint64_t rstart, rsize; 468243693Sgonzo int reserved; 469208538Sraj 470208538Sraj root = fdt_path_offset(fdtp, "/"); 471208538Sraj if (root < 0) { 472208538Sraj sprintf(command_errbuf, "Could not find root node !"); 473208538Sraj return; 474208538Sraj } 475208538Sraj 476208538Sraj memory = fdt_path_offset(fdtp, "/memory"); 477208538Sraj if (memory <= 0) { 478208538Sraj /* Create proper '/memory' node. */ 479208538Sraj memory = fdt_add_subnode(fdtp, root, "memory"); 480208538Sraj if (memory <= 0) { 481208538Sraj sprintf(command_errbuf, "Could not fixup '/memory' " 482208538Sraj "node, error code : %d!\n", memory); 483208538Sraj return; 484208538Sraj } 485208538Sraj 486208538Sraj err = fdt_setprop(fdtp, memory, "device_type", "memory", 487208538Sraj sizeof("memory")); 488208538Sraj 489208538Sraj if (err < 0) 490208538Sraj return; 491208538Sraj } 492208538Sraj 493208538Sraj addr_cellsp = (uint32_t *)fdt_getprop(fdtp, root, "#address-cells", 494208538Sraj NULL); 495208538Sraj size_cellsp = (uint32_t *)fdt_getprop(fdtp, root, "#size-cells", NULL); 496208538Sraj 497208538Sraj if (addr_cellsp == NULL || size_cellsp == NULL) { 498208538Sraj sprintf(command_errbuf, "Could not fixup '/memory' node : " 499208538Sraj "%s %s property not found in root node!\n", 500208538Sraj (!addr_cellsp) ? "#address-cells" : "", 501208538Sraj (!size_cellsp) ? "#size-cells" : ""); 502208538Sraj return; 503208538Sraj } 504208538Sraj 505208538Sraj addr_cells = fdt32_to_cpu(*addr_cellsp); 506208538Sraj size_cells = fdt32_to_cpu(*size_cellsp); 507208538Sraj 508243693Sgonzo /* 509243693Sgonzo * Convert memreserve data to memreserve property 510243693Sgonzo * Check if property already exists 511243693Sgonzo */ 512243693Sgonzo reserved = fdt_num_mem_rsv(fdtp); 513243693Sgonzo if (reserved && 514243693Sgonzo (fdt_getprop(fdtp, root, "memreserve", NULL) == NULL)) { 515243693Sgonzo len = (addr_cells + size_cells) * reserved * sizeof(uint32_t); 516243693Sgonzo sb = buf = (uint8_t *)malloc(len); 517243693Sgonzo if (!buf) 518243693Sgonzo return; 519243693Sgonzo 520243693Sgonzo bzero(buf, len); 521243693Sgonzo 522243693Sgonzo for (i = 0; i < reserved; i++) { 523243693Sgonzo curmr = &si->mr[i]; 524243693Sgonzo if (fdt_get_mem_rsv(fdtp, i, &rstart, &rsize)) 525243693Sgonzo break; 526243693Sgonzo if (rsize) { 527243693Sgonzo /* Ensure endianess, and put cells into a buffer */ 528243693Sgonzo if (addr_cells == 2) 529243693Sgonzo *(uint64_t *)buf = 530243693Sgonzo cpu_to_fdt64(rstart); 531243693Sgonzo else 532243693Sgonzo *(uint32_t *)buf = 533243693Sgonzo cpu_to_fdt32(rstart); 534243693Sgonzo 535243693Sgonzo buf += sizeof(uint32_t) * addr_cells; 536243693Sgonzo if (size_cells == 2) 537243693Sgonzo *(uint64_t *)buf = 538243693Sgonzo cpu_to_fdt64(rsize); 539243693Sgonzo else 540243693Sgonzo *(uint32_t *)buf = 541243693Sgonzo cpu_to_fdt32(rsize); 542243693Sgonzo 543243693Sgonzo buf += sizeof(uint32_t) * size_cells; 544243693Sgonzo } 545243693Sgonzo } 546243693Sgonzo 547243693Sgonzo /* Set property */ 548243693Sgonzo if ((err = fdt_setprop(fdtp, root, "memreserve", sb, len)) < 0) 549243693Sgonzo printf("Could not fixup 'memreserve' property.\n"); 550243693Sgonzo 551243693Sgonzo free(sb); 552243693Sgonzo } 553243693Sgonzo 554208538Sraj /* Count valid memory regions entries in sysinfo. */ 555208538Sraj realmrno = si->mr_no; 556208538Sraj for (i = 0; i < si->mr_no; i++) 557208538Sraj if (si->mr[i].start == 0 && si->mr[i].size == 0) 558208538Sraj realmrno--; 559208538Sraj 560208538Sraj if (realmrno == 0) { 561208538Sraj sprintf(command_errbuf, "Could not fixup '/memory' node : " 562208538Sraj "sysinfo doesn't contain valid memory regions info!\n"); 563208538Sraj return; 564208538Sraj } 565208538Sraj 566208538Sraj if ((reg = (uint32_t *)fdt_getprop(fdtp, memory, "reg", 567208538Sraj &len)) != NULL) { 568208538Sraj 569208538Sraj if (fdt_reg_valid(reg, len, addr_cells, size_cells) == 0) 570208538Sraj /* 571208538Sraj * Do not apply fixup if existing 'reg' property 572208538Sraj * seems to be valid. 573208538Sraj */ 574208538Sraj return; 575208538Sraj } 576208538Sraj 577208538Sraj len = (addr_cells + size_cells) * realmrno * sizeof(uint32_t); 578208538Sraj sb = buf = (uint8_t *)malloc(len); 579208538Sraj if (!buf) 580208538Sraj return; 581208538Sraj 582208538Sraj bzero(buf, len); 583208538Sraj 584208538Sraj for (i = 0; i < si->mr_no; i++) { 585208538Sraj curmr = &si->mr[i]; 586208538Sraj if (curmr->size != 0) { 587208538Sraj /* Ensure endianess, and put cells into a buffer */ 588208538Sraj if (addr_cells == 2) 589208538Sraj *(uint64_t *)buf = 590208538Sraj cpu_to_fdt64(curmr->start); 591208538Sraj else 592208538Sraj *(uint32_t *)buf = 593208538Sraj cpu_to_fdt32(curmr->start); 594208538Sraj 595208538Sraj buf += sizeof(uint32_t) * addr_cells; 596208538Sraj if (size_cells == 2) 597208538Sraj *(uint64_t *)buf = 598208538Sraj cpu_to_fdt64(curmr->size); 599208538Sraj else 600208538Sraj *(uint32_t *)buf = 601208538Sraj cpu_to_fdt32(curmr->size); 602208538Sraj 603208538Sraj buf += sizeof(uint32_t) * size_cells; 604208538Sraj } 605208538Sraj } 606208538Sraj 607208538Sraj /* Set property */ 608208538Sraj if ((err = fdt_setprop(fdtp, memory, "reg", sb, len)) < 0) 609208538Sraj sprintf(command_errbuf, "Could not fixup '/memory' node.\n"); 610243693Sgonzo 611243693Sgonzo free(sb); 612208538Sraj} 613208538Sraj 614208538Srajvoid 615208538Srajfixup_stdout(const char *env) 616208538Sraj{ 617208538Sraj const char *str; 618208538Sraj char *ptr; 619208538Sraj int serialno; 620208538Sraj int len, no, sero; 621208538Sraj const struct fdt_property *prop; 622208538Sraj char *tmp[10]; 623208538Sraj 624208538Sraj str = ub_env_get(env); 625208538Sraj ptr = (char *)str + strlen(str) - 1; 626208538Sraj while (ptr > str && isdigit(*(str - 1))) 627208538Sraj str--; 628208538Sraj 629208538Sraj if (ptr == str) 630208538Sraj return; 631208538Sraj 632208538Sraj serialno = (int)strtol(ptr, NULL, 0); 633208538Sraj no = fdt_path_offset(fdtp, "/chosen"); 634208538Sraj if (no < 0) 635208538Sraj return; 636208538Sraj 637208538Sraj prop = fdt_get_property(fdtp, no, "stdout", &len); 638208538Sraj 639208538Sraj /* If /chosen/stdout does not extist, create it */ 640208538Sraj if (prop == NULL || (prop != NULL && len == 0)) { 641208538Sraj 642208538Sraj bzero(tmp, 10 * sizeof(char)); 643208538Sraj strcpy((char *)&tmp, "serial"); 644208538Sraj if (strlen(ptr) > 3) 645208538Sraj /* Serial number too long */ 646208538Sraj return; 647208538Sraj 648208538Sraj strncpy((char *)tmp + 6, ptr, 3); 649208538Sraj sero = fdt_path_offset(fdtp, (const char *)tmp); 650208538Sraj if (sero < 0) 651208538Sraj /* 652208538Sraj * If serial device we're trying to assign 653208538Sraj * stdout to doesn't exist in DT -- return. 654208538Sraj */ 655208538Sraj return; 656208538Sraj 657208538Sraj fdt_setprop(fdtp, no, "stdout", &tmp, 658208538Sraj strlen((char *)&tmp) + 1); 659208538Sraj fdt_setprop(fdtp, no, "stdin", &tmp, 660208538Sraj strlen((char *)&tmp) + 1); 661208538Sraj } 662208538Sraj} 663208538Sraj 664233230Sraj/* 665233230Sraj * Locate the blob, fix it up and return its location. 666233230Sraj */ 667243693Sgonzostatic vm_offset_t 668208538Srajfdt_fixup(void) 669208538Sraj{ 670208538Sraj const char *env; 671208538Sraj char *ethstr; 672208538Sraj int chosen, err, eth_no, len; 673208538Sraj struct sys_info *si; 674208538Sraj 675208538Sraj env = NULL; 676208538Sraj eth_no = 0; 677208538Sraj ethstr = NULL; 678208538Sraj len = 0; 679208538Sraj 680243693Sgonzo if (fdtp == NULL) { 681243693Sgonzo err = fdt_setup_fdtp(); 682243693Sgonzo if (err) { 683243693Sgonzo sprintf(command_errbuf, "No valid device tree blob found!"); 684243693Sgonzo return (0); 685243693Sgonzo } 686208538Sraj } 687208538Sraj 688208538Sraj /* Create /chosen node (if not exists) */ 689208538Sraj if ((chosen = fdt_subnode_offset(fdtp, 0, "chosen")) == 690208538Sraj -FDT_ERR_NOTFOUND) 691208538Sraj chosen = fdt_add_subnode(fdtp, 0, "chosen"); 692208538Sraj 693208538Sraj /* Value assigned to fixup-applied does not matter. */ 694208538Sraj if (fdt_getprop(fdtp, chosen, "fixup-applied", NULL)) 695233230Sraj goto success; 696208538Sraj 697208538Sraj /* Acquire sys_info */ 698208538Sraj si = ub_get_sys_info(); 699208538Sraj 700208538Sraj while ((env = ub_env_enum(env)) != NULL) { 701208538Sraj if (strncmp(env, "eth", 3) == 0 && 702208538Sraj strncmp(env + (strlen(env) - 4), "addr", 4) == 0) { 703208538Sraj /* 704208538Sraj * Handle Ethernet addrs: parse uboot env eth%daddr 705208538Sraj */ 706208538Sraj 707208538Sraj if (!eth_no) { 708208538Sraj /* 709208538Sraj * Check how many chars we will need to store 710208538Sraj * maximal eth iface number. 711208538Sraj */ 712208538Sraj len = strlen(STRINGIFY(TMP_MAX_ETH)) + 713208538Sraj strlen("ethernet"); 714208538Sraj 715208538Sraj /* 716208538Sraj * Reserve mem for string "ethernet" and len 717208538Sraj * chars for iface no. 718208538Sraj */ 719208538Sraj ethstr = (char *)malloc(len * sizeof(char)); 720208538Sraj bzero(ethstr, len * sizeof(char)); 721208538Sraj strcpy(ethstr, "ethernet0"); 722208538Sraj } 723208538Sraj 724208538Sraj /* Modify blob */ 725208538Sraj fixup_ethernet(env, ethstr, ð_no, len); 726208538Sraj 727208538Sraj } else if (strcmp(env, "consoledev") == 0) 728208538Sraj fixup_stdout(env); 729208538Sraj } 730208538Sraj 731208538Sraj /* Modify cpu(s) and bus clock frequenties in /cpus node [Hz] */ 732208538Sraj fixup_cpubusfreqs(si->clk_cpu, si->clk_bus); 733208538Sraj 734208538Sraj /* Fixup memory regions */ 735208538Sraj fixup_memory(si); 736208538Sraj 737208538Sraj fdt_setprop(fdtp, chosen, "fixup-applied", NULL, 0); 738208538Sraj 739233230Srajsuccess: 740235529Skientzle /* Overwrite the FDT with the fixed version. */ 741235529Skientzle COPYIN(fdtp, fdtp_va, fdtp_size); 742235529Skientzle return (fdtp_va); 743208538Sraj} 744208538Sraj 745243693Sgonzo/* 746243693Sgonzo * Copy DTB blob to specified location and its return size 747243693Sgonzo */ 748208538Srajint 749243693Sgonzofdt_copy(vm_offset_t va) 750243693Sgonzo{ 751243693Sgonzo int err; 752243693Sgonzo 753243693Sgonzo if (fdtp == NULL) { 754243693Sgonzo err = fdt_setup_fdtp(); 755243693Sgonzo if (err) { 756243693Sgonzo printf("No valid device tree blob found!"); 757243693Sgonzo return (0); 758243693Sgonzo } 759243693Sgonzo } 760243693Sgonzo 761243693Sgonzo if (fdt_fixup() == 0) 762243693Sgonzo return (0); 763243693Sgonzo 764243693Sgonzo COPYIN(fdtp, va, fdtp_size); 765243693Sgonzo return (fdtp_size); 766243693Sgonzo} 767243693Sgonzo 768243693Sgonzo 769243693Sgonzo 770243693Sgonzoint 771208538Srajcommand_fdt_internal(int argc, char *argv[]) 772208538Sraj{ 773208538Sraj cmdf_t *cmdh; 774243693Sgonzo int flags; 775208538Sraj char *cmd; 776208538Sraj int i, err; 777208538Sraj 778208538Sraj if (argc < 2) { 779208538Sraj command_errmsg = "usage is 'fdt <command> [<args>]"; 780208538Sraj return (CMD_ERROR); 781208538Sraj } 782208538Sraj 783208538Sraj /* 784208538Sraj * Validate fdt <command>. 785208538Sraj */ 786208538Sraj cmd = strdup(argv[1]); 787208538Sraj i = 0; 788208538Sraj cmdh = NULL; 789208538Sraj while (!(commands[i].name == NULL)) { 790208538Sraj if (strcmp(cmd, commands[i].name) == 0) { 791208538Sraj /* found it */ 792208538Sraj cmdh = commands[i].handler; 793243693Sgonzo flags = commands[i].flags; 794208538Sraj break; 795208538Sraj } 796208538Sraj i++; 797208538Sraj } 798208538Sraj if (cmdh == NULL) { 799208538Sraj command_errmsg = "unknown command"; 800208538Sraj return (CMD_ERROR); 801208538Sraj } 802208538Sraj 803243693Sgonzo if (flags & CMD_REQUIRES_BLOB) { 804243693Sgonzo /* 805243693Sgonzo * Check if uboot env vars were parsed already. If not, do it now. 806243693Sgonzo */ 807243693Sgonzo if (fdt_fixup() == 0) 808243693Sgonzo return (CMD_ERROR); 809243693Sgonzo } 810243693Sgonzo 811208538Sraj /* 812208538Sraj * Call command handler. 813208538Sraj */ 814208538Sraj err = (*cmdh)(argc, argv); 815208538Sraj 816208538Sraj return (err); 817208538Sraj} 818208538Sraj 819208538Srajstatic int 820243693Sgonzofdt_cmd_addr(int argc, char *argv[]) 821243693Sgonzo{ 822247201Skientzle struct preloaded_file *fp; 823247045Skientzle struct fdt_header *hdr; 824247201Skientzle const char *addr; 825247201Skientzle char *cp; 826243693Sgonzo 827247201Skientzle fdt_to_load = NULL; 828247201Skientzle 829243693Sgonzo if (argc > 2) 830243693Sgonzo addr = argv[2]; 831243693Sgonzo else { 832243693Sgonzo sprintf(command_errbuf, "no address specified"); 833243693Sgonzo return (CMD_ERROR); 834243693Sgonzo } 835243693Sgonzo 836247201Skientzle hdr = (struct fdt_header *)strtoul(addr, &cp, 16); 837243693Sgonzo if (cp == addr) { 838243693Sgonzo sprintf(command_errbuf, "Invalid address: %s", addr); 839243693Sgonzo return (CMD_ERROR); 840243693Sgonzo } 841243693Sgonzo 842247201Skientzle while ((fp = file_findfile(NULL, "dtb")) != NULL) { 843247201Skientzle file_discard(fp); 844247201Skientzle } 845243693Sgonzo 846247201Skientzle fdt_to_load = hdr; 847243693Sgonzo return (CMD_OK); 848243693Sgonzo} 849243693Sgonzo 850243693Sgonzostatic int 851208538Srajfdt_cmd_cd(int argc, char *argv[]) 852208538Sraj{ 853208538Sraj char *path; 854208538Sraj char tmp[FDT_CWD_LEN]; 855208538Sraj int len, o; 856208538Sraj 857208538Sraj path = (argc > 2) ? argv[2] : "/"; 858208538Sraj 859208538Sraj if (path[0] == '/') { 860208538Sraj len = strlen(path); 861208538Sraj if (len >= FDT_CWD_LEN) 862208538Sraj goto fail; 863208538Sraj } else { 864208538Sraj /* Handle path specification relative to cwd */ 865208538Sraj len = strlen(cwd) + strlen(path) + 1; 866208538Sraj if (len >= FDT_CWD_LEN) 867208538Sraj goto fail; 868208538Sraj 869208538Sraj strcpy(tmp, cwd); 870208538Sraj strcat(tmp, "/"); 871208538Sraj strcat(tmp, path); 872208538Sraj path = tmp; 873208538Sraj } 874208538Sraj 875208538Sraj o = fdt_path_offset(fdtp, path); 876208538Sraj if (o < 0) { 877208538Sraj sprintf(command_errbuf, "could not find node: '%s'", path); 878208538Sraj return (CMD_ERROR); 879208538Sraj } 880208538Sraj 881208538Sraj strcpy(cwd, path); 882208538Sraj return (CMD_OK); 883208538Sraj 884208538Srajfail: 885208538Sraj sprintf(command_errbuf, "path too long: %d, max allowed: %d", 886208538Sraj len, FDT_CWD_LEN - 1); 887208538Sraj return (CMD_ERROR); 888208538Sraj} 889208538Sraj 890208538Srajstatic int 891208538Srajfdt_cmd_hdr(int argc __unused, char *argv[] __unused) 892208538Sraj{ 893208538Sraj char line[80]; 894208538Sraj int ver; 895208538Sraj 896208538Sraj if (fdtp == NULL) { 897208538Sraj command_errmsg = "no device tree blob pointer?!"; 898208538Sraj return (CMD_ERROR); 899208538Sraj } 900208538Sraj 901208538Sraj ver = fdt_version(fdtp); 902208538Sraj pager_open(); 903208538Sraj sprintf(line, "\nFlattened device tree header (%p):\n", fdtp); 904208538Sraj pager_output(line); 905208538Sraj sprintf(line, " magic = 0x%08x\n", fdt_magic(fdtp)); 906208538Sraj pager_output(line); 907208538Sraj sprintf(line, " size = %d\n", fdt_totalsize(fdtp)); 908208538Sraj pager_output(line); 909208538Sraj sprintf(line, " off_dt_struct = 0x%08x\n", 910208538Sraj fdt_off_dt_struct(fdtp)); 911208538Sraj pager_output(line); 912208538Sraj sprintf(line, " off_dt_strings = 0x%08x\n", 913208538Sraj fdt_off_dt_strings(fdtp)); 914208538Sraj pager_output(line); 915208538Sraj sprintf(line, " off_mem_rsvmap = 0x%08x\n", 916208538Sraj fdt_off_mem_rsvmap(fdtp)); 917208538Sraj pager_output(line); 918208538Sraj sprintf(line, " version = %d\n", ver); 919208538Sraj pager_output(line); 920208538Sraj sprintf(line, " last compatible version = %d\n", 921208538Sraj fdt_last_comp_version(fdtp)); 922208538Sraj pager_output(line); 923208538Sraj if (ver >= 2) { 924208538Sraj sprintf(line, " boot_cpuid = %d\n", 925208538Sraj fdt_boot_cpuid_phys(fdtp)); 926208538Sraj pager_output(line); 927208538Sraj } 928208538Sraj if (ver >= 3) { 929208538Sraj sprintf(line, " size_dt_strings = %d\n", 930208538Sraj fdt_size_dt_strings(fdtp)); 931208538Sraj pager_output(line); 932208538Sraj } 933208538Sraj if (ver >= 17) { 934208538Sraj sprintf(line, " size_dt_struct = %d\n", 935208538Sraj fdt_size_dt_struct(fdtp)); 936208538Sraj pager_output(line); 937208538Sraj } 938208538Sraj pager_close(); 939208538Sraj 940208538Sraj return (CMD_OK); 941208538Sraj} 942208538Sraj 943208538Srajstatic int 944208538Srajfdt_cmd_ls(int argc, char *argv[]) 945208538Sraj{ 946208538Sraj const char *prevname[FDT_MAX_DEPTH] = { NULL }; 947208538Sraj const char *name; 948208538Sraj char *path; 949208538Sraj int i, o, depth, len; 950208538Sraj 951208538Sraj path = (argc > 2) ? argv[2] : NULL; 952208538Sraj if (path == NULL) 953208538Sraj path = cwd; 954208538Sraj 955208538Sraj o = fdt_path_offset(fdtp, path); 956208538Sraj if (o < 0) { 957208538Sraj sprintf(command_errbuf, "could not find node: '%s'", path); 958208538Sraj return (CMD_ERROR); 959208538Sraj } 960208538Sraj 961208538Sraj for (depth = 0; 962208538Sraj (o >= 0) && (depth >= 0); 963208538Sraj o = fdt_next_node(fdtp, o, &depth)) { 964208538Sraj 965208538Sraj name = fdt_get_name(fdtp, o, &len); 966208538Sraj 967208538Sraj if (depth > FDT_MAX_DEPTH) { 968208538Sraj printf("max depth exceeded: %d\n", depth); 969208538Sraj continue; 970208538Sraj } 971208538Sraj 972208538Sraj prevname[depth] = name; 973208538Sraj 974208538Sraj /* Skip root (i = 1) when printing devices */ 975208538Sraj for (i = 1; i <= depth; i++) { 976208538Sraj if (prevname[i] == NULL) 977208538Sraj break; 978208538Sraj 979208538Sraj if (strcmp(cwd, "/") == 0) 980208538Sraj printf("/"); 981208538Sraj printf("%s", prevname[i]); 982208538Sraj } 983208538Sraj printf("\n"); 984208538Sraj } 985208538Sraj 986208538Sraj return (CMD_OK); 987208538Sraj} 988208538Sraj 989208538Srajstatic __inline int 990208538Srajisprint(int c) 991208538Sraj{ 992208538Sraj 993208538Sraj return (c >= ' ' && c <= 0x7e); 994208538Sraj} 995208538Sraj 996208538Srajstatic int 997208538Srajfdt_isprint(const void *data, int len, int *count) 998208538Sraj{ 999208538Sraj const char *d; 1000208538Sraj char ch; 1001208538Sraj int yesno, i; 1002208538Sraj 1003208538Sraj if (len == 0) 1004208538Sraj return (0); 1005208538Sraj 1006208538Sraj d = (const char *)data; 1007208538Sraj if (d[len - 1] != '\0') 1008208538Sraj return (0); 1009208538Sraj 1010208538Sraj *count = 0; 1011208538Sraj yesno = 1; 1012208538Sraj for (i = 0; i < len; i++) { 1013208538Sraj ch = *(d + i); 1014208538Sraj if (isprint(ch) || (ch == '\0' && i > 0)) { 1015208538Sraj /* Count strings */ 1016208538Sraj if (ch == '\0') 1017208538Sraj (*count)++; 1018208538Sraj continue; 1019208538Sraj } 1020208538Sraj 1021208538Sraj yesno = 0; 1022208538Sraj break; 1023208538Sraj } 1024208538Sraj 1025208538Sraj return (yesno); 1026208538Sraj} 1027208538Sraj 1028208538Srajstatic int 1029208538Srajfdt_data_str(const void *data, int len, int count, char **buf) 1030208538Sraj{ 1031233323Sraj char *b, *tmp; 1032208538Sraj const char *d; 1033233323Sraj int buf_len, i, l; 1034208538Sraj 1035208538Sraj /* 1036208538Sraj * Calculate the length for the string and allocate memory. 1037208538Sraj * 1038233323Sraj * Note that 'len' already includes at least one terminator. 1039208538Sraj */ 1040233323Sraj buf_len = len; 1041208538Sraj if (count > 1) { 1042208538Sraj /* 1043208538Sraj * Each token had already a terminator buried in 'len', but we 1044208538Sraj * only need one eventually, don't count space for these. 1045208538Sraj */ 1046233323Sraj buf_len -= count - 1; 1047208538Sraj 1048208538Sraj /* Each consecutive token requires a ", " separator. */ 1049233323Sraj buf_len += count * 2; 1050208538Sraj } 1051208538Sraj 1052233323Sraj /* Add some space for surrounding double quotes. */ 1053233323Sraj buf_len += count * 2; 1054233323Sraj 1055233323Sraj /* Note that string being put in 'tmp' may be as big as 'buf_len'. */ 1056233323Sraj b = (char *)malloc(buf_len); 1057233323Sraj tmp = (char *)malloc(buf_len); 1058208538Sraj if (b == NULL) 1059233323Sraj goto error; 1060233323Sraj 1061233323Sraj if (tmp == NULL) { 1062233323Sraj free(b); 1063233323Sraj goto error; 1064233323Sraj } 1065233323Sraj 1066208538Sraj b[0] = '\0'; 1067208538Sraj 1068208538Sraj /* 1069208538Sraj * Now that we have space, format the string. 1070208538Sraj */ 1071208538Sraj i = 0; 1072208538Sraj do { 1073208538Sraj d = (const char *)data + i; 1074208538Sraj l = strlen(d) + 1; 1075208538Sraj 1076208538Sraj sprintf(tmp, "\"%s\"%s", d, 1077208538Sraj (i + l) < len ? ", " : ""); 1078208538Sraj strcat(b, tmp); 1079208538Sraj 1080208538Sraj i += l; 1081208538Sraj 1082208538Sraj } while (i < len); 1083208538Sraj *buf = b; 1084208538Sraj 1085233323Sraj free(tmp); 1086233323Sraj 1087208538Sraj return (0); 1088233323Srajerror: 1089233323Sraj return (1); 1090208538Sraj} 1091208538Sraj 1092208538Srajstatic int 1093208538Srajfdt_data_cell(const void *data, int len, char **buf) 1094208538Sraj{ 1095233323Sraj char *b, *tmp; 1096208538Sraj const uint32_t *c; 1097208538Sraj int count, i, l; 1098208538Sraj 1099208538Sraj /* Number of cells */ 1100208538Sraj count = len / 4; 1101208538Sraj 1102208538Sraj /* 1103208538Sraj * Calculate the length for the string and allocate memory. 1104208538Sraj */ 1105208538Sraj 1106208538Sraj /* Each byte translates to 2 output characters */ 1107208538Sraj l = len * 2; 1108208538Sraj if (count > 1) { 1109208538Sraj /* Each consecutive cell requires a " " separator. */ 1110208538Sraj l += (count - 1) * 1; 1111208538Sraj } 1112208538Sraj /* Each cell will have a "0x" prefix */ 1113208538Sraj l += count * 2; 1114208538Sraj /* Space for surrounding <> and terminator */ 1115208538Sraj l += 3; 1116208538Sraj 1117208538Sraj b = (char *)malloc(l); 1118233323Sraj tmp = (char *)malloc(l); 1119208538Sraj if (b == NULL) 1120233323Sraj goto error; 1121208538Sraj 1122233323Sraj if (tmp == NULL) { 1123233323Sraj free(b); 1124233323Sraj goto error; 1125233323Sraj } 1126233323Sraj 1127208538Sraj b[0] = '\0'; 1128208538Sraj strcat(b, "<"); 1129208538Sraj 1130208538Sraj for (i = 0; i < len; i += 4) { 1131208538Sraj c = (const uint32_t *)((const uint8_t *)data + i); 1132208538Sraj sprintf(tmp, "0x%08x%s", fdt32_to_cpu(*c), 1133208538Sraj i < (len - 4) ? " " : ""); 1134208538Sraj strcat(b, tmp); 1135208538Sraj } 1136208538Sraj strcat(b, ">"); 1137208538Sraj *buf = b; 1138208538Sraj 1139233323Sraj free(tmp); 1140233323Sraj 1141208538Sraj return (0); 1142233323Srajerror: 1143233323Sraj return (1); 1144208538Sraj} 1145208538Sraj 1146208538Srajstatic int 1147208538Srajfdt_data_bytes(const void *data, int len, char **buf) 1148208538Sraj{ 1149233323Sraj char *b, *tmp; 1150208538Sraj const char *d; 1151208538Sraj int i, l; 1152208538Sraj 1153208538Sraj /* 1154208538Sraj * Calculate the length for the string and allocate memory. 1155208538Sraj */ 1156208538Sraj 1157208538Sraj /* Each byte translates to 2 output characters */ 1158208538Sraj l = len * 2; 1159208538Sraj if (len > 1) 1160208538Sraj /* Each consecutive byte requires a " " separator. */ 1161208538Sraj l += (len - 1) * 1; 1162208538Sraj /* Each byte will have a "0x" prefix */ 1163208538Sraj l += len * 2; 1164208538Sraj /* Space for surrounding [] and terminator. */ 1165208538Sraj l += 3; 1166208538Sraj 1167208538Sraj b = (char *)malloc(l); 1168233323Sraj tmp = (char *)malloc(l); 1169208538Sraj if (b == NULL) 1170233323Sraj goto error; 1171208538Sraj 1172233323Sraj if (tmp == NULL) { 1173233323Sraj free(b); 1174233323Sraj goto error; 1175233323Sraj } 1176233323Sraj 1177208538Sraj b[0] = '\0'; 1178208538Sraj strcat(b, "["); 1179208538Sraj 1180208538Sraj for (i = 0, d = data; i < len; i++) { 1181208538Sraj sprintf(tmp, "0x%02x%s", d[i], i < len - 1 ? " " : ""); 1182208538Sraj strcat(b, tmp); 1183208538Sraj } 1184208538Sraj strcat(b, "]"); 1185208538Sraj *buf = b; 1186208538Sraj 1187233323Sraj free(tmp); 1188233323Sraj 1189208538Sraj return (0); 1190233323Srajerror: 1191233323Sraj return (1); 1192208538Sraj} 1193208538Sraj 1194208538Srajstatic int 1195208538Srajfdt_data_fmt(const void *data, int len, char **buf) 1196208538Sraj{ 1197208538Sraj int count; 1198208538Sraj 1199208538Sraj if (len == 0) { 1200208538Sraj *buf = NULL; 1201208538Sraj return (1); 1202208538Sraj } 1203208538Sraj 1204208538Sraj if (fdt_isprint(data, len, &count)) 1205208538Sraj return (fdt_data_str(data, len, count, buf)); 1206208538Sraj 1207208538Sraj else if ((len % 4) == 0) 1208208538Sraj return (fdt_data_cell(data, len, buf)); 1209208538Sraj 1210208538Sraj else 1211208538Sraj return (fdt_data_bytes(data, len, buf)); 1212208538Sraj} 1213208538Sraj 1214208538Srajstatic int 1215208538Srajfdt_prop(int offset) 1216208538Sraj{ 1217208538Sraj char *line, *buf; 1218208538Sraj const struct fdt_property *prop; 1219208538Sraj const char *name; 1220208538Sraj const void *data; 1221208538Sraj int len, rv; 1222208538Sraj 1223208538Sraj line = NULL; 1224208538Sraj prop = fdt_offset_ptr(fdtp, offset, sizeof(*prop)); 1225208538Sraj if (prop == NULL) 1226208538Sraj return (1); 1227208538Sraj 1228208538Sraj name = fdt_string(fdtp, fdt32_to_cpu(prop->nameoff)); 1229208538Sraj len = fdt32_to_cpu(prop->len); 1230208538Sraj 1231208538Sraj rv = 0; 1232208538Sraj buf = NULL; 1233208538Sraj if (len == 0) { 1234208538Sraj /* Property without value */ 1235208538Sraj line = (char *)malloc(strlen(name) + 2); 1236208538Sraj if (line == NULL) { 1237208538Sraj rv = 2; 1238208538Sraj goto out2; 1239208538Sraj } 1240208538Sraj sprintf(line, "%s\n", name); 1241208538Sraj goto out1; 1242208538Sraj } 1243208538Sraj 1244208538Sraj /* 1245208538Sraj * Process property with value 1246208538Sraj */ 1247208538Sraj data = prop->data; 1248208538Sraj 1249208538Sraj if (fdt_data_fmt(data, len, &buf) != 0) { 1250208538Sraj rv = 3; 1251208538Sraj goto out2; 1252208538Sraj } 1253208538Sraj 1254208538Sraj line = (char *)malloc(strlen(name) + strlen(FDT_PROP_SEP) + 1255208538Sraj strlen(buf) + 2); 1256208538Sraj if (line == NULL) { 1257208538Sraj sprintf(command_errbuf, "could not allocate space for string"); 1258208538Sraj rv = 4; 1259208538Sraj goto out2; 1260208538Sraj } 1261208538Sraj 1262208538Sraj sprintf(line, "%s" FDT_PROP_SEP "%s\n", name, buf); 1263208538Sraj 1264208538Srajout1: 1265208538Sraj pager_open(); 1266208538Sraj pager_output(line); 1267208538Sraj pager_close(); 1268208538Sraj 1269208538Srajout2: 1270208538Sraj if (buf) 1271208538Sraj free(buf); 1272208538Sraj 1273208538Sraj if (line) 1274208538Sraj free(line); 1275208538Sraj 1276208538Sraj return (rv); 1277208538Sraj} 1278208538Sraj 1279208538Srajstatic int 1280208538Srajfdt_modprop(int nodeoff, char *propname, void *value, char mode) 1281208538Sraj{ 1282208538Sraj uint32_t cells[100]; 1283208538Sraj char *buf; 1284208538Sraj int len, rv; 1285208538Sraj const struct fdt_property *p; 1286208538Sraj 1287208538Sraj p = fdt_get_property(fdtp, nodeoff, propname, NULL); 1288208538Sraj 1289208538Sraj if (p != NULL) { 1290208538Sraj if (mode == 1) { 1291208538Sraj /* Adding inexistant value in mode 1 is forbidden */ 1292208538Sraj sprintf(command_errbuf, "property already exists!"); 1293208538Sraj return (CMD_ERROR); 1294208538Sraj } 1295208538Sraj } else if (mode == 0) { 1296208538Sraj sprintf(command_errbuf, "property does not exist!"); 1297208538Sraj return (CMD_ERROR); 1298208538Sraj } 1299208538Sraj len = strlen(value); 1300208538Sraj rv = 0; 1301208538Sraj buf = (char *)value; 1302208538Sraj 1303208538Sraj switch (*buf) { 1304208538Sraj case '&': 1305208538Sraj /* phandles */ 1306208538Sraj break; 1307208538Sraj case '<': 1308208538Sraj /* Data cells */ 1309208538Sraj len = fdt_strtovect(buf, (void *)&cells, 100, 1310208538Sraj sizeof(uint32_t)); 1311208538Sraj 1312208538Sraj rv = fdt_setprop(fdtp, nodeoff, propname, &cells, 1313208538Sraj len * sizeof(uint32_t)); 1314208538Sraj break; 1315208538Sraj case '[': 1316208538Sraj /* Data bytes */ 1317208538Sraj len = fdt_strtovect(buf, (void *)&cells, 100, 1318208538Sraj sizeof(uint8_t)); 1319208538Sraj 1320208538Sraj rv = fdt_setprop(fdtp, nodeoff, propname, &cells, 1321208538Sraj len * sizeof(uint8_t)); 1322208538Sraj break; 1323208538Sraj case '"': 1324208538Sraj default: 1325208538Sraj /* Default -- string */ 1326208538Sraj rv = fdt_setprop_string(fdtp, nodeoff, propname, value); 1327208538Sraj break; 1328208538Sraj } 1329208538Sraj 1330233323Sraj if (rv != 0) { 1331233323Sraj if (rv == -FDT_ERR_NOSPACE) 1332233323Sraj sprintf(command_errbuf, 1333233323Sraj "Device tree blob is too small!\n"); 1334233323Sraj else 1335233323Sraj sprintf(command_errbuf, 1336233323Sraj "Could not add/modify property!\n"); 1337235529Skientzle } else { 1338235529Skientzle COPYIN(fdtp, fdtp_va, fdtp_size); 1339233323Sraj } 1340208538Sraj return (rv); 1341208538Sraj} 1342208538Sraj 1343208538Sraj/* Merge strings from argv into a single string */ 1344208538Srajstatic int 1345208538Srajfdt_merge_strings(int argc, char *argv[], int start, char **buffer) 1346208538Sraj{ 1347208538Sraj char *buf; 1348208538Sraj int i, idx, sz; 1349208538Sraj 1350208538Sraj *buffer = NULL; 1351208538Sraj sz = 0; 1352208538Sraj 1353208538Sraj for (i = start; i < argc; i++) 1354208538Sraj sz += strlen(argv[i]); 1355208538Sraj 1356208538Sraj /* Additional bytes for whitespaces between args */ 1357208538Sraj sz += argc - start; 1358208538Sraj 1359208538Sraj buf = (char *)malloc(sizeof(char) * sz); 1360208538Sraj bzero(buf, sizeof(char) * sz); 1361208538Sraj 1362208538Sraj if (buf == NULL) { 1363208538Sraj sprintf(command_errbuf, "could not allocate space " 1364208538Sraj "for string"); 1365208538Sraj return (1); 1366208538Sraj } 1367208538Sraj 1368208538Sraj idx = 0; 1369208538Sraj for (i = start, idx = 0; i < argc; i++) { 1370208538Sraj strcpy(buf + idx, argv[i]); 1371208538Sraj idx += strlen(argv[i]); 1372208538Sraj buf[idx] = ' '; 1373208538Sraj idx++; 1374208538Sraj } 1375208538Sraj buf[sz - 1] = '\0'; 1376208538Sraj *buffer = buf; 1377208538Sraj return (0); 1378208538Sraj} 1379208538Sraj 1380208538Sraj/* Extract offset and name of node/property from a given path */ 1381208538Srajstatic int 1382208538Srajfdt_extract_nameloc(char **pathp, char **namep, int *nodeoff) 1383208538Sraj{ 1384208538Sraj int o; 1385208538Sraj char *path = *pathp, *name = NULL, *subpath = NULL; 1386208538Sraj 1387208538Sraj subpath = strrchr(path, '/'); 1388208538Sraj if (subpath == NULL) { 1389208538Sraj o = fdt_path_offset(fdtp, cwd); 1390208538Sraj name = path; 1391208538Sraj path = (char *)&cwd; 1392208538Sraj } else { 1393208538Sraj *subpath = '\0'; 1394208538Sraj if (strlen(path) == 0) 1395208538Sraj path = cwd; 1396208538Sraj 1397208538Sraj name = subpath + 1; 1398208538Sraj o = fdt_path_offset(fdtp, path); 1399208538Sraj } 1400208538Sraj 1401208538Sraj if (strlen(name) == 0) { 1402208538Sraj sprintf(command_errbuf, "name not specified"); 1403208538Sraj return (1); 1404208538Sraj } 1405208538Sraj if (o < 0) { 1406208538Sraj sprintf(command_errbuf, "could not find node: '%s'", path); 1407208538Sraj return (1); 1408208538Sraj } 1409208538Sraj *namep = name; 1410208538Sraj *nodeoff = o; 1411208538Sraj *pathp = path; 1412208538Sraj return (0); 1413208538Sraj} 1414208538Sraj 1415208538Srajstatic int 1416208538Srajfdt_cmd_prop(int argc, char *argv[]) 1417208538Sraj{ 1418208538Sraj char *path, *propname, *value; 1419208538Sraj int o, next, depth, rv; 1420208538Sraj uint32_t tag; 1421208538Sraj 1422208538Sraj path = (argc > 2) ? argv[2] : NULL; 1423208538Sraj 1424208538Sraj value = NULL; 1425208538Sraj 1426208538Sraj if (argc > 3) { 1427208538Sraj /* Merge property value strings into one */ 1428208538Sraj if (fdt_merge_strings(argc, argv, 3, &value) != 0) 1429208538Sraj return (CMD_ERROR); 1430208538Sraj } else 1431208538Sraj value = NULL; 1432208538Sraj 1433208538Sraj if (path == NULL) 1434208538Sraj path = cwd; 1435208538Sraj 1436208538Sraj rv = CMD_OK; 1437208538Sraj 1438208538Sraj if (value) { 1439208538Sraj /* If value is specified -- try to modify prop. */ 1440208538Sraj if (fdt_extract_nameloc(&path, &propname, &o) != 0) 1441208538Sraj return (CMD_ERROR); 1442208538Sraj 1443208538Sraj rv = fdt_modprop(o, propname, value, 0); 1444208538Sraj if (rv) 1445208538Sraj return (CMD_ERROR); 1446208538Sraj return (CMD_OK); 1447208538Sraj 1448208538Sraj } 1449208538Sraj /* User wants to display properties */ 1450208538Sraj o = fdt_path_offset(fdtp, path); 1451208538Sraj 1452208538Sraj if (o < 0) { 1453208538Sraj sprintf(command_errbuf, "could not find node: '%s'", path); 1454208538Sraj rv = CMD_ERROR; 1455208538Sraj goto out; 1456208538Sraj } 1457208538Sraj 1458208538Sraj depth = 0; 1459208538Sraj while (depth >= 0) { 1460208538Sraj tag = fdt_next_tag(fdtp, o, &next); 1461208538Sraj switch (tag) { 1462208538Sraj case FDT_NOP: 1463208538Sraj break; 1464208538Sraj case FDT_PROP: 1465208538Sraj if (depth > 1) 1466208538Sraj /* Don't process properties of nested nodes */ 1467208538Sraj break; 1468208538Sraj 1469208538Sraj if (fdt_prop(o) != 0) { 1470208538Sraj sprintf(command_errbuf, "could not process " 1471208538Sraj "property"); 1472208538Sraj rv = CMD_ERROR; 1473208538Sraj goto out; 1474208538Sraj } 1475208538Sraj break; 1476208538Sraj case FDT_BEGIN_NODE: 1477208538Sraj depth++; 1478208538Sraj if (depth > FDT_MAX_DEPTH) { 1479208538Sraj printf("warning: nesting too deep: %d\n", 1480208538Sraj depth); 1481208538Sraj goto out; 1482208538Sraj } 1483208538Sraj break; 1484208538Sraj case FDT_END_NODE: 1485208538Sraj depth--; 1486208538Sraj if (depth == 0) 1487208538Sraj /* 1488208538Sraj * This is the end of our starting node, force 1489208538Sraj * the loop finish. 1490208538Sraj */ 1491208538Sraj depth--; 1492208538Sraj break; 1493208538Sraj } 1494208538Sraj o = next; 1495208538Sraj } 1496208538Srajout: 1497208538Sraj return (rv); 1498208538Sraj} 1499208538Sraj 1500208538Srajstatic int 1501208538Srajfdt_cmd_mkprop(int argc, char *argv[]) 1502208538Sraj{ 1503208538Sraj int o; 1504208538Sraj char *path, *propname, *value; 1505208538Sraj 1506208538Sraj path = (argc > 2) ? argv[2] : NULL; 1507208538Sraj 1508208538Sraj value = NULL; 1509208538Sraj 1510208538Sraj if (argc > 3) { 1511208538Sraj /* Merge property value strings into one */ 1512208538Sraj if (fdt_merge_strings(argc, argv, 3, &value) != 0) 1513208538Sraj return (CMD_ERROR); 1514208538Sraj } else 1515208538Sraj value = NULL; 1516208538Sraj 1517208538Sraj if (fdt_extract_nameloc(&path, &propname, &o) != 0) 1518208538Sraj return (CMD_ERROR); 1519208538Sraj 1520208538Sraj if (fdt_modprop(o, propname, value, 1)) 1521208538Sraj return (CMD_ERROR); 1522208538Sraj 1523247045Skientzle COPYIN(fdtp, fdtp_va, fdtp_size); 1524208538Sraj return (CMD_OK); 1525208538Sraj} 1526208538Sraj 1527208538Srajstatic int 1528208538Srajfdt_cmd_rm(int argc, char *argv[]) 1529208538Sraj{ 1530208538Sraj int o, rv; 1531208538Sraj char *path = NULL, *propname; 1532208538Sraj 1533208538Sraj if (argc > 2) 1534208538Sraj path = argv[2]; 1535208538Sraj else { 1536208538Sraj sprintf(command_errbuf, "no node/property name specified"); 1537208538Sraj return (CMD_ERROR); 1538208538Sraj } 1539208538Sraj 1540208538Sraj o = fdt_path_offset(fdtp, path); 1541208538Sraj if (o < 0) { 1542208538Sraj /* If node not found -- try to find & delete property */ 1543208538Sraj if (fdt_extract_nameloc(&path, &propname, &o) != 0) 1544208538Sraj return (CMD_ERROR); 1545208538Sraj 1546208538Sraj if ((rv = fdt_delprop(fdtp, o, propname)) != 0) { 1547208538Sraj sprintf(command_errbuf, "could not delete" 1548208538Sraj "%s\n", (rv == -FDT_ERR_NOTFOUND) ? 1549208538Sraj "(property/node does not exist)" : ""); 1550208538Sraj return (CMD_ERROR); 1551208538Sraj 1552208538Sraj } else 1553208538Sraj return (CMD_OK); 1554208538Sraj } 1555208538Sraj /* If node exists -- remove node */ 1556208538Sraj rv = fdt_del_node(fdtp, o); 1557208538Sraj if (rv) { 1558208538Sraj sprintf(command_errbuf, "could not delete node"); 1559208538Sraj return (CMD_ERROR); 1560235529Skientzle } else { 1561235529Skientzle COPYIN(fdtp, fdtp_va, fdtp_size); 1562208538Sraj } 1563208538Sraj return (CMD_OK); 1564208538Sraj} 1565208538Sraj 1566208538Srajstatic int 1567208538Srajfdt_cmd_mknode(int argc, char *argv[]) 1568208538Sraj{ 1569208538Sraj int o, rv; 1570208538Sraj char *path = NULL, *nodename = NULL; 1571208538Sraj 1572208538Sraj if (argc > 2) 1573208538Sraj path = argv[2]; 1574208538Sraj else { 1575208538Sraj sprintf(command_errbuf, "no node name specified"); 1576208538Sraj return (CMD_ERROR); 1577208538Sraj } 1578208538Sraj 1579208538Sraj if (fdt_extract_nameloc(&path, &nodename, &o) != 0) 1580208538Sraj return (CMD_ERROR); 1581208538Sraj 1582208538Sraj rv = fdt_add_subnode(fdtp, o, nodename); 1583208538Sraj 1584208538Sraj if (rv < 0) { 1585233323Sraj if (rv == -FDT_ERR_NOSPACE) 1586233323Sraj sprintf(command_errbuf, 1587233323Sraj "Device tree blob is too small!\n"); 1588233323Sraj else 1589233323Sraj sprintf(command_errbuf, 1590233323Sraj "Could not add node!\n"); 1591208538Sraj return (CMD_ERROR); 1592235529Skientzle } else { 1593235529Skientzle COPYIN(fdtp, fdtp_va, fdtp_size); 1594208538Sraj } 1595208538Sraj return (CMD_OK); 1596208538Sraj} 1597208538Sraj 1598208538Srajstatic int 1599208538Srajfdt_cmd_pwd(int argc, char *argv[]) 1600208538Sraj{ 1601233323Sraj char line[FDT_CWD_LEN]; 1602208538Sraj 1603208538Sraj pager_open(); 1604208538Sraj sprintf(line, "%s\n", cwd); 1605208538Sraj pager_output(line); 1606208538Sraj pager_close(); 1607208538Sraj return (CMD_OK); 1608208538Sraj} 1609208538Sraj 1610208538Srajstatic int 1611243693Sgonzofdt_cmd_mres(int argc, char *argv[]) 1612243693Sgonzo{ 1613243693Sgonzo uint64_t start, size; 1614243693Sgonzo int i, total; 1615243693Sgonzo char line[80]; 1616243693Sgonzo 1617243693Sgonzo pager_open(); 1618243693Sgonzo total = fdt_num_mem_rsv(fdtp); 1619243693Sgonzo if (total > 0) { 1620243693Sgonzo pager_output("Reserved memory regions:\n"); 1621243693Sgonzo for (i = 0; i < total; i++) { 1622243693Sgonzo fdt_get_mem_rsv(fdtp, i, &start, &size); 1623243693Sgonzo sprintf(line, "reg#%d: (start: 0x%jx, size: 0x%jx)\n", 1624243693Sgonzo i, start, size); 1625243693Sgonzo pager_output(line); 1626243693Sgonzo } 1627243693Sgonzo } else 1628243693Sgonzo pager_output("No reserved memory regions\n"); 1629243693Sgonzo pager_close(); 1630243693Sgonzo 1631243693Sgonzo return (CMD_OK); 1632243693Sgonzo} 1633243693Sgonzo 1634243693Sgonzostatic int 1635208538Srajfdt_cmd_nyi(int argc, char *argv[]) 1636208538Sraj{ 1637208538Sraj 1638208538Sraj printf("command not yet implemented\n"); 1639208538Sraj return (CMD_ERROR); 1640208538Sraj} 1641