fdt_loader_cmd.c revision 233323
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 233323 2012-03-22 20:34:26Z raj $"); 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#define DEBUG 44208538Sraj 45208538Sraj#ifdef DEBUG 46208538Sraj#define debugf(fmt, args...) do { printf("%s(): ", __func__); \ 47208538Sraj printf(fmt,##args); } while (0) 48208538Sraj#else 49208538Sraj#define debugf(fmt, args...) 50208538Sraj#endif 51208538Sraj 52208538Sraj#define FDT_CWD_LEN 256 53208538Sraj#define FDT_MAX_DEPTH 6 54208538Sraj 55208538Sraj#define FDT_PROP_SEP " = " 56208538Sraj 57208538Sraj#define STR(number) #number 58208538Sraj#define STRINGIFY(number) STR(number) 59208538Sraj 60233230Sraj#define COPYOUT(s,d,l) archsw.arch_copyout((vm_offset_t)(s), d, l) 61233230Sraj 62233230Sraj#define FDT_STATIC_DTB_SYMBOL "fdt_static_dtb" 63233230Sraj 64208538Srajstatic struct fdt_header *fdtp = NULL; 65208538Sraj 66208538Srajstatic int fdt_cmd_nyi(int argc, char *argv[]); 67208538Sraj 68208538Srajstatic int fdt_cmd_mkprop(int argc, char *argv[]); 69208538Srajstatic int fdt_cmd_cd(int argc, char *argv[]); 70208538Srajstatic int fdt_cmd_hdr(int argc, char *argv[]); 71208538Srajstatic int fdt_cmd_ls(int argc, char *argv[]); 72208538Srajstatic int fdt_cmd_prop(int argc, char *argv[]); 73208538Srajstatic int fdt_cmd_pwd(int argc, char *argv[]); 74208538Srajstatic int fdt_cmd_rm(int argc, char *argv[]); 75208538Srajstatic int fdt_cmd_mknode(int argc, char *argv[]); 76208538Sraj 77208538Srajtypedef int cmdf_t(int, char *[]); 78208538Sraj 79208538Srajstruct cmdtab { 80208538Sraj char *name; 81208538Sraj cmdf_t *handler; 82208538Sraj}; 83208538Sraj 84208538Srajstatic const struct cmdtab commands[] = { 85208538Sraj { "alias", &fdt_cmd_nyi }, 86208538Sraj { "cd", &fdt_cmd_cd }, 87208538Sraj { "header", &fdt_cmd_hdr }, 88208538Sraj { "ls", &fdt_cmd_ls }, 89208538Sraj { "mknode", &fdt_cmd_mknode }, 90208538Sraj { "mkprop", &fdt_cmd_mkprop }, 91208538Sraj { "mres", &fdt_cmd_nyi }, 92208538Sraj { "prop", &fdt_cmd_prop }, 93208538Sraj { "pwd", &fdt_cmd_pwd }, 94208538Sraj { "rm", &fdt_cmd_rm }, 95208538Sraj { NULL, NULL } 96208538Sraj}; 97208538Sraj 98208538Srajstatic char cwd[FDT_CWD_LEN] = "/"; 99208538Sraj 100233230Srajstatic vm_offset_t 101233230Srajfdt_find_static_dtb(void) 102233230Sraj{ 103233230Sraj Elf_Sym sym; 104233230Sraj vm_offset_t dyntab, esym; 105233230Sraj uint64_t offs; 106233230Sraj struct preloaded_file *kfp; 107233230Sraj struct file_metadata *md; 108233230Sraj Elf_Sym *symtab; 109233230Sraj Elf_Dyn *dyn; 110233230Sraj char *strtab, *strp; 111233323Sraj int i, sym_count; 112233230Sraj 113233323Sraj symtab = NULL; 114233323Sraj dyntab = esym = 0; 115233323Sraj strtab = strp = NULL; 116233230Sraj 117233230Sraj offs = __elfN(relocation_offset); 118233230Sraj 119233230Sraj kfp = file_findfile(NULL, NULL); 120233230Sraj if (kfp == NULL) 121233230Sraj return (0); 122233230Sraj 123233230Sraj md = file_findmetadata(kfp, MODINFOMD_ESYM); 124233230Sraj if (md == NULL) 125233230Sraj return (0); 126233230Sraj COPYOUT(md->md_data, &esym, sizeof(esym)); 127233230Sraj 128233230Sraj md = file_findmetadata(kfp, MODINFOMD_DYNAMIC); 129233230Sraj if (md == NULL) 130233230Sraj return (0); 131233230Sraj COPYOUT(md->md_data, &dyntab, sizeof(dyntab)); 132233323Sraj 133233230Sraj dyntab += offs; 134233230Sraj 135233230Sraj /* Locate STRTAB and DYNTAB */ 136233230Sraj for (dyn = (Elf_Dyn *)dyntab; dyn->d_tag != DT_NULL; dyn++) { 137233230Sraj if (dyn->d_tag == DT_STRTAB) { 138233230Sraj strtab = (char *)(uintptr_t)(dyn->d_un.d_ptr + offs); 139233230Sraj continue; 140233230Sraj } else if (dyn->d_tag == DT_SYMTAB) { 141233230Sraj symtab = (Elf_Sym *)(uintptr_t) 142233230Sraj (dyn->d_un.d_ptr + offs); 143233230Sraj continue; 144233230Sraj } 145233230Sraj } 146233230Sraj 147233230Sraj if (symtab == NULL || strtab == NULL) { 148233230Sraj /* 149233230Sraj * No symtab? No strtab? That should not happen here, 150233230Sraj * and should have been verified during __elfN(loadimage). 151233230Sraj * This must be some kind of a bug. 152233230Sraj */ 153233230Sraj return (0); 154233230Sraj } 155233230Sraj 156233323Sraj sym_count = (int)((Elf_Sym *)esym - symtab) / sizeof(Elf_Sym); 157233323Sraj 158233230Sraj /* 159233230Sraj * The most efficent way to find a symbol would be to calculate a 160233230Sraj * hash, find proper bucket and chain, and thus find a symbol. 161233230Sraj * However, that would involve code duplication (e.g. for hash 162233230Sraj * function). So we're using simpler and a bit slower way: we're 163233230Sraj * iterating through symbols, searching for the one which name is 164233230Sraj * 'equal' to 'fdt_static_dtb'. To speed up the process a little bit, 165233230Sraj * we are eliminating symbols type of which is not STT_NOTYPE, or(and) 166233230Sraj * those which binding attribute is not STB_GLOBAL. 167233230Sraj */ 168233323Sraj for (i = 0; i < sym_count; i++) { 169233230Sraj COPYOUT(symtab + i, &sym, sizeof(sym)); 170233230Sraj if (ELF_ST_BIND(sym.st_info) != STB_GLOBAL || 171233230Sraj ELF_ST_TYPE(sym.st_info) != STT_NOTYPE) 172233230Sraj continue; 173233230Sraj 174233230Sraj strp = strdupout((vm_offset_t)(strtab + sym.st_name)); 175233230Sraj if (strcmp(strp, FDT_STATIC_DTB_SYMBOL) == 0) { 176233230Sraj /* Found a match ! */ 177233230Sraj free(strp); 178233230Sraj return ((vm_offset_t)(sym.st_value + offs)); 179233230Sraj } 180233230Sraj free(strp); 181233230Sraj } 182233230Sraj return (0); 183233230Sraj} 184233230Sraj 185208538Srajstatic int 186208538Srajfdt_setup_fdtp() 187208538Sraj{ 188208538Sraj struct preloaded_file *bfp; 189208538Sraj int err; 190208538Sraj 191208538Sraj /* 192208538Sraj * Find the device tree blob. 193208538Sraj */ 194208538Sraj bfp = file_findfile(NULL, "dtb"); 195208538Sraj if (bfp == NULL) { 196233323Sraj if ((fdtp = (struct fdt_header *)fdt_find_static_dtb()) == 0) { 197233230Sraj command_errmsg = "no device tree blob found!"; 198233230Sraj return (CMD_ERROR); 199233230Sraj } 200233230Sraj } else { 201233230Sraj /* Dynamic blob has precedence over static. */ 202233230Sraj fdtp = (struct fdt_header *)bfp->f_addr; 203208538Sraj } 204208538Sraj 205208538Sraj /* 206208538Sraj * Validate the blob. 207208538Sraj */ 208208538Sraj err = fdt_check_header(fdtp); 209208538Sraj if (err < 0) { 210208538Sraj if (err == -FDT_ERR_BADVERSION) 211208538Sraj sprintf(command_errbuf, 212208538Sraj "incompatible blob version: %d, should be: %d", 213208538Sraj fdt_version(fdtp), FDT_LAST_SUPPORTED_VERSION); 214208538Sraj 215208538Sraj else 216208538Sraj sprintf(command_errbuf, "error validating blob: %s", 217208538Sraj fdt_strerror(err)); 218208538Sraj return (CMD_ERROR); 219208538Sraj } 220208538Sraj return (CMD_OK); 221208538Sraj} 222208538Sraj 223208538Sraj#define fdt_strtovect(str, cellbuf, lim, cellsize) _fdt_strtovect((str), \ 224208538Sraj (cellbuf), (lim), (cellsize), 0); 225208538Sraj 226208538Sraj/* Force using base 16 */ 227208538Sraj#define fdt_strtovectx(str, cellbuf, lim, cellsize) _fdt_strtovect((str), \ 228208538Sraj (cellbuf), (lim), (cellsize), 16); 229208538Sraj 230208538Srajstatic int 231208538Sraj_fdt_strtovect(char *str, void *cellbuf, int lim, unsigned char cellsize, 232208538Sraj uint8_t base) 233208538Sraj{ 234208538Sraj char *buf = str; 235208538Sraj char *end = str + strlen(str) - 2; 236208538Sraj uint32_t *u32buf = NULL; 237208538Sraj uint8_t *u8buf = NULL; 238208538Sraj int cnt = 0; 239208538Sraj 240208538Sraj if (cellsize == sizeof(uint32_t)) 241208538Sraj u32buf = (uint32_t *)cellbuf; 242208538Sraj else 243208538Sraj u8buf = (uint8_t *)cellbuf; 244208538Sraj 245208538Sraj if (lim == 0) 246208538Sraj return (0); 247208538Sraj 248208538Sraj while (buf < end) { 249208538Sraj 250208538Sraj /* Skip white whitespace(s)/separators */ 251208538Sraj while (!isxdigit(*buf) && buf < end) 252208538Sraj buf++; 253208538Sraj 254208538Sraj if (u32buf != NULL) 255208538Sraj u32buf[cnt] = 256208538Sraj cpu_to_fdt32((uint32_t)strtol(buf, NULL, base)); 257208538Sraj 258208538Sraj else 259208538Sraj u8buf[cnt] = (uint8_t)strtol(buf, NULL, base); 260208538Sraj 261208538Sraj if (cnt + 1 <= lim - 1) 262208538Sraj cnt++; 263208538Sraj else 264208538Sraj break; 265208538Sraj buf++; 266208538Sraj /* Find another number */ 267208538Sraj while ((isxdigit(*buf) || *buf == 'x') && buf < end) 268208538Sraj buf++; 269208538Sraj } 270208538Sraj return (cnt); 271208538Sraj} 272208538Sraj 273208538Sraj#define TMP_MAX_ETH 8 274208538Sraj 275208538Srajvoid 276208538Srajfixup_ethernet(const char *env, char *ethstr, int *eth_no, int len) 277208538Sraj{ 278208538Sraj char *end, *str; 279208538Sraj uint8_t tmp_addr[6]; 280208538Sraj int i, n; 281208538Sraj 282208538Sraj /* Extract interface number */ 283208538Sraj i = strtol(env + 3, &end, 10); 284208538Sraj if (end == (env + 3)) 285208538Sraj /* 'ethaddr' means interface 0 address */ 286208538Sraj n = 0; 287208538Sraj else 288208538Sraj n = i; 289208538Sraj 290208538Sraj if (n > TMP_MAX_ETH) 291208538Sraj return; 292208538Sraj 293208538Sraj str = ub_env_get(env); 294208538Sraj 295208538Sraj /* Convert macaddr string into a vector of uints */ 296208538Sraj fdt_strtovectx(str, &tmp_addr, 6, sizeof(uint8_t)); 297208538Sraj if (n != 0) { 298208538Sraj i = strlen(env) - 7; 299208538Sraj strncpy(ethstr + 8, env + 3, i); 300208538Sraj } 301208538Sraj /* Set actual property to a value from vect */ 302208538Sraj fdt_setprop(fdtp, fdt_path_offset(fdtp, ethstr), 303208538Sraj "local-mac-address", &tmp_addr, 6 * sizeof(uint8_t)); 304208538Sraj 305208538Sraj /* Clear ethernet..XXXX.. string */ 306208538Sraj bzero(ethstr + 8, len - 8); 307208538Sraj 308208538Sraj if (n + 1 > *eth_no) 309208538Sraj *eth_no = n + 1; 310208538Sraj} 311208538Sraj 312208538Srajvoid 313208538Srajfixup_cpubusfreqs(unsigned long cpufreq, unsigned long busfreq) 314208538Sraj{ 315208538Sraj int lo, o = 0, o2, maxo = 0, depth; 316208538Sraj const uint32_t zero = 0; 317208538Sraj 318208538Sraj /* We want to modify every subnode of /cpus */ 319208538Sraj o = fdt_path_offset(fdtp, "/cpus"); 320208538Sraj 321208538Sraj /* maxo should contain offset of node next to /cpus */ 322208538Sraj depth = 0; 323208538Sraj maxo = o; 324208538Sraj while (depth != -1) 325208538Sraj maxo = fdt_next_node(fdtp, maxo, &depth); 326208538Sraj 327208538Sraj /* Find CPU frequency properties */ 328208538Sraj o = fdt_node_offset_by_prop_value(fdtp, o, "clock-frequency", 329208538Sraj &zero, sizeof(uint32_t)); 330208538Sraj 331208538Sraj o2 = fdt_node_offset_by_prop_value(fdtp, o, "bus-frequency", &zero, 332208538Sraj sizeof(uint32_t)); 333208538Sraj 334208538Sraj lo = MIN(o, o2); 335208538Sraj 336208538Sraj while (o != -FDT_ERR_NOTFOUND && o2 != -FDT_ERR_NOTFOUND) { 337208538Sraj 338208538Sraj o = fdt_node_offset_by_prop_value(fdtp, lo, 339208538Sraj "clock-frequency", &zero, sizeof(uint32_t)); 340208538Sraj 341208538Sraj o2 = fdt_node_offset_by_prop_value(fdtp, lo, "bus-frequency", 342208538Sraj &zero, sizeof(uint32_t)); 343208538Sraj 344208538Sraj /* We're only interested in /cpus subnode(s) */ 345208538Sraj if (lo > maxo) 346208538Sraj break; 347208538Sraj 348208538Sraj fdt_setprop_inplace_cell(fdtp, lo, "clock-frequency", 349208538Sraj (uint32_t)cpufreq); 350208538Sraj 351208538Sraj fdt_setprop_inplace_cell(fdtp, lo, "bus-frequency", 352208538Sraj (uint32_t)busfreq); 353208538Sraj 354208538Sraj lo = MIN(o, o2); 355208538Sraj } 356208538Sraj} 357208538Sraj 358208538Srajint 359208538Srajfdt_reg_valid(uint32_t *reg, int len, int addr_cells, int size_cells) 360208538Sraj{ 361208538Sraj int cells_in_tuple, i, tuples, tuple_size; 362208538Sraj uint32_t cur_start, cur_size; 363208538Sraj 364208538Sraj cells_in_tuple = (addr_cells + size_cells); 365208538Sraj tuple_size = cells_in_tuple * sizeof(uint32_t); 366208538Sraj tuples = len / tuple_size; 367208538Sraj if (tuples == 0) 368208538Sraj return (EINVAL); 369208538Sraj 370208538Sraj for (i = 0; i < tuples; i++) { 371208538Sraj if (addr_cells == 2) 372208538Sraj cur_start = fdt64_to_cpu(reg[i * cells_in_tuple]); 373208538Sraj else 374208538Sraj cur_start = fdt32_to_cpu(reg[i * cells_in_tuple]); 375208538Sraj 376208538Sraj if (size_cells == 2) 377208538Sraj cur_size = fdt64_to_cpu(reg[i * cells_in_tuple + 2]); 378208538Sraj else 379208538Sraj cur_size = fdt32_to_cpu(reg[i * cells_in_tuple + 1]); 380208538Sraj 381208538Sraj if (cur_size == 0) 382208538Sraj return (EINVAL); 383208538Sraj 384208538Sraj debugf(" reg#%d (start: 0x%0x size: 0x%0x) valid!\n", 385208538Sraj i, cur_start, cur_size); 386208538Sraj } 387208538Sraj return (0); 388208538Sraj} 389208538Sraj 390208538Srajvoid 391208538Srajfixup_memory(struct sys_info *si) 392208538Sraj{ 393208538Sraj struct mem_region *curmr; 394208538Sraj uint32_t addr_cells, size_cells; 395208538Sraj uint32_t *addr_cellsp, *reg, *size_cellsp; 396208538Sraj int err, i, len, memory, realmrno, root; 397208538Sraj uint8_t *buf, *sb; 398208538Sraj 399208538Sraj root = fdt_path_offset(fdtp, "/"); 400208538Sraj if (root < 0) { 401208538Sraj sprintf(command_errbuf, "Could not find root node !"); 402208538Sraj return; 403208538Sraj } 404208538Sraj 405208538Sraj memory = fdt_path_offset(fdtp, "/memory"); 406208538Sraj if (memory <= 0) { 407208538Sraj /* Create proper '/memory' node. */ 408208538Sraj memory = fdt_add_subnode(fdtp, root, "memory"); 409208538Sraj if (memory <= 0) { 410208538Sraj sprintf(command_errbuf, "Could not fixup '/memory' " 411208538Sraj "node, error code : %d!\n", memory); 412208538Sraj return; 413208538Sraj } 414208538Sraj 415208538Sraj err = fdt_setprop(fdtp, memory, "device_type", "memory", 416208538Sraj sizeof("memory")); 417208538Sraj 418208538Sraj if (err < 0) 419208538Sraj return; 420208538Sraj } 421208538Sraj 422208538Sraj addr_cellsp = (uint32_t *)fdt_getprop(fdtp, root, "#address-cells", 423208538Sraj NULL); 424208538Sraj size_cellsp = (uint32_t *)fdt_getprop(fdtp, root, "#size-cells", NULL); 425208538Sraj 426208538Sraj if (addr_cellsp == NULL || size_cellsp == NULL) { 427208538Sraj sprintf(command_errbuf, "Could not fixup '/memory' node : " 428208538Sraj "%s %s property not found in root node!\n", 429208538Sraj (!addr_cellsp) ? "#address-cells" : "", 430208538Sraj (!size_cellsp) ? "#size-cells" : ""); 431208538Sraj return; 432208538Sraj } 433208538Sraj 434208538Sraj addr_cells = fdt32_to_cpu(*addr_cellsp); 435208538Sraj size_cells = fdt32_to_cpu(*size_cellsp); 436208538Sraj 437208538Sraj /* Count valid memory regions entries in sysinfo. */ 438208538Sraj realmrno = si->mr_no; 439208538Sraj for (i = 0; i < si->mr_no; i++) 440208538Sraj if (si->mr[i].start == 0 && si->mr[i].size == 0) 441208538Sraj realmrno--; 442208538Sraj 443208538Sraj if (realmrno == 0) { 444208538Sraj sprintf(command_errbuf, "Could not fixup '/memory' node : " 445208538Sraj "sysinfo doesn't contain valid memory regions info!\n"); 446208538Sraj return; 447208538Sraj } 448208538Sraj 449208538Sraj if ((reg = (uint32_t *)fdt_getprop(fdtp, memory, "reg", 450208538Sraj &len)) != NULL) { 451208538Sraj 452208538Sraj if (fdt_reg_valid(reg, len, addr_cells, size_cells) == 0) 453208538Sraj /* 454208538Sraj * Do not apply fixup if existing 'reg' property 455208538Sraj * seems to be valid. 456208538Sraj */ 457208538Sraj return; 458208538Sraj } 459208538Sraj 460208538Sraj len = (addr_cells + size_cells) * realmrno * sizeof(uint32_t); 461208538Sraj sb = buf = (uint8_t *)malloc(len); 462208538Sraj if (!buf) 463208538Sraj return; 464208538Sraj 465208538Sraj bzero(buf, len); 466208538Sraj 467208538Sraj for (i = 0; i < si->mr_no; i++) { 468208538Sraj curmr = &si->mr[i]; 469208538Sraj if (curmr->size != 0) { 470208538Sraj /* Ensure endianess, and put cells into a buffer */ 471208538Sraj if (addr_cells == 2) 472208538Sraj *(uint64_t *)buf = 473208538Sraj cpu_to_fdt64(curmr->start); 474208538Sraj else 475208538Sraj *(uint32_t *)buf = 476208538Sraj cpu_to_fdt32(curmr->start); 477208538Sraj 478208538Sraj buf += sizeof(uint32_t) * addr_cells; 479208538Sraj if (size_cells == 2) 480208538Sraj *(uint64_t *)buf = 481208538Sraj cpu_to_fdt64(curmr->size); 482208538Sraj else 483208538Sraj *(uint32_t *)buf = 484208538Sraj cpu_to_fdt32(curmr->size); 485208538Sraj 486208538Sraj buf += sizeof(uint32_t) * size_cells; 487208538Sraj } 488208538Sraj } 489208538Sraj 490208538Sraj /* Set property */ 491208538Sraj if ((err = fdt_setprop(fdtp, memory, "reg", sb, len)) < 0) 492208538Sraj sprintf(command_errbuf, "Could not fixup '/memory' node.\n"); 493208538Sraj} 494208538Sraj 495208538Srajvoid 496208538Srajfixup_stdout(const char *env) 497208538Sraj{ 498208538Sraj const char *str; 499208538Sraj char *ptr; 500208538Sraj int serialno; 501208538Sraj int len, no, sero; 502208538Sraj const struct fdt_property *prop; 503208538Sraj char *tmp[10]; 504208538Sraj 505208538Sraj str = ub_env_get(env); 506208538Sraj ptr = (char *)str + strlen(str) - 1; 507208538Sraj while (ptr > str && isdigit(*(str - 1))) 508208538Sraj str--; 509208538Sraj 510208538Sraj if (ptr == str) 511208538Sraj return; 512208538Sraj 513208538Sraj serialno = (int)strtol(ptr, NULL, 0); 514208538Sraj no = fdt_path_offset(fdtp, "/chosen"); 515208538Sraj if (no < 0) 516208538Sraj return; 517208538Sraj 518208538Sraj prop = fdt_get_property(fdtp, no, "stdout", &len); 519208538Sraj 520208538Sraj /* If /chosen/stdout does not extist, create it */ 521208538Sraj if (prop == NULL || (prop != NULL && len == 0)) { 522208538Sraj 523208538Sraj bzero(tmp, 10 * sizeof(char)); 524208538Sraj strcpy((char *)&tmp, "serial"); 525208538Sraj if (strlen(ptr) > 3) 526208538Sraj /* Serial number too long */ 527208538Sraj return; 528208538Sraj 529208538Sraj strncpy((char *)tmp + 6, ptr, 3); 530208538Sraj sero = fdt_path_offset(fdtp, (const char *)tmp); 531208538Sraj if (sero < 0) 532208538Sraj /* 533208538Sraj * If serial device we're trying to assign 534208538Sraj * stdout to doesn't exist in DT -- return. 535208538Sraj */ 536208538Sraj return; 537208538Sraj 538208538Sraj fdt_setprop(fdtp, no, "stdout", &tmp, 539208538Sraj strlen((char *)&tmp) + 1); 540208538Sraj fdt_setprop(fdtp, no, "stdin", &tmp, 541208538Sraj strlen((char *)&tmp) + 1); 542208538Sraj } 543208538Sraj} 544208538Sraj 545233230Sraj/* 546233230Sraj * Locate the blob, fix it up and return its location. 547233230Sraj */ 548233230Srajvoid * 549208538Srajfdt_fixup(void) 550208538Sraj{ 551208538Sraj const char *env; 552208538Sraj char *ethstr; 553208538Sraj int chosen, err, eth_no, len; 554208538Sraj struct sys_info *si; 555208538Sraj 556208538Sraj env = NULL; 557208538Sraj eth_no = 0; 558208538Sraj ethstr = NULL; 559208538Sraj len = 0; 560208538Sraj 561233230Sraj err = fdt_setup_fdtp(); 562233230Sraj if (err) { 563233230Sraj sprintf(command_errbuf, "No valid device tree blob found!"); 564233230Sraj return (NULL); 565208538Sraj } 566208538Sraj 567208538Sraj /* Create /chosen node (if not exists) */ 568208538Sraj if ((chosen = fdt_subnode_offset(fdtp, 0, "chosen")) == 569208538Sraj -FDT_ERR_NOTFOUND) 570208538Sraj chosen = fdt_add_subnode(fdtp, 0, "chosen"); 571208538Sraj 572208538Sraj /* Value assigned to fixup-applied does not matter. */ 573208538Sraj if (fdt_getprop(fdtp, chosen, "fixup-applied", NULL)) 574233230Sraj goto success; 575208538Sraj 576208538Sraj /* Acquire sys_info */ 577208538Sraj si = ub_get_sys_info(); 578208538Sraj 579208538Sraj while ((env = ub_env_enum(env)) != NULL) { 580208538Sraj if (strncmp(env, "eth", 3) == 0 && 581208538Sraj strncmp(env + (strlen(env) - 4), "addr", 4) == 0) { 582208538Sraj /* 583208538Sraj * Handle Ethernet addrs: parse uboot env eth%daddr 584208538Sraj */ 585208538Sraj 586208538Sraj if (!eth_no) { 587208538Sraj /* 588208538Sraj * Check how many chars we will need to store 589208538Sraj * maximal eth iface number. 590208538Sraj */ 591208538Sraj len = strlen(STRINGIFY(TMP_MAX_ETH)) + 592208538Sraj strlen("ethernet"); 593208538Sraj 594208538Sraj /* 595208538Sraj * Reserve mem for string "ethernet" and len 596208538Sraj * chars for iface no. 597208538Sraj */ 598208538Sraj ethstr = (char *)malloc(len * sizeof(char)); 599208538Sraj bzero(ethstr, len * sizeof(char)); 600208538Sraj strcpy(ethstr, "ethernet0"); 601208538Sraj } 602208538Sraj 603208538Sraj /* Modify blob */ 604208538Sraj fixup_ethernet(env, ethstr, ð_no, len); 605208538Sraj 606208538Sraj } else if (strcmp(env, "consoledev") == 0) 607208538Sraj fixup_stdout(env); 608208538Sraj } 609208538Sraj 610208538Sraj /* Modify cpu(s) and bus clock frequenties in /cpus node [Hz] */ 611208538Sraj fixup_cpubusfreqs(si->clk_cpu, si->clk_bus); 612208538Sraj 613208538Sraj /* Fixup memory regions */ 614208538Sraj fixup_memory(si); 615208538Sraj 616208538Sraj fdt_setprop(fdtp, chosen, "fixup-applied", NULL, 0); 617208538Sraj 618233230Srajsuccess: 619233230Sraj return (fdtp); 620208538Sraj} 621208538Sraj 622208538Srajint 623208538Srajcommand_fdt_internal(int argc, char *argv[]) 624208538Sraj{ 625208538Sraj cmdf_t *cmdh; 626208538Sraj char *cmd; 627208538Sraj int i, err; 628208538Sraj 629208538Sraj if (argc < 2) { 630208538Sraj command_errmsg = "usage is 'fdt <command> [<args>]"; 631208538Sraj return (CMD_ERROR); 632208538Sraj } 633208538Sraj 634208538Sraj /* 635208538Sraj * Check if uboot env vars were parsed already. If not, do it now. 636208538Sraj */ 637233230Sraj if (fdt_fixup() == NULL) 638233230Sraj return (CMD_ERROR); 639208538Sraj 640208538Sraj /* 641208538Sraj * Validate fdt <command>. 642208538Sraj */ 643208538Sraj cmd = strdup(argv[1]); 644208538Sraj i = 0; 645208538Sraj cmdh = NULL; 646208538Sraj while (!(commands[i].name == NULL)) { 647208538Sraj if (strcmp(cmd, commands[i].name) == 0) { 648208538Sraj /* found it */ 649208538Sraj cmdh = commands[i].handler; 650208538Sraj break; 651208538Sraj } 652208538Sraj i++; 653208538Sraj } 654208538Sraj if (cmdh == NULL) { 655208538Sraj command_errmsg = "unknown command"; 656208538Sraj return (CMD_ERROR); 657208538Sraj } 658208538Sraj 659208538Sraj /* 660208538Sraj * Call command handler. 661208538Sraj */ 662208538Sraj err = (*cmdh)(argc, argv); 663208538Sraj 664208538Sraj return (err); 665208538Sraj} 666208538Sraj 667208538Srajstatic int 668208538Srajfdt_cmd_cd(int argc, char *argv[]) 669208538Sraj{ 670208538Sraj char *path; 671208538Sraj char tmp[FDT_CWD_LEN]; 672208538Sraj int len, o; 673208538Sraj 674208538Sraj path = (argc > 2) ? argv[2] : "/"; 675208538Sraj 676208538Sraj if (path[0] == '/') { 677208538Sraj len = strlen(path); 678208538Sraj if (len >= FDT_CWD_LEN) 679208538Sraj goto fail; 680208538Sraj } else { 681208538Sraj /* Handle path specification relative to cwd */ 682208538Sraj len = strlen(cwd) + strlen(path) + 1; 683208538Sraj if (len >= FDT_CWD_LEN) 684208538Sraj goto fail; 685208538Sraj 686208538Sraj strcpy(tmp, cwd); 687208538Sraj strcat(tmp, "/"); 688208538Sraj strcat(tmp, path); 689208538Sraj path = tmp; 690208538Sraj } 691208538Sraj 692208538Sraj o = fdt_path_offset(fdtp, path); 693208538Sraj if (o < 0) { 694208538Sraj sprintf(command_errbuf, "could not find node: '%s'", path); 695208538Sraj return (CMD_ERROR); 696208538Sraj } 697208538Sraj 698208538Sraj strcpy(cwd, path); 699208538Sraj return (CMD_OK); 700208538Sraj 701208538Srajfail: 702208538Sraj sprintf(command_errbuf, "path too long: %d, max allowed: %d", 703208538Sraj len, FDT_CWD_LEN - 1); 704208538Sraj return (CMD_ERROR); 705208538Sraj} 706208538Sraj 707208538Srajstatic int 708208538Srajfdt_cmd_hdr(int argc __unused, char *argv[] __unused) 709208538Sraj{ 710208538Sraj char line[80]; 711208538Sraj int ver; 712208538Sraj 713208538Sraj if (fdtp == NULL) { 714208538Sraj command_errmsg = "no device tree blob pointer?!"; 715208538Sraj return (CMD_ERROR); 716208538Sraj } 717208538Sraj 718208538Sraj ver = fdt_version(fdtp); 719208538Sraj pager_open(); 720208538Sraj sprintf(line, "\nFlattened device tree header (%p):\n", fdtp); 721208538Sraj pager_output(line); 722208538Sraj sprintf(line, " magic = 0x%08x\n", fdt_magic(fdtp)); 723208538Sraj pager_output(line); 724208538Sraj sprintf(line, " size = %d\n", fdt_totalsize(fdtp)); 725208538Sraj pager_output(line); 726208538Sraj sprintf(line, " off_dt_struct = 0x%08x\n", 727208538Sraj fdt_off_dt_struct(fdtp)); 728208538Sraj pager_output(line); 729208538Sraj sprintf(line, " off_dt_strings = 0x%08x\n", 730208538Sraj fdt_off_dt_strings(fdtp)); 731208538Sraj pager_output(line); 732208538Sraj sprintf(line, " off_mem_rsvmap = 0x%08x\n", 733208538Sraj fdt_off_mem_rsvmap(fdtp)); 734208538Sraj pager_output(line); 735208538Sraj sprintf(line, " version = %d\n", ver); 736208538Sraj pager_output(line); 737208538Sraj sprintf(line, " last compatible version = %d\n", 738208538Sraj fdt_last_comp_version(fdtp)); 739208538Sraj pager_output(line); 740208538Sraj if (ver >= 2) { 741208538Sraj sprintf(line, " boot_cpuid = %d\n", 742208538Sraj fdt_boot_cpuid_phys(fdtp)); 743208538Sraj pager_output(line); 744208538Sraj } 745208538Sraj if (ver >= 3) { 746208538Sraj sprintf(line, " size_dt_strings = %d\n", 747208538Sraj fdt_size_dt_strings(fdtp)); 748208538Sraj pager_output(line); 749208538Sraj } 750208538Sraj if (ver >= 17) { 751208538Sraj sprintf(line, " size_dt_struct = %d\n", 752208538Sraj fdt_size_dt_struct(fdtp)); 753208538Sraj pager_output(line); 754208538Sraj } 755208538Sraj pager_close(); 756208538Sraj 757208538Sraj return (CMD_OK); 758208538Sraj} 759208538Sraj 760208538Srajstatic int 761208538Srajfdt_cmd_ls(int argc, char *argv[]) 762208538Sraj{ 763208538Sraj const char *prevname[FDT_MAX_DEPTH] = { NULL }; 764208538Sraj const char *name; 765208538Sraj char *path; 766208538Sraj int i, o, depth, len; 767208538Sraj 768208538Sraj path = (argc > 2) ? argv[2] : NULL; 769208538Sraj if (path == NULL) 770208538Sraj path = cwd; 771208538Sraj 772208538Sraj o = fdt_path_offset(fdtp, path); 773208538Sraj if (o < 0) { 774208538Sraj sprintf(command_errbuf, "could not find node: '%s'", path); 775208538Sraj return (CMD_ERROR); 776208538Sraj } 777208538Sraj 778208538Sraj for (depth = 0; 779208538Sraj (o >= 0) && (depth >= 0); 780208538Sraj o = fdt_next_node(fdtp, o, &depth)) { 781208538Sraj 782208538Sraj name = fdt_get_name(fdtp, o, &len); 783208538Sraj 784208538Sraj if (depth > FDT_MAX_DEPTH) { 785208538Sraj printf("max depth exceeded: %d\n", depth); 786208538Sraj continue; 787208538Sraj } 788208538Sraj 789208538Sraj prevname[depth] = name; 790208538Sraj 791208538Sraj /* Skip root (i = 1) when printing devices */ 792208538Sraj for (i = 1; i <= depth; i++) { 793208538Sraj if (prevname[i] == NULL) 794208538Sraj break; 795208538Sraj 796208538Sraj if (strcmp(cwd, "/") == 0) 797208538Sraj printf("/"); 798208538Sraj printf("%s", prevname[i]); 799208538Sraj } 800208538Sraj printf("\n"); 801208538Sraj } 802208538Sraj 803208538Sraj return (CMD_OK); 804208538Sraj} 805208538Sraj 806208538Srajstatic __inline int 807208538Srajisprint(int c) 808208538Sraj{ 809208538Sraj 810208538Sraj return (c >= ' ' && c <= 0x7e); 811208538Sraj} 812208538Sraj 813208538Srajstatic int 814208538Srajfdt_isprint(const void *data, int len, int *count) 815208538Sraj{ 816208538Sraj const char *d; 817208538Sraj char ch; 818208538Sraj int yesno, i; 819208538Sraj 820208538Sraj if (len == 0) 821208538Sraj return (0); 822208538Sraj 823208538Sraj d = (const char *)data; 824208538Sraj if (d[len - 1] != '\0') 825208538Sraj return (0); 826208538Sraj 827208538Sraj *count = 0; 828208538Sraj yesno = 1; 829208538Sraj for (i = 0; i < len; i++) { 830208538Sraj ch = *(d + i); 831208538Sraj if (isprint(ch) || (ch == '\0' && i > 0)) { 832208538Sraj /* Count strings */ 833208538Sraj if (ch == '\0') 834208538Sraj (*count)++; 835208538Sraj continue; 836208538Sraj } 837208538Sraj 838208538Sraj yesno = 0; 839208538Sraj break; 840208538Sraj } 841208538Sraj 842208538Sraj return (yesno); 843208538Sraj} 844208538Sraj 845208538Srajstatic int 846208538Srajfdt_data_str(const void *data, int len, int count, char **buf) 847208538Sraj{ 848233323Sraj char *b, *tmp; 849208538Sraj const char *d; 850233323Sraj int buf_len, i, l; 851208538Sraj 852208538Sraj /* 853208538Sraj * Calculate the length for the string and allocate memory. 854208538Sraj * 855233323Sraj * Note that 'len' already includes at least one terminator. 856208538Sraj */ 857233323Sraj buf_len = len; 858208538Sraj if (count > 1) { 859208538Sraj /* 860208538Sraj * Each token had already a terminator buried in 'len', but we 861208538Sraj * only need one eventually, don't count space for these. 862208538Sraj */ 863233323Sraj buf_len -= count - 1; 864208538Sraj 865208538Sraj /* Each consecutive token requires a ", " separator. */ 866233323Sraj buf_len += count * 2; 867208538Sraj } 868208538Sraj 869233323Sraj /* Add some space for surrounding double quotes. */ 870233323Sraj buf_len += count * 2; 871233323Sraj 872233323Sraj /* Note that string being put in 'tmp' may be as big as 'buf_len'. */ 873233323Sraj b = (char *)malloc(buf_len); 874233323Sraj tmp = (char *)malloc(buf_len); 875208538Sraj if (b == NULL) 876233323Sraj goto error; 877233323Sraj 878233323Sraj if (tmp == NULL) { 879233323Sraj free(b); 880233323Sraj goto error; 881233323Sraj } 882233323Sraj 883208538Sraj b[0] = '\0'; 884208538Sraj 885208538Sraj /* 886208538Sraj * Now that we have space, format the string. 887208538Sraj */ 888208538Sraj i = 0; 889208538Sraj do { 890208538Sraj d = (const char *)data + i; 891208538Sraj l = strlen(d) + 1; 892208538Sraj 893208538Sraj sprintf(tmp, "\"%s\"%s", d, 894208538Sraj (i + l) < len ? ", " : ""); 895208538Sraj strcat(b, tmp); 896208538Sraj 897208538Sraj i += l; 898208538Sraj 899208538Sraj } while (i < len); 900208538Sraj *buf = b; 901208538Sraj 902233323Sraj free(tmp); 903233323Sraj 904208538Sraj return (0); 905233323Srajerror: 906233323Sraj return (1); 907208538Sraj} 908208538Sraj 909208538Srajstatic int 910208538Srajfdt_data_cell(const void *data, int len, char **buf) 911208538Sraj{ 912233323Sraj char *b, *tmp; 913208538Sraj const uint32_t *c; 914208538Sraj int count, i, l; 915208538Sraj 916208538Sraj /* Number of cells */ 917208538Sraj count = len / 4; 918208538Sraj 919208538Sraj /* 920208538Sraj * Calculate the length for the string and allocate memory. 921208538Sraj */ 922208538Sraj 923208538Sraj /* Each byte translates to 2 output characters */ 924208538Sraj l = len * 2; 925208538Sraj if (count > 1) { 926208538Sraj /* Each consecutive cell requires a " " separator. */ 927208538Sraj l += (count - 1) * 1; 928208538Sraj } 929208538Sraj /* Each cell will have a "0x" prefix */ 930208538Sraj l += count * 2; 931208538Sraj /* Space for surrounding <> and terminator */ 932208538Sraj l += 3; 933208538Sraj 934208538Sraj b = (char *)malloc(l); 935233323Sraj tmp = (char *)malloc(l); 936208538Sraj if (b == NULL) 937233323Sraj goto error; 938208538Sraj 939233323Sraj if (tmp == NULL) { 940233323Sraj free(b); 941233323Sraj goto error; 942233323Sraj } 943233323Sraj 944208538Sraj b[0] = '\0'; 945208538Sraj strcat(b, "<"); 946208538Sraj 947208538Sraj for (i = 0; i < len; i += 4) { 948208538Sraj c = (const uint32_t *)((const uint8_t *)data + i); 949208538Sraj sprintf(tmp, "0x%08x%s", fdt32_to_cpu(*c), 950208538Sraj i < (len - 4) ? " " : ""); 951208538Sraj strcat(b, tmp); 952208538Sraj } 953208538Sraj strcat(b, ">"); 954208538Sraj *buf = b; 955208538Sraj 956233323Sraj free(tmp); 957233323Sraj 958208538Sraj return (0); 959233323Srajerror: 960233323Sraj return (1); 961208538Sraj} 962208538Sraj 963208538Srajstatic int 964208538Srajfdt_data_bytes(const void *data, int len, char **buf) 965208538Sraj{ 966233323Sraj char *b, *tmp; 967208538Sraj const char *d; 968208538Sraj int i, l; 969208538Sraj 970208538Sraj /* 971208538Sraj * Calculate the length for the string and allocate memory. 972208538Sraj */ 973208538Sraj 974208538Sraj /* Each byte translates to 2 output characters */ 975208538Sraj l = len * 2; 976208538Sraj if (len > 1) 977208538Sraj /* Each consecutive byte requires a " " separator. */ 978208538Sraj l += (len - 1) * 1; 979208538Sraj /* Each byte will have a "0x" prefix */ 980208538Sraj l += len * 2; 981208538Sraj /* Space for surrounding [] and terminator. */ 982208538Sraj l += 3; 983208538Sraj 984208538Sraj b = (char *)malloc(l); 985233323Sraj tmp = (char *)malloc(l); 986208538Sraj if (b == NULL) 987233323Sraj goto error; 988208538Sraj 989233323Sraj if (tmp == NULL) { 990233323Sraj free(b); 991233323Sraj goto error; 992233323Sraj } 993233323Sraj 994208538Sraj b[0] = '\0'; 995208538Sraj strcat(b, "["); 996208538Sraj 997208538Sraj for (i = 0, d = data; i < len; i++) { 998208538Sraj sprintf(tmp, "0x%02x%s", d[i], i < len - 1 ? " " : ""); 999208538Sraj strcat(b, tmp); 1000208538Sraj } 1001208538Sraj strcat(b, "]"); 1002208538Sraj *buf = b; 1003208538Sraj 1004233323Sraj free(tmp); 1005233323Sraj 1006208538Sraj return (0); 1007233323Srajerror: 1008233323Sraj return (1); 1009208538Sraj} 1010208538Sraj 1011208538Srajstatic int 1012208538Srajfdt_data_fmt(const void *data, int len, char **buf) 1013208538Sraj{ 1014208538Sraj int count; 1015208538Sraj 1016208538Sraj if (len == 0) { 1017208538Sraj *buf = NULL; 1018208538Sraj return (1); 1019208538Sraj } 1020208538Sraj 1021208538Sraj if (fdt_isprint(data, len, &count)) 1022208538Sraj return (fdt_data_str(data, len, count, buf)); 1023208538Sraj 1024208538Sraj else if ((len % 4) == 0) 1025208538Sraj return (fdt_data_cell(data, len, buf)); 1026208538Sraj 1027208538Sraj else 1028208538Sraj return (fdt_data_bytes(data, len, buf)); 1029208538Sraj} 1030208538Sraj 1031208538Srajstatic int 1032208538Srajfdt_prop(int offset) 1033208538Sraj{ 1034208538Sraj char *line, *buf; 1035208538Sraj const struct fdt_property *prop; 1036208538Sraj const char *name; 1037208538Sraj const void *data; 1038208538Sraj int len, rv; 1039208538Sraj 1040208538Sraj line = NULL; 1041208538Sraj prop = fdt_offset_ptr(fdtp, offset, sizeof(*prop)); 1042208538Sraj if (prop == NULL) 1043208538Sraj return (1); 1044208538Sraj 1045208538Sraj name = fdt_string(fdtp, fdt32_to_cpu(prop->nameoff)); 1046208538Sraj len = fdt32_to_cpu(prop->len); 1047208538Sraj 1048208538Sraj rv = 0; 1049208538Sraj buf = NULL; 1050208538Sraj if (len == 0) { 1051208538Sraj /* Property without value */ 1052208538Sraj line = (char *)malloc(strlen(name) + 2); 1053208538Sraj if (line == NULL) { 1054208538Sraj rv = 2; 1055208538Sraj goto out2; 1056208538Sraj } 1057208538Sraj sprintf(line, "%s\n", name); 1058208538Sraj goto out1; 1059208538Sraj } 1060208538Sraj 1061208538Sraj /* 1062208538Sraj * Process property with value 1063208538Sraj */ 1064208538Sraj data = prop->data; 1065208538Sraj 1066208538Sraj if (fdt_data_fmt(data, len, &buf) != 0) { 1067208538Sraj rv = 3; 1068208538Sraj goto out2; 1069208538Sraj } 1070208538Sraj 1071208538Sraj line = (char *)malloc(strlen(name) + strlen(FDT_PROP_SEP) + 1072208538Sraj strlen(buf) + 2); 1073208538Sraj if (line == NULL) { 1074208538Sraj sprintf(command_errbuf, "could not allocate space for string"); 1075208538Sraj rv = 4; 1076208538Sraj goto out2; 1077208538Sraj } 1078208538Sraj 1079208538Sraj sprintf(line, "%s" FDT_PROP_SEP "%s\n", name, buf); 1080208538Sraj 1081208538Srajout1: 1082208538Sraj pager_open(); 1083208538Sraj pager_output(line); 1084208538Sraj pager_close(); 1085208538Sraj 1086208538Srajout2: 1087208538Sraj if (buf) 1088208538Sraj free(buf); 1089208538Sraj 1090208538Sraj if (line) 1091208538Sraj free(line); 1092208538Sraj 1093208538Sraj return (rv); 1094208538Sraj} 1095208538Sraj 1096208538Srajstatic int 1097208538Srajfdt_modprop(int nodeoff, char *propname, void *value, char mode) 1098208538Sraj{ 1099208538Sraj uint32_t cells[100]; 1100208538Sraj char *buf; 1101208538Sraj int len, rv; 1102208538Sraj const struct fdt_property *p; 1103208538Sraj 1104208538Sraj p = fdt_get_property(fdtp, nodeoff, propname, NULL); 1105208538Sraj 1106208538Sraj if (p != NULL) { 1107208538Sraj if (mode == 1) { 1108208538Sraj /* Adding inexistant value in mode 1 is forbidden */ 1109208538Sraj sprintf(command_errbuf, "property already exists!"); 1110208538Sraj return (CMD_ERROR); 1111208538Sraj } 1112208538Sraj } else if (mode == 0) { 1113208538Sraj sprintf(command_errbuf, "property does not exist!"); 1114208538Sraj return (CMD_ERROR); 1115208538Sraj } 1116208538Sraj len = strlen(value); 1117208538Sraj rv = 0; 1118208538Sraj buf = (char *)value; 1119208538Sraj 1120208538Sraj switch (*buf) { 1121208538Sraj case '&': 1122208538Sraj /* phandles */ 1123208538Sraj break; 1124208538Sraj case '<': 1125208538Sraj /* Data cells */ 1126208538Sraj len = fdt_strtovect(buf, (void *)&cells, 100, 1127208538Sraj sizeof(uint32_t)); 1128208538Sraj 1129208538Sraj rv = fdt_setprop(fdtp, nodeoff, propname, &cells, 1130208538Sraj len * sizeof(uint32_t)); 1131208538Sraj break; 1132208538Sraj case '[': 1133208538Sraj /* Data bytes */ 1134208538Sraj len = fdt_strtovect(buf, (void *)&cells, 100, 1135208538Sraj sizeof(uint8_t)); 1136208538Sraj 1137208538Sraj rv = fdt_setprop(fdtp, nodeoff, propname, &cells, 1138208538Sraj len * sizeof(uint8_t)); 1139208538Sraj break; 1140208538Sraj case '"': 1141208538Sraj default: 1142208538Sraj /* Default -- string */ 1143208538Sraj rv = fdt_setprop_string(fdtp, nodeoff, propname, value); 1144208538Sraj break; 1145208538Sraj } 1146208538Sraj 1147233323Sraj if (rv != 0) { 1148233323Sraj if (rv == -FDT_ERR_NOSPACE) 1149233323Sraj sprintf(command_errbuf, 1150233323Sraj "Device tree blob is too small!\n"); 1151233323Sraj else 1152233323Sraj sprintf(command_errbuf, 1153233323Sraj "Could not add/modify property!\n"); 1154233323Sraj } 1155208538Sraj return (rv); 1156208538Sraj} 1157208538Sraj 1158208538Sraj/* Merge strings from argv into a single string */ 1159208538Srajstatic int 1160208538Srajfdt_merge_strings(int argc, char *argv[], int start, char **buffer) 1161208538Sraj{ 1162208538Sraj char *buf; 1163208538Sraj int i, idx, sz; 1164208538Sraj 1165208538Sraj *buffer = NULL; 1166208538Sraj sz = 0; 1167208538Sraj 1168208538Sraj for (i = start; i < argc; i++) 1169208538Sraj sz += strlen(argv[i]); 1170208538Sraj 1171208538Sraj /* Additional bytes for whitespaces between args */ 1172208538Sraj sz += argc - start; 1173208538Sraj 1174208538Sraj buf = (char *)malloc(sizeof(char) * sz); 1175208538Sraj bzero(buf, sizeof(char) * sz); 1176208538Sraj 1177208538Sraj if (buf == NULL) { 1178208538Sraj sprintf(command_errbuf, "could not allocate space " 1179208538Sraj "for string"); 1180208538Sraj return (1); 1181208538Sraj } 1182208538Sraj 1183208538Sraj idx = 0; 1184208538Sraj for (i = start, idx = 0; i < argc; i++) { 1185208538Sraj strcpy(buf + idx, argv[i]); 1186208538Sraj idx += strlen(argv[i]); 1187208538Sraj buf[idx] = ' '; 1188208538Sraj idx++; 1189208538Sraj } 1190208538Sraj buf[sz - 1] = '\0'; 1191208538Sraj *buffer = buf; 1192208538Sraj return (0); 1193208538Sraj} 1194208538Sraj 1195208538Sraj/* Extract offset and name of node/property from a given path */ 1196208538Srajstatic int 1197208538Srajfdt_extract_nameloc(char **pathp, char **namep, int *nodeoff) 1198208538Sraj{ 1199208538Sraj int o; 1200208538Sraj char *path = *pathp, *name = NULL, *subpath = NULL; 1201208538Sraj 1202208538Sraj subpath = strrchr(path, '/'); 1203208538Sraj if (subpath == NULL) { 1204208538Sraj o = fdt_path_offset(fdtp, cwd); 1205208538Sraj name = path; 1206208538Sraj path = (char *)&cwd; 1207208538Sraj } else { 1208208538Sraj *subpath = '\0'; 1209208538Sraj if (strlen(path) == 0) 1210208538Sraj path = cwd; 1211208538Sraj 1212208538Sraj name = subpath + 1; 1213208538Sraj o = fdt_path_offset(fdtp, path); 1214208538Sraj } 1215208538Sraj 1216208538Sraj if (strlen(name) == 0) { 1217208538Sraj sprintf(command_errbuf, "name not specified"); 1218208538Sraj return (1); 1219208538Sraj } 1220208538Sraj if (o < 0) { 1221208538Sraj sprintf(command_errbuf, "could not find node: '%s'", path); 1222208538Sraj return (1); 1223208538Sraj } 1224208538Sraj *namep = name; 1225208538Sraj *nodeoff = o; 1226208538Sraj *pathp = path; 1227208538Sraj return (0); 1228208538Sraj} 1229208538Sraj 1230208538Srajstatic int 1231208538Srajfdt_cmd_prop(int argc, char *argv[]) 1232208538Sraj{ 1233208538Sraj char *path, *propname, *value; 1234208538Sraj int o, next, depth, rv; 1235208538Sraj uint32_t tag; 1236208538Sraj 1237208538Sraj path = (argc > 2) ? argv[2] : NULL; 1238208538Sraj 1239208538Sraj value = NULL; 1240208538Sraj 1241208538Sraj if (argc > 3) { 1242208538Sraj /* Merge property value strings into one */ 1243208538Sraj if (fdt_merge_strings(argc, argv, 3, &value) != 0) 1244208538Sraj return (CMD_ERROR); 1245208538Sraj } else 1246208538Sraj value = NULL; 1247208538Sraj 1248208538Sraj if (path == NULL) 1249208538Sraj path = cwd; 1250208538Sraj 1251208538Sraj rv = CMD_OK; 1252208538Sraj 1253208538Sraj if (value) { 1254208538Sraj /* If value is specified -- try to modify prop. */ 1255208538Sraj if (fdt_extract_nameloc(&path, &propname, &o) != 0) 1256208538Sraj return (CMD_ERROR); 1257208538Sraj 1258208538Sraj rv = fdt_modprop(o, propname, value, 0); 1259208538Sraj if (rv) 1260208538Sraj return (CMD_ERROR); 1261208538Sraj return (CMD_OK); 1262208538Sraj 1263208538Sraj } 1264208538Sraj /* User wants to display properties */ 1265208538Sraj o = fdt_path_offset(fdtp, path); 1266208538Sraj 1267208538Sraj if (o < 0) { 1268208538Sraj sprintf(command_errbuf, "could not find node: '%s'", path); 1269208538Sraj rv = CMD_ERROR; 1270208538Sraj goto out; 1271208538Sraj } 1272208538Sraj 1273208538Sraj depth = 0; 1274208538Sraj while (depth >= 0) { 1275208538Sraj tag = fdt_next_tag(fdtp, o, &next); 1276208538Sraj switch (tag) { 1277208538Sraj case FDT_NOP: 1278208538Sraj break; 1279208538Sraj case FDT_PROP: 1280208538Sraj if (depth > 1) 1281208538Sraj /* Don't process properties of nested nodes */ 1282208538Sraj break; 1283208538Sraj 1284208538Sraj if (fdt_prop(o) != 0) { 1285208538Sraj sprintf(command_errbuf, "could not process " 1286208538Sraj "property"); 1287208538Sraj rv = CMD_ERROR; 1288208538Sraj goto out; 1289208538Sraj } 1290208538Sraj break; 1291208538Sraj case FDT_BEGIN_NODE: 1292208538Sraj depth++; 1293208538Sraj if (depth > FDT_MAX_DEPTH) { 1294208538Sraj printf("warning: nesting too deep: %d\n", 1295208538Sraj depth); 1296208538Sraj goto out; 1297208538Sraj } 1298208538Sraj break; 1299208538Sraj case FDT_END_NODE: 1300208538Sraj depth--; 1301208538Sraj if (depth == 0) 1302208538Sraj /* 1303208538Sraj * This is the end of our starting node, force 1304208538Sraj * the loop finish. 1305208538Sraj */ 1306208538Sraj depth--; 1307208538Sraj break; 1308208538Sraj } 1309208538Sraj o = next; 1310208538Sraj } 1311208538Srajout: 1312208538Sraj return (rv); 1313208538Sraj} 1314208538Sraj 1315208538Srajstatic int 1316208538Srajfdt_cmd_mkprop(int argc, char *argv[]) 1317208538Sraj{ 1318208538Sraj int o; 1319208538Sraj char *path, *propname, *value; 1320208538Sraj 1321208538Sraj path = (argc > 2) ? argv[2] : NULL; 1322208538Sraj 1323208538Sraj value = NULL; 1324208538Sraj 1325208538Sraj if (argc > 3) { 1326208538Sraj /* Merge property value strings into one */ 1327208538Sraj if (fdt_merge_strings(argc, argv, 3, &value) != 0) 1328208538Sraj return (CMD_ERROR); 1329208538Sraj } else 1330208538Sraj value = NULL; 1331208538Sraj 1332208538Sraj if (fdt_extract_nameloc(&path, &propname, &o) != 0) 1333208538Sraj return (CMD_ERROR); 1334208538Sraj 1335208538Sraj if (fdt_modprop(o, propname, value, 1)) 1336208538Sraj return (CMD_ERROR); 1337208538Sraj 1338208538Sraj return (CMD_OK); 1339208538Sraj} 1340208538Sraj 1341208538Srajstatic int 1342208538Srajfdt_cmd_rm(int argc, char *argv[]) 1343208538Sraj{ 1344208538Sraj int o, rv; 1345208538Sraj char *path = NULL, *propname; 1346208538Sraj 1347208538Sraj if (argc > 2) 1348208538Sraj path = argv[2]; 1349208538Sraj else { 1350208538Sraj sprintf(command_errbuf, "no node/property name specified"); 1351208538Sraj return (CMD_ERROR); 1352208538Sraj } 1353208538Sraj 1354208538Sraj o = fdt_path_offset(fdtp, path); 1355208538Sraj if (o < 0) { 1356208538Sraj /* If node not found -- try to find & delete property */ 1357208538Sraj if (fdt_extract_nameloc(&path, &propname, &o) != 0) 1358208538Sraj return (CMD_ERROR); 1359208538Sraj 1360208538Sraj if ((rv = fdt_delprop(fdtp, o, propname)) != 0) { 1361208538Sraj sprintf(command_errbuf, "could not delete" 1362208538Sraj "%s\n", (rv == -FDT_ERR_NOTFOUND) ? 1363208538Sraj "(property/node does not exist)" : ""); 1364208538Sraj return (CMD_ERROR); 1365208538Sraj 1366208538Sraj } else 1367208538Sraj return (CMD_OK); 1368208538Sraj } 1369208538Sraj /* If node exists -- remove node */ 1370208538Sraj rv = fdt_del_node(fdtp, o); 1371208538Sraj if (rv) { 1372208538Sraj sprintf(command_errbuf, "could not delete node"); 1373208538Sraj return (CMD_ERROR); 1374208538Sraj } 1375208538Sraj return (CMD_OK); 1376208538Sraj} 1377208538Sraj 1378208538Srajstatic int 1379208538Srajfdt_cmd_mknode(int argc, char *argv[]) 1380208538Sraj{ 1381208538Sraj int o, rv; 1382208538Sraj char *path = NULL, *nodename = NULL; 1383208538Sraj 1384208538Sraj if (argc > 2) 1385208538Sraj path = argv[2]; 1386208538Sraj else { 1387208538Sraj sprintf(command_errbuf, "no node name specified"); 1388208538Sraj return (CMD_ERROR); 1389208538Sraj } 1390208538Sraj 1391208538Sraj if (fdt_extract_nameloc(&path, &nodename, &o) != 0) 1392208538Sraj return (CMD_ERROR); 1393208538Sraj 1394208538Sraj rv = fdt_add_subnode(fdtp, o, nodename); 1395208538Sraj 1396208538Sraj if (rv < 0) { 1397233323Sraj if (rv == -FDT_ERR_NOSPACE) 1398233323Sraj sprintf(command_errbuf, 1399233323Sraj "Device tree blob is too small!\n"); 1400233323Sraj else 1401233323Sraj sprintf(command_errbuf, 1402233323Sraj "Could not add node!\n"); 1403208538Sraj return (CMD_ERROR); 1404208538Sraj } 1405208538Sraj return (CMD_OK); 1406208538Sraj} 1407208538Sraj 1408208538Srajstatic int 1409208538Srajfdt_cmd_pwd(int argc, char *argv[]) 1410208538Sraj{ 1411233323Sraj char line[FDT_CWD_LEN]; 1412208538Sraj 1413208538Sraj pager_open(); 1414208538Sraj sprintf(line, "%s\n", cwd); 1415208538Sraj pager_output(line); 1416208538Sraj pager_close(); 1417208538Sraj return (CMD_OK); 1418208538Sraj} 1419208538Sraj 1420208538Srajstatic int 1421208538Srajfdt_cmd_nyi(int argc, char *argv[]) 1422208538Sraj{ 1423208538Sraj 1424208538Sraj printf("command not yet implemented\n"); 1425208538Sraj return (CMD_ERROR); 1426208538Sraj} 1427