fdt_loader_cmd.c revision 275763
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: stable/10/sys/boot/fdt/fdt_loader_cmd.c 275763 2014-12-14 15:33:45Z andrew $"); 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" 41275763Sandrew#include "fdt_platform.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 55235529Skientzle#define COPYOUT(s,d,l) archsw.arch_copyout(s, d, l) 56235529Skientzle#define COPYIN(s,d,l) archsw.arch_copyin(s, d, l) 57233230Sraj 58233230Sraj#define FDT_STATIC_DTB_SYMBOL "fdt_static_dtb" 59233230Sraj 60243693Sgonzo#define CMD_REQUIRES_BLOB 0x01 61243693Sgonzo 62247201Skientzle/* Location of FDT yet to be loaded. */ 63247250Skientzle/* This may be in read-only memory, so can't be manipulated directly. */ 64247201Skientzlestatic struct fdt_header *fdt_to_load = NULL; 65247250Skientzle/* Location of FDT on heap. */ 66247250Skientzle/* This is the copy we actually manipulate. */ 67208538Srajstatic struct fdt_header *fdtp = NULL; 68235529Skientzle/* Size of FDT blob */ 69235529Skientzlestatic size_t fdtp_size = 0; 70247250Skientzle/* Location of FDT in kernel or module. */ 71247250Skientzle/* This won't be set if FDT is loaded from disk or memory. */ 72247250Skientzle/* If it is set, we'll update it when fdt_copy() gets called. */ 73235529Skientzlestatic vm_offset_t fdtp_va = 0; 74208538Sraj 75243693Sgonzostatic int fdt_load_dtb(vm_offset_t va); 76243693Sgonzo 77208538Srajstatic int fdt_cmd_nyi(int argc, char *argv[]); 78208538Sraj 79243693Sgonzostatic int fdt_cmd_addr(int argc, char *argv[]); 80208538Srajstatic int fdt_cmd_mkprop(int argc, char *argv[]); 81208538Srajstatic int fdt_cmd_cd(int argc, char *argv[]); 82208538Srajstatic int fdt_cmd_hdr(int argc, char *argv[]); 83208538Srajstatic int fdt_cmd_ls(int argc, char *argv[]); 84208538Srajstatic int fdt_cmd_prop(int argc, char *argv[]); 85208538Srajstatic int fdt_cmd_pwd(int argc, char *argv[]); 86208538Srajstatic int fdt_cmd_rm(int argc, char *argv[]); 87208538Srajstatic int fdt_cmd_mknode(int argc, char *argv[]); 88243693Sgonzostatic int fdt_cmd_mres(int argc, char *argv[]); 89208538Sraj 90208538Srajtypedef int cmdf_t(int, char *[]); 91208538Sraj 92208538Srajstruct cmdtab { 93275762Sandrew const char *name; 94275762Sandrew cmdf_t *handler; 95275762Sandrew int flags; 96208538Sraj}; 97208538Sraj 98208538Srajstatic const struct cmdtab commands[] = { 99243693Sgonzo { "addr", &fdt_cmd_addr, 0 }, 100243693Sgonzo { "alias", &fdt_cmd_nyi, 0 }, 101243693Sgonzo { "cd", &fdt_cmd_cd, CMD_REQUIRES_BLOB }, 102243693Sgonzo { "header", &fdt_cmd_hdr, CMD_REQUIRES_BLOB }, 103243693Sgonzo { "ls", &fdt_cmd_ls, CMD_REQUIRES_BLOB }, 104243693Sgonzo { "mknode", &fdt_cmd_mknode, CMD_REQUIRES_BLOB }, 105243693Sgonzo { "mkprop", &fdt_cmd_mkprop, CMD_REQUIRES_BLOB }, 106243693Sgonzo { "mres", &fdt_cmd_mres, CMD_REQUIRES_BLOB }, 107243693Sgonzo { "prop", &fdt_cmd_prop, CMD_REQUIRES_BLOB }, 108243693Sgonzo { "pwd", &fdt_cmd_pwd, CMD_REQUIRES_BLOB }, 109243693Sgonzo { "rm", &fdt_cmd_rm, CMD_REQUIRES_BLOB }, 110208538Sraj { NULL, NULL } 111208538Sraj}; 112208538Sraj 113208538Srajstatic char cwd[FDT_CWD_LEN] = "/"; 114208538Sraj 115233230Srajstatic vm_offset_t 116235529Skientzlefdt_find_static_dtb() 117233230Sraj{ 118248121Sian Elf_Ehdr *ehdr; 119248121Sian Elf_Shdr *shdr; 120233230Sraj Elf_Sym sym; 121248121Sian vm_offset_t strtab, symtab, fdt_start; 122233230Sraj uint64_t offs; 123233230Sraj struct preloaded_file *kfp; 124233230Sraj struct file_metadata *md; 125235529Skientzle char *strp; 126248121Sian int i, sym_count; 127233230Sraj 128265068Sian debugf("fdt_find_static_dtb()\n"); 129265068Sian 130248934Skientzle sym_count = symtab = strtab = 0; 131235529Skientzle strp = NULL; 132233230Sraj 133233230Sraj offs = __elfN(relocation_offset); 134233230Sraj 135233230Sraj kfp = file_findfile(NULL, NULL); 136233230Sraj if (kfp == NULL) 137233230Sraj return (0); 138233230Sraj 139248121Sian /* Locate the dynamic symbols and strtab. */ 140248121Sian md = file_findmetadata(kfp, MODINFOMD_ELFHDR); 141233230Sraj if (md == NULL) 142233230Sraj return (0); 143248121Sian ehdr = (Elf_Ehdr *)md->md_data; 144233230Sraj 145248121Sian md = file_findmetadata(kfp, MODINFOMD_SHDR); 146233230Sraj if (md == NULL) 147233230Sraj return (0); 148248121Sian shdr = (Elf_Shdr *)md->md_data; 149233230Sraj 150248121Sian for (i = 0; i < ehdr->e_shnum; ++i) { 151248121Sian if (shdr[i].sh_type == SHT_DYNSYM && symtab == 0) { 152248121Sian symtab = shdr[i].sh_addr + offs; 153248121Sian sym_count = shdr[i].sh_size / sizeof(Elf_Sym); 154248121Sian } else if (shdr[i].sh_type == SHT_STRTAB && strtab == 0) { 155248121Sian strtab = shdr[i].sh_addr + offs; 156233230Sraj } 157233230Sraj } 158233230Sraj 159233230Sraj /* 160233230Sraj * The most efficent way to find a symbol would be to calculate a 161233230Sraj * hash, find proper bucket and chain, and thus find a symbol. 162233230Sraj * However, that would involve code duplication (e.g. for hash 163233230Sraj * function). So we're using simpler and a bit slower way: we're 164233230Sraj * iterating through symbols, searching for the one which name is 165233230Sraj * 'equal' to 'fdt_static_dtb'. To speed up the process a little bit, 166233230Sraj * we are eliminating symbols type of which is not STT_NOTYPE, or(and) 167233230Sraj * those which binding attribute is not STB_GLOBAL. 168233230Sraj */ 169235529Skientzle fdt_start = 0; 170235529Skientzle while (sym_count > 0 && fdt_start == 0) { 171235529Skientzle COPYOUT(symtab, &sym, sizeof(sym)); 172235529Skientzle symtab += sizeof(sym); 173235529Skientzle --sym_count; 174233230Sraj if (ELF_ST_BIND(sym.st_info) != STB_GLOBAL || 175233230Sraj ELF_ST_TYPE(sym.st_info) != STT_NOTYPE) 176233230Sraj continue; 177235529Skientzle strp = strdupout(strtab + sym.st_name); 178235529Skientzle if (strcmp(strp, FDT_STATIC_DTB_SYMBOL) == 0) 179235529Skientzle fdt_start = (vm_offset_t)sym.st_value + offs; 180233230Sraj free(strp); 181233230Sraj } 182235529Skientzle return (fdt_start); 183233230Sraj} 184233230Sraj 185208538Srajstatic int 186243693Sgonzofdt_load_dtb(vm_offset_t va) 187208538Sraj{ 188235529Skientzle struct fdt_header header; 189208538Sraj int err; 190208538Sraj 191265068Sian debugf("fdt_load_dtb(0x%08jx)\n", (uintmax_t)va); 192265068Sian 193243693Sgonzo COPYOUT(va, &header, sizeof(header)); 194243693Sgonzo err = fdt_check_header(&header); 195243693Sgonzo if (err < 0) { 196243693Sgonzo if (err == -FDT_ERR_BADVERSION) 197243693Sgonzo sprintf(command_errbuf, 198243693Sgonzo "incompatible blob version: %d, should be: %d", 199243693Sgonzo fdt_version(fdtp), FDT_LAST_SUPPORTED_VERSION); 200243693Sgonzo 201243693Sgonzo else 202243693Sgonzo sprintf(command_errbuf, "error validating blob: %s", 203243693Sgonzo fdt_strerror(err)); 204243693Sgonzo return (1); 205243693Sgonzo } 206243693Sgonzo 207208538Sraj /* 208243693Sgonzo * Release previous blob 209208538Sraj */ 210243693Sgonzo if (fdtp) 211243693Sgonzo free(fdtp); 212208538Sraj 213235529Skientzle fdtp_size = fdt_totalsize(&header); 214235529Skientzle fdtp = malloc(fdtp_size); 215243693Sgonzo 216235529Skientzle if (fdtp == NULL) { 217235529Skientzle command_errmsg = "can't allocate memory for device tree copy"; 218243693Sgonzo return (1); 219235529Skientzle } 220235529Skientzle 221243693Sgonzo fdtp_va = va; 222243693Sgonzo COPYOUT(va, fdtp, fdtp_size); 223243693Sgonzo debugf("DTB blob found at 0x%jx, size: 0x%jx\n", (uintmax_t)va, (uintmax_t)fdtp_size); 224208538Sraj 225243693Sgonzo return (0); 226243693Sgonzo} 227243693Sgonzo 228275763Sandrewint 229247045Skientzlefdt_load_dtb_addr(struct fdt_header *header) 230243693Sgonzo{ 231265065Sian int err; 232243693Sgonzo 233265068Sian debugf("fdt_load_dtb_addr(0x%p)\n", header); 234265068Sian 235247250Skientzle fdtp_size = fdt_totalsize(header); 236265065Sian err = fdt_check_header(header); 237265065Sian if (err < 0) { 238265065Sian sprintf(command_errbuf, "error validating blob: %s", 239265065Sian fdt_strerror(err)); 240265065Sian return (err); 241265065Sian } 242247250Skientzle free(fdtp); 243247250Skientzle if ((fdtp = malloc(fdtp_size)) == NULL) { 244247250Skientzle command_errmsg = "can't allocate memory for device tree copy"; 245247045Skientzle return (1); 246208538Sraj } 247247250Skientzle 248247250Skientzle fdtp_va = 0; // Don't write this back into module or kernel. 249247250Skientzle bcopy(header, fdtp, fdtp_size); 250247250Skientzle return (0); 251247045Skientzle} 252243693Sgonzo 253275763Sandrewint 254265068Sianfdt_load_dtb_file(const char * filename) 255265068Sian{ 256265068Sian struct preloaded_file *bfp, *oldbfp; 257265068Sian int err; 258265068Sian 259265068Sian debugf("fdt_load_dtb_file(%s)\n", filename); 260265068Sian 261265068Sian oldbfp = file_findfile(NULL, "dtb"); 262265068Sian 263265068Sian /* Attempt to load and validate a new dtb from a file. */ 264265068Sian if ((bfp = file_loadraw(filename, "dtb")) == NULL) { 265265068Sian sprintf(command_errbuf, "failed to load file '%s'", filename); 266265068Sian return (1); 267265068Sian } 268265068Sian if ((err = fdt_load_dtb(bfp->f_addr)) != 0) { 269265068Sian file_discard(bfp); 270265068Sian return (err); 271265068Sian } 272265068Sian 273265068Sian /* A new dtb was validated, discard any previous file. */ 274265068Sian if (oldbfp) 275265068Sian file_discard(oldbfp); 276265068Sian return (0); 277265068Sian} 278265068Sian 279265069Sianint 280247045Skientzlefdt_setup_fdtp() 281247045Skientzle{ 282265066Sian struct preloaded_file *bfp; 283265066Sian vm_offset_t va; 284265066Sian 285265068Sian debugf("fdt_setup_fdtp()\n"); 286265068Sian 287265068Sian /* If we already loaded a file, use it. */ 288265066Sian if ((bfp = file_findfile(NULL, "dtb")) != NULL) { 289265068Sian if (fdt_load_dtb(bfp->f_addr) == 0) { 290265068Sian printf("Using DTB from loaded file '%s'.\n", 291265068Sian bfp->f_name); 292265068Sian return (0); 293265068Sian } 294265066Sian } 295265068Sian 296265068Sian /* If we were given the address of a valid blob in memory, use it. */ 297265066Sian if (fdt_to_load != NULL) { 298265068Sian if (fdt_load_dtb_addr(fdt_to_load) == 0) { 299265068Sian printf("Using DTB from memory address 0x%08X.\n", 300265068Sian (unsigned int)fdt_to_load); 301265068Sian return (0); 302265068Sian } 303265066Sian } 304247045Skientzle 305275763Sandrew if (fdt_platform_load_dtb() == 0) 306275763Sandrew return (0); 307265068Sian 308265068Sian /* If there is a dtb compiled into the kernel, use it. */ 309265066Sian if ((va = fdt_find_static_dtb()) != 0) { 310265068Sian if (fdt_load_dtb(va) == 0) { 311265068Sian printf("Using DTB compiled into kernel.\n"); 312265068Sian return (0); 313265068Sian } 314265066Sian } 315265066Sian 316265068Sian command_errmsg = "No device tree blob found!\n"; 317265066Sian return (1); 318208538Sraj} 319208538Sraj 320208538Sraj#define fdt_strtovect(str, cellbuf, lim, cellsize) _fdt_strtovect((str), \ 321208538Sraj (cellbuf), (lim), (cellsize), 0); 322208538Sraj 323208538Sraj/* Force using base 16 */ 324208538Sraj#define fdt_strtovectx(str, cellbuf, lim, cellsize) _fdt_strtovect((str), \ 325208538Sraj (cellbuf), (lim), (cellsize), 16); 326208538Sraj 327208538Srajstatic int 328275762Sandrew_fdt_strtovect(const char *str, void *cellbuf, int lim, unsigned char cellsize, 329208538Sraj uint8_t base) 330208538Sraj{ 331275762Sandrew const char *buf = str; 332275762Sandrew const char *end = str + strlen(str) - 2; 333208538Sraj uint32_t *u32buf = NULL; 334208538Sraj uint8_t *u8buf = NULL; 335208538Sraj int cnt = 0; 336208538Sraj 337208538Sraj if (cellsize == sizeof(uint32_t)) 338208538Sraj u32buf = (uint32_t *)cellbuf; 339208538Sraj else 340208538Sraj u8buf = (uint8_t *)cellbuf; 341208538Sraj 342208538Sraj if (lim == 0) 343208538Sraj return (0); 344208538Sraj 345208538Sraj while (buf < end) { 346208538Sraj 347208538Sraj /* Skip white whitespace(s)/separators */ 348208538Sraj while (!isxdigit(*buf) && buf < end) 349208538Sraj buf++; 350208538Sraj 351208538Sraj if (u32buf != NULL) 352208538Sraj u32buf[cnt] = 353208538Sraj cpu_to_fdt32((uint32_t)strtol(buf, NULL, base)); 354208538Sraj 355208538Sraj else 356208538Sraj u8buf[cnt] = (uint8_t)strtol(buf, NULL, base); 357208538Sraj 358208538Sraj if (cnt + 1 <= lim - 1) 359208538Sraj cnt++; 360208538Sraj else 361208538Sraj break; 362208538Sraj buf++; 363208538Sraj /* Find another number */ 364208538Sraj while ((isxdigit(*buf) || *buf == 'x') && buf < end) 365208538Sraj buf++; 366208538Sraj } 367208538Sraj return (cnt); 368208538Sraj} 369208538Sraj 370275763Sandrewvoid 371275763Sandrewfdt_fixup_ethernet(const char *str, char *ethstr, int len) 372208538Sraj{ 373208538Sraj uint8_t tmp_addr[6]; 374208538Sraj 375208538Sraj /* Convert macaddr string into a vector of uints */ 376208538Sraj fdt_strtovectx(str, &tmp_addr, 6, sizeof(uint8_t)); 377208538Sraj /* Set actual property to a value from vect */ 378208538Sraj fdt_setprop(fdtp, fdt_path_offset(fdtp, ethstr), 379208538Sraj "local-mac-address", &tmp_addr, 6 * sizeof(uint8_t)); 380208538Sraj} 381208538Sraj 382275763Sandrewvoid 383275763Sandrewfdt_fixup_cpubusfreqs(unsigned long cpufreq, unsigned long busfreq) 384208538Sraj{ 385208538Sraj int lo, o = 0, o2, maxo = 0, depth; 386208538Sraj const uint32_t zero = 0; 387208538Sraj 388208538Sraj /* We want to modify every subnode of /cpus */ 389208538Sraj o = fdt_path_offset(fdtp, "/cpus"); 390235261Skientzle if (o < 0) 391235261Skientzle return; 392208538Sraj 393208538Sraj /* maxo should contain offset of node next to /cpus */ 394208538Sraj depth = 0; 395208538Sraj maxo = o; 396208538Sraj while (depth != -1) 397208538Sraj maxo = fdt_next_node(fdtp, maxo, &depth); 398208538Sraj 399208538Sraj /* Find CPU frequency properties */ 400208538Sraj o = fdt_node_offset_by_prop_value(fdtp, o, "clock-frequency", 401208538Sraj &zero, sizeof(uint32_t)); 402208538Sraj 403208538Sraj o2 = fdt_node_offset_by_prop_value(fdtp, o, "bus-frequency", &zero, 404208538Sraj sizeof(uint32_t)); 405208538Sraj 406208538Sraj lo = MIN(o, o2); 407208538Sraj 408208538Sraj while (o != -FDT_ERR_NOTFOUND && o2 != -FDT_ERR_NOTFOUND) { 409208538Sraj 410208538Sraj o = fdt_node_offset_by_prop_value(fdtp, lo, 411208538Sraj "clock-frequency", &zero, sizeof(uint32_t)); 412208538Sraj 413208538Sraj o2 = fdt_node_offset_by_prop_value(fdtp, lo, "bus-frequency", 414208538Sraj &zero, sizeof(uint32_t)); 415208538Sraj 416208538Sraj /* We're only interested in /cpus subnode(s) */ 417208538Sraj if (lo > maxo) 418208538Sraj break; 419208538Sraj 420208538Sraj fdt_setprop_inplace_cell(fdtp, lo, "clock-frequency", 421208538Sraj (uint32_t)cpufreq); 422208538Sraj 423208538Sraj fdt_setprop_inplace_cell(fdtp, lo, "bus-frequency", 424208538Sraj (uint32_t)busfreq); 425208538Sraj 426208538Sraj lo = MIN(o, o2); 427208538Sraj } 428208538Sraj} 429208538Sraj 430247250Skientzlestatic int 431208538Srajfdt_reg_valid(uint32_t *reg, int len, int addr_cells, int size_cells) 432208538Sraj{ 433208538Sraj int cells_in_tuple, i, tuples, tuple_size; 434208538Sraj uint32_t cur_start, cur_size; 435208538Sraj 436208538Sraj cells_in_tuple = (addr_cells + size_cells); 437208538Sraj tuple_size = cells_in_tuple * sizeof(uint32_t); 438208538Sraj tuples = len / tuple_size; 439208538Sraj if (tuples == 0) 440208538Sraj return (EINVAL); 441208538Sraj 442208538Sraj for (i = 0; i < tuples; i++) { 443208538Sraj if (addr_cells == 2) 444208538Sraj cur_start = fdt64_to_cpu(reg[i * cells_in_tuple]); 445208538Sraj else 446208538Sraj cur_start = fdt32_to_cpu(reg[i * cells_in_tuple]); 447208538Sraj 448208538Sraj if (size_cells == 2) 449208538Sraj cur_size = fdt64_to_cpu(reg[i * cells_in_tuple + 2]); 450208538Sraj else 451208538Sraj cur_size = fdt32_to_cpu(reg[i * cells_in_tuple + 1]); 452208538Sraj 453208538Sraj if (cur_size == 0) 454208538Sraj return (EINVAL); 455208538Sraj 456208538Sraj debugf(" reg#%d (start: 0x%0x size: 0x%0x) valid!\n", 457208538Sraj i, cur_start, cur_size); 458208538Sraj } 459208538Sraj return (0); 460208538Sraj} 461208538Sraj 462275763Sandrewvoid 463275763Sandrewfdt_fixup_memory(struct fdt_mem_region *region, size_t num) 464208538Sraj{ 465275763Sandrew struct fdt_mem_region *curmr; 466208538Sraj uint32_t addr_cells, size_cells; 467208538Sraj uint32_t *addr_cellsp, *reg, *size_cellsp; 468275763Sandrew int err, i, len, memory, root; 469275763Sandrew size_t realmrno; 470208538Sraj uint8_t *buf, *sb; 471243693Sgonzo uint64_t rstart, rsize; 472243693Sgonzo int reserved; 473208538Sraj 474208538Sraj root = fdt_path_offset(fdtp, "/"); 475208538Sraj if (root < 0) { 476208538Sraj sprintf(command_errbuf, "Could not find root node !"); 477208538Sraj return; 478208538Sraj } 479208538Sraj 480208538Sraj memory = fdt_path_offset(fdtp, "/memory"); 481208538Sraj if (memory <= 0) { 482208538Sraj /* Create proper '/memory' node. */ 483208538Sraj memory = fdt_add_subnode(fdtp, root, "memory"); 484208538Sraj if (memory <= 0) { 485208538Sraj sprintf(command_errbuf, "Could not fixup '/memory' " 486208538Sraj "node, error code : %d!\n", memory); 487208538Sraj return; 488208538Sraj } 489208538Sraj 490208538Sraj err = fdt_setprop(fdtp, memory, "device_type", "memory", 491208538Sraj sizeof("memory")); 492208538Sraj 493208538Sraj if (err < 0) 494208538Sraj return; 495208538Sraj } 496208538Sraj 497208538Sraj addr_cellsp = (uint32_t *)fdt_getprop(fdtp, root, "#address-cells", 498208538Sraj NULL); 499208538Sraj size_cellsp = (uint32_t *)fdt_getprop(fdtp, root, "#size-cells", NULL); 500208538Sraj 501208538Sraj if (addr_cellsp == NULL || size_cellsp == NULL) { 502208538Sraj sprintf(command_errbuf, "Could not fixup '/memory' node : " 503208538Sraj "%s %s property not found in root node!\n", 504208538Sraj (!addr_cellsp) ? "#address-cells" : "", 505208538Sraj (!size_cellsp) ? "#size-cells" : ""); 506208538Sraj return; 507208538Sraj } 508208538Sraj 509208538Sraj addr_cells = fdt32_to_cpu(*addr_cellsp); 510208538Sraj size_cells = fdt32_to_cpu(*size_cellsp); 511208538Sraj 512243693Sgonzo /* 513243693Sgonzo * Convert memreserve data to memreserve property 514243693Sgonzo * Check if property already exists 515243693Sgonzo */ 516243693Sgonzo reserved = fdt_num_mem_rsv(fdtp); 517243693Sgonzo if (reserved && 518243693Sgonzo (fdt_getprop(fdtp, root, "memreserve", NULL) == NULL)) { 519243693Sgonzo len = (addr_cells + size_cells) * reserved * sizeof(uint32_t); 520243693Sgonzo sb = buf = (uint8_t *)malloc(len); 521243693Sgonzo if (!buf) 522243693Sgonzo return; 523243693Sgonzo 524243693Sgonzo bzero(buf, len); 525243693Sgonzo 526243693Sgonzo for (i = 0; i < reserved; i++) { 527243693Sgonzo if (fdt_get_mem_rsv(fdtp, i, &rstart, &rsize)) 528243693Sgonzo break; 529243693Sgonzo if (rsize) { 530243693Sgonzo /* Ensure endianess, and put cells into a buffer */ 531243693Sgonzo if (addr_cells == 2) 532243693Sgonzo *(uint64_t *)buf = 533243693Sgonzo cpu_to_fdt64(rstart); 534243693Sgonzo else 535243693Sgonzo *(uint32_t *)buf = 536243693Sgonzo cpu_to_fdt32(rstart); 537243693Sgonzo 538243693Sgonzo buf += sizeof(uint32_t) * addr_cells; 539243693Sgonzo if (size_cells == 2) 540243693Sgonzo *(uint64_t *)buf = 541243693Sgonzo cpu_to_fdt64(rsize); 542243693Sgonzo else 543243693Sgonzo *(uint32_t *)buf = 544243693Sgonzo cpu_to_fdt32(rsize); 545243693Sgonzo 546243693Sgonzo buf += sizeof(uint32_t) * size_cells; 547243693Sgonzo } 548243693Sgonzo } 549243693Sgonzo 550243693Sgonzo /* Set property */ 551243693Sgonzo if ((err = fdt_setprop(fdtp, root, "memreserve", sb, len)) < 0) 552243693Sgonzo printf("Could not fixup 'memreserve' property.\n"); 553243693Sgonzo 554243693Sgonzo free(sb); 555243693Sgonzo } 556243693Sgonzo 557208538Sraj /* Count valid memory regions entries in sysinfo. */ 558275763Sandrew realmrno = num; 559275763Sandrew for (i = 0; i < num; i++) 560275763Sandrew if (region[i].start == 0 && region[i].size == 0) 561208538Sraj realmrno--; 562208538Sraj 563208538Sraj if (realmrno == 0) { 564208538Sraj sprintf(command_errbuf, "Could not fixup '/memory' node : " 565208538Sraj "sysinfo doesn't contain valid memory regions info!\n"); 566208538Sraj return; 567208538Sraj } 568208538Sraj 569208538Sraj if ((reg = (uint32_t *)fdt_getprop(fdtp, memory, "reg", 570208538Sraj &len)) != NULL) { 571208538Sraj 572208538Sraj if (fdt_reg_valid(reg, len, addr_cells, size_cells) == 0) 573208538Sraj /* 574208538Sraj * Do not apply fixup if existing 'reg' property 575208538Sraj * seems to be valid. 576208538Sraj */ 577208538Sraj return; 578208538Sraj } 579208538Sraj 580208538Sraj len = (addr_cells + size_cells) * realmrno * sizeof(uint32_t); 581208538Sraj sb = buf = (uint8_t *)malloc(len); 582208538Sraj if (!buf) 583208538Sraj return; 584208538Sraj 585208538Sraj bzero(buf, len); 586208538Sraj 587275763Sandrew for (i = 0; i < num; i++) { 588275763Sandrew curmr = ®ion[i]; 589208538Sraj if (curmr->size != 0) { 590208538Sraj /* Ensure endianess, and put cells into a buffer */ 591208538Sraj if (addr_cells == 2) 592208538Sraj *(uint64_t *)buf = 593208538Sraj cpu_to_fdt64(curmr->start); 594208538Sraj else 595208538Sraj *(uint32_t *)buf = 596208538Sraj cpu_to_fdt32(curmr->start); 597208538Sraj 598208538Sraj buf += sizeof(uint32_t) * addr_cells; 599208538Sraj if (size_cells == 2) 600208538Sraj *(uint64_t *)buf = 601208538Sraj cpu_to_fdt64(curmr->size); 602208538Sraj else 603208538Sraj *(uint32_t *)buf = 604208538Sraj cpu_to_fdt32(curmr->size); 605208538Sraj 606208538Sraj buf += sizeof(uint32_t) * size_cells; 607208538Sraj } 608208538Sraj } 609208538Sraj 610208538Sraj /* Set property */ 611208538Sraj if ((err = fdt_setprop(fdtp, memory, "reg", sb, len)) < 0) 612208538Sraj sprintf(command_errbuf, "Could not fixup '/memory' node.\n"); 613243693Sgonzo 614243693Sgonzo free(sb); 615208538Sraj} 616208538Sraj 617275763Sandrewvoid 618275763Sandrewfdt_fixup_stdout(const char *str) 619208538Sraj{ 620208538Sraj char *ptr; 621208538Sraj int serialno; 622208538Sraj int len, no, sero; 623208538Sraj const struct fdt_property *prop; 624208538Sraj char *tmp[10]; 625208538Sraj 626208538Sraj ptr = (char *)str + strlen(str) - 1; 627208538Sraj while (ptr > str && isdigit(*(str - 1))) 628208538Sraj str--; 629208538Sraj 630208538Sraj if (ptr == str) 631208538Sraj return; 632208538Sraj 633208538Sraj serialno = (int)strtol(ptr, NULL, 0); 634208538Sraj no = fdt_path_offset(fdtp, "/chosen"); 635208538Sraj if (no < 0) 636208538Sraj return; 637208538Sraj 638208538Sraj prop = fdt_get_property(fdtp, no, "stdout", &len); 639208538Sraj 640208538Sraj /* If /chosen/stdout does not extist, create it */ 641208538Sraj if (prop == NULL || (prop != NULL && len == 0)) { 642208538Sraj 643208538Sraj bzero(tmp, 10 * sizeof(char)); 644208538Sraj strcpy((char *)&tmp, "serial"); 645208538Sraj if (strlen(ptr) > 3) 646208538Sraj /* Serial number too long */ 647208538Sraj return; 648208538Sraj 649208538Sraj strncpy((char *)tmp + 6, ptr, 3); 650208538Sraj sero = fdt_path_offset(fdtp, (const char *)tmp); 651208538Sraj if (sero < 0) 652208538Sraj /* 653208538Sraj * If serial device we're trying to assign 654208538Sraj * stdout to doesn't exist in DT -- return. 655208538Sraj */ 656208538Sraj return; 657208538Sraj 658208538Sraj fdt_setprop(fdtp, no, "stdout", &tmp, 659208538Sraj strlen((char *)&tmp) + 1); 660208538Sraj fdt_setprop(fdtp, no, "stdin", &tmp, 661208538Sraj strlen((char *)&tmp) + 1); 662208538Sraj } 663208538Sraj} 664208538Sraj 665233230Sraj/* 666233230Sraj * Locate the blob, fix it up and return its location. 667233230Sraj */ 668247250Skientzlestatic int 669208538Srajfdt_fixup(void) 670208538Sraj{ 671275763Sandrew int chosen, len; 672208538Sraj 673208538Sraj len = 0; 674208538Sraj 675265068Sian debugf("fdt_fixup()\n"); 676265068Sian 677265065Sian if (fdtp == NULL && fdt_setup_fdtp() != 0) 678265065Sian return (0); 679208538Sraj 680208538Sraj /* Create /chosen node (if not exists) */ 681208538Sraj if ((chosen = fdt_subnode_offset(fdtp, 0, "chosen")) == 682208538Sraj -FDT_ERR_NOTFOUND) 683208538Sraj chosen = fdt_add_subnode(fdtp, 0, "chosen"); 684208538Sraj 685208538Sraj /* Value assigned to fixup-applied does not matter. */ 686208538Sraj if (fdt_getprop(fdtp, chosen, "fixup-applied", NULL)) 687247250Skientzle return (1); 688208538Sraj 689275763Sandrew fdt_platform_fixups(); 690208538Sraj 691208538Sraj fdt_setprop(fdtp, chosen, "fixup-applied", NULL, 0); 692247250Skientzle return (1); 693208538Sraj} 694208538Sraj 695243693Sgonzo/* 696247250Skientzle * Copy DTB blob to specified location and return size 697243693Sgonzo */ 698208538Srajint 699243693Sgonzofdt_copy(vm_offset_t va) 700243693Sgonzo{ 701243693Sgonzo int err; 702265068Sian debugf("fdt_copy va 0x%08x\n", va); 703243693Sgonzo if (fdtp == NULL) { 704243693Sgonzo err = fdt_setup_fdtp(); 705243693Sgonzo if (err) { 706265065Sian printf("No valid device tree blob found!\n"); 707243693Sgonzo return (0); 708243693Sgonzo } 709243693Sgonzo } 710243693Sgonzo 711243693Sgonzo if (fdt_fixup() == 0) 712243693Sgonzo return (0); 713243693Sgonzo 714247250Skientzle if (fdtp_va != 0) { 715247250Skientzle /* Overwrite the FDT with the fixed version. */ 716247250Skientzle /* XXX Is this really appropriate? */ 717247250Skientzle COPYIN(fdtp, fdtp_va, fdtp_size); 718247250Skientzle } 719243693Sgonzo COPYIN(fdtp, va, fdtp_size); 720243693Sgonzo return (fdtp_size); 721243693Sgonzo} 722243693Sgonzo 723243693Sgonzo 724243693Sgonzo 725243693Sgonzoint 726208538Srajcommand_fdt_internal(int argc, char *argv[]) 727208538Sraj{ 728208538Sraj cmdf_t *cmdh; 729243693Sgonzo int flags; 730208538Sraj char *cmd; 731208538Sraj int i, err; 732208538Sraj 733208538Sraj if (argc < 2) { 734208538Sraj command_errmsg = "usage is 'fdt <command> [<args>]"; 735208538Sraj return (CMD_ERROR); 736208538Sraj } 737208538Sraj 738208538Sraj /* 739208538Sraj * Validate fdt <command>. 740208538Sraj */ 741208538Sraj cmd = strdup(argv[1]); 742208538Sraj i = 0; 743208538Sraj cmdh = NULL; 744208538Sraj while (!(commands[i].name == NULL)) { 745208538Sraj if (strcmp(cmd, commands[i].name) == 0) { 746208538Sraj /* found it */ 747208538Sraj cmdh = commands[i].handler; 748243693Sgonzo flags = commands[i].flags; 749208538Sraj break; 750208538Sraj } 751208538Sraj i++; 752208538Sraj } 753208538Sraj if (cmdh == NULL) { 754208538Sraj command_errmsg = "unknown command"; 755208538Sraj return (CMD_ERROR); 756208538Sraj } 757208538Sraj 758243693Sgonzo if (flags & CMD_REQUIRES_BLOB) { 759243693Sgonzo /* 760243693Sgonzo * Check if uboot env vars were parsed already. If not, do it now. 761243693Sgonzo */ 762243693Sgonzo if (fdt_fixup() == 0) 763243693Sgonzo return (CMD_ERROR); 764243693Sgonzo } 765243693Sgonzo 766208538Sraj /* 767208538Sraj * Call command handler. 768208538Sraj */ 769208538Sraj err = (*cmdh)(argc, argv); 770208538Sraj 771208538Sraj return (err); 772208538Sraj} 773208538Sraj 774208538Srajstatic int 775243693Sgonzofdt_cmd_addr(int argc, char *argv[]) 776243693Sgonzo{ 777247201Skientzle struct preloaded_file *fp; 778247045Skientzle struct fdt_header *hdr; 779247201Skientzle const char *addr; 780247201Skientzle char *cp; 781243693Sgonzo 782247201Skientzle fdt_to_load = NULL; 783247201Skientzle 784243693Sgonzo if (argc > 2) 785243693Sgonzo addr = argv[2]; 786243693Sgonzo else { 787243693Sgonzo sprintf(command_errbuf, "no address specified"); 788243693Sgonzo return (CMD_ERROR); 789243693Sgonzo } 790243693Sgonzo 791247201Skientzle hdr = (struct fdt_header *)strtoul(addr, &cp, 16); 792243693Sgonzo if (cp == addr) { 793243693Sgonzo sprintf(command_errbuf, "Invalid address: %s", addr); 794243693Sgonzo return (CMD_ERROR); 795243693Sgonzo } 796243693Sgonzo 797247201Skientzle while ((fp = file_findfile(NULL, "dtb")) != NULL) { 798247201Skientzle file_discard(fp); 799247201Skientzle } 800243693Sgonzo 801247201Skientzle fdt_to_load = hdr; 802243693Sgonzo return (CMD_OK); 803243693Sgonzo} 804243693Sgonzo 805243693Sgonzostatic int 806208538Srajfdt_cmd_cd(int argc, char *argv[]) 807208538Sraj{ 808208538Sraj char *path; 809208538Sraj char tmp[FDT_CWD_LEN]; 810208538Sraj int len, o; 811208538Sraj 812208538Sraj path = (argc > 2) ? argv[2] : "/"; 813208538Sraj 814208538Sraj if (path[0] == '/') { 815208538Sraj len = strlen(path); 816208538Sraj if (len >= FDT_CWD_LEN) 817208538Sraj goto fail; 818208538Sraj } else { 819208538Sraj /* Handle path specification relative to cwd */ 820208538Sraj len = strlen(cwd) + strlen(path) + 1; 821208538Sraj if (len >= FDT_CWD_LEN) 822208538Sraj goto fail; 823208538Sraj 824208538Sraj strcpy(tmp, cwd); 825208538Sraj strcat(tmp, "/"); 826208538Sraj strcat(tmp, path); 827208538Sraj path = tmp; 828208538Sraj } 829208538Sraj 830208538Sraj o = fdt_path_offset(fdtp, path); 831208538Sraj if (o < 0) { 832208538Sraj sprintf(command_errbuf, "could not find node: '%s'", path); 833208538Sraj return (CMD_ERROR); 834208538Sraj } 835208538Sraj 836208538Sraj strcpy(cwd, path); 837208538Sraj return (CMD_OK); 838208538Sraj 839208538Srajfail: 840208538Sraj sprintf(command_errbuf, "path too long: %d, max allowed: %d", 841208538Sraj len, FDT_CWD_LEN - 1); 842208538Sraj return (CMD_ERROR); 843208538Sraj} 844208538Sraj 845208538Srajstatic int 846208538Srajfdt_cmd_hdr(int argc __unused, char *argv[] __unused) 847208538Sraj{ 848208538Sraj char line[80]; 849208538Sraj int ver; 850208538Sraj 851208538Sraj if (fdtp == NULL) { 852208538Sraj command_errmsg = "no device tree blob pointer?!"; 853208538Sraj return (CMD_ERROR); 854208538Sraj } 855208538Sraj 856208538Sraj ver = fdt_version(fdtp); 857208538Sraj pager_open(); 858208538Sraj sprintf(line, "\nFlattened device tree header (%p):\n", fdtp); 859208538Sraj pager_output(line); 860208538Sraj sprintf(line, " magic = 0x%08x\n", fdt_magic(fdtp)); 861208538Sraj pager_output(line); 862208538Sraj sprintf(line, " size = %d\n", fdt_totalsize(fdtp)); 863208538Sraj pager_output(line); 864208538Sraj sprintf(line, " off_dt_struct = 0x%08x\n", 865208538Sraj fdt_off_dt_struct(fdtp)); 866208538Sraj pager_output(line); 867208538Sraj sprintf(line, " off_dt_strings = 0x%08x\n", 868208538Sraj fdt_off_dt_strings(fdtp)); 869208538Sraj pager_output(line); 870208538Sraj sprintf(line, " off_mem_rsvmap = 0x%08x\n", 871208538Sraj fdt_off_mem_rsvmap(fdtp)); 872208538Sraj pager_output(line); 873208538Sraj sprintf(line, " version = %d\n", ver); 874208538Sraj pager_output(line); 875208538Sraj sprintf(line, " last compatible version = %d\n", 876208538Sraj fdt_last_comp_version(fdtp)); 877208538Sraj pager_output(line); 878208538Sraj if (ver >= 2) { 879208538Sraj sprintf(line, " boot_cpuid = %d\n", 880208538Sraj fdt_boot_cpuid_phys(fdtp)); 881208538Sraj pager_output(line); 882208538Sraj } 883208538Sraj if (ver >= 3) { 884208538Sraj sprintf(line, " size_dt_strings = %d\n", 885208538Sraj fdt_size_dt_strings(fdtp)); 886208538Sraj pager_output(line); 887208538Sraj } 888208538Sraj if (ver >= 17) { 889208538Sraj sprintf(line, " size_dt_struct = %d\n", 890208538Sraj fdt_size_dt_struct(fdtp)); 891208538Sraj pager_output(line); 892208538Sraj } 893208538Sraj pager_close(); 894208538Sraj 895208538Sraj return (CMD_OK); 896208538Sraj} 897208538Sraj 898208538Srajstatic int 899208538Srajfdt_cmd_ls(int argc, char *argv[]) 900208538Sraj{ 901208538Sraj const char *prevname[FDT_MAX_DEPTH] = { NULL }; 902208538Sraj const char *name; 903208538Sraj char *path; 904208538Sraj int i, o, depth, len; 905208538Sraj 906208538Sraj path = (argc > 2) ? argv[2] : NULL; 907208538Sraj if (path == NULL) 908208538Sraj path = cwd; 909208538Sraj 910208538Sraj o = fdt_path_offset(fdtp, path); 911208538Sraj if (o < 0) { 912208538Sraj sprintf(command_errbuf, "could not find node: '%s'", path); 913208538Sraj return (CMD_ERROR); 914208538Sraj } 915208538Sraj 916208538Sraj for (depth = 0; 917208538Sraj (o >= 0) && (depth >= 0); 918208538Sraj o = fdt_next_node(fdtp, o, &depth)) { 919208538Sraj 920208538Sraj name = fdt_get_name(fdtp, o, &len); 921208538Sraj 922208538Sraj if (depth > FDT_MAX_DEPTH) { 923208538Sraj printf("max depth exceeded: %d\n", depth); 924208538Sraj continue; 925208538Sraj } 926208538Sraj 927208538Sraj prevname[depth] = name; 928208538Sraj 929208538Sraj /* Skip root (i = 1) when printing devices */ 930208538Sraj for (i = 1; i <= depth; i++) { 931208538Sraj if (prevname[i] == NULL) 932208538Sraj break; 933208538Sraj 934208538Sraj if (strcmp(cwd, "/") == 0) 935208538Sraj printf("/"); 936208538Sraj printf("%s", prevname[i]); 937208538Sraj } 938208538Sraj printf("\n"); 939208538Sraj } 940208538Sraj 941208538Sraj return (CMD_OK); 942208538Sraj} 943208538Sraj 944208538Srajstatic __inline int 945208538Srajisprint(int c) 946208538Sraj{ 947208538Sraj 948208538Sraj return (c >= ' ' && c <= 0x7e); 949208538Sraj} 950208538Sraj 951208538Srajstatic int 952208538Srajfdt_isprint(const void *data, int len, int *count) 953208538Sraj{ 954208538Sraj const char *d; 955208538Sraj char ch; 956208538Sraj int yesno, i; 957208538Sraj 958208538Sraj if (len == 0) 959208538Sraj return (0); 960208538Sraj 961208538Sraj d = (const char *)data; 962208538Sraj if (d[len - 1] != '\0') 963208538Sraj return (0); 964208538Sraj 965208538Sraj *count = 0; 966208538Sraj yesno = 1; 967208538Sraj for (i = 0; i < len; i++) { 968208538Sraj ch = *(d + i); 969208538Sraj if (isprint(ch) || (ch == '\0' && i > 0)) { 970208538Sraj /* Count strings */ 971208538Sraj if (ch == '\0') 972208538Sraj (*count)++; 973208538Sraj continue; 974208538Sraj } 975208538Sraj 976208538Sraj yesno = 0; 977208538Sraj break; 978208538Sraj } 979208538Sraj 980208538Sraj return (yesno); 981208538Sraj} 982208538Sraj 983208538Srajstatic int 984208538Srajfdt_data_str(const void *data, int len, int count, char **buf) 985208538Sraj{ 986233323Sraj char *b, *tmp; 987208538Sraj const char *d; 988233323Sraj int buf_len, i, l; 989208538Sraj 990208538Sraj /* 991208538Sraj * Calculate the length for the string and allocate memory. 992208538Sraj * 993233323Sraj * Note that 'len' already includes at least one terminator. 994208538Sraj */ 995233323Sraj buf_len = len; 996208538Sraj if (count > 1) { 997208538Sraj /* 998208538Sraj * Each token had already a terminator buried in 'len', but we 999208538Sraj * only need one eventually, don't count space for these. 1000208538Sraj */ 1001233323Sraj buf_len -= count - 1; 1002208538Sraj 1003208538Sraj /* Each consecutive token requires a ", " separator. */ 1004233323Sraj buf_len += count * 2; 1005208538Sraj } 1006208538Sraj 1007233323Sraj /* Add some space for surrounding double quotes. */ 1008233323Sraj buf_len += count * 2; 1009233323Sraj 1010233323Sraj /* Note that string being put in 'tmp' may be as big as 'buf_len'. */ 1011233323Sraj b = (char *)malloc(buf_len); 1012233323Sraj tmp = (char *)malloc(buf_len); 1013208538Sraj if (b == NULL) 1014233323Sraj goto error; 1015233323Sraj 1016233323Sraj if (tmp == NULL) { 1017233323Sraj free(b); 1018233323Sraj goto error; 1019233323Sraj } 1020233323Sraj 1021208538Sraj b[0] = '\0'; 1022208538Sraj 1023208538Sraj /* 1024208538Sraj * Now that we have space, format the string. 1025208538Sraj */ 1026208538Sraj i = 0; 1027208538Sraj do { 1028208538Sraj d = (const char *)data + i; 1029208538Sraj l = strlen(d) + 1; 1030208538Sraj 1031208538Sraj sprintf(tmp, "\"%s\"%s", d, 1032208538Sraj (i + l) < len ? ", " : ""); 1033208538Sraj strcat(b, tmp); 1034208538Sraj 1035208538Sraj i += l; 1036208538Sraj 1037208538Sraj } while (i < len); 1038208538Sraj *buf = b; 1039208538Sraj 1040233323Sraj free(tmp); 1041233323Sraj 1042208538Sraj return (0); 1043233323Srajerror: 1044233323Sraj return (1); 1045208538Sraj} 1046208538Sraj 1047208538Srajstatic int 1048208538Srajfdt_data_cell(const void *data, int len, char **buf) 1049208538Sraj{ 1050233323Sraj char *b, *tmp; 1051208538Sraj const uint32_t *c; 1052208538Sraj int count, i, l; 1053208538Sraj 1054208538Sraj /* Number of cells */ 1055208538Sraj count = len / 4; 1056208538Sraj 1057208538Sraj /* 1058208538Sraj * Calculate the length for the string and allocate memory. 1059208538Sraj */ 1060208538Sraj 1061208538Sraj /* Each byte translates to 2 output characters */ 1062208538Sraj l = len * 2; 1063208538Sraj if (count > 1) { 1064208538Sraj /* Each consecutive cell requires a " " separator. */ 1065208538Sraj l += (count - 1) * 1; 1066208538Sraj } 1067208538Sraj /* Each cell will have a "0x" prefix */ 1068208538Sraj l += count * 2; 1069208538Sraj /* Space for surrounding <> and terminator */ 1070208538Sraj l += 3; 1071208538Sraj 1072208538Sraj b = (char *)malloc(l); 1073233323Sraj tmp = (char *)malloc(l); 1074208538Sraj if (b == NULL) 1075233323Sraj goto error; 1076208538Sraj 1077233323Sraj if (tmp == NULL) { 1078233323Sraj free(b); 1079233323Sraj goto error; 1080233323Sraj } 1081233323Sraj 1082208538Sraj b[0] = '\0'; 1083208538Sraj strcat(b, "<"); 1084208538Sraj 1085208538Sraj for (i = 0; i < len; i += 4) { 1086208538Sraj c = (const uint32_t *)((const uint8_t *)data + i); 1087208538Sraj sprintf(tmp, "0x%08x%s", fdt32_to_cpu(*c), 1088208538Sraj i < (len - 4) ? " " : ""); 1089208538Sraj strcat(b, tmp); 1090208538Sraj } 1091208538Sraj strcat(b, ">"); 1092208538Sraj *buf = b; 1093208538Sraj 1094233323Sraj free(tmp); 1095233323Sraj 1096208538Sraj return (0); 1097233323Srajerror: 1098233323Sraj return (1); 1099208538Sraj} 1100208538Sraj 1101208538Srajstatic int 1102208538Srajfdt_data_bytes(const void *data, int len, char **buf) 1103208538Sraj{ 1104233323Sraj char *b, *tmp; 1105208538Sraj const char *d; 1106208538Sraj int i, l; 1107208538Sraj 1108208538Sraj /* 1109208538Sraj * Calculate the length for the string and allocate memory. 1110208538Sraj */ 1111208538Sraj 1112208538Sraj /* Each byte translates to 2 output characters */ 1113208538Sraj l = len * 2; 1114208538Sraj if (len > 1) 1115208538Sraj /* Each consecutive byte requires a " " separator. */ 1116208538Sraj l += (len - 1) * 1; 1117208538Sraj /* Each byte will have a "0x" prefix */ 1118208538Sraj l += len * 2; 1119208538Sraj /* Space for surrounding [] and terminator. */ 1120208538Sraj l += 3; 1121208538Sraj 1122208538Sraj b = (char *)malloc(l); 1123233323Sraj tmp = (char *)malloc(l); 1124208538Sraj if (b == NULL) 1125233323Sraj goto error; 1126208538Sraj 1127233323Sraj if (tmp == NULL) { 1128233323Sraj free(b); 1129233323Sraj goto error; 1130233323Sraj } 1131233323Sraj 1132208538Sraj b[0] = '\0'; 1133208538Sraj strcat(b, "["); 1134208538Sraj 1135208538Sraj for (i = 0, d = data; i < len; i++) { 1136208538Sraj sprintf(tmp, "0x%02x%s", d[i], i < len - 1 ? " " : ""); 1137208538Sraj strcat(b, tmp); 1138208538Sraj } 1139208538Sraj strcat(b, "]"); 1140208538Sraj *buf = b; 1141208538Sraj 1142233323Sraj free(tmp); 1143233323Sraj 1144208538Sraj return (0); 1145233323Srajerror: 1146233323Sraj return (1); 1147208538Sraj} 1148208538Sraj 1149208538Srajstatic int 1150208538Srajfdt_data_fmt(const void *data, int len, char **buf) 1151208538Sraj{ 1152208538Sraj int count; 1153208538Sraj 1154208538Sraj if (len == 0) { 1155208538Sraj *buf = NULL; 1156208538Sraj return (1); 1157208538Sraj } 1158208538Sraj 1159208538Sraj if (fdt_isprint(data, len, &count)) 1160208538Sraj return (fdt_data_str(data, len, count, buf)); 1161208538Sraj 1162208538Sraj else if ((len % 4) == 0) 1163208538Sraj return (fdt_data_cell(data, len, buf)); 1164208538Sraj 1165208538Sraj else 1166208538Sraj return (fdt_data_bytes(data, len, buf)); 1167208538Sraj} 1168208538Sraj 1169208538Srajstatic int 1170208538Srajfdt_prop(int offset) 1171208538Sraj{ 1172208538Sraj char *line, *buf; 1173208538Sraj const struct fdt_property *prop; 1174208538Sraj const char *name; 1175208538Sraj const void *data; 1176208538Sraj int len, rv; 1177208538Sraj 1178208538Sraj line = NULL; 1179208538Sraj prop = fdt_offset_ptr(fdtp, offset, sizeof(*prop)); 1180208538Sraj if (prop == NULL) 1181208538Sraj return (1); 1182208538Sraj 1183208538Sraj name = fdt_string(fdtp, fdt32_to_cpu(prop->nameoff)); 1184208538Sraj len = fdt32_to_cpu(prop->len); 1185208538Sraj 1186208538Sraj rv = 0; 1187208538Sraj buf = NULL; 1188208538Sraj if (len == 0) { 1189208538Sraj /* Property without value */ 1190208538Sraj line = (char *)malloc(strlen(name) + 2); 1191208538Sraj if (line == NULL) { 1192208538Sraj rv = 2; 1193208538Sraj goto out2; 1194208538Sraj } 1195208538Sraj sprintf(line, "%s\n", name); 1196208538Sraj goto out1; 1197208538Sraj } 1198208538Sraj 1199208538Sraj /* 1200208538Sraj * Process property with value 1201208538Sraj */ 1202208538Sraj data = prop->data; 1203208538Sraj 1204208538Sraj if (fdt_data_fmt(data, len, &buf) != 0) { 1205208538Sraj rv = 3; 1206208538Sraj goto out2; 1207208538Sraj } 1208208538Sraj 1209208538Sraj line = (char *)malloc(strlen(name) + strlen(FDT_PROP_SEP) + 1210208538Sraj strlen(buf) + 2); 1211208538Sraj if (line == NULL) { 1212208538Sraj sprintf(command_errbuf, "could not allocate space for string"); 1213208538Sraj rv = 4; 1214208538Sraj goto out2; 1215208538Sraj } 1216208538Sraj 1217208538Sraj sprintf(line, "%s" FDT_PROP_SEP "%s\n", name, buf); 1218208538Sraj 1219208538Srajout1: 1220208538Sraj pager_open(); 1221208538Sraj pager_output(line); 1222208538Sraj pager_close(); 1223208538Sraj 1224208538Srajout2: 1225208538Sraj if (buf) 1226208538Sraj free(buf); 1227208538Sraj 1228208538Sraj if (line) 1229208538Sraj free(line); 1230208538Sraj 1231208538Sraj return (rv); 1232208538Sraj} 1233208538Sraj 1234208538Srajstatic int 1235208538Srajfdt_modprop(int nodeoff, char *propname, void *value, char mode) 1236208538Sraj{ 1237208538Sraj uint32_t cells[100]; 1238275762Sandrew const char *buf; 1239208538Sraj int len, rv; 1240208538Sraj const struct fdt_property *p; 1241208538Sraj 1242208538Sraj p = fdt_get_property(fdtp, nodeoff, propname, NULL); 1243208538Sraj 1244208538Sraj if (p != NULL) { 1245208538Sraj if (mode == 1) { 1246208538Sraj /* Adding inexistant value in mode 1 is forbidden */ 1247208538Sraj sprintf(command_errbuf, "property already exists!"); 1248208538Sraj return (CMD_ERROR); 1249208538Sraj } 1250208538Sraj } else if (mode == 0) { 1251208538Sraj sprintf(command_errbuf, "property does not exist!"); 1252208538Sraj return (CMD_ERROR); 1253208538Sraj } 1254208538Sraj len = strlen(value); 1255208538Sraj rv = 0; 1256275762Sandrew buf = value; 1257208538Sraj 1258208538Sraj switch (*buf) { 1259208538Sraj case '&': 1260208538Sraj /* phandles */ 1261208538Sraj break; 1262208538Sraj case '<': 1263208538Sraj /* Data cells */ 1264208538Sraj len = fdt_strtovect(buf, (void *)&cells, 100, 1265208538Sraj sizeof(uint32_t)); 1266208538Sraj 1267208538Sraj rv = fdt_setprop(fdtp, nodeoff, propname, &cells, 1268208538Sraj len * sizeof(uint32_t)); 1269208538Sraj break; 1270208538Sraj case '[': 1271208538Sraj /* Data bytes */ 1272208538Sraj len = fdt_strtovect(buf, (void *)&cells, 100, 1273208538Sraj sizeof(uint8_t)); 1274208538Sraj 1275208538Sraj rv = fdt_setprop(fdtp, nodeoff, propname, &cells, 1276208538Sraj len * sizeof(uint8_t)); 1277208538Sraj break; 1278208538Sraj case '"': 1279208538Sraj default: 1280208538Sraj /* Default -- string */ 1281208538Sraj rv = fdt_setprop_string(fdtp, nodeoff, propname, value); 1282208538Sraj break; 1283208538Sraj } 1284208538Sraj 1285233323Sraj if (rv != 0) { 1286233323Sraj if (rv == -FDT_ERR_NOSPACE) 1287233323Sraj sprintf(command_errbuf, 1288233323Sraj "Device tree blob is too small!\n"); 1289233323Sraj else 1290233323Sraj sprintf(command_errbuf, 1291233323Sraj "Could not add/modify property!\n"); 1292233323Sraj } 1293208538Sraj return (rv); 1294208538Sraj} 1295208538Sraj 1296208538Sraj/* Merge strings from argv into a single string */ 1297208538Srajstatic int 1298208538Srajfdt_merge_strings(int argc, char *argv[], int start, char **buffer) 1299208538Sraj{ 1300208538Sraj char *buf; 1301208538Sraj int i, idx, sz; 1302208538Sraj 1303208538Sraj *buffer = NULL; 1304208538Sraj sz = 0; 1305208538Sraj 1306208538Sraj for (i = start; i < argc; i++) 1307208538Sraj sz += strlen(argv[i]); 1308208538Sraj 1309208538Sraj /* Additional bytes for whitespaces between args */ 1310208538Sraj sz += argc - start; 1311208538Sraj 1312208538Sraj buf = (char *)malloc(sizeof(char) * sz); 1313208538Sraj bzero(buf, sizeof(char) * sz); 1314208538Sraj 1315208538Sraj if (buf == NULL) { 1316208538Sraj sprintf(command_errbuf, "could not allocate space " 1317208538Sraj "for string"); 1318208538Sraj return (1); 1319208538Sraj } 1320208538Sraj 1321208538Sraj idx = 0; 1322208538Sraj for (i = start, idx = 0; i < argc; i++) { 1323208538Sraj strcpy(buf + idx, argv[i]); 1324208538Sraj idx += strlen(argv[i]); 1325208538Sraj buf[idx] = ' '; 1326208538Sraj idx++; 1327208538Sraj } 1328208538Sraj buf[sz - 1] = '\0'; 1329208538Sraj *buffer = buf; 1330208538Sraj return (0); 1331208538Sraj} 1332208538Sraj 1333208538Sraj/* Extract offset and name of node/property from a given path */ 1334208538Srajstatic int 1335208538Srajfdt_extract_nameloc(char **pathp, char **namep, int *nodeoff) 1336208538Sraj{ 1337208538Sraj int o; 1338208538Sraj char *path = *pathp, *name = NULL, *subpath = NULL; 1339208538Sraj 1340208538Sraj subpath = strrchr(path, '/'); 1341208538Sraj if (subpath == NULL) { 1342208538Sraj o = fdt_path_offset(fdtp, cwd); 1343208538Sraj name = path; 1344208538Sraj path = (char *)&cwd; 1345208538Sraj } else { 1346208538Sraj *subpath = '\0'; 1347208538Sraj if (strlen(path) == 0) 1348208538Sraj path = cwd; 1349208538Sraj 1350208538Sraj name = subpath + 1; 1351208538Sraj o = fdt_path_offset(fdtp, path); 1352208538Sraj } 1353208538Sraj 1354208538Sraj if (strlen(name) == 0) { 1355208538Sraj sprintf(command_errbuf, "name not specified"); 1356208538Sraj return (1); 1357208538Sraj } 1358208538Sraj if (o < 0) { 1359208538Sraj sprintf(command_errbuf, "could not find node: '%s'", path); 1360208538Sraj return (1); 1361208538Sraj } 1362208538Sraj *namep = name; 1363208538Sraj *nodeoff = o; 1364208538Sraj *pathp = path; 1365208538Sraj return (0); 1366208538Sraj} 1367208538Sraj 1368208538Srajstatic int 1369208538Srajfdt_cmd_prop(int argc, char *argv[]) 1370208538Sraj{ 1371208538Sraj char *path, *propname, *value; 1372208538Sraj int o, next, depth, rv; 1373208538Sraj uint32_t tag; 1374208538Sraj 1375208538Sraj path = (argc > 2) ? argv[2] : NULL; 1376208538Sraj 1377208538Sraj value = NULL; 1378208538Sraj 1379208538Sraj if (argc > 3) { 1380208538Sraj /* Merge property value strings into one */ 1381208538Sraj if (fdt_merge_strings(argc, argv, 3, &value) != 0) 1382208538Sraj return (CMD_ERROR); 1383208538Sraj } else 1384208538Sraj value = NULL; 1385208538Sraj 1386208538Sraj if (path == NULL) 1387208538Sraj path = cwd; 1388208538Sraj 1389208538Sraj rv = CMD_OK; 1390208538Sraj 1391208538Sraj if (value) { 1392208538Sraj /* If value is specified -- try to modify prop. */ 1393208538Sraj if (fdt_extract_nameloc(&path, &propname, &o) != 0) 1394208538Sraj return (CMD_ERROR); 1395208538Sraj 1396208538Sraj rv = fdt_modprop(o, propname, value, 0); 1397208538Sraj if (rv) 1398208538Sraj return (CMD_ERROR); 1399208538Sraj return (CMD_OK); 1400208538Sraj 1401208538Sraj } 1402208538Sraj /* User wants to display properties */ 1403208538Sraj o = fdt_path_offset(fdtp, path); 1404208538Sraj 1405208538Sraj if (o < 0) { 1406208538Sraj sprintf(command_errbuf, "could not find node: '%s'", path); 1407208538Sraj rv = CMD_ERROR; 1408208538Sraj goto out; 1409208538Sraj } 1410208538Sraj 1411208538Sraj depth = 0; 1412208538Sraj while (depth >= 0) { 1413208538Sraj tag = fdt_next_tag(fdtp, o, &next); 1414208538Sraj switch (tag) { 1415208538Sraj case FDT_NOP: 1416208538Sraj break; 1417208538Sraj case FDT_PROP: 1418208538Sraj if (depth > 1) 1419208538Sraj /* Don't process properties of nested nodes */ 1420208538Sraj break; 1421208538Sraj 1422208538Sraj if (fdt_prop(o) != 0) { 1423208538Sraj sprintf(command_errbuf, "could not process " 1424208538Sraj "property"); 1425208538Sraj rv = CMD_ERROR; 1426208538Sraj goto out; 1427208538Sraj } 1428208538Sraj break; 1429208538Sraj case FDT_BEGIN_NODE: 1430208538Sraj depth++; 1431208538Sraj if (depth > FDT_MAX_DEPTH) { 1432208538Sraj printf("warning: nesting too deep: %d\n", 1433208538Sraj depth); 1434208538Sraj goto out; 1435208538Sraj } 1436208538Sraj break; 1437208538Sraj case FDT_END_NODE: 1438208538Sraj depth--; 1439208538Sraj if (depth == 0) 1440208538Sraj /* 1441208538Sraj * This is the end of our starting node, force 1442208538Sraj * the loop finish. 1443208538Sraj */ 1444208538Sraj depth--; 1445208538Sraj break; 1446208538Sraj } 1447208538Sraj o = next; 1448208538Sraj } 1449208538Srajout: 1450208538Sraj return (rv); 1451208538Sraj} 1452208538Sraj 1453208538Srajstatic int 1454208538Srajfdt_cmd_mkprop(int argc, char *argv[]) 1455208538Sraj{ 1456208538Sraj int o; 1457208538Sraj char *path, *propname, *value; 1458208538Sraj 1459208538Sraj path = (argc > 2) ? argv[2] : NULL; 1460208538Sraj 1461208538Sraj value = NULL; 1462208538Sraj 1463208538Sraj if (argc > 3) { 1464208538Sraj /* Merge property value strings into one */ 1465208538Sraj if (fdt_merge_strings(argc, argv, 3, &value) != 0) 1466208538Sraj return (CMD_ERROR); 1467208538Sraj } else 1468208538Sraj value = NULL; 1469208538Sraj 1470208538Sraj if (fdt_extract_nameloc(&path, &propname, &o) != 0) 1471208538Sraj return (CMD_ERROR); 1472208538Sraj 1473208538Sraj if (fdt_modprop(o, propname, value, 1)) 1474208538Sraj return (CMD_ERROR); 1475208538Sraj 1476208538Sraj return (CMD_OK); 1477208538Sraj} 1478208538Sraj 1479208538Srajstatic int 1480208538Srajfdt_cmd_rm(int argc, char *argv[]) 1481208538Sraj{ 1482208538Sraj int o, rv; 1483208538Sraj char *path = NULL, *propname; 1484208538Sraj 1485208538Sraj if (argc > 2) 1486208538Sraj path = argv[2]; 1487208538Sraj else { 1488208538Sraj sprintf(command_errbuf, "no node/property name specified"); 1489208538Sraj return (CMD_ERROR); 1490208538Sraj } 1491208538Sraj 1492208538Sraj o = fdt_path_offset(fdtp, path); 1493208538Sraj if (o < 0) { 1494208538Sraj /* If node not found -- try to find & delete property */ 1495208538Sraj if (fdt_extract_nameloc(&path, &propname, &o) != 0) 1496208538Sraj return (CMD_ERROR); 1497208538Sraj 1498208538Sraj if ((rv = fdt_delprop(fdtp, o, propname)) != 0) { 1499208538Sraj sprintf(command_errbuf, "could not delete" 1500208538Sraj "%s\n", (rv == -FDT_ERR_NOTFOUND) ? 1501208538Sraj "(property/node does not exist)" : ""); 1502208538Sraj return (CMD_ERROR); 1503208538Sraj 1504208538Sraj } else 1505208538Sraj return (CMD_OK); 1506208538Sraj } 1507208538Sraj /* If node exists -- remove node */ 1508208538Sraj rv = fdt_del_node(fdtp, o); 1509208538Sraj if (rv) { 1510208538Sraj sprintf(command_errbuf, "could not delete node"); 1511208538Sraj return (CMD_ERROR); 1512208538Sraj } 1513208538Sraj return (CMD_OK); 1514208538Sraj} 1515208538Sraj 1516208538Srajstatic int 1517208538Srajfdt_cmd_mknode(int argc, char *argv[]) 1518208538Sraj{ 1519208538Sraj int o, rv; 1520208538Sraj char *path = NULL, *nodename = NULL; 1521208538Sraj 1522208538Sraj if (argc > 2) 1523208538Sraj path = argv[2]; 1524208538Sraj else { 1525208538Sraj sprintf(command_errbuf, "no node name specified"); 1526208538Sraj return (CMD_ERROR); 1527208538Sraj } 1528208538Sraj 1529208538Sraj if (fdt_extract_nameloc(&path, &nodename, &o) != 0) 1530208538Sraj return (CMD_ERROR); 1531208538Sraj 1532208538Sraj rv = fdt_add_subnode(fdtp, o, nodename); 1533208538Sraj 1534208538Sraj if (rv < 0) { 1535233323Sraj if (rv == -FDT_ERR_NOSPACE) 1536233323Sraj sprintf(command_errbuf, 1537233323Sraj "Device tree blob is too small!\n"); 1538233323Sraj else 1539233323Sraj sprintf(command_errbuf, 1540233323Sraj "Could not add node!\n"); 1541208538Sraj return (CMD_ERROR); 1542208538Sraj } 1543208538Sraj return (CMD_OK); 1544208538Sraj} 1545208538Sraj 1546208538Srajstatic int 1547208538Srajfdt_cmd_pwd(int argc, char *argv[]) 1548208538Sraj{ 1549233323Sraj char line[FDT_CWD_LEN]; 1550208538Sraj 1551208538Sraj pager_open(); 1552208538Sraj sprintf(line, "%s\n", cwd); 1553208538Sraj pager_output(line); 1554208538Sraj pager_close(); 1555208538Sraj return (CMD_OK); 1556208538Sraj} 1557208538Sraj 1558208538Srajstatic int 1559243693Sgonzofdt_cmd_mres(int argc, char *argv[]) 1560243693Sgonzo{ 1561243693Sgonzo uint64_t start, size; 1562243693Sgonzo int i, total; 1563243693Sgonzo char line[80]; 1564243693Sgonzo 1565243693Sgonzo pager_open(); 1566243693Sgonzo total = fdt_num_mem_rsv(fdtp); 1567243693Sgonzo if (total > 0) { 1568243693Sgonzo pager_output("Reserved memory regions:\n"); 1569243693Sgonzo for (i = 0; i < total; i++) { 1570243693Sgonzo fdt_get_mem_rsv(fdtp, i, &start, &size); 1571243693Sgonzo sprintf(line, "reg#%d: (start: 0x%jx, size: 0x%jx)\n", 1572243693Sgonzo i, start, size); 1573243693Sgonzo pager_output(line); 1574243693Sgonzo } 1575243693Sgonzo } else 1576243693Sgonzo pager_output("No reserved memory regions\n"); 1577243693Sgonzo pager_close(); 1578243693Sgonzo 1579243693Sgonzo return (CMD_OK); 1580243693Sgonzo} 1581243693Sgonzo 1582243693Sgonzostatic int 1583208538Srajfdt_cmd_nyi(int argc, char *argv[]) 1584208538Sraj{ 1585208538Sraj 1586208538Sraj printf("command not yet implemented\n"); 1587208538Sraj return (CMD_ERROR); 1588208538Sraj} 1589