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