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$"); 32208538Sraj 33208538Sraj#include <stand.h> 34208538Sraj#include <fdt.h> 35208538Sraj#include <libfdt.h> 36233230Sraj#include <sys/param.h> 37233230Sraj#include <sys/linker.h> 38233230Sraj#include <machine/elf.h> 39208538Sraj 40208538Sraj#include "bootstrap.h" 41208538Sraj#include "glue.h" 42208538Sraj 43208538Sraj#ifdef DEBUG 44208538Sraj#define debugf(fmt, args...) do { printf("%s(): ", __func__); \ 45208538Sraj printf(fmt,##args); } while (0) 46208538Sraj#else 47208538Sraj#define debugf(fmt, args...) 48208538Sraj#endif 49208538Sraj 50208538Sraj#define FDT_CWD_LEN 256 51208538Sraj#define FDT_MAX_DEPTH 6 52208538Sraj 53208538Sraj#define FDT_PROP_SEP " = " 54208538Sraj 55208538Sraj#define STR(number) #number 56208538Sraj#define STRINGIFY(number) STR(number) 57208538Sraj 58235529Skientzle#define COPYOUT(s,d,l) archsw.arch_copyout(s, d, l) 59235529Skientzle#define COPYIN(s,d,l) archsw.arch_copyin(s, d, l) 60233230Sraj 61233230Sraj#define FDT_STATIC_DTB_SYMBOL "fdt_static_dtb" 62233230Sraj 63243693Sgonzo#define CMD_REQUIRES_BLOB 0x01 64243693Sgonzo 65247201Skientzle/* Location of FDT yet to be loaded. */ 66247250Skientzle/* This may be in read-only memory, so can't be manipulated directly. */ 67247201Skientzlestatic struct fdt_header *fdt_to_load = NULL; 68247250Skientzle/* Location of FDT on heap. */ 69247250Skientzle/* This is the copy we actually manipulate. */ 70208538Srajstatic struct fdt_header *fdtp = NULL; 71235529Skientzle/* Size of FDT blob */ 72235529Skientzlestatic size_t fdtp_size = 0; 73247250Skientzle/* Location of FDT in kernel or module. */ 74247250Skientzle/* This won't be set if FDT is loaded from disk or memory. */ 75247250Skientzle/* If it is set, we'll update it when fdt_copy() gets called. */ 76235529Skientzlestatic vm_offset_t fdtp_va = 0; 77208538Sraj 78243693Sgonzostatic int fdt_load_dtb(vm_offset_t va); 79243693Sgonzo 80208538Srajstatic int fdt_cmd_nyi(int argc, char *argv[]); 81208538Sraj 82243693Sgonzostatic int fdt_cmd_addr(int argc, char *argv[]); 83208538Srajstatic int fdt_cmd_mkprop(int argc, char *argv[]); 84208538Srajstatic int fdt_cmd_cd(int argc, char *argv[]); 85208538Srajstatic int fdt_cmd_hdr(int argc, char *argv[]); 86208538Srajstatic int fdt_cmd_ls(int argc, char *argv[]); 87208538Srajstatic int fdt_cmd_prop(int argc, char *argv[]); 88208538Srajstatic int fdt_cmd_pwd(int argc, char *argv[]); 89208538Srajstatic int fdt_cmd_rm(int argc, char *argv[]); 90208538Srajstatic int fdt_cmd_mknode(int argc, char *argv[]); 91243693Sgonzostatic int fdt_cmd_mres(int argc, char *argv[]); 92208538Sraj 93208538Srajtypedef int cmdf_t(int, char *[]); 94208538Sraj 95208538Srajstruct cmdtab { 96208538Sraj char *name; 97208538Sraj cmdf_t *handler; 98243693Sgonzo int flags; 99208538Sraj}; 100208538Sraj 101208538Srajstatic const struct cmdtab commands[] = { 102243693Sgonzo { "addr", &fdt_cmd_addr, 0 }, 103243693Sgonzo { "alias", &fdt_cmd_nyi, 0 }, 104243693Sgonzo { "cd", &fdt_cmd_cd, CMD_REQUIRES_BLOB }, 105243693Sgonzo { "header", &fdt_cmd_hdr, CMD_REQUIRES_BLOB }, 106243693Sgonzo { "ls", &fdt_cmd_ls, CMD_REQUIRES_BLOB }, 107243693Sgonzo { "mknode", &fdt_cmd_mknode, CMD_REQUIRES_BLOB }, 108243693Sgonzo { "mkprop", &fdt_cmd_mkprop, CMD_REQUIRES_BLOB }, 109243693Sgonzo { "mres", &fdt_cmd_mres, CMD_REQUIRES_BLOB }, 110243693Sgonzo { "prop", &fdt_cmd_prop, CMD_REQUIRES_BLOB }, 111243693Sgonzo { "pwd", &fdt_cmd_pwd, CMD_REQUIRES_BLOB }, 112243693Sgonzo { "rm", &fdt_cmd_rm, CMD_REQUIRES_BLOB }, 113208538Sraj { NULL, NULL } 114208538Sraj}; 115208538Sraj 116208538Srajstatic char cwd[FDT_CWD_LEN] = "/"; 117208538Sraj 118233230Srajstatic vm_offset_t 119235529Skientzlefdt_find_static_dtb() 120233230Sraj{ 121248121Sian Elf_Ehdr *ehdr; 122248121Sian Elf_Shdr *shdr; 123233230Sraj Elf_Sym sym; 124248121Sian vm_offset_t strtab, symtab, fdt_start; 125233230Sraj uint64_t offs; 126233230Sraj struct preloaded_file *kfp; 127233230Sraj struct file_metadata *md; 128235529Skientzle char *strp; 129248121Sian int i, sym_count; 130233230Sraj 131265068Sian debugf("fdt_find_static_dtb()\n"); 132265068Sian 133248934Skientzle sym_count = symtab = strtab = 0; 134235529Skientzle strp = NULL; 135233230Sraj 136233230Sraj offs = __elfN(relocation_offset); 137233230Sraj 138233230Sraj kfp = file_findfile(NULL, NULL); 139233230Sraj if (kfp == NULL) 140233230Sraj return (0); 141233230Sraj 142248121Sian /* Locate the dynamic symbols and strtab. */ 143248121Sian md = file_findmetadata(kfp, MODINFOMD_ELFHDR); 144233230Sraj if (md == NULL) 145233230Sraj return (0); 146248121Sian ehdr = (Elf_Ehdr *)md->md_data; 147233230Sraj 148248121Sian md = file_findmetadata(kfp, MODINFOMD_SHDR); 149233230Sraj if (md == NULL) 150233230Sraj return (0); 151248121Sian shdr = (Elf_Shdr *)md->md_data; 152233230Sraj 153248121Sian for (i = 0; i < ehdr->e_shnum; ++i) { 154248121Sian if (shdr[i].sh_type == SHT_DYNSYM && symtab == 0) { 155248121Sian symtab = shdr[i].sh_addr + offs; 156248121Sian sym_count = shdr[i].sh_size / sizeof(Elf_Sym); 157248121Sian } else if (shdr[i].sh_type == SHT_STRTAB && strtab == 0) { 158248121Sian strtab = shdr[i].sh_addr + offs; 159233230Sraj } 160233230Sraj } 161233230Sraj 162233230Sraj /* 163233230Sraj * The most efficent way to find a symbol would be to calculate a 164233230Sraj * hash, find proper bucket and chain, and thus find a symbol. 165233230Sraj * However, that would involve code duplication (e.g. for hash 166233230Sraj * function). So we're using simpler and a bit slower way: we're 167233230Sraj * iterating through symbols, searching for the one which name is 168233230Sraj * 'equal' to 'fdt_static_dtb'. To speed up the process a little bit, 169233230Sraj * we are eliminating symbols type of which is not STT_NOTYPE, or(and) 170233230Sraj * those which binding attribute is not STB_GLOBAL. 171233230Sraj */ 172235529Skientzle fdt_start = 0; 173235529Skientzle while (sym_count > 0 && fdt_start == 0) { 174235529Skientzle COPYOUT(symtab, &sym, sizeof(sym)); 175235529Skientzle symtab += sizeof(sym); 176235529Skientzle --sym_count; 177233230Sraj if (ELF_ST_BIND(sym.st_info) != STB_GLOBAL || 178233230Sraj ELF_ST_TYPE(sym.st_info) != STT_NOTYPE) 179233230Sraj continue; 180235529Skientzle strp = strdupout(strtab + sym.st_name); 181235529Skientzle if (strcmp(strp, FDT_STATIC_DTB_SYMBOL) == 0) 182235529Skientzle fdt_start = (vm_offset_t)sym.st_value + offs; 183233230Sraj free(strp); 184233230Sraj } 185235529Skientzle return (fdt_start); 186233230Sraj} 187233230Sraj 188208538Srajstatic int 189243693Sgonzofdt_load_dtb(vm_offset_t va) 190208538Sraj{ 191235529Skientzle struct fdt_header header; 192208538Sraj int err; 193208538Sraj 194265068Sian debugf("fdt_load_dtb(0x%08jx)\n", (uintmax_t)va); 195265068Sian 196243693Sgonzo COPYOUT(va, &header, sizeof(header)); 197243693Sgonzo err = fdt_check_header(&header); 198243693Sgonzo if (err < 0) { 199243693Sgonzo if (err == -FDT_ERR_BADVERSION) 200243693Sgonzo sprintf(command_errbuf, 201243693Sgonzo "incompatible blob version: %d, should be: %d", 202243693Sgonzo fdt_version(fdtp), FDT_LAST_SUPPORTED_VERSION); 203243693Sgonzo 204243693Sgonzo else 205243693Sgonzo sprintf(command_errbuf, "error validating blob: %s", 206243693Sgonzo fdt_strerror(err)); 207243693Sgonzo return (1); 208243693Sgonzo } 209243693Sgonzo 210208538Sraj /* 211243693Sgonzo * Release previous blob 212208538Sraj */ 213243693Sgonzo if (fdtp) 214243693Sgonzo free(fdtp); 215208538Sraj 216235529Skientzle fdtp_size = fdt_totalsize(&header); 217235529Skientzle fdtp = malloc(fdtp_size); 218243693Sgonzo 219235529Skientzle if (fdtp == NULL) { 220235529Skientzle command_errmsg = "can't allocate memory for device tree copy"; 221243693Sgonzo return (1); 222235529Skientzle } 223235529Skientzle 224243693Sgonzo fdtp_va = va; 225243693Sgonzo COPYOUT(va, fdtp, fdtp_size); 226243693Sgonzo debugf("DTB blob found at 0x%jx, size: 0x%jx\n", (uintmax_t)va, (uintmax_t)fdtp_size); 227208538Sraj 228243693Sgonzo return (0); 229243693Sgonzo} 230243693Sgonzo 231243693Sgonzostatic int 232247045Skientzlefdt_load_dtb_addr(struct fdt_header *header) 233243693Sgonzo{ 234265065Sian int err; 235243693Sgonzo 236265068Sian debugf("fdt_load_dtb_addr(0x%p)\n", header); 237265068Sian 238247250Skientzle fdtp_size = fdt_totalsize(header); 239265065Sian err = fdt_check_header(header); 240265065Sian if (err < 0) { 241265065Sian sprintf(command_errbuf, "error validating blob: %s", 242265065Sian fdt_strerror(err)); 243265065Sian return (err); 244265065Sian } 245247250Skientzle free(fdtp); 246247250Skientzle if ((fdtp = malloc(fdtp_size)) == NULL) { 247247250Skientzle command_errmsg = "can't allocate memory for device tree copy"; 248247045Skientzle return (1); 249208538Sraj } 250247250Skientzle 251247250Skientzle fdtp_va = 0; // Don't write this back into module or kernel. 252247250Skientzle bcopy(header, fdtp, fdtp_size); 253247250Skientzle return (0); 254247045Skientzle} 255243693Sgonzo 256247045Skientzlestatic int 257265068Sianfdt_load_dtb_file(const char * filename) 258265068Sian{ 259265068Sian struct preloaded_file *bfp, *oldbfp; 260265068Sian int err; 261265068Sian 262265068Sian debugf("fdt_load_dtb_file(%s)\n", filename); 263265068Sian 264265068Sian oldbfp = file_findfile(NULL, "dtb"); 265265068Sian 266265068Sian /* Attempt to load and validate a new dtb from a file. */ 267265068Sian if ((bfp = file_loadraw(filename, "dtb")) == NULL) { 268265068Sian sprintf(command_errbuf, "failed to load file '%s'", filename); 269265068Sian return (1); 270265068Sian } 271265068Sian if ((err = fdt_load_dtb(bfp->f_addr)) != 0) { 272265068Sian file_discard(bfp); 273265068Sian return (err); 274265068Sian } 275265068Sian 276265068Sian /* A new dtb was validated, discard any previous file. */ 277265068Sian if (oldbfp) 278265068Sian file_discard(oldbfp); 279265068Sian return (0); 280265068Sian} 281265068Sian 282265069Sianint 283247045Skientzlefdt_setup_fdtp() 284247045Skientzle{ 285265066Sian struct preloaded_file *bfp; 286265066Sian struct fdt_header *hdr; 287265066Sian const char *s; 288265066Sian char *p; 289265066Sian vm_offset_t va; 290265066Sian 291265068Sian debugf("fdt_setup_fdtp()\n"); 292265068Sian 293265068Sian /* If we already loaded a file, use it. */ 294265066Sian if ((bfp = file_findfile(NULL, "dtb")) != NULL) { 295265068Sian if (fdt_load_dtb(bfp->f_addr) == 0) { 296265068Sian printf("Using DTB from loaded file '%s'.\n", 297265068Sian bfp->f_name); 298265068Sian return (0); 299265068Sian } 300265066Sian } 301265068Sian 302265068Sian /* If we were given the address of a valid blob in memory, use it. */ 303265066Sian if (fdt_to_load != NULL) { 304265068Sian if (fdt_load_dtb_addr(fdt_to_load) == 0) { 305265068Sian printf("Using DTB from memory address 0x%08X.\n", 306265068Sian (unsigned int)fdt_to_load); 307265068Sian return (0); 308265068Sian } 309265066Sian } 310247045Skientzle 311265068Sian /* 312265068Sian * If the U-boot environment contains a variable giving the address of a 313265068Sian * valid blob in memory, use it. Board vendors use both fdtaddr and 314265068Sian * fdt_addr names. 315265068Sian */ 316265066Sian s = ub_env_get("fdtaddr"); 317265066Sian if (s == NULL) 318265066Sian s = ub_env_get("fdt_addr"); 319265066Sian if (s != NULL && *s != '\0') { 320265066Sian hdr = (struct fdt_header *)strtoul(s, &p, 16); 321265066Sian if (*p == '\0') { 322265068Sian if (fdt_load_dtb_addr(hdr) == 0) { 323265068Sian printf("Using DTB provided by U-Boot at " 324265068Sian "address 0x%p.\n", hdr); 325265068Sian return (0); 326265068Sian } 327265066Sian } 328265066Sian } 329265068Sian 330265068Sian /* 331265068Sian * If the U-boot environment contains a variable giving the name of a 332265068Sian * file, use it if we can load and validate it. 333265068Sian */ 334265068Sian s = ub_env_get("fdtfile"); 335265068Sian if (s == NULL) 336265068Sian s = ub_env_get("fdt_file"); 337265068Sian if (s != NULL && *s != '\0') { 338265068Sian if (fdt_load_dtb_file(s) == 0) { 339265068Sian printf("Loaded DTB from file '%s'.\n", s); 340265068Sian return (0); 341265068Sian } 342265068Sian } 343265068Sian 344265068Sian /* If there is a dtb compiled into the kernel, use it. */ 345265066Sian if ((va = fdt_find_static_dtb()) != 0) { 346265068Sian if (fdt_load_dtb(va) == 0) { 347265068Sian printf("Using DTB compiled into kernel.\n"); 348265068Sian return (0); 349265068Sian } 350265066Sian } 351265066Sian 352265068Sian command_errmsg = "No device tree blob found!\n"; 353265066Sian return (1); 354208538Sraj} 355208538Sraj 356208538Sraj#define fdt_strtovect(str, cellbuf, lim, cellsize) _fdt_strtovect((str), \ 357208538Sraj (cellbuf), (lim), (cellsize), 0); 358208538Sraj 359208538Sraj/* Force using base 16 */ 360208538Sraj#define fdt_strtovectx(str, cellbuf, lim, cellsize) _fdt_strtovect((str), \ 361208538Sraj (cellbuf), (lim), (cellsize), 16); 362208538Sraj 363208538Srajstatic int 364208538Sraj_fdt_strtovect(char *str, void *cellbuf, int lim, unsigned char cellsize, 365208538Sraj uint8_t base) 366208538Sraj{ 367208538Sraj char *buf = str; 368208538Sraj char *end = str + strlen(str) - 2; 369208538Sraj uint32_t *u32buf = NULL; 370208538Sraj uint8_t *u8buf = NULL; 371208538Sraj int cnt = 0; 372208538Sraj 373208538Sraj if (cellsize == sizeof(uint32_t)) 374208538Sraj u32buf = (uint32_t *)cellbuf; 375208538Sraj else 376208538Sraj u8buf = (uint8_t *)cellbuf; 377208538Sraj 378208538Sraj if (lim == 0) 379208538Sraj return (0); 380208538Sraj 381208538Sraj while (buf < end) { 382208538Sraj 383208538Sraj /* Skip white whitespace(s)/separators */ 384208538Sraj while (!isxdigit(*buf) && buf < end) 385208538Sraj buf++; 386208538Sraj 387208538Sraj if (u32buf != NULL) 388208538Sraj u32buf[cnt] = 389208538Sraj cpu_to_fdt32((uint32_t)strtol(buf, NULL, base)); 390208538Sraj 391208538Sraj else 392208538Sraj u8buf[cnt] = (uint8_t)strtol(buf, NULL, base); 393208538Sraj 394208538Sraj if (cnt + 1 <= lim - 1) 395208538Sraj cnt++; 396208538Sraj else 397208538Sraj break; 398208538Sraj buf++; 399208538Sraj /* Find another number */ 400208538Sraj while ((isxdigit(*buf) || *buf == 'x') && buf < end) 401208538Sraj buf++; 402208538Sraj } 403208538Sraj return (cnt); 404208538Sraj} 405208538Sraj 406208538Sraj#define TMP_MAX_ETH 8 407208538Sraj 408247250Skientzlestatic void 409208538Srajfixup_ethernet(const char *env, char *ethstr, int *eth_no, int len) 410208538Sraj{ 411208538Sraj char *end, *str; 412208538Sraj uint8_t tmp_addr[6]; 413208538Sraj int i, n; 414208538Sraj 415208538Sraj /* Extract interface number */ 416208538Sraj i = strtol(env + 3, &end, 10); 417208538Sraj if (end == (env + 3)) 418208538Sraj /* 'ethaddr' means interface 0 address */ 419208538Sraj n = 0; 420208538Sraj else 421208538Sraj n = i; 422208538Sraj 423208538Sraj if (n > TMP_MAX_ETH) 424208538Sraj return; 425208538Sraj 426208538Sraj str = ub_env_get(env); 427208538Sraj 428208538Sraj /* Convert macaddr string into a vector of uints */ 429208538Sraj fdt_strtovectx(str, &tmp_addr, 6, sizeof(uint8_t)); 430208538Sraj if (n != 0) { 431208538Sraj i = strlen(env) - 7; 432208538Sraj strncpy(ethstr + 8, env + 3, i); 433208538Sraj } 434208538Sraj /* Set actual property to a value from vect */ 435208538Sraj fdt_setprop(fdtp, fdt_path_offset(fdtp, ethstr), 436208538Sraj "local-mac-address", &tmp_addr, 6 * sizeof(uint8_t)); 437208538Sraj 438208538Sraj /* Clear ethernet..XXXX.. string */ 439208538Sraj bzero(ethstr + 8, len - 8); 440208538Sraj 441208538Sraj if (n + 1 > *eth_no) 442208538Sraj *eth_no = n + 1; 443208538Sraj} 444208538Sraj 445247250Skientzlestatic void 446208538Srajfixup_cpubusfreqs(unsigned long cpufreq, unsigned long busfreq) 447208538Sraj{ 448208538Sraj int lo, o = 0, o2, maxo = 0, depth; 449208538Sraj const uint32_t zero = 0; 450208538Sraj 451208538Sraj /* We want to modify every subnode of /cpus */ 452208538Sraj o = fdt_path_offset(fdtp, "/cpus"); 453235261Skientzle if (o < 0) 454235261Skientzle return; 455208538Sraj 456208538Sraj /* maxo should contain offset of node next to /cpus */ 457208538Sraj depth = 0; 458208538Sraj maxo = o; 459208538Sraj while (depth != -1) 460208538Sraj maxo = fdt_next_node(fdtp, maxo, &depth); 461208538Sraj 462208538Sraj /* Find CPU frequency properties */ 463208538Sraj o = fdt_node_offset_by_prop_value(fdtp, o, "clock-frequency", 464208538Sraj &zero, sizeof(uint32_t)); 465208538Sraj 466208538Sraj o2 = fdt_node_offset_by_prop_value(fdtp, o, "bus-frequency", &zero, 467208538Sraj sizeof(uint32_t)); 468208538Sraj 469208538Sraj lo = MIN(o, o2); 470208538Sraj 471208538Sraj while (o != -FDT_ERR_NOTFOUND && o2 != -FDT_ERR_NOTFOUND) { 472208538Sraj 473208538Sraj o = fdt_node_offset_by_prop_value(fdtp, lo, 474208538Sraj "clock-frequency", &zero, sizeof(uint32_t)); 475208538Sraj 476208538Sraj o2 = fdt_node_offset_by_prop_value(fdtp, lo, "bus-frequency", 477208538Sraj &zero, sizeof(uint32_t)); 478208538Sraj 479208538Sraj /* We're only interested in /cpus subnode(s) */ 480208538Sraj if (lo > maxo) 481208538Sraj break; 482208538Sraj 483208538Sraj fdt_setprop_inplace_cell(fdtp, lo, "clock-frequency", 484208538Sraj (uint32_t)cpufreq); 485208538Sraj 486208538Sraj fdt_setprop_inplace_cell(fdtp, lo, "bus-frequency", 487208538Sraj (uint32_t)busfreq); 488208538Sraj 489208538Sraj lo = MIN(o, o2); 490208538Sraj } 491208538Sraj} 492208538Sraj 493247250Skientzlestatic int 494208538Srajfdt_reg_valid(uint32_t *reg, int len, int addr_cells, int size_cells) 495208538Sraj{ 496208538Sraj int cells_in_tuple, i, tuples, tuple_size; 497208538Sraj uint32_t cur_start, cur_size; 498208538Sraj 499208538Sraj cells_in_tuple = (addr_cells + size_cells); 500208538Sraj tuple_size = cells_in_tuple * sizeof(uint32_t); 501208538Sraj tuples = len / tuple_size; 502208538Sraj if (tuples == 0) 503208538Sraj return (EINVAL); 504208538Sraj 505208538Sraj for (i = 0; i < tuples; i++) { 506208538Sraj if (addr_cells == 2) 507208538Sraj cur_start = fdt64_to_cpu(reg[i * cells_in_tuple]); 508208538Sraj else 509208538Sraj cur_start = fdt32_to_cpu(reg[i * cells_in_tuple]); 510208538Sraj 511208538Sraj if (size_cells == 2) 512208538Sraj cur_size = fdt64_to_cpu(reg[i * cells_in_tuple + 2]); 513208538Sraj else 514208538Sraj cur_size = fdt32_to_cpu(reg[i * cells_in_tuple + 1]); 515208538Sraj 516208538Sraj if (cur_size == 0) 517208538Sraj return (EINVAL); 518208538Sraj 519208538Sraj debugf(" reg#%d (start: 0x%0x size: 0x%0x) valid!\n", 520208538Sraj i, cur_start, cur_size); 521208538Sraj } 522208538Sraj return (0); 523208538Sraj} 524208538Sraj 525247250Skientzlestatic void 526208538Srajfixup_memory(struct sys_info *si) 527208538Sraj{ 528208538Sraj struct mem_region *curmr; 529208538Sraj uint32_t addr_cells, size_cells; 530208538Sraj uint32_t *addr_cellsp, *reg, *size_cellsp; 531208538Sraj int err, i, len, memory, realmrno, root; 532208538Sraj uint8_t *buf, *sb; 533243693Sgonzo uint64_t rstart, rsize; 534243693Sgonzo int reserved; 535208538Sraj 536208538Sraj root = fdt_path_offset(fdtp, "/"); 537208538Sraj if (root < 0) { 538208538Sraj sprintf(command_errbuf, "Could not find root node !"); 539208538Sraj return; 540208538Sraj } 541208538Sraj 542208538Sraj memory = fdt_path_offset(fdtp, "/memory"); 543208538Sraj if (memory <= 0) { 544208538Sraj /* Create proper '/memory' node. */ 545208538Sraj memory = fdt_add_subnode(fdtp, root, "memory"); 546208538Sraj if (memory <= 0) { 547208538Sraj sprintf(command_errbuf, "Could not fixup '/memory' " 548208538Sraj "node, error code : %d!\n", memory); 549208538Sraj return; 550208538Sraj } 551208538Sraj 552208538Sraj err = fdt_setprop(fdtp, memory, "device_type", "memory", 553208538Sraj sizeof("memory")); 554208538Sraj 555208538Sraj if (err < 0) 556208538Sraj return; 557208538Sraj } 558208538Sraj 559208538Sraj addr_cellsp = (uint32_t *)fdt_getprop(fdtp, root, "#address-cells", 560208538Sraj NULL); 561208538Sraj size_cellsp = (uint32_t *)fdt_getprop(fdtp, root, "#size-cells", NULL); 562208538Sraj 563208538Sraj if (addr_cellsp == NULL || size_cellsp == NULL) { 564208538Sraj sprintf(command_errbuf, "Could not fixup '/memory' node : " 565208538Sraj "%s %s property not found in root node!\n", 566208538Sraj (!addr_cellsp) ? "#address-cells" : "", 567208538Sraj (!size_cellsp) ? "#size-cells" : ""); 568208538Sraj return; 569208538Sraj } 570208538Sraj 571208538Sraj addr_cells = fdt32_to_cpu(*addr_cellsp); 572208538Sraj size_cells = fdt32_to_cpu(*size_cellsp); 573208538Sraj 574243693Sgonzo /* 575243693Sgonzo * Convert memreserve data to memreserve property 576243693Sgonzo * Check if property already exists 577243693Sgonzo */ 578243693Sgonzo reserved = fdt_num_mem_rsv(fdtp); 579243693Sgonzo if (reserved && 580243693Sgonzo (fdt_getprop(fdtp, root, "memreserve", NULL) == NULL)) { 581243693Sgonzo len = (addr_cells + size_cells) * reserved * sizeof(uint32_t); 582243693Sgonzo sb = buf = (uint8_t *)malloc(len); 583243693Sgonzo if (!buf) 584243693Sgonzo return; 585243693Sgonzo 586243693Sgonzo bzero(buf, len); 587243693Sgonzo 588243693Sgonzo for (i = 0; i < reserved; i++) { 589243693Sgonzo curmr = &si->mr[i]; 590243693Sgonzo if (fdt_get_mem_rsv(fdtp, i, &rstart, &rsize)) 591243693Sgonzo break; 592243693Sgonzo if (rsize) { 593243693Sgonzo /* Ensure endianess, and put cells into a buffer */ 594243693Sgonzo if (addr_cells == 2) 595243693Sgonzo *(uint64_t *)buf = 596243693Sgonzo cpu_to_fdt64(rstart); 597243693Sgonzo else 598243693Sgonzo *(uint32_t *)buf = 599243693Sgonzo cpu_to_fdt32(rstart); 600243693Sgonzo 601243693Sgonzo buf += sizeof(uint32_t) * addr_cells; 602243693Sgonzo if (size_cells == 2) 603243693Sgonzo *(uint64_t *)buf = 604243693Sgonzo cpu_to_fdt64(rsize); 605243693Sgonzo else 606243693Sgonzo *(uint32_t *)buf = 607243693Sgonzo cpu_to_fdt32(rsize); 608243693Sgonzo 609243693Sgonzo buf += sizeof(uint32_t) * size_cells; 610243693Sgonzo } 611243693Sgonzo } 612243693Sgonzo 613243693Sgonzo /* Set property */ 614243693Sgonzo if ((err = fdt_setprop(fdtp, root, "memreserve", sb, len)) < 0) 615243693Sgonzo printf("Could not fixup 'memreserve' property.\n"); 616243693Sgonzo 617243693Sgonzo free(sb); 618243693Sgonzo } 619243693Sgonzo 620208538Sraj /* Count valid memory regions entries in sysinfo. */ 621208538Sraj realmrno = si->mr_no; 622208538Sraj for (i = 0; i < si->mr_no; i++) 623208538Sraj if (si->mr[i].start == 0 && si->mr[i].size == 0) 624208538Sraj realmrno--; 625208538Sraj 626208538Sraj if (realmrno == 0) { 627208538Sraj sprintf(command_errbuf, "Could not fixup '/memory' node : " 628208538Sraj "sysinfo doesn't contain valid memory regions info!\n"); 629208538Sraj return; 630208538Sraj } 631208538Sraj 632208538Sraj if ((reg = (uint32_t *)fdt_getprop(fdtp, memory, "reg", 633208538Sraj &len)) != NULL) { 634208538Sraj 635208538Sraj if (fdt_reg_valid(reg, len, addr_cells, size_cells) == 0) 636208538Sraj /* 637208538Sraj * Do not apply fixup if existing 'reg' property 638208538Sraj * seems to be valid. 639208538Sraj */ 640208538Sraj return; 641208538Sraj } 642208538Sraj 643208538Sraj len = (addr_cells + size_cells) * realmrno * sizeof(uint32_t); 644208538Sraj sb = buf = (uint8_t *)malloc(len); 645208538Sraj if (!buf) 646208538Sraj return; 647208538Sraj 648208538Sraj bzero(buf, len); 649208538Sraj 650208538Sraj for (i = 0; i < si->mr_no; i++) { 651208538Sraj curmr = &si->mr[i]; 652208538Sraj if (curmr->size != 0) { 653208538Sraj /* Ensure endianess, and put cells into a buffer */ 654208538Sraj if (addr_cells == 2) 655208538Sraj *(uint64_t *)buf = 656208538Sraj cpu_to_fdt64(curmr->start); 657208538Sraj else 658208538Sraj *(uint32_t *)buf = 659208538Sraj cpu_to_fdt32(curmr->start); 660208538Sraj 661208538Sraj buf += sizeof(uint32_t) * addr_cells; 662208538Sraj if (size_cells == 2) 663208538Sraj *(uint64_t *)buf = 664208538Sraj cpu_to_fdt64(curmr->size); 665208538Sraj else 666208538Sraj *(uint32_t *)buf = 667208538Sraj cpu_to_fdt32(curmr->size); 668208538Sraj 669208538Sraj buf += sizeof(uint32_t) * size_cells; 670208538Sraj } 671208538Sraj } 672208538Sraj 673208538Sraj /* Set property */ 674208538Sraj if ((err = fdt_setprop(fdtp, memory, "reg", sb, len)) < 0) 675208538Sraj sprintf(command_errbuf, "Could not fixup '/memory' node.\n"); 676243693Sgonzo 677243693Sgonzo free(sb); 678208538Sraj} 679208538Sraj 680247250Skientzlestatic void 681208538Srajfixup_stdout(const char *env) 682208538Sraj{ 683208538Sraj const char *str; 684208538Sraj char *ptr; 685208538Sraj int serialno; 686208538Sraj int len, no, sero; 687208538Sraj const struct fdt_property *prop; 688208538Sraj char *tmp[10]; 689208538Sraj 690208538Sraj str = ub_env_get(env); 691208538Sraj ptr = (char *)str + strlen(str) - 1; 692208538Sraj while (ptr > str && isdigit(*(str - 1))) 693208538Sraj str--; 694208538Sraj 695208538Sraj if (ptr == str) 696208538Sraj return; 697208538Sraj 698208538Sraj serialno = (int)strtol(ptr, NULL, 0); 699208538Sraj no = fdt_path_offset(fdtp, "/chosen"); 700208538Sraj if (no < 0) 701208538Sraj return; 702208538Sraj 703208538Sraj prop = fdt_get_property(fdtp, no, "stdout", &len); 704208538Sraj 705208538Sraj /* If /chosen/stdout does not extist, create it */ 706208538Sraj if (prop == NULL || (prop != NULL && len == 0)) { 707208538Sraj 708208538Sraj bzero(tmp, 10 * sizeof(char)); 709208538Sraj strcpy((char *)&tmp, "serial"); 710208538Sraj if (strlen(ptr) > 3) 711208538Sraj /* Serial number too long */ 712208538Sraj return; 713208538Sraj 714208538Sraj strncpy((char *)tmp + 6, ptr, 3); 715208538Sraj sero = fdt_path_offset(fdtp, (const char *)tmp); 716208538Sraj if (sero < 0) 717208538Sraj /* 718208538Sraj * If serial device we're trying to assign 719208538Sraj * stdout to doesn't exist in DT -- return. 720208538Sraj */ 721208538Sraj return; 722208538Sraj 723208538Sraj fdt_setprop(fdtp, no, "stdout", &tmp, 724208538Sraj strlen((char *)&tmp) + 1); 725208538Sraj fdt_setprop(fdtp, no, "stdin", &tmp, 726208538Sraj strlen((char *)&tmp) + 1); 727208538Sraj } 728208538Sraj} 729208538Sraj 730233230Sraj/* 731233230Sraj * Locate the blob, fix it up and return its location. 732233230Sraj */ 733247250Skientzlestatic int 734208538Srajfdt_fixup(void) 735208538Sraj{ 736208538Sraj const char *env; 737208538Sraj char *ethstr; 738265065Sian int chosen, eth_no, len; 739208538Sraj struct sys_info *si; 740208538Sraj 741208538Sraj env = NULL; 742208538Sraj eth_no = 0; 743208538Sraj ethstr = NULL; 744208538Sraj len = 0; 745208538Sraj 746265068Sian debugf("fdt_fixup()\n"); 747265068Sian 748265065Sian if (fdtp == NULL && fdt_setup_fdtp() != 0) 749265065Sian return (0); 750208538Sraj 751208538Sraj /* Create /chosen node (if not exists) */ 752208538Sraj if ((chosen = fdt_subnode_offset(fdtp, 0, "chosen")) == 753208538Sraj -FDT_ERR_NOTFOUND) 754208538Sraj chosen = fdt_add_subnode(fdtp, 0, "chosen"); 755208538Sraj 756208538Sraj /* Value assigned to fixup-applied does not matter. */ 757208538Sraj if (fdt_getprop(fdtp, chosen, "fixup-applied", NULL)) 758247250Skientzle return (1); 759208538Sraj 760208538Sraj /* Acquire sys_info */ 761208538Sraj si = ub_get_sys_info(); 762208538Sraj 763208538Sraj while ((env = ub_env_enum(env)) != NULL) { 764208538Sraj if (strncmp(env, "eth", 3) == 0 && 765208538Sraj strncmp(env + (strlen(env) - 4), "addr", 4) == 0) { 766208538Sraj /* 767208538Sraj * Handle Ethernet addrs: parse uboot env eth%daddr 768208538Sraj */ 769208538Sraj 770208538Sraj if (!eth_no) { 771208538Sraj /* 772208538Sraj * Check how many chars we will need to store 773208538Sraj * maximal eth iface number. 774208538Sraj */ 775208538Sraj len = strlen(STRINGIFY(TMP_MAX_ETH)) + 776208538Sraj strlen("ethernet"); 777208538Sraj 778208538Sraj /* 779208538Sraj * Reserve mem for string "ethernet" and len 780208538Sraj * chars for iface no. 781208538Sraj */ 782208538Sraj ethstr = (char *)malloc(len * sizeof(char)); 783208538Sraj bzero(ethstr, len * sizeof(char)); 784208538Sraj strcpy(ethstr, "ethernet0"); 785208538Sraj } 786208538Sraj 787208538Sraj /* Modify blob */ 788208538Sraj fixup_ethernet(env, ethstr, ð_no, len); 789208538Sraj 790208538Sraj } else if (strcmp(env, "consoledev") == 0) 791208538Sraj fixup_stdout(env); 792208538Sraj } 793208538Sraj 794208538Sraj /* Modify cpu(s) and bus clock frequenties in /cpus node [Hz] */ 795208538Sraj fixup_cpubusfreqs(si->clk_cpu, si->clk_bus); 796208538Sraj 797208538Sraj /* Fixup memory regions */ 798208538Sraj fixup_memory(si); 799208538Sraj 800208538Sraj fdt_setprop(fdtp, chosen, "fixup-applied", NULL, 0); 801247250Skientzle return (1); 802208538Sraj} 803208538Sraj 804243693Sgonzo/* 805247250Skientzle * Copy DTB blob to specified location and return size 806243693Sgonzo */ 807208538Srajint 808243693Sgonzofdt_copy(vm_offset_t va) 809243693Sgonzo{ 810243693Sgonzo int err; 811265068Sian debugf("fdt_copy va 0x%08x\n", va); 812243693Sgonzo if (fdtp == NULL) { 813243693Sgonzo err = fdt_setup_fdtp(); 814243693Sgonzo if (err) { 815265065Sian printf("No valid device tree blob found!\n"); 816243693Sgonzo return (0); 817243693Sgonzo } 818243693Sgonzo } 819243693Sgonzo 820243693Sgonzo if (fdt_fixup() == 0) 821243693Sgonzo return (0); 822243693Sgonzo 823247250Skientzle if (fdtp_va != 0) { 824247250Skientzle /* Overwrite the FDT with the fixed version. */ 825247250Skientzle /* XXX Is this really appropriate? */ 826247250Skientzle COPYIN(fdtp, fdtp_va, fdtp_size); 827247250Skientzle } 828243693Sgonzo COPYIN(fdtp, va, fdtp_size); 829243693Sgonzo return (fdtp_size); 830243693Sgonzo} 831243693Sgonzo 832243693Sgonzo 833243693Sgonzo 834243693Sgonzoint 835208538Srajcommand_fdt_internal(int argc, char *argv[]) 836208538Sraj{ 837208538Sraj cmdf_t *cmdh; 838243693Sgonzo int flags; 839208538Sraj char *cmd; 840208538Sraj int i, err; 841208538Sraj 842208538Sraj if (argc < 2) { 843208538Sraj command_errmsg = "usage is 'fdt <command> [<args>]"; 844208538Sraj return (CMD_ERROR); 845208538Sraj } 846208538Sraj 847208538Sraj /* 848208538Sraj * Validate fdt <command>. 849208538Sraj */ 850208538Sraj cmd = strdup(argv[1]); 851208538Sraj i = 0; 852208538Sraj cmdh = NULL; 853208538Sraj while (!(commands[i].name == NULL)) { 854208538Sraj if (strcmp(cmd, commands[i].name) == 0) { 855208538Sraj /* found it */ 856208538Sraj cmdh = commands[i].handler; 857243693Sgonzo flags = commands[i].flags; 858208538Sraj break; 859208538Sraj } 860208538Sraj i++; 861208538Sraj } 862208538Sraj if (cmdh == NULL) { 863208538Sraj command_errmsg = "unknown command"; 864208538Sraj return (CMD_ERROR); 865208538Sraj } 866208538Sraj 867243693Sgonzo if (flags & CMD_REQUIRES_BLOB) { 868243693Sgonzo /* 869243693Sgonzo * Check if uboot env vars were parsed already. If not, do it now. 870243693Sgonzo */ 871243693Sgonzo if (fdt_fixup() == 0) 872243693Sgonzo return (CMD_ERROR); 873243693Sgonzo } 874243693Sgonzo 875208538Sraj /* 876208538Sraj * Call command handler. 877208538Sraj */ 878208538Sraj err = (*cmdh)(argc, argv); 879208538Sraj 880208538Sraj return (err); 881208538Sraj} 882208538Sraj 883208538Srajstatic int 884243693Sgonzofdt_cmd_addr(int argc, char *argv[]) 885243693Sgonzo{ 886247201Skientzle struct preloaded_file *fp; 887247045Skientzle struct fdt_header *hdr; 888247201Skientzle const char *addr; 889247201Skientzle char *cp; 890243693Sgonzo 891247201Skientzle fdt_to_load = NULL; 892247201Skientzle 893243693Sgonzo if (argc > 2) 894243693Sgonzo addr = argv[2]; 895243693Sgonzo else { 896243693Sgonzo sprintf(command_errbuf, "no address specified"); 897243693Sgonzo return (CMD_ERROR); 898243693Sgonzo } 899243693Sgonzo 900247201Skientzle hdr = (struct fdt_header *)strtoul(addr, &cp, 16); 901243693Sgonzo if (cp == addr) { 902243693Sgonzo sprintf(command_errbuf, "Invalid address: %s", addr); 903243693Sgonzo return (CMD_ERROR); 904243693Sgonzo } 905243693Sgonzo 906247201Skientzle while ((fp = file_findfile(NULL, "dtb")) != NULL) { 907247201Skientzle file_discard(fp); 908247201Skientzle } 909243693Sgonzo 910247201Skientzle fdt_to_load = hdr; 911243693Sgonzo return (CMD_OK); 912243693Sgonzo} 913243693Sgonzo 914243693Sgonzostatic int 915208538Srajfdt_cmd_cd(int argc, char *argv[]) 916208538Sraj{ 917208538Sraj char *path; 918208538Sraj char tmp[FDT_CWD_LEN]; 919208538Sraj int len, o; 920208538Sraj 921208538Sraj path = (argc > 2) ? argv[2] : "/"; 922208538Sraj 923208538Sraj if (path[0] == '/') { 924208538Sraj len = strlen(path); 925208538Sraj if (len >= FDT_CWD_LEN) 926208538Sraj goto fail; 927208538Sraj } else { 928208538Sraj /* Handle path specification relative to cwd */ 929208538Sraj len = strlen(cwd) + strlen(path) + 1; 930208538Sraj if (len >= FDT_CWD_LEN) 931208538Sraj goto fail; 932208538Sraj 933208538Sraj strcpy(tmp, cwd); 934208538Sraj strcat(tmp, "/"); 935208538Sraj strcat(tmp, path); 936208538Sraj path = tmp; 937208538Sraj } 938208538Sraj 939208538Sraj o = fdt_path_offset(fdtp, path); 940208538Sraj if (o < 0) { 941208538Sraj sprintf(command_errbuf, "could not find node: '%s'", path); 942208538Sraj return (CMD_ERROR); 943208538Sraj } 944208538Sraj 945208538Sraj strcpy(cwd, path); 946208538Sraj return (CMD_OK); 947208538Sraj 948208538Srajfail: 949208538Sraj sprintf(command_errbuf, "path too long: %d, max allowed: %d", 950208538Sraj len, FDT_CWD_LEN - 1); 951208538Sraj return (CMD_ERROR); 952208538Sraj} 953208538Sraj 954208538Srajstatic int 955208538Srajfdt_cmd_hdr(int argc __unused, char *argv[] __unused) 956208538Sraj{ 957208538Sraj char line[80]; 958208538Sraj int ver; 959208538Sraj 960208538Sraj if (fdtp == NULL) { 961208538Sraj command_errmsg = "no device tree blob pointer?!"; 962208538Sraj return (CMD_ERROR); 963208538Sraj } 964208538Sraj 965208538Sraj ver = fdt_version(fdtp); 966208538Sraj pager_open(); 967208538Sraj sprintf(line, "\nFlattened device tree header (%p):\n", fdtp); 968208538Sraj pager_output(line); 969208538Sraj sprintf(line, " magic = 0x%08x\n", fdt_magic(fdtp)); 970208538Sraj pager_output(line); 971208538Sraj sprintf(line, " size = %d\n", fdt_totalsize(fdtp)); 972208538Sraj pager_output(line); 973208538Sraj sprintf(line, " off_dt_struct = 0x%08x\n", 974208538Sraj fdt_off_dt_struct(fdtp)); 975208538Sraj pager_output(line); 976208538Sraj sprintf(line, " off_dt_strings = 0x%08x\n", 977208538Sraj fdt_off_dt_strings(fdtp)); 978208538Sraj pager_output(line); 979208538Sraj sprintf(line, " off_mem_rsvmap = 0x%08x\n", 980208538Sraj fdt_off_mem_rsvmap(fdtp)); 981208538Sraj pager_output(line); 982208538Sraj sprintf(line, " version = %d\n", ver); 983208538Sraj pager_output(line); 984208538Sraj sprintf(line, " last compatible version = %d\n", 985208538Sraj fdt_last_comp_version(fdtp)); 986208538Sraj pager_output(line); 987208538Sraj if (ver >= 2) { 988208538Sraj sprintf(line, " boot_cpuid = %d\n", 989208538Sraj fdt_boot_cpuid_phys(fdtp)); 990208538Sraj pager_output(line); 991208538Sraj } 992208538Sraj if (ver >= 3) { 993208538Sraj sprintf(line, " size_dt_strings = %d\n", 994208538Sraj fdt_size_dt_strings(fdtp)); 995208538Sraj pager_output(line); 996208538Sraj } 997208538Sraj if (ver >= 17) { 998208538Sraj sprintf(line, " size_dt_struct = %d\n", 999208538Sraj fdt_size_dt_struct(fdtp)); 1000208538Sraj pager_output(line); 1001208538Sraj } 1002208538Sraj pager_close(); 1003208538Sraj 1004208538Sraj return (CMD_OK); 1005208538Sraj} 1006208538Sraj 1007208538Srajstatic int 1008208538Srajfdt_cmd_ls(int argc, char *argv[]) 1009208538Sraj{ 1010208538Sraj const char *prevname[FDT_MAX_DEPTH] = { NULL }; 1011208538Sraj const char *name; 1012208538Sraj char *path; 1013208538Sraj int i, o, depth, len; 1014208538Sraj 1015208538Sraj path = (argc > 2) ? argv[2] : NULL; 1016208538Sraj if (path == NULL) 1017208538Sraj path = cwd; 1018208538Sraj 1019208538Sraj o = fdt_path_offset(fdtp, path); 1020208538Sraj if (o < 0) { 1021208538Sraj sprintf(command_errbuf, "could not find node: '%s'", path); 1022208538Sraj return (CMD_ERROR); 1023208538Sraj } 1024208538Sraj 1025208538Sraj for (depth = 0; 1026208538Sraj (o >= 0) && (depth >= 0); 1027208538Sraj o = fdt_next_node(fdtp, o, &depth)) { 1028208538Sraj 1029208538Sraj name = fdt_get_name(fdtp, o, &len); 1030208538Sraj 1031208538Sraj if (depth > FDT_MAX_DEPTH) { 1032208538Sraj printf("max depth exceeded: %d\n", depth); 1033208538Sraj continue; 1034208538Sraj } 1035208538Sraj 1036208538Sraj prevname[depth] = name; 1037208538Sraj 1038208538Sraj /* Skip root (i = 1) when printing devices */ 1039208538Sraj for (i = 1; i <= depth; i++) { 1040208538Sraj if (prevname[i] == NULL) 1041208538Sraj break; 1042208538Sraj 1043208538Sraj if (strcmp(cwd, "/") == 0) 1044208538Sraj printf("/"); 1045208538Sraj printf("%s", prevname[i]); 1046208538Sraj } 1047208538Sraj printf("\n"); 1048208538Sraj } 1049208538Sraj 1050208538Sraj return (CMD_OK); 1051208538Sraj} 1052208538Sraj 1053208538Srajstatic __inline int 1054208538Srajisprint(int c) 1055208538Sraj{ 1056208538Sraj 1057208538Sraj return (c >= ' ' && c <= 0x7e); 1058208538Sraj} 1059208538Sraj 1060208538Srajstatic int 1061208538Srajfdt_isprint(const void *data, int len, int *count) 1062208538Sraj{ 1063208538Sraj const char *d; 1064208538Sraj char ch; 1065208538Sraj int yesno, i; 1066208538Sraj 1067208538Sraj if (len == 0) 1068208538Sraj return (0); 1069208538Sraj 1070208538Sraj d = (const char *)data; 1071208538Sraj if (d[len - 1] != '\0') 1072208538Sraj return (0); 1073208538Sraj 1074208538Sraj *count = 0; 1075208538Sraj yesno = 1; 1076208538Sraj for (i = 0; i < len; i++) { 1077208538Sraj ch = *(d + i); 1078208538Sraj if (isprint(ch) || (ch == '\0' && i > 0)) { 1079208538Sraj /* Count strings */ 1080208538Sraj if (ch == '\0') 1081208538Sraj (*count)++; 1082208538Sraj continue; 1083208538Sraj } 1084208538Sraj 1085208538Sraj yesno = 0; 1086208538Sraj break; 1087208538Sraj } 1088208538Sraj 1089208538Sraj return (yesno); 1090208538Sraj} 1091208538Sraj 1092208538Srajstatic int 1093208538Srajfdt_data_str(const void *data, int len, int count, char **buf) 1094208538Sraj{ 1095233323Sraj char *b, *tmp; 1096208538Sraj const char *d; 1097233323Sraj int buf_len, i, l; 1098208538Sraj 1099208538Sraj /* 1100208538Sraj * Calculate the length for the string and allocate memory. 1101208538Sraj * 1102233323Sraj * Note that 'len' already includes at least one terminator. 1103208538Sraj */ 1104233323Sraj buf_len = len; 1105208538Sraj if (count > 1) { 1106208538Sraj /* 1107208538Sraj * Each token had already a terminator buried in 'len', but we 1108208538Sraj * only need one eventually, don't count space for these. 1109208538Sraj */ 1110233323Sraj buf_len -= count - 1; 1111208538Sraj 1112208538Sraj /* Each consecutive token requires a ", " separator. */ 1113233323Sraj buf_len += count * 2; 1114208538Sraj } 1115208538Sraj 1116233323Sraj /* Add some space for surrounding double quotes. */ 1117233323Sraj buf_len += count * 2; 1118233323Sraj 1119233323Sraj /* Note that string being put in 'tmp' may be as big as 'buf_len'. */ 1120233323Sraj b = (char *)malloc(buf_len); 1121233323Sraj tmp = (char *)malloc(buf_len); 1122208538Sraj if (b == NULL) 1123233323Sraj goto error; 1124233323Sraj 1125233323Sraj if (tmp == NULL) { 1126233323Sraj free(b); 1127233323Sraj goto error; 1128233323Sraj } 1129233323Sraj 1130208538Sraj b[0] = '\0'; 1131208538Sraj 1132208538Sraj /* 1133208538Sraj * Now that we have space, format the string. 1134208538Sraj */ 1135208538Sraj i = 0; 1136208538Sraj do { 1137208538Sraj d = (const char *)data + i; 1138208538Sraj l = strlen(d) + 1; 1139208538Sraj 1140208538Sraj sprintf(tmp, "\"%s\"%s", d, 1141208538Sraj (i + l) < len ? ", " : ""); 1142208538Sraj strcat(b, tmp); 1143208538Sraj 1144208538Sraj i += l; 1145208538Sraj 1146208538Sraj } while (i < len); 1147208538Sraj *buf = b; 1148208538Sraj 1149233323Sraj free(tmp); 1150233323Sraj 1151208538Sraj return (0); 1152233323Srajerror: 1153233323Sraj return (1); 1154208538Sraj} 1155208538Sraj 1156208538Srajstatic int 1157208538Srajfdt_data_cell(const void *data, int len, char **buf) 1158208538Sraj{ 1159233323Sraj char *b, *tmp; 1160208538Sraj const uint32_t *c; 1161208538Sraj int count, i, l; 1162208538Sraj 1163208538Sraj /* Number of cells */ 1164208538Sraj count = len / 4; 1165208538Sraj 1166208538Sraj /* 1167208538Sraj * Calculate the length for the string and allocate memory. 1168208538Sraj */ 1169208538Sraj 1170208538Sraj /* Each byte translates to 2 output characters */ 1171208538Sraj l = len * 2; 1172208538Sraj if (count > 1) { 1173208538Sraj /* Each consecutive cell requires a " " separator. */ 1174208538Sraj l += (count - 1) * 1; 1175208538Sraj } 1176208538Sraj /* Each cell will have a "0x" prefix */ 1177208538Sraj l += count * 2; 1178208538Sraj /* Space for surrounding <> and terminator */ 1179208538Sraj l += 3; 1180208538Sraj 1181208538Sraj b = (char *)malloc(l); 1182233323Sraj tmp = (char *)malloc(l); 1183208538Sraj if (b == NULL) 1184233323Sraj goto error; 1185208538Sraj 1186233323Sraj if (tmp == NULL) { 1187233323Sraj free(b); 1188233323Sraj goto error; 1189233323Sraj } 1190233323Sraj 1191208538Sraj b[0] = '\0'; 1192208538Sraj strcat(b, "<"); 1193208538Sraj 1194208538Sraj for (i = 0; i < len; i += 4) { 1195208538Sraj c = (const uint32_t *)((const uint8_t *)data + i); 1196208538Sraj sprintf(tmp, "0x%08x%s", fdt32_to_cpu(*c), 1197208538Sraj i < (len - 4) ? " " : ""); 1198208538Sraj strcat(b, tmp); 1199208538Sraj } 1200208538Sraj strcat(b, ">"); 1201208538Sraj *buf = b; 1202208538Sraj 1203233323Sraj free(tmp); 1204233323Sraj 1205208538Sraj return (0); 1206233323Srajerror: 1207233323Sraj return (1); 1208208538Sraj} 1209208538Sraj 1210208538Srajstatic int 1211208538Srajfdt_data_bytes(const void *data, int len, char **buf) 1212208538Sraj{ 1213233323Sraj char *b, *tmp; 1214208538Sraj const char *d; 1215208538Sraj int i, l; 1216208538Sraj 1217208538Sraj /* 1218208538Sraj * Calculate the length for the string and allocate memory. 1219208538Sraj */ 1220208538Sraj 1221208538Sraj /* Each byte translates to 2 output characters */ 1222208538Sraj l = len * 2; 1223208538Sraj if (len > 1) 1224208538Sraj /* Each consecutive byte requires a " " separator. */ 1225208538Sraj l += (len - 1) * 1; 1226208538Sraj /* Each byte will have a "0x" prefix */ 1227208538Sraj l += len * 2; 1228208538Sraj /* Space for surrounding [] and terminator. */ 1229208538Sraj l += 3; 1230208538Sraj 1231208538Sraj b = (char *)malloc(l); 1232233323Sraj tmp = (char *)malloc(l); 1233208538Sraj if (b == NULL) 1234233323Sraj goto error; 1235208538Sraj 1236233323Sraj if (tmp == NULL) { 1237233323Sraj free(b); 1238233323Sraj goto error; 1239233323Sraj } 1240233323Sraj 1241208538Sraj b[0] = '\0'; 1242208538Sraj strcat(b, "["); 1243208538Sraj 1244208538Sraj for (i = 0, d = data; i < len; i++) { 1245208538Sraj sprintf(tmp, "0x%02x%s", d[i], i < len - 1 ? " " : ""); 1246208538Sraj strcat(b, tmp); 1247208538Sraj } 1248208538Sraj strcat(b, "]"); 1249208538Sraj *buf = b; 1250208538Sraj 1251233323Sraj free(tmp); 1252233323Sraj 1253208538Sraj return (0); 1254233323Srajerror: 1255233323Sraj return (1); 1256208538Sraj} 1257208538Sraj 1258208538Srajstatic int 1259208538Srajfdt_data_fmt(const void *data, int len, char **buf) 1260208538Sraj{ 1261208538Sraj int count; 1262208538Sraj 1263208538Sraj if (len == 0) { 1264208538Sraj *buf = NULL; 1265208538Sraj return (1); 1266208538Sraj } 1267208538Sraj 1268208538Sraj if (fdt_isprint(data, len, &count)) 1269208538Sraj return (fdt_data_str(data, len, count, buf)); 1270208538Sraj 1271208538Sraj else if ((len % 4) == 0) 1272208538Sraj return (fdt_data_cell(data, len, buf)); 1273208538Sraj 1274208538Sraj else 1275208538Sraj return (fdt_data_bytes(data, len, buf)); 1276208538Sraj} 1277208538Sraj 1278208538Srajstatic int 1279208538Srajfdt_prop(int offset) 1280208538Sraj{ 1281208538Sraj char *line, *buf; 1282208538Sraj const struct fdt_property *prop; 1283208538Sraj const char *name; 1284208538Sraj const void *data; 1285208538Sraj int len, rv; 1286208538Sraj 1287208538Sraj line = NULL; 1288208538Sraj prop = fdt_offset_ptr(fdtp, offset, sizeof(*prop)); 1289208538Sraj if (prop == NULL) 1290208538Sraj return (1); 1291208538Sraj 1292208538Sraj name = fdt_string(fdtp, fdt32_to_cpu(prop->nameoff)); 1293208538Sraj len = fdt32_to_cpu(prop->len); 1294208538Sraj 1295208538Sraj rv = 0; 1296208538Sraj buf = NULL; 1297208538Sraj if (len == 0) { 1298208538Sraj /* Property without value */ 1299208538Sraj line = (char *)malloc(strlen(name) + 2); 1300208538Sraj if (line == NULL) { 1301208538Sraj rv = 2; 1302208538Sraj goto out2; 1303208538Sraj } 1304208538Sraj sprintf(line, "%s\n", name); 1305208538Sraj goto out1; 1306208538Sraj } 1307208538Sraj 1308208538Sraj /* 1309208538Sraj * Process property with value 1310208538Sraj */ 1311208538Sraj data = prop->data; 1312208538Sraj 1313208538Sraj if (fdt_data_fmt(data, len, &buf) != 0) { 1314208538Sraj rv = 3; 1315208538Sraj goto out2; 1316208538Sraj } 1317208538Sraj 1318208538Sraj line = (char *)malloc(strlen(name) + strlen(FDT_PROP_SEP) + 1319208538Sraj strlen(buf) + 2); 1320208538Sraj if (line == NULL) { 1321208538Sraj sprintf(command_errbuf, "could not allocate space for string"); 1322208538Sraj rv = 4; 1323208538Sraj goto out2; 1324208538Sraj } 1325208538Sraj 1326208538Sraj sprintf(line, "%s" FDT_PROP_SEP "%s\n", name, buf); 1327208538Sraj 1328208538Srajout1: 1329208538Sraj pager_open(); 1330208538Sraj pager_output(line); 1331208538Sraj pager_close(); 1332208538Sraj 1333208538Srajout2: 1334208538Sraj if (buf) 1335208538Sraj free(buf); 1336208538Sraj 1337208538Sraj if (line) 1338208538Sraj free(line); 1339208538Sraj 1340208538Sraj return (rv); 1341208538Sraj} 1342208538Sraj 1343208538Srajstatic int 1344208538Srajfdt_modprop(int nodeoff, char *propname, void *value, char mode) 1345208538Sraj{ 1346208538Sraj uint32_t cells[100]; 1347208538Sraj char *buf; 1348208538Sraj int len, rv; 1349208538Sraj const struct fdt_property *p; 1350208538Sraj 1351208538Sraj p = fdt_get_property(fdtp, nodeoff, propname, NULL); 1352208538Sraj 1353208538Sraj if (p != NULL) { 1354208538Sraj if (mode == 1) { 1355208538Sraj /* Adding inexistant value in mode 1 is forbidden */ 1356208538Sraj sprintf(command_errbuf, "property already exists!"); 1357208538Sraj return (CMD_ERROR); 1358208538Sraj } 1359208538Sraj } else if (mode == 0) { 1360208538Sraj sprintf(command_errbuf, "property does not exist!"); 1361208538Sraj return (CMD_ERROR); 1362208538Sraj } 1363208538Sraj len = strlen(value); 1364208538Sraj rv = 0; 1365208538Sraj buf = (char *)value; 1366208538Sraj 1367208538Sraj switch (*buf) { 1368208538Sraj case '&': 1369208538Sraj /* phandles */ 1370208538Sraj break; 1371208538Sraj case '<': 1372208538Sraj /* Data cells */ 1373208538Sraj len = fdt_strtovect(buf, (void *)&cells, 100, 1374208538Sraj sizeof(uint32_t)); 1375208538Sraj 1376208538Sraj rv = fdt_setprop(fdtp, nodeoff, propname, &cells, 1377208538Sraj len * sizeof(uint32_t)); 1378208538Sraj break; 1379208538Sraj case '[': 1380208538Sraj /* Data bytes */ 1381208538Sraj len = fdt_strtovect(buf, (void *)&cells, 100, 1382208538Sraj sizeof(uint8_t)); 1383208538Sraj 1384208538Sraj rv = fdt_setprop(fdtp, nodeoff, propname, &cells, 1385208538Sraj len * sizeof(uint8_t)); 1386208538Sraj break; 1387208538Sraj case '"': 1388208538Sraj default: 1389208538Sraj /* Default -- string */ 1390208538Sraj rv = fdt_setprop_string(fdtp, nodeoff, propname, value); 1391208538Sraj break; 1392208538Sraj } 1393208538Sraj 1394233323Sraj if (rv != 0) { 1395233323Sraj if (rv == -FDT_ERR_NOSPACE) 1396233323Sraj sprintf(command_errbuf, 1397233323Sraj "Device tree blob is too small!\n"); 1398233323Sraj else 1399233323Sraj sprintf(command_errbuf, 1400233323Sraj "Could not add/modify property!\n"); 1401233323Sraj } 1402208538Sraj return (rv); 1403208538Sraj} 1404208538Sraj 1405208538Sraj/* Merge strings from argv into a single string */ 1406208538Srajstatic int 1407208538Srajfdt_merge_strings(int argc, char *argv[], int start, char **buffer) 1408208538Sraj{ 1409208538Sraj char *buf; 1410208538Sraj int i, idx, sz; 1411208538Sraj 1412208538Sraj *buffer = NULL; 1413208538Sraj sz = 0; 1414208538Sraj 1415208538Sraj for (i = start; i < argc; i++) 1416208538Sraj sz += strlen(argv[i]); 1417208538Sraj 1418208538Sraj /* Additional bytes for whitespaces between args */ 1419208538Sraj sz += argc - start; 1420208538Sraj 1421208538Sraj buf = (char *)malloc(sizeof(char) * sz); 1422208538Sraj bzero(buf, sizeof(char) * sz); 1423208538Sraj 1424208538Sraj if (buf == NULL) { 1425208538Sraj sprintf(command_errbuf, "could not allocate space " 1426208538Sraj "for string"); 1427208538Sraj return (1); 1428208538Sraj } 1429208538Sraj 1430208538Sraj idx = 0; 1431208538Sraj for (i = start, idx = 0; i < argc; i++) { 1432208538Sraj strcpy(buf + idx, argv[i]); 1433208538Sraj idx += strlen(argv[i]); 1434208538Sraj buf[idx] = ' '; 1435208538Sraj idx++; 1436208538Sraj } 1437208538Sraj buf[sz - 1] = '\0'; 1438208538Sraj *buffer = buf; 1439208538Sraj return (0); 1440208538Sraj} 1441208538Sraj 1442208538Sraj/* Extract offset and name of node/property from a given path */ 1443208538Srajstatic int 1444208538Srajfdt_extract_nameloc(char **pathp, char **namep, int *nodeoff) 1445208538Sraj{ 1446208538Sraj int o; 1447208538Sraj char *path = *pathp, *name = NULL, *subpath = NULL; 1448208538Sraj 1449208538Sraj subpath = strrchr(path, '/'); 1450208538Sraj if (subpath == NULL) { 1451208538Sraj o = fdt_path_offset(fdtp, cwd); 1452208538Sraj name = path; 1453208538Sraj path = (char *)&cwd; 1454208538Sraj } else { 1455208538Sraj *subpath = '\0'; 1456208538Sraj if (strlen(path) == 0) 1457208538Sraj path = cwd; 1458208538Sraj 1459208538Sraj name = subpath + 1; 1460208538Sraj o = fdt_path_offset(fdtp, path); 1461208538Sraj } 1462208538Sraj 1463208538Sraj if (strlen(name) == 0) { 1464208538Sraj sprintf(command_errbuf, "name not specified"); 1465208538Sraj return (1); 1466208538Sraj } 1467208538Sraj if (o < 0) { 1468208538Sraj sprintf(command_errbuf, "could not find node: '%s'", path); 1469208538Sraj return (1); 1470208538Sraj } 1471208538Sraj *namep = name; 1472208538Sraj *nodeoff = o; 1473208538Sraj *pathp = path; 1474208538Sraj return (0); 1475208538Sraj} 1476208538Sraj 1477208538Srajstatic int 1478208538Srajfdt_cmd_prop(int argc, char *argv[]) 1479208538Sraj{ 1480208538Sraj char *path, *propname, *value; 1481208538Sraj int o, next, depth, rv; 1482208538Sraj uint32_t tag; 1483208538Sraj 1484208538Sraj path = (argc > 2) ? argv[2] : NULL; 1485208538Sraj 1486208538Sraj value = NULL; 1487208538Sraj 1488208538Sraj if (argc > 3) { 1489208538Sraj /* Merge property value strings into one */ 1490208538Sraj if (fdt_merge_strings(argc, argv, 3, &value) != 0) 1491208538Sraj return (CMD_ERROR); 1492208538Sraj } else 1493208538Sraj value = NULL; 1494208538Sraj 1495208538Sraj if (path == NULL) 1496208538Sraj path = cwd; 1497208538Sraj 1498208538Sraj rv = CMD_OK; 1499208538Sraj 1500208538Sraj if (value) { 1501208538Sraj /* If value is specified -- try to modify prop. */ 1502208538Sraj if (fdt_extract_nameloc(&path, &propname, &o) != 0) 1503208538Sraj return (CMD_ERROR); 1504208538Sraj 1505208538Sraj rv = fdt_modprop(o, propname, value, 0); 1506208538Sraj if (rv) 1507208538Sraj return (CMD_ERROR); 1508208538Sraj return (CMD_OK); 1509208538Sraj 1510208538Sraj } 1511208538Sraj /* User wants to display properties */ 1512208538Sraj o = fdt_path_offset(fdtp, path); 1513208538Sraj 1514208538Sraj if (o < 0) { 1515208538Sraj sprintf(command_errbuf, "could not find node: '%s'", path); 1516208538Sraj rv = CMD_ERROR; 1517208538Sraj goto out; 1518208538Sraj } 1519208538Sraj 1520208538Sraj depth = 0; 1521208538Sraj while (depth >= 0) { 1522208538Sraj tag = fdt_next_tag(fdtp, o, &next); 1523208538Sraj switch (tag) { 1524208538Sraj case FDT_NOP: 1525208538Sraj break; 1526208538Sraj case FDT_PROP: 1527208538Sraj if (depth > 1) 1528208538Sraj /* Don't process properties of nested nodes */ 1529208538Sraj break; 1530208538Sraj 1531208538Sraj if (fdt_prop(o) != 0) { 1532208538Sraj sprintf(command_errbuf, "could not process " 1533208538Sraj "property"); 1534208538Sraj rv = CMD_ERROR; 1535208538Sraj goto out; 1536208538Sraj } 1537208538Sraj break; 1538208538Sraj case FDT_BEGIN_NODE: 1539208538Sraj depth++; 1540208538Sraj if (depth > FDT_MAX_DEPTH) { 1541208538Sraj printf("warning: nesting too deep: %d\n", 1542208538Sraj depth); 1543208538Sraj goto out; 1544208538Sraj } 1545208538Sraj break; 1546208538Sraj case FDT_END_NODE: 1547208538Sraj depth--; 1548208538Sraj if (depth == 0) 1549208538Sraj /* 1550208538Sraj * This is the end of our starting node, force 1551208538Sraj * the loop finish. 1552208538Sraj */ 1553208538Sraj depth--; 1554208538Sraj break; 1555208538Sraj } 1556208538Sraj o = next; 1557208538Sraj } 1558208538Srajout: 1559208538Sraj return (rv); 1560208538Sraj} 1561208538Sraj 1562208538Srajstatic int 1563208538Srajfdt_cmd_mkprop(int argc, char *argv[]) 1564208538Sraj{ 1565208538Sraj int o; 1566208538Sraj char *path, *propname, *value; 1567208538Sraj 1568208538Sraj path = (argc > 2) ? argv[2] : NULL; 1569208538Sraj 1570208538Sraj value = NULL; 1571208538Sraj 1572208538Sraj if (argc > 3) { 1573208538Sraj /* Merge property value strings into one */ 1574208538Sraj if (fdt_merge_strings(argc, argv, 3, &value) != 0) 1575208538Sraj return (CMD_ERROR); 1576208538Sraj } else 1577208538Sraj value = NULL; 1578208538Sraj 1579208538Sraj if (fdt_extract_nameloc(&path, &propname, &o) != 0) 1580208538Sraj return (CMD_ERROR); 1581208538Sraj 1582208538Sraj if (fdt_modprop(o, propname, value, 1)) 1583208538Sraj return (CMD_ERROR); 1584208538Sraj 1585208538Sraj return (CMD_OK); 1586208538Sraj} 1587208538Sraj 1588208538Srajstatic int 1589208538Srajfdt_cmd_rm(int argc, char *argv[]) 1590208538Sraj{ 1591208538Sraj int o, rv; 1592208538Sraj char *path = NULL, *propname; 1593208538Sraj 1594208538Sraj if (argc > 2) 1595208538Sraj path = argv[2]; 1596208538Sraj else { 1597208538Sraj sprintf(command_errbuf, "no node/property name specified"); 1598208538Sraj return (CMD_ERROR); 1599208538Sraj } 1600208538Sraj 1601208538Sraj o = fdt_path_offset(fdtp, path); 1602208538Sraj if (o < 0) { 1603208538Sraj /* If node not found -- try to find & delete property */ 1604208538Sraj if (fdt_extract_nameloc(&path, &propname, &o) != 0) 1605208538Sraj return (CMD_ERROR); 1606208538Sraj 1607208538Sraj if ((rv = fdt_delprop(fdtp, o, propname)) != 0) { 1608208538Sraj sprintf(command_errbuf, "could not delete" 1609208538Sraj "%s\n", (rv == -FDT_ERR_NOTFOUND) ? 1610208538Sraj "(property/node does not exist)" : ""); 1611208538Sraj return (CMD_ERROR); 1612208538Sraj 1613208538Sraj } else 1614208538Sraj return (CMD_OK); 1615208538Sraj } 1616208538Sraj /* If node exists -- remove node */ 1617208538Sraj rv = fdt_del_node(fdtp, o); 1618208538Sraj if (rv) { 1619208538Sraj sprintf(command_errbuf, "could not delete node"); 1620208538Sraj return (CMD_ERROR); 1621208538Sraj } 1622208538Sraj return (CMD_OK); 1623208538Sraj} 1624208538Sraj 1625208538Srajstatic int 1626208538Srajfdt_cmd_mknode(int argc, char *argv[]) 1627208538Sraj{ 1628208538Sraj int o, rv; 1629208538Sraj char *path = NULL, *nodename = NULL; 1630208538Sraj 1631208538Sraj if (argc > 2) 1632208538Sraj path = argv[2]; 1633208538Sraj else { 1634208538Sraj sprintf(command_errbuf, "no node name specified"); 1635208538Sraj return (CMD_ERROR); 1636208538Sraj } 1637208538Sraj 1638208538Sraj if (fdt_extract_nameloc(&path, &nodename, &o) != 0) 1639208538Sraj return (CMD_ERROR); 1640208538Sraj 1641208538Sraj rv = fdt_add_subnode(fdtp, o, nodename); 1642208538Sraj 1643208538Sraj if (rv < 0) { 1644233323Sraj if (rv == -FDT_ERR_NOSPACE) 1645233323Sraj sprintf(command_errbuf, 1646233323Sraj "Device tree blob is too small!\n"); 1647233323Sraj else 1648233323Sraj sprintf(command_errbuf, 1649233323Sraj "Could not add node!\n"); 1650208538Sraj return (CMD_ERROR); 1651208538Sraj } 1652208538Sraj return (CMD_OK); 1653208538Sraj} 1654208538Sraj 1655208538Srajstatic int 1656208538Srajfdt_cmd_pwd(int argc, char *argv[]) 1657208538Sraj{ 1658233323Sraj char line[FDT_CWD_LEN]; 1659208538Sraj 1660208538Sraj pager_open(); 1661208538Sraj sprintf(line, "%s\n", cwd); 1662208538Sraj pager_output(line); 1663208538Sraj pager_close(); 1664208538Sraj return (CMD_OK); 1665208538Sraj} 1666208538Sraj 1667208538Srajstatic int 1668243693Sgonzofdt_cmd_mres(int argc, char *argv[]) 1669243693Sgonzo{ 1670243693Sgonzo uint64_t start, size; 1671243693Sgonzo int i, total; 1672243693Sgonzo char line[80]; 1673243693Sgonzo 1674243693Sgonzo pager_open(); 1675243693Sgonzo total = fdt_num_mem_rsv(fdtp); 1676243693Sgonzo if (total > 0) { 1677243693Sgonzo pager_output("Reserved memory regions:\n"); 1678243693Sgonzo for (i = 0; i < total; i++) { 1679243693Sgonzo fdt_get_mem_rsv(fdtp, i, &start, &size); 1680243693Sgonzo sprintf(line, "reg#%d: (start: 0x%jx, size: 0x%jx)\n", 1681243693Sgonzo i, start, size); 1682243693Sgonzo pager_output(line); 1683243693Sgonzo } 1684243693Sgonzo } else 1685243693Sgonzo pager_output("No reserved memory regions\n"); 1686243693Sgonzo pager_close(); 1687243693Sgonzo 1688243693Sgonzo return (CMD_OK); 1689243693Sgonzo} 1690243693Sgonzo 1691243693Sgonzostatic int 1692208538Srajfdt_cmd_nyi(int argc, char *argv[]) 1693208538Sraj{ 1694208538Sraj 1695208538Sraj printf("command not yet implemented\n"); 1696208538Sraj return (CMD_ERROR); 1697208538Sraj} 1698