2 * Copyright (c) 2009-2010 The FreeBSD Foundation
5 * This software was developed by Semihalf under sponsorship from
6 * the FreeBSD Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
36 #include <sys/param.h>
37 #include <sys/linker.h>
38 #include <machine/elf.h>
40 #include "bootstrap.h"
46 #define debugf(fmt, args...) do { printf("%s(): ", __func__); \
47 printf(fmt,##args); } while (0)
49 #define debugf(fmt, args...)
52 #define FDT_CWD_LEN 256
53 #define FDT_MAX_DEPTH 6
55 #define FDT_PROP_SEP " = "
57 #define STR(number) #number
58 #define STRINGIFY(number) STR(number)
60 #define COPYOUT(s,d,l) archsw.arch_copyout((vm_offset_t)(s), d, l)
62 #define FDT_STATIC_DTB_SYMBOL "fdt_static_dtb"
64 static struct fdt_header *fdtp = NULL;
66 static int fdt_cmd_nyi(int argc, char *argv[]);
68 static int fdt_cmd_mkprop(int argc, char *argv[]);
69 static int fdt_cmd_cd(int argc, char *argv[]);
70 static int fdt_cmd_hdr(int argc, char *argv[]);
71 static int fdt_cmd_ls(int argc, char *argv[]);
72 static int fdt_cmd_prop(int argc, char *argv[]);
73 static int fdt_cmd_pwd(int argc, char *argv[]);
74 static int fdt_cmd_rm(int argc, char *argv[]);
75 static int fdt_cmd_mknode(int argc, char *argv[]);
77 typedef int cmdf_t(int, char *[]);
84 static const struct cmdtab commands[] = {
85 { "alias", &fdt_cmd_nyi },
86 { "cd", &fdt_cmd_cd },
87 { "header", &fdt_cmd_hdr },
88 { "ls", &fdt_cmd_ls },
89 { "mknode", &fdt_cmd_mknode },
90 { "mkprop", &fdt_cmd_mkprop },
91 { "mres", &fdt_cmd_nyi },
92 { "prop", &fdt_cmd_prop },
93 { "pwd", &fdt_cmd_pwd },
94 { "rm", &fdt_cmd_rm },
98 static char cwd[FDT_CWD_LEN] = "/";
101 fdt_find_static_dtb(void)
104 vm_offset_t dyntab, esym;
106 struct preloaded_file *kfp;
107 struct file_metadata *md;
115 strtab = strp = NULL;
117 offs = __elfN(relocation_offset);
119 kfp = file_findfile(NULL, NULL);
123 md = file_findmetadata(kfp, MODINFOMD_ESYM);
126 COPYOUT(md->md_data, &esym, sizeof(esym));
128 md = file_findmetadata(kfp, MODINFOMD_DYNAMIC);
131 COPYOUT(md->md_data, &dyntab, sizeof(dyntab));
135 /* Locate STRTAB and DYNTAB */
136 for (dyn = (Elf_Dyn *)dyntab; dyn->d_tag != DT_NULL; dyn++) {
137 if (dyn->d_tag == DT_STRTAB) {
138 strtab = (char *)(uintptr_t)(dyn->d_un.d_ptr + offs);
140 } else if (dyn->d_tag == DT_SYMTAB) {
141 symtab = (Elf_Sym *)(uintptr_t)
142 (dyn->d_un.d_ptr + offs);
147 if (symtab == NULL || strtab == NULL) {
149 * No symtab? No strtab? That should not happen here,
150 * and should have been verified during __elfN(loadimage).
151 * This must be some kind of a bug.
156 sym_count = (int)((Elf_Sym *)esym - symtab) / sizeof(Elf_Sym);
159 * The most efficent way to find a symbol would be to calculate a
160 * hash, find proper bucket and chain, and thus find a symbol.
161 * However, that would involve code duplication (e.g. for hash
162 * function). So we're using simpler and a bit slower way: we're
163 * iterating through symbols, searching for the one which name is
164 * 'equal' to 'fdt_static_dtb'. To speed up the process a little bit,
165 * we are eliminating symbols type of which is not STT_NOTYPE, or(and)
166 * those which binding attribute is not STB_GLOBAL.
168 for (i = 0; i < sym_count; i++) {
169 COPYOUT(symtab + i, &sym, sizeof(sym));
170 if (ELF_ST_BIND(sym.st_info) != STB_GLOBAL ||
171 ELF_ST_TYPE(sym.st_info) != STT_NOTYPE)
174 strp = strdupout((vm_offset_t)(strtab + sym.st_name));
175 if (strcmp(strp, FDT_STATIC_DTB_SYMBOL) == 0) {
176 /* Found a match ! */
178 return ((vm_offset_t)(sym.st_value + offs));
188 struct preloaded_file *bfp;
192 * Find the device tree blob.
194 bfp = file_findfile(NULL, "dtb");
196 if ((fdtp = (struct fdt_header *)fdt_find_static_dtb()) == 0) {
197 command_errmsg = "no device tree blob found!";
201 /* Dynamic blob has precedence over static. */
202 fdtp = (struct fdt_header *)bfp->f_addr;
208 err = fdt_check_header(fdtp);
210 if (err == -FDT_ERR_BADVERSION)
211 sprintf(command_errbuf,
212 "incompatible blob version: %d, should be: %d",
213 fdt_version(fdtp), FDT_LAST_SUPPORTED_VERSION);
216 sprintf(command_errbuf, "error validating blob: %s",
223 #define fdt_strtovect(str, cellbuf, lim, cellsize) _fdt_strtovect((str), \
224 (cellbuf), (lim), (cellsize), 0);
226 /* Force using base 16 */
227 #define fdt_strtovectx(str, cellbuf, lim, cellsize) _fdt_strtovect((str), \
228 (cellbuf), (lim), (cellsize), 16);
231 _fdt_strtovect(char *str, void *cellbuf, int lim, unsigned char cellsize,
235 char *end = str + strlen(str) - 2;
236 uint32_t *u32buf = NULL;
237 uint8_t *u8buf = NULL;
240 if (cellsize == sizeof(uint32_t))
241 u32buf = (uint32_t *)cellbuf;
243 u8buf = (uint8_t *)cellbuf;
250 /* Skip white whitespace(s)/separators */
251 while (!isxdigit(*buf) && buf < end)
256 cpu_to_fdt32((uint32_t)strtol(buf, NULL, base));
259 u8buf[cnt] = (uint8_t)strtol(buf, NULL, base);
261 if (cnt + 1 <= lim - 1)
266 /* Find another number */
267 while ((isxdigit(*buf) || *buf == 'x') && buf < end)
273 #define TMP_MAX_ETH 8
276 fixup_ethernet(const char *env, char *ethstr, int *eth_no, int len)
282 /* Extract interface number */
283 i = strtol(env + 3, &end, 10);
284 if (end == (env + 3))
285 /* 'ethaddr' means interface 0 address */
293 str = ub_env_get(env);
295 /* Convert macaddr string into a vector of uints */
296 fdt_strtovectx(str, &tmp_addr, 6, sizeof(uint8_t));
299 strncpy(ethstr + 8, env + 3, i);
301 /* Set actual property to a value from vect */
302 fdt_setprop(fdtp, fdt_path_offset(fdtp, ethstr),
303 "local-mac-address", &tmp_addr, 6 * sizeof(uint8_t));
305 /* Clear ethernet..XXXX.. string */
306 bzero(ethstr + 8, len - 8);
313 fixup_cpubusfreqs(unsigned long cpufreq, unsigned long busfreq)
315 int lo, o = 0, o2, maxo = 0, depth;
316 const uint32_t zero = 0;
318 /* We want to modify every subnode of /cpus */
319 o = fdt_path_offset(fdtp, "/cpus");
321 /* maxo should contain offset of node next to /cpus */
325 maxo = fdt_next_node(fdtp, maxo, &depth);
327 /* Find CPU frequency properties */
328 o = fdt_node_offset_by_prop_value(fdtp, o, "clock-frequency",
329 &zero, sizeof(uint32_t));
331 o2 = fdt_node_offset_by_prop_value(fdtp, o, "bus-frequency", &zero,
336 while (o != -FDT_ERR_NOTFOUND && o2 != -FDT_ERR_NOTFOUND) {
338 o = fdt_node_offset_by_prop_value(fdtp, lo,
339 "clock-frequency", &zero, sizeof(uint32_t));
341 o2 = fdt_node_offset_by_prop_value(fdtp, lo, "bus-frequency",
342 &zero, sizeof(uint32_t));
344 /* We're only interested in /cpus subnode(s) */
348 fdt_setprop_inplace_cell(fdtp, lo, "clock-frequency",
351 fdt_setprop_inplace_cell(fdtp, lo, "bus-frequency",
359 fdt_reg_valid(uint32_t *reg, int len, int addr_cells, int size_cells)
361 int cells_in_tuple, i, tuples, tuple_size;
362 uint32_t cur_start, cur_size;
364 cells_in_tuple = (addr_cells + size_cells);
365 tuple_size = cells_in_tuple * sizeof(uint32_t);
366 tuples = len / tuple_size;
370 for (i = 0; i < tuples; i++) {
372 cur_start = fdt64_to_cpu(reg[i * cells_in_tuple]);
374 cur_start = fdt32_to_cpu(reg[i * cells_in_tuple]);
377 cur_size = fdt64_to_cpu(reg[i * cells_in_tuple + 2]);
379 cur_size = fdt32_to_cpu(reg[i * cells_in_tuple + 1]);
384 debugf(" reg#%d (start: 0x%0x size: 0x%0x) valid!\n",
385 i, cur_start, cur_size);
391 fixup_memory(struct sys_info *si)
393 struct mem_region *curmr;
394 uint32_t addr_cells, size_cells;
395 uint32_t *addr_cellsp, *reg, *size_cellsp;
396 int err, i, len, memory, realmrno, root;
399 root = fdt_path_offset(fdtp, "/");
401 sprintf(command_errbuf, "Could not find root node !");
405 memory = fdt_path_offset(fdtp, "/memory");
407 /* Create proper '/memory' node. */
408 memory = fdt_add_subnode(fdtp, root, "memory");
410 sprintf(command_errbuf, "Could not fixup '/memory' "
411 "node, error code : %d!\n", memory);
415 err = fdt_setprop(fdtp, memory, "device_type", "memory",
422 addr_cellsp = (uint32_t *)fdt_getprop(fdtp, root, "#address-cells",
424 size_cellsp = (uint32_t *)fdt_getprop(fdtp, root, "#size-cells", NULL);
426 if (addr_cellsp == NULL || size_cellsp == NULL) {
427 sprintf(command_errbuf, "Could not fixup '/memory' node : "
428 "%s %s property not found in root node!\n",
429 (!addr_cellsp) ? "#address-cells" : "",
430 (!size_cellsp) ? "#size-cells" : "");
434 addr_cells = fdt32_to_cpu(*addr_cellsp);
435 size_cells = fdt32_to_cpu(*size_cellsp);
437 /* Count valid memory regions entries in sysinfo. */
438 realmrno = si->mr_no;
439 for (i = 0; i < si->mr_no; i++)
440 if (si->mr[i].start == 0 && si->mr[i].size == 0)
444 sprintf(command_errbuf, "Could not fixup '/memory' node : "
445 "sysinfo doesn't contain valid memory regions info!\n");
449 if ((reg = (uint32_t *)fdt_getprop(fdtp, memory, "reg",
452 if (fdt_reg_valid(reg, len, addr_cells, size_cells) == 0)
454 * Do not apply fixup if existing 'reg' property
460 len = (addr_cells + size_cells) * realmrno * sizeof(uint32_t);
461 sb = buf = (uint8_t *)malloc(len);
467 for (i = 0; i < si->mr_no; i++) {
469 if (curmr->size != 0) {
470 /* Ensure endianess, and put cells into a buffer */
473 cpu_to_fdt64(curmr->start);
476 cpu_to_fdt32(curmr->start);
478 buf += sizeof(uint32_t) * addr_cells;
481 cpu_to_fdt64(curmr->size);
484 cpu_to_fdt32(curmr->size);
486 buf += sizeof(uint32_t) * size_cells;
491 if ((err = fdt_setprop(fdtp, memory, "reg", sb, len)) < 0)
492 sprintf(command_errbuf, "Could not fixup '/memory' node.\n");
496 fixup_stdout(const char *env)
502 const struct fdt_property *prop;
505 str = ub_env_get(env);
506 ptr = (char *)str + strlen(str) - 1;
507 while (ptr > str && isdigit(*(str - 1)))
513 serialno = (int)strtol(ptr, NULL, 0);
514 no = fdt_path_offset(fdtp, "/chosen");
518 prop = fdt_get_property(fdtp, no, "stdout", &len);
520 /* If /chosen/stdout does not extist, create it */
521 if (prop == NULL || (prop != NULL && len == 0)) {
523 bzero(tmp, 10 * sizeof(char));
524 strcpy((char *)&tmp, "serial");
526 /* Serial number too long */
529 strncpy((char *)tmp + 6, ptr, 3);
530 sero = fdt_path_offset(fdtp, (const char *)tmp);
533 * If serial device we're trying to assign
534 * stdout to doesn't exist in DT -- return.
538 fdt_setprop(fdtp, no, "stdout", &tmp,
539 strlen((char *)&tmp) + 1);
540 fdt_setprop(fdtp, no, "stdin", &tmp,
541 strlen((char *)&tmp) + 1);
546 * Locate the blob, fix it up and return its location.
553 int chosen, err, eth_no, len;
561 err = fdt_setup_fdtp();
563 sprintf(command_errbuf, "No valid device tree blob found!");
567 /* Create /chosen node (if not exists) */
568 if ((chosen = fdt_subnode_offset(fdtp, 0, "chosen")) ==
570 chosen = fdt_add_subnode(fdtp, 0, "chosen");
572 /* Value assigned to fixup-applied does not matter. */
573 if (fdt_getprop(fdtp, chosen, "fixup-applied", NULL))
576 /* Acquire sys_info */
577 si = ub_get_sys_info();
579 while ((env = ub_env_enum(env)) != NULL) {
580 if (strncmp(env, "eth", 3) == 0 &&
581 strncmp(env + (strlen(env) - 4), "addr", 4) == 0) {
583 * Handle Ethernet addrs: parse uboot env eth%daddr
588 * Check how many chars we will need to store
589 * maximal eth iface number.
591 len = strlen(STRINGIFY(TMP_MAX_ETH)) +
595 * Reserve mem for string "ethernet" and len
596 * chars for iface no.
598 ethstr = (char *)malloc(len * sizeof(char));
599 bzero(ethstr, len * sizeof(char));
600 strcpy(ethstr, "ethernet0");
604 fixup_ethernet(env, ethstr, ð_no, len);
606 } else if (strcmp(env, "consoledev") == 0)
610 /* Modify cpu(s) and bus clock frequenties in /cpus node [Hz] */
611 fixup_cpubusfreqs(si->clk_cpu, si->clk_bus);
613 /* Fixup memory regions */
616 fdt_setprop(fdtp, chosen, "fixup-applied", NULL, 0);
623 command_fdt_internal(int argc, char *argv[])
630 command_errmsg = "usage is 'fdt <command> [<args>]";
635 * Check if uboot env vars were parsed already. If not, do it now.
637 if (fdt_fixup() == NULL)
641 * Validate fdt <command>.
643 cmd = strdup(argv[1]);
646 while (!(commands[i].name == NULL)) {
647 if (strcmp(cmd, commands[i].name) == 0) {
649 cmdh = commands[i].handler;
655 command_errmsg = "unknown command";
660 * Call command handler.
662 err = (*cmdh)(argc, argv);
668 fdt_cmd_cd(int argc, char *argv[])
671 char tmp[FDT_CWD_LEN];
674 path = (argc > 2) ? argv[2] : "/";
676 if (path[0] == '/') {
678 if (len >= FDT_CWD_LEN)
681 /* Handle path specification relative to cwd */
682 len = strlen(cwd) + strlen(path) + 1;
683 if (len >= FDT_CWD_LEN)
692 o = fdt_path_offset(fdtp, path);
694 sprintf(command_errbuf, "could not find node: '%s'", path);
702 sprintf(command_errbuf, "path too long: %d, max allowed: %d",
703 len, FDT_CWD_LEN - 1);
708 fdt_cmd_hdr(int argc __unused, char *argv[] __unused)
714 command_errmsg = "no device tree blob pointer?!";
718 ver = fdt_version(fdtp);
720 sprintf(line, "\nFlattened device tree header (%p):\n", fdtp);
722 sprintf(line, " magic = 0x%08x\n", fdt_magic(fdtp));
724 sprintf(line, " size = %d\n", fdt_totalsize(fdtp));
726 sprintf(line, " off_dt_struct = 0x%08x\n",
727 fdt_off_dt_struct(fdtp));
729 sprintf(line, " off_dt_strings = 0x%08x\n",
730 fdt_off_dt_strings(fdtp));
732 sprintf(line, " off_mem_rsvmap = 0x%08x\n",
733 fdt_off_mem_rsvmap(fdtp));
735 sprintf(line, " version = %d\n", ver);
737 sprintf(line, " last compatible version = %d\n",
738 fdt_last_comp_version(fdtp));
741 sprintf(line, " boot_cpuid = %d\n",
742 fdt_boot_cpuid_phys(fdtp));
746 sprintf(line, " size_dt_strings = %d\n",
747 fdt_size_dt_strings(fdtp));
751 sprintf(line, " size_dt_struct = %d\n",
752 fdt_size_dt_struct(fdtp));
761 fdt_cmd_ls(int argc, char *argv[])
763 const char *prevname[FDT_MAX_DEPTH] = { NULL };
766 int i, o, depth, len;
768 path = (argc > 2) ? argv[2] : NULL;
772 o = fdt_path_offset(fdtp, path);
774 sprintf(command_errbuf, "could not find node: '%s'", path);
779 (o >= 0) && (depth >= 0);
780 o = fdt_next_node(fdtp, o, &depth)) {
782 name = fdt_get_name(fdtp, o, &len);
784 if (depth > FDT_MAX_DEPTH) {
785 printf("max depth exceeded: %d\n", depth);
789 prevname[depth] = name;
791 /* Skip root (i = 1) when printing devices */
792 for (i = 1; i <= depth; i++) {
793 if (prevname[i] == NULL)
796 if (strcmp(cwd, "/") == 0)
798 printf("%s", prevname[i]);
810 return (c >= ' ' && c <= 0x7e);
814 fdt_isprint(const void *data, int len, int *count)
823 d = (const char *)data;
824 if (d[len - 1] != '\0')
829 for (i = 0; i < len; i++) {
831 if (isprint(ch) || (ch == '\0' && i > 0)) {
846 fdt_data_str(const void *data, int len, int count, char **buf)
853 * Calculate the length for the string and allocate memory.
855 * Note that 'len' already includes at least one terminator.
860 * Each token had already a terminator buried in 'len', but we
861 * only need one eventually, don't count space for these.
863 buf_len -= count - 1;
865 /* Each consecutive token requires a ", " separator. */
866 buf_len += count * 2;
869 /* Add some space for surrounding double quotes. */
870 buf_len += count * 2;
872 /* Note that string being put in 'tmp' may be as big as 'buf_len'. */
873 b = (char *)malloc(buf_len);
874 tmp = (char *)malloc(buf_len);
886 * Now that we have space, format the string.
890 d = (const char *)data + i;
893 sprintf(tmp, "\"%s\"%s", d,
894 (i + l) < len ? ", " : "");
910 fdt_data_cell(const void *data, int len, char **buf)
916 /* Number of cells */
920 * Calculate the length for the string and allocate memory.
923 /* Each byte translates to 2 output characters */
926 /* Each consecutive cell requires a " " separator. */
927 l += (count - 1) * 1;
929 /* Each cell will have a "0x" prefix */
931 /* Space for surrounding <> and terminator */
934 b = (char *)malloc(l);
935 tmp = (char *)malloc(l);
947 for (i = 0; i < len; i += 4) {
948 c = (const uint32_t *)((const uint8_t *)data + i);
949 sprintf(tmp, "0x%08x%s", fdt32_to_cpu(*c),
950 i < (len - 4) ? " " : "");
964 fdt_data_bytes(const void *data, int len, char **buf)
971 * Calculate the length for the string and allocate memory.
974 /* Each byte translates to 2 output characters */
977 /* Each consecutive byte requires a " " separator. */
979 /* Each byte will have a "0x" prefix */
981 /* Space for surrounding [] and terminator. */
984 b = (char *)malloc(l);
985 tmp = (char *)malloc(l);
997 for (i = 0, d = data; i < len; i++) {
998 sprintf(tmp, "0x%02x%s", d[i], i < len - 1 ? " " : "");
1012 fdt_data_fmt(const void *data, int len, char **buf)
1021 if (fdt_isprint(data, len, &count))
1022 return (fdt_data_str(data, len, count, buf));
1024 else if ((len % 4) == 0)
1025 return (fdt_data_cell(data, len, buf));
1028 return (fdt_data_bytes(data, len, buf));
1032 fdt_prop(int offset)
1035 const struct fdt_property *prop;
1041 prop = fdt_offset_ptr(fdtp, offset, sizeof(*prop));
1045 name = fdt_string(fdtp, fdt32_to_cpu(prop->nameoff));
1046 len = fdt32_to_cpu(prop->len);
1051 /* Property without value */
1052 line = (char *)malloc(strlen(name) + 2);
1057 sprintf(line, "%s\n", name);
1062 * Process property with value
1066 if (fdt_data_fmt(data, len, &buf) != 0) {
1071 line = (char *)malloc(strlen(name) + strlen(FDT_PROP_SEP) +
1074 sprintf(command_errbuf, "could not allocate space for string");
1079 sprintf(line, "%s" FDT_PROP_SEP "%s\n", name, buf);
1097 fdt_modprop(int nodeoff, char *propname, void *value, char mode)
1099 uint32_t cells[100];
1102 const struct fdt_property *p;
1104 p = fdt_get_property(fdtp, nodeoff, propname, NULL);
1108 /* Adding inexistant value in mode 1 is forbidden */
1109 sprintf(command_errbuf, "property already exists!");
1112 } else if (mode == 0) {
1113 sprintf(command_errbuf, "property does not exist!");
1116 len = strlen(value);
1118 buf = (char *)value;
1126 len = fdt_strtovect(buf, (void *)&cells, 100,
1129 rv = fdt_setprop(fdtp, nodeoff, propname, &cells,
1130 len * sizeof(uint32_t));
1134 len = fdt_strtovect(buf, (void *)&cells, 100,
1137 rv = fdt_setprop(fdtp, nodeoff, propname, &cells,
1138 len * sizeof(uint8_t));
1142 /* Default -- string */
1143 rv = fdt_setprop_string(fdtp, nodeoff, propname, value);
1148 if (rv == -FDT_ERR_NOSPACE)
1149 sprintf(command_errbuf,
1150 "Device tree blob is too small!\n");
1152 sprintf(command_errbuf,
1153 "Could not add/modify property!\n");
1158 /* Merge strings from argv into a single string */
1160 fdt_merge_strings(int argc, char *argv[], int start, char **buffer)
1168 for (i = start; i < argc; i++)
1169 sz += strlen(argv[i]);
1171 /* Additional bytes for whitespaces between args */
1174 buf = (char *)malloc(sizeof(char) * sz);
1175 bzero(buf, sizeof(char) * sz);
1178 sprintf(command_errbuf, "could not allocate space "
1184 for (i = start, idx = 0; i < argc; i++) {
1185 strcpy(buf + idx, argv[i]);
1186 idx += strlen(argv[i]);
1195 /* Extract offset and name of node/property from a given path */
1197 fdt_extract_nameloc(char **pathp, char **namep, int *nodeoff)
1200 char *path = *pathp, *name = NULL, *subpath = NULL;
1202 subpath = strrchr(path, '/');
1203 if (subpath == NULL) {
1204 o = fdt_path_offset(fdtp, cwd);
1206 path = (char *)&cwd;
1209 if (strlen(path) == 0)
1213 o = fdt_path_offset(fdtp, path);
1216 if (strlen(name) == 0) {
1217 sprintf(command_errbuf, "name not specified");
1221 sprintf(command_errbuf, "could not find node: '%s'", path);
1231 fdt_cmd_prop(int argc, char *argv[])
1233 char *path, *propname, *value;
1234 int o, next, depth, rv;
1237 path = (argc > 2) ? argv[2] : NULL;
1242 /* Merge property value strings into one */
1243 if (fdt_merge_strings(argc, argv, 3, &value) != 0)
1254 /* If value is specified -- try to modify prop. */
1255 if (fdt_extract_nameloc(&path, &propname, &o) != 0)
1258 rv = fdt_modprop(o, propname, value, 0);
1264 /* User wants to display properties */
1265 o = fdt_path_offset(fdtp, path);
1268 sprintf(command_errbuf, "could not find node: '%s'", path);
1274 while (depth >= 0) {
1275 tag = fdt_next_tag(fdtp, o, &next);
1281 /* Don't process properties of nested nodes */
1284 if (fdt_prop(o) != 0) {
1285 sprintf(command_errbuf, "could not process "
1291 case FDT_BEGIN_NODE:
1293 if (depth > FDT_MAX_DEPTH) {
1294 printf("warning: nesting too deep: %d\n",
1303 * This is the end of our starting node, force
1316 fdt_cmd_mkprop(int argc, char *argv[])
1319 char *path, *propname, *value;
1321 path = (argc > 2) ? argv[2] : NULL;
1326 /* Merge property value strings into one */
1327 if (fdt_merge_strings(argc, argv, 3, &value) != 0)
1332 if (fdt_extract_nameloc(&path, &propname, &o) != 0)
1335 if (fdt_modprop(o, propname, value, 1))
1342 fdt_cmd_rm(int argc, char *argv[])
1345 char *path = NULL, *propname;
1350 sprintf(command_errbuf, "no node/property name specified");
1354 o = fdt_path_offset(fdtp, path);
1356 /* If node not found -- try to find & delete property */
1357 if (fdt_extract_nameloc(&path, &propname, &o) != 0)
1360 if ((rv = fdt_delprop(fdtp, o, propname)) != 0) {
1361 sprintf(command_errbuf, "could not delete"
1362 "%s\n", (rv == -FDT_ERR_NOTFOUND) ?
1363 "(property/node does not exist)" : "");
1369 /* If node exists -- remove node */
1370 rv = fdt_del_node(fdtp, o);
1372 sprintf(command_errbuf, "could not delete node");
1379 fdt_cmd_mknode(int argc, char *argv[])
1382 char *path = NULL, *nodename = NULL;
1387 sprintf(command_errbuf, "no node name specified");
1391 if (fdt_extract_nameloc(&path, &nodename, &o) != 0)
1394 rv = fdt_add_subnode(fdtp, o, nodename);
1397 if (rv == -FDT_ERR_NOSPACE)
1398 sprintf(command_errbuf,
1399 "Device tree blob is too small!\n");
1401 sprintf(command_errbuf,
1402 "Could not add node!\n");
1409 fdt_cmd_pwd(int argc, char *argv[])
1411 char line[FDT_CWD_LEN];
1414 sprintf(line, "%s\n", cwd);
1421 fdt_cmd_nyi(int argc, char *argv[])
1424 printf("command not yet implemented\n");