]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sys/boot/fdt/fdt_loader_cmd.c
MFC r273913:
[FreeBSD/stable/10.git] / sys / boot / fdt / fdt_loader_cmd.c
1 /*-
2  * Copyright (c) 2009-2010 The FreeBSD Foundation
3  * All rights reserved.
4  *
5  * This software was developed by Semihalf under sponsorship from
6  * the FreeBSD Foundation.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
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.
16  *
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
27  * SUCH DAMAGE.
28  */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include <stand.h>
34 #include <fdt.h>
35 #include <libfdt.h>
36 #include <sys/param.h>
37 #include <sys/linker.h>
38 #include <machine/elf.h>
39
40 #include "bootstrap.h"
41 #include "glue.h"
42
43 #ifdef DEBUG
44 #define debugf(fmt, args...) do { printf("%s(): ", __func__);   \
45     printf(fmt,##args); } while (0)
46 #else
47 #define debugf(fmt, args...)
48 #endif
49
50 #define FDT_CWD_LEN     256
51 #define FDT_MAX_DEPTH   6
52
53 #define FDT_PROP_SEP    " = "
54
55 #define STR(number) #number
56 #define STRINGIFY(number) STR(number)
57
58 #define COPYOUT(s,d,l)  archsw.arch_copyout(s, d, l)
59 #define COPYIN(s,d,l)   archsw.arch_copyin(s, d, l)
60
61 #define FDT_STATIC_DTB_SYMBOL   "fdt_static_dtb"
62
63 #define CMD_REQUIRES_BLOB       0x01
64
65 /* Location of FDT yet to be loaded. */
66 /* This may be in read-only memory, so can't be manipulated directly. */
67 static struct fdt_header *fdt_to_load = NULL;
68 /* Location of FDT on heap. */
69 /* This is the copy we actually manipulate. */
70 static struct fdt_header *fdtp = NULL;
71 /* Size of FDT blob */
72 static size_t fdtp_size = 0;
73 /* Location of FDT in kernel or module. */
74 /* This won't be set if FDT is loaded from disk or memory. */
75 /* If it is set, we'll update it when fdt_copy() gets called. */
76 static vm_offset_t fdtp_va = 0;
77
78 static int fdt_load_dtb(vm_offset_t va);
79
80 static int fdt_cmd_nyi(int argc, char *argv[]);
81
82 static int fdt_cmd_addr(int argc, char *argv[]);
83 static int fdt_cmd_mkprop(int argc, char *argv[]);
84 static int fdt_cmd_cd(int argc, char *argv[]);
85 static int fdt_cmd_hdr(int argc, char *argv[]);
86 static int fdt_cmd_ls(int argc, char *argv[]);
87 static int fdt_cmd_prop(int argc, char *argv[]);
88 static int fdt_cmd_pwd(int argc, char *argv[]);
89 static int fdt_cmd_rm(int argc, char *argv[]);
90 static int fdt_cmd_mknode(int argc, char *argv[]);
91 static int fdt_cmd_mres(int argc, char *argv[]);
92
93 typedef int cmdf_t(int, char *[]);
94
95 struct cmdtab {
96         const char      *name;
97         cmdf_t          *handler;
98         int             flags;
99 };
100
101 static const struct cmdtab commands[] = {
102         { "addr", &fdt_cmd_addr,        0 },
103         { "alias", &fdt_cmd_nyi,        0 },
104         { "cd", &fdt_cmd_cd,            CMD_REQUIRES_BLOB },
105         { "header", &fdt_cmd_hdr,       CMD_REQUIRES_BLOB },
106         { "ls", &fdt_cmd_ls,            CMD_REQUIRES_BLOB },
107         { "mknode", &fdt_cmd_mknode,    CMD_REQUIRES_BLOB },
108         { "mkprop", &fdt_cmd_mkprop,    CMD_REQUIRES_BLOB },
109         { "mres", &fdt_cmd_mres,        CMD_REQUIRES_BLOB },
110         { "prop", &fdt_cmd_prop,        CMD_REQUIRES_BLOB },
111         { "pwd", &fdt_cmd_pwd,          CMD_REQUIRES_BLOB },
112         { "rm", &fdt_cmd_rm,            CMD_REQUIRES_BLOB },
113         { NULL, NULL }
114 };
115
116 static char cwd[FDT_CWD_LEN] = "/";
117
118 static vm_offset_t
119 fdt_find_static_dtb()
120 {
121         Elf_Ehdr *ehdr;
122         Elf_Shdr *shdr;
123         Elf_Sym sym;
124         vm_offset_t strtab, symtab, fdt_start;
125         uint64_t offs;
126         struct preloaded_file *kfp;
127         struct file_metadata *md;
128         char *strp;
129         int i, sym_count;
130
131         debugf("fdt_find_static_dtb()\n");
132
133         sym_count = symtab = strtab = 0;
134         strp = NULL;
135
136         offs = __elfN(relocation_offset);
137
138         kfp = file_findfile(NULL, NULL);
139         if (kfp == NULL)
140                 return (0);
141
142         /* Locate the dynamic symbols and strtab. */
143         md = file_findmetadata(kfp, MODINFOMD_ELFHDR);
144         if (md == NULL)
145                 return (0);
146         ehdr = (Elf_Ehdr *)md->md_data;
147
148         md = file_findmetadata(kfp, MODINFOMD_SHDR);
149         if (md == NULL)
150                 return (0);
151         shdr = (Elf_Shdr *)md->md_data;
152
153         for (i = 0; i < ehdr->e_shnum; ++i) {
154                 if (shdr[i].sh_type == SHT_DYNSYM && symtab == 0) {
155                         symtab = shdr[i].sh_addr + offs;
156                         sym_count = shdr[i].sh_size / sizeof(Elf_Sym);
157                 } else if (shdr[i].sh_type == SHT_STRTAB && strtab == 0) {
158                         strtab = shdr[i].sh_addr + offs;
159                 }
160         }
161
162         /*
163          * The most efficent way to find a symbol would be to calculate a
164          * hash, find proper bucket and chain, and thus find a symbol.
165          * However, that would involve code duplication (e.g. for hash
166          * function). So we're using simpler and a bit slower way: we're
167          * iterating through symbols, searching for the one which name is
168          * 'equal' to 'fdt_static_dtb'. To speed up the process a little bit,
169          * we are eliminating symbols type of which is not STT_NOTYPE, or(and)
170          * those which binding attribute is not STB_GLOBAL.
171          */
172         fdt_start = 0;
173         while (sym_count > 0 && fdt_start == 0) {
174                 COPYOUT(symtab, &sym, sizeof(sym));
175                 symtab += sizeof(sym);
176                 --sym_count;
177                 if (ELF_ST_BIND(sym.st_info) != STB_GLOBAL ||
178                     ELF_ST_TYPE(sym.st_info) != STT_NOTYPE)
179                         continue;
180                 strp = strdupout(strtab + sym.st_name);
181                 if (strcmp(strp, FDT_STATIC_DTB_SYMBOL) == 0)
182                         fdt_start = (vm_offset_t)sym.st_value + offs;
183                 free(strp);
184         }
185         return (fdt_start);
186 }
187
188 static int
189 fdt_load_dtb(vm_offset_t va)
190 {
191         struct fdt_header header;
192         int err;
193
194         debugf("fdt_load_dtb(0x%08jx)\n", (uintmax_t)va);
195
196         COPYOUT(va, &header, sizeof(header));
197         err = fdt_check_header(&header);
198         if (err < 0) {
199                 if (err == -FDT_ERR_BADVERSION)
200                         sprintf(command_errbuf,
201                             "incompatible blob version: %d, should be: %d",
202                             fdt_version(fdtp), FDT_LAST_SUPPORTED_VERSION);
203
204                 else
205                         sprintf(command_errbuf, "error validating blob: %s",
206                             fdt_strerror(err));
207                 return (1);
208         }
209
210         /*
211          * Release previous blob
212          */
213         if (fdtp)
214                 free(fdtp);
215
216         fdtp_size = fdt_totalsize(&header);
217         fdtp = malloc(fdtp_size);
218
219         if (fdtp == NULL) {
220                 command_errmsg = "can't allocate memory for device tree copy";
221                 return (1);
222         }
223
224         fdtp_va = va;
225         COPYOUT(va, fdtp, fdtp_size);
226         debugf("DTB blob found at 0x%jx, size: 0x%jx\n", (uintmax_t)va, (uintmax_t)fdtp_size);
227
228         return (0);
229 }
230
231 static int
232 fdt_load_dtb_addr(struct fdt_header *header)
233 {
234         int err;
235
236         debugf("fdt_load_dtb_addr(0x%p)\n", header);
237
238         fdtp_size = fdt_totalsize(header);
239         err = fdt_check_header(header);
240         if (err < 0) {
241                 sprintf(command_errbuf, "error validating blob: %s",
242                     fdt_strerror(err));
243                 return (err);
244         }
245         free(fdtp);
246         if ((fdtp = malloc(fdtp_size)) == NULL) {
247                 command_errmsg = "can't allocate memory for device tree copy";
248                 return (1);
249         }
250
251         fdtp_va = 0; // Don't write this back into module or kernel.
252         bcopy(header, fdtp, fdtp_size);
253         return (0);
254 }
255
256 static int
257 fdt_load_dtb_file(const char * filename)
258 {
259         struct preloaded_file *bfp, *oldbfp;
260         int err;
261
262         debugf("fdt_load_dtb_file(%s)\n", filename);
263
264         oldbfp = file_findfile(NULL, "dtb");
265
266         /* Attempt to load and validate a new dtb from a file. */
267         if ((bfp = file_loadraw(filename, "dtb")) == NULL) {
268                 sprintf(command_errbuf, "failed to load file '%s'", filename);
269                 return (1);
270         }
271         if ((err = fdt_load_dtb(bfp->f_addr)) != 0) {
272                 file_discard(bfp);
273                 return (err);
274         }
275
276         /* A new dtb was validated, discard any previous file. */
277         if (oldbfp)
278                 file_discard(oldbfp);
279         return (0);
280 }
281
282 int
283 fdt_setup_fdtp()
284 {
285         struct preloaded_file *bfp;
286         struct fdt_header *hdr;
287         const char *s;
288         char *p;
289         vm_offset_t va;
290         
291         debugf("fdt_setup_fdtp()\n");
292
293         /* If we already loaded a file, use it. */
294         if ((bfp = file_findfile(NULL, "dtb")) != NULL) {
295                 if (fdt_load_dtb(bfp->f_addr) == 0) {
296                         printf("Using DTB from loaded file '%s'.\n", 
297                             bfp->f_name);
298                         return (0);
299                 }
300         }
301
302         /* If we were given the address of a valid blob in memory, use it. */
303         if (fdt_to_load != NULL) {
304                 if (fdt_load_dtb_addr(fdt_to_load) == 0) {
305                         printf("Using DTB from memory address 0x%08X.\n",
306                             (unsigned int)fdt_to_load);
307                         return (0);
308                 }
309         }
310
311         /*
312          * If the U-boot environment contains a variable giving the address of a
313          * valid blob in memory, use it.  The U-boot README says the right
314          * variable for fdt data loaded into ram is fdt_addr_r, so try that
315          * first.  Board vendors also use both fdtaddr and fdt_addr names.
316          */
317         s = ub_env_get("fdt_addr_r");
318         if (s == NULL)
319                 s = ub_env_get("fdtaddr");
320         if (s == NULL)
321                 s = ub_env_get("fdt_addr");
322         if (s != NULL && *s != '\0') {
323                 hdr = (struct fdt_header *)strtoul(s, &p, 16);
324                 if (*p == '\0') {
325                         if (fdt_load_dtb_addr(hdr) == 0) {
326                                 printf("Using DTB provided by U-Boot at "
327                                     "address 0x%p.\n", hdr);
328                                 return (0);
329                         }
330                 }
331         }
332
333         /*
334          * If the U-boot environment contains a variable giving the name of a
335          * file, use it if we can load and validate it.
336          */
337         s = ub_env_get("fdtfile");
338         if (s == NULL)
339                 s = ub_env_get("fdt_file");
340         if (s != NULL && *s != '\0') {
341                 if (fdt_load_dtb_file(s) == 0) {
342                         printf("Loaded DTB from file '%s'.\n", s);
343                         return (0);
344                 }
345         }
346
347         /* If there is a dtb compiled into the kernel, use it. */
348         if ((va = fdt_find_static_dtb()) != 0) {
349                 if (fdt_load_dtb(va) == 0) {
350                         printf("Using DTB compiled into kernel.\n");
351                         return (0);
352                 }
353         }
354         
355         command_errmsg = "No device tree blob found!\n";
356         return (1);
357 }
358
359 #define fdt_strtovect(str, cellbuf, lim, cellsize) _fdt_strtovect((str), \
360     (cellbuf), (lim), (cellsize), 0);
361
362 /* Force using base 16 */
363 #define fdt_strtovectx(str, cellbuf, lim, cellsize) _fdt_strtovect((str), \
364     (cellbuf), (lim), (cellsize), 16);
365
366 static int
367 _fdt_strtovect(const char *str, void *cellbuf, int lim, unsigned char cellsize,
368     uint8_t base)
369 {
370         const char *buf = str;
371         const char *end = str + strlen(str) - 2;
372         uint32_t *u32buf = NULL;
373         uint8_t *u8buf = NULL;
374         int cnt = 0;
375
376         if (cellsize == sizeof(uint32_t))
377                 u32buf = (uint32_t *)cellbuf;
378         else
379                 u8buf = (uint8_t *)cellbuf;
380
381         if (lim == 0)
382                 return (0);
383
384         while (buf < end) {
385
386                 /* Skip white whitespace(s)/separators */
387                 while (!isxdigit(*buf) && buf < end)
388                         buf++;
389
390                 if (u32buf != NULL)
391                         u32buf[cnt] =
392                             cpu_to_fdt32((uint32_t)strtol(buf, NULL, base));
393
394                 else
395                         u8buf[cnt] = (uint8_t)strtol(buf, NULL, base);
396
397                 if (cnt + 1 <= lim - 1)
398                         cnt++;
399                 else
400                         break;
401                 buf++;
402                 /* Find another number */
403                 while ((isxdigit(*buf) || *buf == 'x') && buf < end)
404                         buf++;
405         }
406         return (cnt);
407 }
408
409 #define TMP_MAX_ETH     8
410
411 static void
412 fixup_ethernet(const char *env, char *ethstr, int *eth_no, int len)
413 {
414         const char *str;
415         char *end;
416         uint8_t tmp_addr[6];
417         int i, n;
418
419         /* Extract interface number */
420         i = strtol(env + 3, &end, 10);
421         if (end == (env + 3))
422                 /* 'ethaddr' means interface 0 address */
423                 n = 0;
424         else
425                 n = i;
426
427         if (n > TMP_MAX_ETH)
428                 return;
429
430         str = ub_env_get(env);
431
432         /* Convert macaddr string into a vector of uints */
433         fdt_strtovectx(str, &tmp_addr, 6, sizeof(uint8_t));
434         if (n != 0) {
435                 i = strlen(env) - 7;
436                 strncpy(ethstr + 8, env + 3, i);
437         }
438         /* Set actual property to a value from vect */
439         fdt_setprop(fdtp, fdt_path_offset(fdtp, ethstr),
440             "local-mac-address", &tmp_addr, 6 * sizeof(uint8_t));
441
442         /* Clear ethernet..XXXX.. string */
443         bzero(ethstr + 8, len - 8);
444
445         if (n + 1 > *eth_no)
446                 *eth_no = n + 1;
447 }
448
449 static void
450 fixup_cpubusfreqs(unsigned long cpufreq, unsigned long busfreq)
451 {
452         int lo, o = 0, o2, maxo = 0, depth;
453         const uint32_t zero = 0;
454
455         /* We want to modify every subnode of /cpus */
456         o = fdt_path_offset(fdtp, "/cpus");
457         if (o < 0)
458                 return;
459
460         /* maxo should contain offset of node next to /cpus */
461         depth = 0;
462         maxo = o;
463         while (depth != -1)
464                 maxo = fdt_next_node(fdtp, maxo, &depth);
465
466         /* Find CPU frequency properties */
467         o = fdt_node_offset_by_prop_value(fdtp, o, "clock-frequency",
468             &zero, sizeof(uint32_t));
469
470         o2 = fdt_node_offset_by_prop_value(fdtp, o, "bus-frequency", &zero,
471             sizeof(uint32_t));
472
473         lo = MIN(o, o2);
474
475         while (o != -FDT_ERR_NOTFOUND && o2 != -FDT_ERR_NOTFOUND) {
476
477                 o = fdt_node_offset_by_prop_value(fdtp, lo,
478                     "clock-frequency", &zero, sizeof(uint32_t));
479
480                 o2 = fdt_node_offset_by_prop_value(fdtp, lo, "bus-frequency",
481                     &zero, sizeof(uint32_t));
482
483                 /* We're only interested in /cpus subnode(s) */
484                 if (lo > maxo)
485                         break;
486
487                 fdt_setprop_inplace_cell(fdtp, lo, "clock-frequency",
488                     (uint32_t)cpufreq);
489
490                 fdt_setprop_inplace_cell(fdtp, lo, "bus-frequency",
491                     (uint32_t)busfreq);
492
493                 lo = MIN(o, o2);
494         }
495 }
496
497 static int
498 fdt_reg_valid(uint32_t *reg, int len, int addr_cells, int size_cells)
499 {
500         int cells_in_tuple, i, tuples, tuple_size;
501         uint32_t cur_start, cur_size;
502
503         cells_in_tuple = (addr_cells + size_cells);
504         tuple_size = cells_in_tuple * sizeof(uint32_t);
505         tuples = len / tuple_size;
506         if (tuples == 0)
507                 return (EINVAL);
508
509         for (i = 0; i < tuples; i++) {
510                 if (addr_cells == 2)
511                         cur_start = fdt64_to_cpu(reg[i * cells_in_tuple]);
512                 else
513                         cur_start = fdt32_to_cpu(reg[i * cells_in_tuple]);
514
515                 if (size_cells == 2)
516                         cur_size = fdt64_to_cpu(reg[i * cells_in_tuple + 2]);
517                 else
518                         cur_size = fdt32_to_cpu(reg[i * cells_in_tuple + 1]);
519
520                 if (cur_size == 0)
521                         return (EINVAL);
522
523                 debugf(" reg#%d (start: 0x%0x size: 0x%0x) valid!\n",
524                     i, cur_start, cur_size);
525         }
526         return (0);
527 }
528
529 static void
530 fixup_memory(struct sys_info *si)
531 {
532         struct mem_region *curmr;
533         uint32_t addr_cells, size_cells;
534         uint32_t *addr_cellsp, *reg,  *size_cellsp;
535         int err, i, len, memory, realmrno, root;
536         uint8_t *buf, *sb;
537         uint64_t rstart, rsize;
538         int reserved;
539
540         root = fdt_path_offset(fdtp, "/");
541         if (root < 0) {
542                 sprintf(command_errbuf, "Could not find root node !");
543                 return;
544         }
545
546         memory = fdt_path_offset(fdtp, "/memory");
547         if (memory <= 0) {
548                 /* Create proper '/memory' node. */
549                 memory = fdt_add_subnode(fdtp, root, "memory");
550                 if (memory <= 0) {
551                         sprintf(command_errbuf, "Could not fixup '/memory' "
552                             "node, error code : %d!\n", memory);
553                         return;
554                 }
555
556                 err = fdt_setprop(fdtp, memory, "device_type", "memory",
557                     sizeof("memory"));
558
559                 if (err < 0)
560                         return;
561         }
562
563         addr_cellsp = (uint32_t *)fdt_getprop(fdtp, root, "#address-cells",
564             NULL);
565         size_cellsp = (uint32_t *)fdt_getprop(fdtp, root, "#size-cells", NULL);
566
567         if (addr_cellsp == NULL || size_cellsp == NULL) {
568                 sprintf(command_errbuf, "Could not fixup '/memory' node : "
569                     "%s %s property not found in root node!\n",
570                     (!addr_cellsp) ? "#address-cells" : "",
571                     (!size_cellsp) ? "#size-cells" : "");
572                 return;
573         }
574
575         addr_cells = fdt32_to_cpu(*addr_cellsp);
576         size_cells = fdt32_to_cpu(*size_cellsp);
577
578         /*
579          * Convert memreserve data to memreserve property
580          * Check if property already exists
581          */
582         reserved = fdt_num_mem_rsv(fdtp);
583         if (reserved &&
584             (fdt_getprop(fdtp, root, "memreserve", NULL) == NULL)) {
585                 len = (addr_cells + size_cells) * reserved * sizeof(uint32_t);
586                 sb = buf = (uint8_t *)malloc(len);
587                 if (!buf)
588                         return;
589
590                 bzero(buf, len);
591
592                 for (i = 0; i < reserved; i++) {
593                         curmr = &si->mr[i];
594                         if (fdt_get_mem_rsv(fdtp, i, &rstart, &rsize))
595                                 break;
596                         if (rsize) {
597                                 /* Ensure endianess, and put cells into a buffer */
598                                 if (addr_cells == 2)
599                                         *(uint64_t *)buf =
600                                             cpu_to_fdt64(rstart);
601                                 else
602                                         *(uint32_t *)buf =
603                                             cpu_to_fdt32(rstart);
604
605                                 buf += sizeof(uint32_t) * addr_cells;
606                                 if (size_cells == 2)
607                                         *(uint64_t *)buf =
608                                             cpu_to_fdt64(rsize);
609                                 else
610                                         *(uint32_t *)buf =
611                                             cpu_to_fdt32(rsize);
612
613                                 buf += sizeof(uint32_t) * size_cells;
614                         }
615                 }
616
617                 /* Set property */
618                 if ((err = fdt_setprop(fdtp, root, "memreserve", sb, len)) < 0)
619                         printf("Could not fixup 'memreserve' property.\n");
620
621                 free(sb);
622         } 
623
624         /* Count valid memory regions entries in sysinfo. */
625         realmrno = si->mr_no;
626         for (i = 0; i < si->mr_no; i++)
627                 if (si->mr[i].start == 0 && si->mr[i].size == 0)
628                         realmrno--;
629
630         if (realmrno == 0) {
631                 sprintf(command_errbuf, "Could not fixup '/memory' node : "
632                     "sysinfo doesn't contain valid memory regions info!\n");
633                 return;
634         }
635
636         if ((reg = (uint32_t *)fdt_getprop(fdtp, memory, "reg",
637             &len)) != NULL) {
638
639                 if (fdt_reg_valid(reg, len, addr_cells, size_cells) == 0)
640                         /*
641                          * Do not apply fixup if existing 'reg' property
642                          * seems to be valid.
643                          */
644                         return;
645         }
646
647         len = (addr_cells + size_cells) * realmrno * sizeof(uint32_t);
648         sb = buf = (uint8_t *)malloc(len);
649         if (!buf)
650                 return;
651
652         bzero(buf, len);
653
654         for (i = 0; i < si->mr_no; i++) {
655                 curmr = &si->mr[i];
656                 if (curmr->size != 0) {
657                         /* Ensure endianess, and put cells into a buffer */
658                         if (addr_cells == 2)
659                                 *(uint64_t *)buf =
660                                     cpu_to_fdt64(curmr->start);
661                         else
662                                 *(uint32_t *)buf =
663                                     cpu_to_fdt32(curmr->start);
664
665                         buf += sizeof(uint32_t) * addr_cells;
666                         if (size_cells == 2)
667                                 *(uint64_t *)buf =
668                                     cpu_to_fdt64(curmr->size);
669                         else
670                                 *(uint32_t *)buf =
671                                     cpu_to_fdt32(curmr->size);
672
673                         buf += sizeof(uint32_t) * size_cells;
674                 }
675         }
676
677         /* Set property */
678         if ((err = fdt_setprop(fdtp, memory, "reg", sb, len)) < 0)
679                 sprintf(command_errbuf, "Could not fixup '/memory' node.\n");
680
681         free(sb);
682 }
683
684 static void
685 fixup_stdout(const char *env)
686 {
687         const char *str;
688         char *ptr;
689         int serialno;
690         int len, no, sero;
691         const struct fdt_property *prop;
692         char *tmp[10];
693
694         str = ub_env_get(env);
695         ptr = (char *)str + strlen(str) - 1;
696         while (ptr > str && isdigit(*(str - 1)))
697                 str--;
698
699         if (ptr == str)
700                 return;
701
702         serialno = (int)strtol(ptr, NULL, 0);
703         no = fdt_path_offset(fdtp, "/chosen");
704         if (no < 0)
705                 return;
706
707         prop = fdt_get_property(fdtp, no, "stdout", &len);
708
709         /* If /chosen/stdout does not extist, create it */
710         if (prop == NULL || (prop != NULL && len == 0)) {
711
712                 bzero(tmp, 10 * sizeof(char));
713                 strcpy((char *)&tmp, "serial");
714                 if (strlen(ptr) > 3)
715                         /* Serial number too long */
716                         return;
717
718                 strncpy((char *)tmp + 6, ptr, 3);
719                 sero = fdt_path_offset(fdtp, (const char *)tmp);
720                 if (sero < 0)
721                         /*
722                          * If serial device we're trying to assign
723                          * stdout to doesn't exist in DT -- return.
724                          */
725                         return;
726
727                 fdt_setprop(fdtp, no, "stdout", &tmp,
728                     strlen((char *)&tmp) + 1);
729                 fdt_setprop(fdtp, no, "stdin", &tmp,
730                     strlen((char *)&tmp) + 1);
731         }
732 }
733
734 /*
735  * Locate the blob, fix it up and return its location.
736  */
737 static int
738 fdt_fixup(void)
739 {
740         const char *env;
741         char *ethstr;
742         int chosen, eth_no, len;
743         struct sys_info *si;
744
745         env = NULL;
746         eth_no = 0;
747         ethstr = NULL;
748         len = 0;
749
750         debugf("fdt_fixup()\n");
751
752         if (fdtp == NULL && fdt_setup_fdtp() != 0)
753                 return (0);
754
755         /* Create /chosen node (if not exists) */
756         if ((chosen = fdt_subnode_offset(fdtp, 0, "chosen")) ==
757             -FDT_ERR_NOTFOUND)
758                 chosen = fdt_add_subnode(fdtp, 0, "chosen");
759
760         /* Value assigned to fixup-applied does not matter. */
761         if (fdt_getprop(fdtp, chosen, "fixup-applied", NULL))
762                 return (1);
763
764         /* Acquire sys_info */
765         si = ub_get_sys_info();
766
767         while ((env = ub_env_enum(env)) != NULL) {
768                 if (strncmp(env, "eth", 3) == 0 &&
769                     strncmp(env + (strlen(env) - 4), "addr", 4) == 0) {
770                         /*
771                          * Handle Ethernet addrs: parse uboot env eth%daddr
772                          */
773
774                         if (!eth_no) {
775                                 /*
776                                  * Check how many chars we will need to store
777                                  * maximal eth iface number.
778                                  */
779                                 len = strlen(STRINGIFY(TMP_MAX_ETH)) +
780                                     strlen("ethernet");
781
782                                 /*
783                                  * Reserve mem for string "ethernet" and len
784                                  * chars for iface no.
785                                  */
786                                 ethstr = (char *)malloc(len * sizeof(char));
787                                 bzero(ethstr, len * sizeof(char));
788                                 strcpy(ethstr, "ethernet0");
789                         }
790
791                         /* Modify blob */
792                         fixup_ethernet(env, ethstr, &eth_no, len);
793
794                 } else if (strcmp(env, "consoledev") == 0)
795                         fixup_stdout(env);
796         }
797
798         /* Modify cpu(s) and bus clock frequenties in /cpus node [Hz] */
799         fixup_cpubusfreqs(si->clk_cpu, si->clk_bus);
800
801         /* Fixup memory regions */
802         fixup_memory(si);
803
804         fdt_setprop(fdtp, chosen, "fixup-applied", NULL, 0);
805         return (1);
806 }
807
808 /*
809  * Copy DTB blob to specified location and return size
810  */
811 int
812 fdt_copy(vm_offset_t va)
813 {
814         int err;
815         debugf("fdt_copy va 0x%08x\n", va);
816         if (fdtp == NULL) {
817                 err = fdt_setup_fdtp();
818                 if (err) {
819                         printf("No valid device tree blob found!\n");
820                         return (0);
821                 }
822         }
823
824         if (fdt_fixup() == 0)
825                 return (0);
826
827         if (fdtp_va != 0) {
828                 /* Overwrite the FDT with the fixed version. */
829                 /* XXX Is this really appropriate? */
830                 COPYIN(fdtp, fdtp_va, fdtp_size);
831         }
832         COPYIN(fdtp, va, fdtp_size);
833         return (fdtp_size);
834 }
835
836
837
838 int
839 command_fdt_internal(int argc, char *argv[])
840 {
841         cmdf_t *cmdh;
842         int flags;
843         char *cmd;
844         int i, err;
845
846         if (argc < 2) {
847                 command_errmsg = "usage is 'fdt <command> [<args>]";
848                 return (CMD_ERROR);
849         }
850
851         /*
852          * Validate fdt <command>.
853          */
854         cmd = strdup(argv[1]);
855         i = 0;
856         cmdh = NULL;
857         while (!(commands[i].name == NULL)) {
858                 if (strcmp(cmd, commands[i].name) == 0) {
859                         /* found it */
860                         cmdh = commands[i].handler;
861                         flags = commands[i].flags;
862                         break;
863                 }
864                 i++;
865         }
866         if (cmdh == NULL) {
867                 command_errmsg = "unknown command";
868                 return (CMD_ERROR);
869         }
870
871         if (flags & CMD_REQUIRES_BLOB) {
872                 /*
873                  * Check if uboot env vars were parsed already. If not, do it now.
874                  */
875                 if (fdt_fixup() == 0)
876                         return (CMD_ERROR);
877         }
878
879         /*
880          * Call command handler.
881          */
882         err = (*cmdh)(argc, argv);
883
884         return (err);
885 }
886
887 static int
888 fdt_cmd_addr(int argc, char *argv[])
889 {
890         struct preloaded_file *fp;
891         struct fdt_header *hdr;
892         const char *addr;
893         char *cp;
894
895         fdt_to_load = NULL;
896
897         if (argc > 2)
898                 addr = argv[2];
899         else {
900                 sprintf(command_errbuf, "no address specified");
901                 return (CMD_ERROR);
902         }
903
904         hdr = (struct fdt_header *)strtoul(addr, &cp, 16);
905         if (cp == addr) {
906                 sprintf(command_errbuf, "Invalid address: %s", addr);
907                 return (CMD_ERROR);
908         }
909
910         while ((fp = file_findfile(NULL, "dtb")) != NULL) {
911                 file_discard(fp);
912         }
913
914         fdt_to_load = hdr;
915         return (CMD_OK);
916 }
917
918 static int
919 fdt_cmd_cd(int argc, char *argv[])
920 {
921         char *path;
922         char tmp[FDT_CWD_LEN];
923         int len, o;
924
925         path = (argc > 2) ? argv[2] : "/";
926
927         if (path[0] == '/') {
928                 len = strlen(path);
929                 if (len >= FDT_CWD_LEN)
930                         goto fail;
931         } else {
932                 /* Handle path specification relative to cwd */
933                 len = strlen(cwd) + strlen(path) + 1;
934                 if (len >= FDT_CWD_LEN)
935                         goto fail;
936
937                 strcpy(tmp, cwd);
938                 strcat(tmp, "/");
939                 strcat(tmp, path);
940                 path = tmp;
941         }
942
943         o = fdt_path_offset(fdtp, path);
944         if (o < 0) {
945                 sprintf(command_errbuf, "could not find node: '%s'", path);
946                 return (CMD_ERROR);
947         }
948
949         strcpy(cwd, path);
950         return (CMD_OK);
951
952 fail:
953         sprintf(command_errbuf, "path too long: %d, max allowed: %d",
954             len, FDT_CWD_LEN - 1);
955         return (CMD_ERROR);
956 }
957
958 static int
959 fdt_cmd_hdr(int argc __unused, char *argv[] __unused)
960 {
961         char line[80];
962         int ver;
963
964         if (fdtp == NULL) {
965                 command_errmsg = "no device tree blob pointer?!";
966                 return (CMD_ERROR);
967         }
968
969         ver = fdt_version(fdtp);
970         pager_open();
971         sprintf(line, "\nFlattened device tree header (%p):\n", fdtp);
972         pager_output(line);
973         sprintf(line, " magic                   = 0x%08x\n", fdt_magic(fdtp));
974         pager_output(line);
975         sprintf(line, " size                    = %d\n", fdt_totalsize(fdtp));
976         pager_output(line);
977         sprintf(line, " off_dt_struct           = 0x%08x\n",
978             fdt_off_dt_struct(fdtp));
979         pager_output(line);
980         sprintf(line, " off_dt_strings          = 0x%08x\n",
981             fdt_off_dt_strings(fdtp));
982         pager_output(line);
983         sprintf(line, " off_mem_rsvmap          = 0x%08x\n",
984             fdt_off_mem_rsvmap(fdtp));
985         pager_output(line);
986         sprintf(line, " version                 = %d\n", ver); 
987         pager_output(line);
988         sprintf(line, " last compatible version = %d\n",
989             fdt_last_comp_version(fdtp));
990         pager_output(line);
991         if (ver >= 2) {
992                 sprintf(line, " boot_cpuid              = %d\n",
993                     fdt_boot_cpuid_phys(fdtp));
994                 pager_output(line);
995         }
996         if (ver >= 3) {
997                 sprintf(line, " size_dt_strings         = %d\n",
998                     fdt_size_dt_strings(fdtp));
999                 pager_output(line);
1000         }
1001         if (ver >= 17) {
1002                 sprintf(line, " size_dt_struct          = %d\n",
1003                     fdt_size_dt_struct(fdtp));
1004                 pager_output(line);
1005         }
1006         pager_close();
1007
1008         return (CMD_OK);
1009 }
1010
1011 static int
1012 fdt_cmd_ls(int argc, char *argv[])
1013 {
1014         const char *prevname[FDT_MAX_DEPTH] = { NULL };
1015         const char *name;
1016         char *path;
1017         int i, o, depth, len;
1018
1019         path = (argc > 2) ? argv[2] : NULL;
1020         if (path == NULL)
1021                 path = cwd;
1022
1023         o = fdt_path_offset(fdtp, path);
1024         if (o < 0) {
1025                 sprintf(command_errbuf, "could not find node: '%s'", path);
1026                 return (CMD_ERROR);
1027         }
1028
1029         for (depth = 0;
1030             (o >= 0) && (depth >= 0);
1031             o = fdt_next_node(fdtp, o, &depth)) {
1032
1033                 name = fdt_get_name(fdtp, o, &len);
1034
1035                 if (depth > FDT_MAX_DEPTH) {
1036                         printf("max depth exceeded: %d\n", depth);
1037                         continue;
1038                 }
1039
1040                 prevname[depth] = name;
1041
1042                 /* Skip root (i = 1) when printing devices */
1043                 for (i = 1; i <= depth; i++) {
1044                         if (prevname[i] == NULL)
1045                                 break;
1046
1047                         if (strcmp(cwd, "/") == 0)
1048                                 printf("/");
1049                         printf("%s", prevname[i]);
1050                 }
1051                 printf("\n");
1052         }
1053
1054         return (CMD_OK);
1055 }
1056
1057 static __inline int
1058 isprint(int c)
1059 {
1060
1061         return (c >= ' ' && c <= 0x7e);
1062 }
1063
1064 static int
1065 fdt_isprint(const void *data, int len, int *count)
1066 {
1067         const char *d;
1068         char ch;
1069         int yesno, i;
1070
1071         if (len == 0)
1072                 return (0);
1073
1074         d = (const char *)data;
1075         if (d[len - 1] != '\0')
1076                 return (0);
1077
1078         *count = 0;
1079         yesno = 1;
1080         for (i = 0; i < len; i++) {
1081                 ch = *(d + i);
1082                 if (isprint(ch) || (ch == '\0' && i > 0)) {
1083                         /* Count strings */
1084                         if (ch == '\0')
1085                                 (*count)++;
1086                         continue;
1087                 }
1088
1089                 yesno = 0;
1090                 break;
1091         }
1092
1093         return (yesno);
1094 }
1095
1096 static int
1097 fdt_data_str(const void *data, int len, int count, char **buf)
1098 {
1099         char *b, *tmp;
1100         const char *d;
1101         int buf_len, i, l;
1102
1103         /*
1104          * Calculate the length for the string and allocate memory.
1105          *
1106          * Note that 'len' already includes at least one terminator.
1107          */
1108         buf_len = len;
1109         if (count > 1) {
1110                 /*
1111                  * Each token had already a terminator buried in 'len', but we
1112                  * only need one eventually, don't count space for these.
1113                  */
1114                 buf_len -= count - 1;
1115
1116                 /* Each consecutive token requires a ", " separator. */
1117                 buf_len += count * 2;
1118         }
1119
1120         /* Add some space for surrounding double quotes. */
1121         buf_len += count * 2;
1122
1123         /* Note that string being put in 'tmp' may be as big as 'buf_len'. */
1124         b = (char *)malloc(buf_len);
1125         tmp = (char *)malloc(buf_len);
1126         if (b == NULL)
1127                 goto error;
1128
1129         if (tmp == NULL) {
1130                 free(b);
1131                 goto error;
1132         }
1133
1134         b[0] = '\0';
1135
1136         /*
1137          * Now that we have space, format the string.
1138          */
1139         i = 0;
1140         do {
1141                 d = (const char *)data + i;
1142                 l = strlen(d) + 1;
1143
1144                 sprintf(tmp, "\"%s\"%s", d,
1145                     (i + l) < len ?  ", " : "");
1146                 strcat(b, tmp);
1147
1148                 i += l;
1149
1150         } while (i < len);
1151         *buf = b;
1152
1153         free(tmp);
1154
1155         return (0);
1156 error:
1157         return (1);
1158 }
1159
1160 static int
1161 fdt_data_cell(const void *data, int len, char **buf)
1162 {
1163         char *b, *tmp;
1164         const uint32_t *c;
1165         int count, i, l;
1166
1167         /* Number of cells */
1168         count = len / 4;
1169
1170         /*
1171          * Calculate the length for the string and allocate memory.
1172          */
1173
1174         /* Each byte translates to 2 output characters */
1175         l = len * 2;
1176         if (count > 1) {
1177                 /* Each consecutive cell requires a " " separator. */
1178                 l += (count - 1) * 1;
1179         }
1180         /* Each cell will have a "0x" prefix */
1181         l += count * 2;
1182         /* Space for surrounding <> and terminator */
1183         l += 3;
1184
1185         b = (char *)malloc(l);
1186         tmp = (char *)malloc(l);
1187         if (b == NULL)
1188                 goto error;
1189
1190         if (tmp == NULL) {
1191                 free(b);
1192                 goto error;
1193         }
1194
1195         b[0] = '\0';
1196         strcat(b, "<");
1197
1198         for (i = 0; i < len; i += 4) {
1199                 c = (const uint32_t *)((const uint8_t *)data + i);
1200                 sprintf(tmp, "0x%08x%s", fdt32_to_cpu(*c),
1201                     i < (len - 4) ? " " : "");
1202                 strcat(b, tmp);
1203         }
1204         strcat(b, ">");
1205         *buf = b;
1206
1207         free(tmp);
1208
1209         return (0);
1210 error:
1211         return (1);
1212 }
1213
1214 static int
1215 fdt_data_bytes(const void *data, int len, char **buf)
1216 {
1217         char *b, *tmp;
1218         const char *d;
1219         int i, l;
1220
1221         /*
1222          * Calculate the length for the string and allocate memory.
1223          */
1224
1225         /* Each byte translates to 2 output characters */
1226         l = len * 2;
1227         if (len > 1)
1228                 /* Each consecutive byte requires a " " separator. */
1229                 l += (len - 1) * 1;
1230         /* Each byte will have a "0x" prefix */
1231         l += len * 2;
1232         /* Space for surrounding [] and terminator. */
1233         l += 3;
1234
1235         b = (char *)malloc(l);
1236         tmp = (char *)malloc(l);
1237         if (b == NULL)
1238                 goto error;
1239
1240         if (tmp == NULL) {
1241                 free(b);
1242                 goto error;
1243         }
1244
1245         b[0] = '\0';
1246         strcat(b, "[");
1247
1248         for (i = 0, d = data; i < len; i++) {
1249                 sprintf(tmp, "0x%02x%s", d[i], i < len - 1 ? " " : "");
1250                 strcat(b, tmp);
1251         }
1252         strcat(b, "]");
1253         *buf = b;
1254
1255         free(tmp);
1256
1257         return (0);
1258 error:
1259         return (1);
1260 }
1261
1262 static int
1263 fdt_data_fmt(const void *data, int len, char **buf)
1264 {
1265         int count;
1266
1267         if (len == 0) {
1268                 *buf = NULL;
1269                 return (1);
1270         }
1271
1272         if (fdt_isprint(data, len, &count))
1273                 return (fdt_data_str(data, len, count, buf));
1274
1275         else if ((len % 4) == 0)
1276                 return (fdt_data_cell(data, len, buf));
1277
1278         else
1279                 return (fdt_data_bytes(data, len, buf));
1280 }
1281
1282 static int
1283 fdt_prop(int offset)
1284 {
1285         char *line, *buf;
1286         const struct fdt_property *prop;
1287         const char *name;
1288         const void *data;
1289         int len, rv;
1290
1291         line = NULL;
1292         prop = fdt_offset_ptr(fdtp, offset, sizeof(*prop));
1293         if (prop == NULL)
1294                 return (1);
1295
1296         name = fdt_string(fdtp, fdt32_to_cpu(prop->nameoff));
1297         len = fdt32_to_cpu(prop->len);
1298
1299         rv = 0;
1300         buf = NULL;
1301         if (len == 0) {
1302                 /* Property without value */
1303                 line = (char *)malloc(strlen(name) + 2);
1304                 if (line == NULL) {
1305                         rv = 2;
1306                         goto out2;
1307                 }
1308                 sprintf(line, "%s\n", name);
1309                 goto out1;
1310         }
1311
1312         /*
1313          * Process property with value
1314          */
1315         data = prop->data;
1316
1317         if (fdt_data_fmt(data, len, &buf) != 0) {
1318                 rv = 3;
1319                 goto out2;
1320         }
1321
1322         line = (char *)malloc(strlen(name) + strlen(FDT_PROP_SEP) +
1323             strlen(buf) + 2);
1324         if (line == NULL) {
1325                 sprintf(command_errbuf, "could not allocate space for string");
1326                 rv = 4;
1327                 goto out2;
1328         }
1329
1330         sprintf(line, "%s" FDT_PROP_SEP "%s\n", name, buf);
1331
1332 out1:
1333         pager_open();
1334         pager_output(line);
1335         pager_close();
1336
1337 out2:
1338         if (buf)
1339                 free(buf);
1340
1341         if (line)
1342                 free(line);
1343
1344         return (rv);
1345 }
1346
1347 static int
1348 fdt_modprop(int nodeoff, char *propname, void *value, char mode)
1349 {
1350         uint32_t cells[100];
1351         const char *buf;
1352         int len, rv;
1353         const struct fdt_property *p;
1354
1355         p = fdt_get_property(fdtp, nodeoff, propname, NULL);
1356
1357         if (p != NULL) {
1358                 if (mode == 1) {
1359                          /* Adding inexistant value in mode 1 is forbidden */
1360                         sprintf(command_errbuf, "property already exists!");
1361                         return (CMD_ERROR);
1362                 }
1363         } else if (mode == 0) {
1364                 sprintf(command_errbuf, "property does not exist!");
1365                 return (CMD_ERROR);
1366         }
1367         len = strlen(value);
1368         rv = 0;
1369         buf = value;
1370
1371         switch (*buf) {
1372         case '&':
1373                 /* phandles */
1374                 break;
1375         case '<':
1376                 /* Data cells */
1377                 len = fdt_strtovect(buf, (void *)&cells, 100,
1378                     sizeof(uint32_t));
1379
1380                 rv = fdt_setprop(fdtp, nodeoff, propname, &cells,
1381                     len * sizeof(uint32_t));
1382                 break;
1383         case '[':
1384                 /* Data bytes */
1385                 len = fdt_strtovect(buf, (void *)&cells, 100,
1386                     sizeof(uint8_t));
1387
1388                 rv = fdt_setprop(fdtp, nodeoff, propname, &cells,
1389                     len * sizeof(uint8_t));
1390                 break;
1391         case '"':
1392         default:
1393                 /* Default -- string */
1394                 rv = fdt_setprop_string(fdtp, nodeoff, propname, value);
1395                 break;
1396         }
1397
1398         if (rv != 0) {
1399                 if (rv == -FDT_ERR_NOSPACE)
1400                         sprintf(command_errbuf,
1401                             "Device tree blob is too small!\n");
1402                 else
1403                         sprintf(command_errbuf,
1404                             "Could not add/modify property!\n");
1405         }
1406         return (rv);
1407 }
1408
1409 /* Merge strings from argv into a single string */
1410 static int
1411 fdt_merge_strings(int argc, char *argv[], int start, char **buffer)
1412 {
1413         char *buf;
1414         int i, idx, sz;
1415
1416         *buffer = NULL;
1417         sz = 0;
1418
1419         for (i = start; i < argc; i++)
1420                 sz += strlen(argv[i]);
1421
1422         /* Additional bytes for whitespaces between args */
1423         sz += argc - start;
1424
1425         buf = (char *)malloc(sizeof(char) * sz);
1426         bzero(buf, sizeof(char) * sz);
1427
1428         if (buf == NULL) {
1429                 sprintf(command_errbuf, "could not allocate space "
1430                     "for string");
1431                 return (1);
1432         }
1433
1434         idx = 0;
1435         for (i = start, idx = 0; i < argc; i++) {
1436                 strcpy(buf + idx, argv[i]);
1437                 idx += strlen(argv[i]);
1438                 buf[idx] = ' ';
1439                 idx++;
1440         }
1441         buf[sz - 1] = '\0';
1442         *buffer = buf;
1443         return (0);
1444 }
1445
1446 /* Extract offset and name of node/property from a given path */
1447 static int
1448 fdt_extract_nameloc(char **pathp, char **namep, int *nodeoff)
1449 {
1450         int o;
1451         char *path = *pathp, *name = NULL, *subpath = NULL;
1452
1453         subpath = strrchr(path, '/');
1454         if (subpath == NULL) {
1455                 o = fdt_path_offset(fdtp, cwd);
1456                 name = path;
1457                 path = (char *)&cwd;
1458         } else {
1459                 *subpath = '\0';
1460                 if (strlen(path) == 0)
1461                         path = cwd;
1462
1463                 name = subpath + 1;
1464                 o = fdt_path_offset(fdtp, path);
1465         }
1466
1467         if (strlen(name) == 0) {
1468                 sprintf(command_errbuf, "name not specified");
1469                 return (1);
1470         }
1471         if (o < 0) {
1472                 sprintf(command_errbuf, "could not find node: '%s'", path);
1473                 return (1);
1474         }
1475         *namep = name;
1476         *nodeoff = o;
1477         *pathp = path;
1478         return (0);
1479 }
1480
1481 static int
1482 fdt_cmd_prop(int argc, char *argv[])
1483 {
1484         char *path, *propname, *value;
1485         int o, next, depth, rv;
1486         uint32_t tag;
1487
1488         path = (argc > 2) ? argv[2] : NULL;
1489
1490         value = NULL;
1491
1492         if (argc > 3) {
1493                 /* Merge property value strings into one */
1494                 if (fdt_merge_strings(argc, argv, 3, &value) != 0)
1495                         return (CMD_ERROR);
1496         } else
1497                 value = NULL;
1498
1499         if (path == NULL)
1500                 path = cwd;
1501
1502         rv = CMD_OK;
1503
1504         if (value) {
1505                 /* If value is specified -- try to modify prop. */
1506                 if (fdt_extract_nameloc(&path, &propname, &o) != 0)
1507                         return (CMD_ERROR);
1508
1509                 rv = fdt_modprop(o, propname, value, 0);
1510                 if (rv)
1511                         return (CMD_ERROR);
1512                 return (CMD_OK);
1513
1514         }
1515         /* User wants to display properties */
1516         o = fdt_path_offset(fdtp, path);
1517
1518         if (o < 0) {
1519                 sprintf(command_errbuf, "could not find node: '%s'", path);
1520                 rv = CMD_ERROR;
1521                 goto out;
1522         }
1523
1524         depth = 0;
1525         while (depth >= 0) {
1526                 tag = fdt_next_tag(fdtp, o, &next);
1527                 switch (tag) {
1528                 case FDT_NOP:
1529                         break;
1530                 case FDT_PROP:
1531                         if (depth > 1)
1532                                 /* Don't process properties of nested nodes */
1533                                 break;
1534
1535                         if (fdt_prop(o) != 0) {
1536                                 sprintf(command_errbuf, "could not process "
1537                                     "property");
1538                                 rv = CMD_ERROR;
1539                                 goto out;
1540                         }
1541                         break;
1542                 case FDT_BEGIN_NODE:
1543                         depth++;
1544                         if (depth > FDT_MAX_DEPTH) {
1545                                 printf("warning: nesting too deep: %d\n",
1546                                     depth);
1547                                 goto out;
1548                         }
1549                         break;
1550                 case FDT_END_NODE:
1551                         depth--;
1552                         if (depth == 0)
1553                                 /*
1554                                  * This is the end of our starting node, force
1555                                  * the loop finish.
1556                                  */
1557                                 depth--;
1558                         break;
1559                 }
1560                 o = next;
1561         }
1562 out:
1563         return (rv);
1564 }
1565
1566 static int
1567 fdt_cmd_mkprop(int argc, char *argv[])
1568 {
1569         int o;
1570         char *path, *propname, *value;
1571
1572         path = (argc > 2) ? argv[2] : NULL;
1573
1574         value = NULL;
1575
1576         if (argc > 3) {
1577                 /* Merge property value strings into one */
1578                 if (fdt_merge_strings(argc, argv, 3, &value) != 0)
1579                         return (CMD_ERROR);
1580         } else
1581                 value = NULL;
1582
1583         if (fdt_extract_nameloc(&path, &propname, &o) != 0)
1584                 return (CMD_ERROR);
1585
1586         if (fdt_modprop(o, propname, value, 1))
1587                 return (CMD_ERROR);
1588
1589         return (CMD_OK);
1590 }
1591
1592 static int
1593 fdt_cmd_rm(int argc, char *argv[])
1594 {
1595         int o, rv;
1596         char *path = NULL, *propname;
1597
1598         if (argc > 2)
1599                 path = argv[2];
1600         else {
1601                 sprintf(command_errbuf, "no node/property name specified");
1602                 return (CMD_ERROR);
1603         }
1604
1605         o = fdt_path_offset(fdtp, path);
1606         if (o < 0) {
1607                 /* If node not found -- try to find & delete property */
1608                 if (fdt_extract_nameloc(&path, &propname, &o) != 0)
1609                         return (CMD_ERROR);
1610
1611                 if ((rv = fdt_delprop(fdtp, o, propname)) != 0) {
1612                         sprintf(command_errbuf, "could not delete"
1613                             "%s\n", (rv == -FDT_ERR_NOTFOUND) ?
1614                             "(property/node does not exist)" : "");
1615                         return (CMD_ERROR);
1616
1617                 } else
1618                         return (CMD_OK);
1619         }
1620         /* If node exists -- remove node */
1621         rv = fdt_del_node(fdtp, o);
1622         if (rv) {
1623                 sprintf(command_errbuf, "could not delete node");
1624                 return (CMD_ERROR);
1625         }
1626         return (CMD_OK);
1627 }
1628
1629 static int
1630 fdt_cmd_mknode(int argc, char *argv[])
1631 {
1632         int o, rv;
1633         char *path = NULL, *nodename = NULL;
1634
1635         if (argc > 2)
1636                 path = argv[2];
1637         else {
1638                 sprintf(command_errbuf, "no node name specified");
1639                 return (CMD_ERROR);
1640         }
1641
1642         if (fdt_extract_nameloc(&path, &nodename, &o) != 0)
1643                 return (CMD_ERROR);
1644
1645         rv = fdt_add_subnode(fdtp, o, nodename);
1646
1647         if (rv < 0) {
1648                 if (rv == -FDT_ERR_NOSPACE)
1649                         sprintf(command_errbuf,
1650                             "Device tree blob is too small!\n");
1651                 else
1652                         sprintf(command_errbuf,
1653                             "Could not add node!\n");
1654                 return (CMD_ERROR);
1655         }
1656         return (CMD_OK);
1657 }
1658
1659 static int
1660 fdt_cmd_pwd(int argc, char *argv[])
1661 {
1662         char line[FDT_CWD_LEN];
1663
1664         pager_open();
1665         sprintf(line, "%s\n", cwd);
1666         pager_output(line);
1667         pager_close();
1668         return (CMD_OK);
1669 }
1670
1671 static int
1672 fdt_cmd_mres(int argc, char *argv[])
1673 {
1674         uint64_t start, size;
1675         int i, total;
1676         char line[80];
1677
1678         pager_open();
1679         total = fdt_num_mem_rsv(fdtp);
1680         if (total > 0) {
1681                 pager_output("Reserved memory regions:\n");
1682                 for (i = 0; i < total; i++) {
1683                         fdt_get_mem_rsv(fdtp, i, &start, &size);
1684                         sprintf(line, "reg#%d: (start: 0x%jx, size: 0x%jx)\n", 
1685                             i, start, size);
1686                         pager_output(line);
1687                 }
1688         } else
1689                 pager_output("No reserved memory regions\n");
1690         pager_close();
1691
1692         return (CMD_OK);
1693 }
1694
1695 static int
1696 fdt_cmd_nyi(int argc, char *argv[])
1697 {
1698
1699         printf("command not yet implemented\n");
1700         return (CMD_ERROR);
1701 }