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