fdt_loader_cmd.c revision 247201
1208538Sraj/*-
2208538Sraj * Copyright (c) 2009-2010 The FreeBSD Foundation
3208538Sraj * All rights reserved.
4208538Sraj *
5208538Sraj * This software was developed by Semihalf under sponsorship from
6208538Sraj * the FreeBSD Foundation.
7208538Sraj *
8208538Sraj * Redistribution and use in source and binary forms, with or without
9208538Sraj * modification, are permitted provided that the following conditions
10208538Sraj * are met:
11208538Sraj * 1. Redistributions of source code must retain the above copyright
12208538Sraj *    notice, this list of conditions and the following disclaimer.
13208538Sraj * 2. Redistributions in binary form must reproduce the above copyright
14208538Sraj *    notice, this list of conditions and the following disclaimer in the
15208538Sraj *    documentation and/or other materials provided with the distribution.
16208538Sraj *
17208538Sraj * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18208538Sraj * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19208538Sraj * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20208538Sraj * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21208538Sraj * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22208538Sraj * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23208538Sraj * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24208538Sraj * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25208538Sraj * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26208538Sraj * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27208538Sraj * SUCH DAMAGE.
28208538Sraj */
29208538Sraj
30208538Sraj#include <sys/cdefs.h>
31208538Sraj__FBSDID("$FreeBSD: head/sys/boot/fdt/fdt_loader_cmd.c 247201 2013-02-23 20:34:47Z kientzle $");
32208538Sraj
33208538Sraj#include <stand.h>
34208538Sraj#include <fdt.h>
35208538Sraj#include <libfdt.h>
36233230Sraj#include <sys/param.h>
37233230Sraj#include <sys/linker.h>
38233230Sraj#include <machine/elf.h>
39208538Sraj
40208538Sraj#include "bootstrap.h"
41208538Sraj#include "glue.h"
42208538Sraj
43208538Sraj#ifdef DEBUG
44208538Sraj#define debugf(fmt, args...) do { printf("%s(): ", __func__);	\
45208538Sraj    printf(fmt,##args); } while (0)
46208538Sraj#else
47208538Sraj#define debugf(fmt, args...)
48208538Sraj#endif
49208538Sraj
50208538Sraj#define FDT_CWD_LEN	256
51208538Sraj#define FDT_MAX_DEPTH	6
52208538Sraj
53208538Sraj#define FDT_PROP_SEP	" = "
54208538Sraj
55208538Sraj#define STR(number) #number
56208538Sraj#define STRINGIFY(number) STR(number)
57208538Sraj
58235529Skientzle#define COPYOUT(s,d,l)	archsw.arch_copyout(s, d, l)
59235529Skientzle#define COPYIN(s,d,l)	archsw.arch_copyin(s, d, l)
60233230Sraj
61233230Sraj#define FDT_STATIC_DTB_SYMBOL	"fdt_static_dtb"
62233230Sraj
63243693Sgonzo#define	CMD_REQUIRES_BLOB	0x01
64243693Sgonzo
65247201Skientzle/* Location of FDT yet to be loaded. */
66247201Skientzlestatic struct fdt_header *fdt_to_load = NULL;
67247201Skientzle/* Local copy of FDT on heap. */
68208538Srajstatic struct fdt_header *fdtp = NULL;
69235529Skientzle/* Size of FDT blob */
70235529Skientzlestatic size_t fdtp_size = 0;
71235529Skientzle/* Location of FDT in kernel or module */
72235529Skientzlestatic vm_offset_t fdtp_va = 0;
73208538Sraj
74243693Sgonzostatic int fdt_load_dtb(vm_offset_t va);
75243693Sgonzo
76208538Srajstatic int fdt_cmd_nyi(int argc, char *argv[]);
77208538Sraj
78243693Sgonzostatic int fdt_cmd_addr(int argc, char *argv[]);
79208538Srajstatic int fdt_cmd_mkprop(int argc, char *argv[]);
80208538Srajstatic int fdt_cmd_cd(int argc, char *argv[]);
81208538Srajstatic int fdt_cmd_hdr(int argc, char *argv[]);
82208538Srajstatic int fdt_cmd_ls(int argc, char *argv[]);
83208538Srajstatic int fdt_cmd_prop(int argc, char *argv[]);
84208538Srajstatic int fdt_cmd_pwd(int argc, char *argv[]);
85208538Srajstatic int fdt_cmd_rm(int argc, char *argv[]);
86208538Srajstatic int fdt_cmd_mknode(int argc, char *argv[]);
87243693Sgonzostatic int fdt_cmd_mres(int argc, char *argv[]);
88208538Sraj
89208538Srajtypedef int cmdf_t(int, char *[]);
90208538Sraj
91208538Srajstruct cmdtab {
92208538Sraj	char	*name;
93208538Sraj	cmdf_t	*handler;
94243693Sgonzo	int	flags;
95208538Sraj};
96208538Sraj
97208538Srajstatic const struct cmdtab commands[] = {
98243693Sgonzo	{ "addr", &fdt_cmd_addr,	0 },
99243693Sgonzo	{ "alias", &fdt_cmd_nyi,	0 },
100243693Sgonzo	{ "cd", &fdt_cmd_cd,		CMD_REQUIRES_BLOB },
101243693Sgonzo	{ "header", &fdt_cmd_hdr,	CMD_REQUIRES_BLOB },
102243693Sgonzo	{ "ls", &fdt_cmd_ls,		CMD_REQUIRES_BLOB },
103243693Sgonzo	{ "mknode", &fdt_cmd_mknode,	CMD_REQUIRES_BLOB },
104243693Sgonzo	{ "mkprop", &fdt_cmd_mkprop,	CMD_REQUIRES_BLOB },
105243693Sgonzo	{ "mres", &fdt_cmd_mres,	CMD_REQUIRES_BLOB },
106243693Sgonzo	{ "prop", &fdt_cmd_prop,	CMD_REQUIRES_BLOB },
107243693Sgonzo	{ "pwd", &fdt_cmd_pwd,		CMD_REQUIRES_BLOB },
108243693Sgonzo	{ "rm", &fdt_cmd_rm,		CMD_REQUIRES_BLOB },
109208538Sraj	{ NULL, NULL }
110208538Sraj};
111208538Sraj
112208538Srajstatic char cwd[FDT_CWD_LEN] = "/";
113208538Sraj
114233230Srajstatic vm_offset_t
115235529Skientzlefdt_find_static_dtb()
116233230Sraj{
117235529Skientzle	Elf_Dyn dyn;
118233230Sraj	Elf_Sym sym;
119235529Skientzle	vm_offset_t dyntab, esym, strtab, symtab, fdt_start;
120233230Sraj	uint64_t offs;
121233230Sraj	struct preloaded_file *kfp;
122233230Sraj	struct file_metadata *md;
123235529Skientzle	char *strp;
124235529Skientzle	int sym_count;
125233230Sraj
126235529Skientzle	symtab = strtab = dyntab = esym = 0;
127235529Skientzle	strp = NULL;
128233230Sraj
129233230Sraj	offs = __elfN(relocation_offset);
130233230Sraj
131233230Sraj	kfp = file_findfile(NULL, NULL);
132233230Sraj	if (kfp == NULL)
133233230Sraj		return (0);
134233230Sraj
135233230Sraj	md = file_findmetadata(kfp, MODINFOMD_ESYM);
136233230Sraj	if (md == NULL)
137233230Sraj		return (0);
138235529Skientzle	bcopy(md->md_data, &esym, sizeof(esym));
139243693Sgonzo	/* esym is already offset */
140233230Sraj
141233230Sraj	md = file_findmetadata(kfp, MODINFOMD_DYNAMIC);
142233230Sraj	if (md == NULL)
143233230Sraj		return (0);
144235529Skientzle	bcopy(md->md_data, &dyntab, sizeof(dyntab));
145233230Sraj	dyntab += offs;
146233230Sraj
147233230Sraj	/* Locate STRTAB and DYNTAB */
148235529Skientzle	for (;;) {
149235529Skientzle		COPYOUT(dyntab, &dyn, sizeof(dyn));
150235529Skientzle		if (dyn.d_tag == DT_STRTAB) {
151235529Skientzle			strtab = (vm_offset_t)(dyn.d_un.d_ptr) + offs;
152235529Skientzle		} else if (dyn.d_tag == DT_SYMTAB) {
153235529Skientzle			symtab = (vm_offset_t)(dyn.d_un.d_ptr) + offs;
154235529Skientzle		} else if (dyn.d_tag == DT_NULL) {
155235529Skientzle			break;
156233230Sraj		}
157235529Skientzle		dyntab += sizeof(dyn);
158233230Sraj	}
159233230Sraj
160235529Skientzle	if (symtab == 0 || strtab == 0) {
161233230Sraj		/*
162233230Sraj		 * No symtab? No strtab? That should not happen here,
163233230Sraj		 * and should have been verified during __elfN(loadimage).
164233230Sraj		 * This must be some kind of a bug.
165233230Sraj		 */
166233230Sraj		return (0);
167233230Sraj	}
168233230Sraj
169235529Skientzle	sym_count = (int)(esym - symtab) / sizeof(Elf_Sym);
170233323Sraj
171233230Sraj	/*
172233230Sraj	 * The most efficent way to find a symbol would be to calculate a
173233230Sraj	 * hash, find proper bucket and chain, and thus find a symbol.
174233230Sraj	 * However, that would involve code duplication (e.g. for hash
175233230Sraj	 * function). So we're using simpler and a bit slower way: we're
176233230Sraj	 * iterating through symbols, searching for the one which name is
177233230Sraj	 * 'equal' to 'fdt_static_dtb'. To speed up the process a little bit,
178233230Sraj	 * we are eliminating symbols type of which is not STT_NOTYPE, or(and)
179233230Sraj	 * those which binding attribute is not STB_GLOBAL.
180233230Sraj	 */
181235529Skientzle	fdt_start = 0;
182235529Skientzle	while (sym_count > 0 && fdt_start == 0) {
183235529Skientzle		COPYOUT(symtab, &sym, sizeof(sym));
184235529Skientzle		symtab += sizeof(sym);
185235529Skientzle		--sym_count;
186233230Sraj		if (ELF_ST_BIND(sym.st_info) != STB_GLOBAL ||
187233230Sraj		    ELF_ST_TYPE(sym.st_info) != STT_NOTYPE)
188233230Sraj			continue;
189235529Skientzle		strp = strdupout(strtab + sym.st_name);
190235529Skientzle		if (strcmp(strp, FDT_STATIC_DTB_SYMBOL) == 0)
191235529Skientzle			fdt_start = (vm_offset_t)sym.st_value + offs;
192233230Sraj		free(strp);
193233230Sraj	}
194235529Skientzle	printf("fdt_start: 0x%08jX\n", (intmax_t)fdt_start);
195235529Skientzle	return (fdt_start);
196233230Sraj}
197233230Sraj
198208538Srajstatic int
199243693Sgonzofdt_load_dtb(vm_offset_t va)
200208538Sraj{
201235529Skientzle	struct fdt_header header;
202208538Sraj	int err;
203208538Sraj
204243693Sgonzo	COPYOUT(va, &header, sizeof(header));
205243693Sgonzo	err = fdt_check_header(&header);
206243693Sgonzo	if (err < 0) {
207243693Sgonzo		if (err == -FDT_ERR_BADVERSION)
208243693Sgonzo			sprintf(command_errbuf,
209243693Sgonzo			    "incompatible blob version: %d, should be: %d",
210243693Sgonzo			    fdt_version(fdtp), FDT_LAST_SUPPORTED_VERSION);
211243693Sgonzo
212243693Sgonzo		else
213243693Sgonzo			sprintf(command_errbuf, "error validating blob: %s",
214243693Sgonzo			    fdt_strerror(err));
215243693Sgonzo		return (1);
216243693Sgonzo	}
217243693Sgonzo
218208538Sraj	/*
219243693Sgonzo	 * Release previous blob
220208538Sraj	 */
221243693Sgonzo	if (fdtp)
222243693Sgonzo		free(fdtp);
223208538Sraj
224235529Skientzle	fdtp_size = fdt_totalsize(&header);
225235529Skientzle	fdtp = malloc(fdtp_size);
226243693Sgonzo
227235529Skientzle	if (fdtp == NULL) {
228235529Skientzle		command_errmsg = "can't allocate memory for device tree copy";
229243693Sgonzo		return (1);
230235529Skientzle	}
231235529Skientzle
232243693Sgonzo	fdtp_va = va;
233243693Sgonzo	COPYOUT(va, fdtp, fdtp_size);
234243693Sgonzo	debugf("DTB blob found at 0x%jx, size: 0x%jx\n", (uintmax_t)va, (uintmax_t)fdtp_size);
235208538Sraj
236243693Sgonzo	return (0);
237243693Sgonzo}
238243693Sgonzo
239243693Sgonzostatic int
240247045Skientzlefdt_load_dtb_addr(struct fdt_header *header)
241243693Sgonzo{
242243693Sgonzo	struct preloaded_file *bfp;
243243693Sgonzo
244247045Skientzle	bfp = mem_load_raw("dtb", "memory.dtb", header, fdt_totalsize(header));
245243693Sgonzo	if (bfp == NULL) {
246247045Skientzle		command_errmsg = "unable to copy DTB into module directory";
247247045Skientzle		return (1);
248208538Sraj	}
249247045Skientzle	return fdt_load_dtb(bfp->f_addr);
250247045Skientzle}
251243693Sgonzo
252247045Skientzlestatic int
253247045Skientzlefdt_setup_fdtp()
254247045Skientzle{
255247045Skientzle  struct preloaded_file *bfp;
256247045Skientzle  struct fdt_header *hdr;
257247201Skientzle  const char *s;
258247201Skientzle  char *p;
259247045Skientzle  vm_offset_t va;
260247045Skientzle
261247045Skientzle  if ((bfp = file_findfile(NULL, "dtb")) != NULL) {
262247045Skientzle	  printf("Using DTB from loaded file.\n");
263247045Skientzle	  return fdt_load_dtb(bfp->f_addr);
264247201Skientzle  }
265247045Skientzle
266247201Skientzle  if (fdt_to_load != NULL) {
267247201Skientzle	  printf("Using DTB from memory address 0x%08X.\n",
268247201Skientzle		 (unsigned int)fdt_to_load);
269247201Skientzle	  return fdt_load_dtb_addr(fdt_to_load);
270247201Skientzle  }
271247201Skientzle
272247045Skientzle  s = ub_env_get("fdtaddr");
273247045Skientzle  if (s != NULL && *s != '\0') {
274247045Skientzle	  hdr = (struct fdt_header *)strtoul(s, &p, 16);
275247045Skientzle	  if (*p == '\0') {
276247045Skientzle		  printf("Using DTB provided by U-Boot.\n");
277247045Skientzle		  return fdt_load_dtb_addr(hdr);
278247045Skientzle	  }
279247045Skientzle  }
280247045Skientzle
281247045Skientzle  if ((va = fdt_find_static_dtb()) != 0) {
282247045Skientzle	  printf("Using DTB compiled into kernel.\n");
283247045Skientzle	  return (fdt_load_dtb(va));
284247045Skientzle  }
285247045Skientzle
286247045Skientzle  command_errmsg = "no device tree blob found!";
287247045Skientzle  return (1);
288208538Sraj}
289208538Sraj
290208538Sraj#define fdt_strtovect(str, cellbuf, lim, cellsize) _fdt_strtovect((str), \
291208538Sraj    (cellbuf), (lim), (cellsize), 0);
292208538Sraj
293208538Sraj/* Force using base 16 */
294208538Sraj#define fdt_strtovectx(str, cellbuf, lim, cellsize) _fdt_strtovect((str), \
295208538Sraj    (cellbuf), (lim), (cellsize), 16);
296208538Sraj
297208538Srajstatic int
298208538Sraj_fdt_strtovect(char *str, void *cellbuf, int lim, unsigned char cellsize,
299208538Sraj    uint8_t base)
300208538Sraj{
301208538Sraj	char *buf = str;
302208538Sraj	char *end = str + strlen(str) - 2;
303208538Sraj	uint32_t *u32buf = NULL;
304208538Sraj	uint8_t *u8buf = NULL;
305208538Sraj	int cnt = 0;
306208538Sraj
307208538Sraj	if (cellsize == sizeof(uint32_t))
308208538Sraj		u32buf = (uint32_t *)cellbuf;
309208538Sraj	else
310208538Sraj		u8buf = (uint8_t *)cellbuf;
311208538Sraj
312208538Sraj	if (lim == 0)
313208538Sraj		return (0);
314208538Sraj
315208538Sraj	while (buf < end) {
316208538Sraj
317208538Sraj		/* Skip white whitespace(s)/separators */
318208538Sraj		while (!isxdigit(*buf) && buf < end)
319208538Sraj			buf++;
320208538Sraj
321208538Sraj		if (u32buf != NULL)
322208538Sraj			u32buf[cnt] =
323208538Sraj			    cpu_to_fdt32((uint32_t)strtol(buf, NULL, base));
324208538Sraj
325208538Sraj		else
326208538Sraj			u8buf[cnt] = (uint8_t)strtol(buf, NULL, base);
327208538Sraj
328208538Sraj		if (cnt + 1 <= lim - 1)
329208538Sraj			cnt++;
330208538Sraj		else
331208538Sraj			break;
332208538Sraj		buf++;
333208538Sraj		/* Find another number */
334208538Sraj		while ((isxdigit(*buf) || *buf == 'x') && buf < end)
335208538Sraj			buf++;
336208538Sraj	}
337208538Sraj	return (cnt);
338208538Sraj}
339208538Sraj
340208538Sraj#define	TMP_MAX_ETH	8
341208538Sraj
342208538Srajvoid
343208538Srajfixup_ethernet(const char *env, char *ethstr, int *eth_no, int len)
344208538Sraj{
345208538Sraj	char *end, *str;
346208538Sraj	uint8_t tmp_addr[6];
347208538Sraj	int i, n;
348208538Sraj
349208538Sraj	/* Extract interface number */
350208538Sraj	i = strtol(env + 3, &end, 10);
351208538Sraj	if (end == (env + 3))
352208538Sraj		/* 'ethaddr' means interface 0 address */
353208538Sraj		n = 0;
354208538Sraj	else
355208538Sraj		n = i;
356208538Sraj
357208538Sraj	if (n > TMP_MAX_ETH)
358208538Sraj		return;
359208538Sraj
360208538Sraj	str = ub_env_get(env);
361208538Sraj
362208538Sraj	/* Convert macaddr string into a vector of uints */
363208538Sraj	fdt_strtovectx(str, &tmp_addr, 6, sizeof(uint8_t));
364208538Sraj	if (n != 0) {
365208538Sraj		i = strlen(env) - 7;
366208538Sraj		strncpy(ethstr + 8, env + 3, i);
367208538Sraj	}
368208538Sraj	/* Set actual property to a value from vect */
369208538Sraj	fdt_setprop(fdtp, fdt_path_offset(fdtp, ethstr),
370208538Sraj	    "local-mac-address", &tmp_addr, 6 * sizeof(uint8_t));
371208538Sraj
372208538Sraj	/* Clear ethernet..XXXX.. string */
373208538Sraj	bzero(ethstr + 8, len - 8);
374208538Sraj
375208538Sraj	if (n + 1 > *eth_no)
376208538Sraj		*eth_no = n + 1;
377208538Sraj}
378208538Sraj
379208538Srajvoid
380208538Srajfixup_cpubusfreqs(unsigned long cpufreq, unsigned long busfreq)
381208538Sraj{
382208538Sraj	int lo, o = 0, o2, maxo = 0, depth;
383208538Sraj	const uint32_t zero = 0;
384208538Sraj
385208538Sraj	/* We want to modify every subnode of /cpus */
386208538Sraj	o = fdt_path_offset(fdtp, "/cpus");
387235261Skientzle	if (o < 0)
388235261Skientzle		return;
389208538Sraj
390208538Sraj	/* maxo should contain offset of node next to /cpus */
391208538Sraj	depth = 0;
392208538Sraj	maxo = o;
393208538Sraj	while (depth != -1)
394208538Sraj		maxo = fdt_next_node(fdtp, maxo, &depth);
395208538Sraj
396208538Sraj	/* Find CPU frequency properties */
397208538Sraj	o = fdt_node_offset_by_prop_value(fdtp, o, "clock-frequency",
398208538Sraj	    &zero, sizeof(uint32_t));
399208538Sraj
400208538Sraj	o2 = fdt_node_offset_by_prop_value(fdtp, o, "bus-frequency", &zero,
401208538Sraj	    sizeof(uint32_t));
402208538Sraj
403208538Sraj	lo = MIN(o, o2);
404208538Sraj
405208538Sraj	while (o != -FDT_ERR_NOTFOUND && o2 != -FDT_ERR_NOTFOUND) {
406208538Sraj
407208538Sraj		o = fdt_node_offset_by_prop_value(fdtp, lo,
408208538Sraj		    "clock-frequency", &zero, sizeof(uint32_t));
409208538Sraj
410208538Sraj		o2 = fdt_node_offset_by_prop_value(fdtp, lo, "bus-frequency",
411208538Sraj		    &zero, sizeof(uint32_t));
412208538Sraj
413208538Sraj		/* We're only interested in /cpus subnode(s) */
414208538Sraj		if (lo > maxo)
415208538Sraj			break;
416208538Sraj
417208538Sraj		fdt_setprop_inplace_cell(fdtp, lo, "clock-frequency",
418208538Sraj		    (uint32_t)cpufreq);
419208538Sraj
420208538Sraj		fdt_setprop_inplace_cell(fdtp, lo, "bus-frequency",
421208538Sraj		    (uint32_t)busfreq);
422208538Sraj
423208538Sraj		lo = MIN(o, o2);
424208538Sraj	}
425208538Sraj}
426208538Sraj
427208538Srajint
428208538Srajfdt_reg_valid(uint32_t *reg, int len, int addr_cells, int size_cells)
429208538Sraj{
430208538Sraj	int cells_in_tuple, i, tuples, tuple_size;
431208538Sraj	uint32_t cur_start, cur_size;
432208538Sraj
433208538Sraj	cells_in_tuple = (addr_cells + size_cells);
434208538Sraj	tuple_size = cells_in_tuple * sizeof(uint32_t);
435208538Sraj	tuples = len / tuple_size;
436208538Sraj	if (tuples == 0)
437208538Sraj		return (EINVAL);
438208538Sraj
439208538Sraj	for (i = 0; i < tuples; i++) {
440208538Sraj		if (addr_cells == 2)
441208538Sraj			cur_start = fdt64_to_cpu(reg[i * cells_in_tuple]);
442208538Sraj		else
443208538Sraj			cur_start = fdt32_to_cpu(reg[i * cells_in_tuple]);
444208538Sraj
445208538Sraj		if (size_cells == 2)
446208538Sraj			cur_size = fdt64_to_cpu(reg[i * cells_in_tuple + 2]);
447208538Sraj		else
448208538Sraj			cur_size = fdt32_to_cpu(reg[i * cells_in_tuple + 1]);
449208538Sraj
450208538Sraj		if (cur_size == 0)
451208538Sraj			return (EINVAL);
452208538Sraj
453208538Sraj		debugf(" reg#%d (start: 0x%0x size: 0x%0x) valid!\n",
454208538Sraj		    i, cur_start, cur_size);
455208538Sraj	}
456208538Sraj	return (0);
457208538Sraj}
458208538Sraj
459208538Srajvoid
460208538Srajfixup_memory(struct sys_info *si)
461208538Sraj{
462208538Sraj	struct mem_region *curmr;
463208538Sraj	uint32_t addr_cells, size_cells;
464208538Sraj	uint32_t *addr_cellsp, *reg,  *size_cellsp;
465208538Sraj	int err, i, len, memory, realmrno, root;
466208538Sraj	uint8_t *buf, *sb;
467243693Sgonzo	uint64_t rstart, rsize;
468243693Sgonzo	int reserved;
469208538Sraj
470208538Sraj	root = fdt_path_offset(fdtp, "/");
471208538Sraj	if (root < 0) {
472208538Sraj		sprintf(command_errbuf, "Could not find root node !");
473208538Sraj		return;
474208538Sraj	}
475208538Sraj
476208538Sraj	memory = fdt_path_offset(fdtp, "/memory");
477208538Sraj	if (memory <= 0) {
478208538Sraj		/* Create proper '/memory' node. */
479208538Sraj		memory = fdt_add_subnode(fdtp, root, "memory");
480208538Sraj		if (memory <= 0) {
481208538Sraj			sprintf(command_errbuf, "Could not fixup '/memory' "
482208538Sraj			    "node, error code : %d!\n", memory);
483208538Sraj			return;
484208538Sraj		}
485208538Sraj
486208538Sraj		err = fdt_setprop(fdtp, memory, "device_type", "memory",
487208538Sraj		    sizeof("memory"));
488208538Sraj
489208538Sraj		if (err < 0)
490208538Sraj			return;
491208538Sraj	}
492208538Sraj
493208538Sraj	addr_cellsp = (uint32_t *)fdt_getprop(fdtp, root, "#address-cells",
494208538Sraj	    NULL);
495208538Sraj	size_cellsp = (uint32_t *)fdt_getprop(fdtp, root, "#size-cells", NULL);
496208538Sraj
497208538Sraj	if (addr_cellsp == NULL || size_cellsp == NULL) {
498208538Sraj		sprintf(command_errbuf, "Could not fixup '/memory' node : "
499208538Sraj		    "%s %s property not found in root node!\n",
500208538Sraj		    (!addr_cellsp) ? "#address-cells" : "",
501208538Sraj		    (!size_cellsp) ? "#size-cells" : "");
502208538Sraj		return;
503208538Sraj	}
504208538Sraj
505208538Sraj	addr_cells = fdt32_to_cpu(*addr_cellsp);
506208538Sraj	size_cells = fdt32_to_cpu(*size_cellsp);
507208538Sraj
508243693Sgonzo	/*
509243693Sgonzo	 * Convert memreserve data to memreserve property
510243693Sgonzo	 * Check if property already exists
511243693Sgonzo	 */
512243693Sgonzo	reserved = fdt_num_mem_rsv(fdtp);
513243693Sgonzo	if (reserved &&
514243693Sgonzo	    (fdt_getprop(fdtp, root, "memreserve", NULL) == NULL)) {
515243693Sgonzo		len = (addr_cells + size_cells) * reserved * sizeof(uint32_t);
516243693Sgonzo		sb = buf = (uint8_t *)malloc(len);
517243693Sgonzo		if (!buf)
518243693Sgonzo			return;
519243693Sgonzo
520243693Sgonzo		bzero(buf, len);
521243693Sgonzo
522243693Sgonzo		for (i = 0; i < reserved; i++) {
523243693Sgonzo			curmr = &si->mr[i];
524243693Sgonzo			if (fdt_get_mem_rsv(fdtp, i, &rstart, &rsize))
525243693Sgonzo				break;
526243693Sgonzo			if (rsize) {
527243693Sgonzo				/* Ensure endianess, and put cells into a buffer */
528243693Sgonzo				if (addr_cells == 2)
529243693Sgonzo					*(uint64_t *)buf =
530243693Sgonzo					    cpu_to_fdt64(rstart);
531243693Sgonzo				else
532243693Sgonzo					*(uint32_t *)buf =
533243693Sgonzo					    cpu_to_fdt32(rstart);
534243693Sgonzo
535243693Sgonzo				buf += sizeof(uint32_t) * addr_cells;
536243693Sgonzo				if (size_cells == 2)
537243693Sgonzo					*(uint64_t *)buf =
538243693Sgonzo					    cpu_to_fdt64(rsize);
539243693Sgonzo				else
540243693Sgonzo					*(uint32_t *)buf =
541243693Sgonzo					    cpu_to_fdt32(rsize);
542243693Sgonzo
543243693Sgonzo				buf += sizeof(uint32_t) * size_cells;
544243693Sgonzo			}
545243693Sgonzo		}
546243693Sgonzo
547243693Sgonzo		/* Set property */
548243693Sgonzo		if ((err = fdt_setprop(fdtp, root, "memreserve", sb, len)) < 0)
549243693Sgonzo			printf("Could not fixup 'memreserve' property.\n");
550243693Sgonzo
551243693Sgonzo		free(sb);
552243693Sgonzo	}
553243693Sgonzo
554208538Sraj	/* Count valid memory regions entries in sysinfo. */
555208538Sraj	realmrno = si->mr_no;
556208538Sraj	for (i = 0; i < si->mr_no; i++)
557208538Sraj		if (si->mr[i].start == 0 && si->mr[i].size == 0)
558208538Sraj			realmrno--;
559208538Sraj
560208538Sraj	if (realmrno == 0) {
561208538Sraj		sprintf(command_errbuf, "Could not fixup '/memory' node : "
562208538Sraj		    "sysinfo doesn't contain valid memory regions info!\n");
563208538Sraj		return;
564208538Sraj	}
565208538Sraj
566208538Sraj	if ((reg = (uint32_t *)fdt_getprop(fdtp, memory, "reg",
567208538Sraj	    &len)) != NULL) {
568208538Sraj
569208538Sraj		if (fdt_reg_valid(reg, len, addr_cells, size_cells) == 0)
570208538Sraj			/*
571208538Sraj			 * Do not apply fixup if existing 'reg' property
572208538Sraj			 * seems to be valid.
573208538Sraj			 */
574208538Sraj			return;
575208538Sraj	}
576208538Sraj
577208538Sraj	len = (addr_cells + size_cells) * realmrno * sizeof(uint32_t);
578208538Sraj	sb = buf = (uint8_t *)malloc(len);
579208538Sraj	if (!buf)
580208538Sraj		return;
581208538Sraj
582208538Sraj	bzero(buf, len);
583208538Sraj
584208538Sraj	for (i = 0; i < si->mr_no; i++) {
585208538Sraj		curmr = &si->mr[i];
586208538Sraj		if (curmr->size != 0) {
587208538Sraj			/* Ensure endianess, and put cells into a buffer */
588208538Sraj			if (addr_cells == 2)
589208538Sraj				*(uint64_t *)buf =
590208538Sraj				    cpu_to_fdt64(curmr->start);
591208538Sraj			else
592208538Sraj				*(uint32_t *)buf =
593208538Sraj				    cpu_to_fdt32(curmr->start);
594208538Sraj
595208538Sraj			buf += sizeof(uint32_t) * addr_cells;
596208538Sraj			if (size_cells == 2)
597208538Sraj				*(uint64_t *)buf =
598208538Sraj				    cpu_to_fdt64(curmr->size);
599208538Sraj			else
600208538Sraj				*(uint32_t *)buf =
601208538Sraj				    cpu_to_fdt32(curmr->size);
602208538Sraj
603208538Sraj			buf += sizeof(uint32_t) * size_cells;
604208538Sraj		}
605208538Sraj	}
606208538Sraj
607208538Sraj	/* Set property */
608208538Sraj	if ((err = fdt_setprop(fdtp, memory, "reg", sb, len)) < 0)
609208538Sraj		sprintf(command_errbuf, "Could not fixup '/memory' node.\n");
610243693Sgonzo
611243693Sgonzo	free(sb);
612208538Sraj}
613208538Sraj
614208538Srajvoid
615208538Srajfixup_stdout(const char *env)
616208538Sraj{
617208538Sraj	const char *str;
618208538Sraj	char *ptr;
619208538Sraj	int serialno;
620208538Sraj	int len, no, sero;
621208538Sraj	const struct fdt_property *prop;
622208538Sraj	char *tmp[10];
623208538Sraj
624208538Sraj	str = ub_env_get(env);
625208538Sraj	ptr = (char *)str + strlen(str) - 1;
626208538Sraj	while (ptr > str && isdigit(*(str - 1)))
627208538Sraj		str--;
628208538Sraj
629208538Sraj	if (ptr == str)
630208538Sraj		return;
631208538Sraj
632208538Sraj	serialno = (int)strtol(ptr, NULL, 0);
633208538Sraj	no = fdt_path_offset(fdtp, "/chosen");
634208538Sraj	if (no < 0)
635208538Sraj		return;
636208538Sraj
637208538Sraj	prop = fdt_get_property(fdtp, no, "stdout", &len);
638208538Sraj
639208538Sraj	/* If /chosen/stdout does not extist, create it */
640208538Sraj	if (prop == NULL || (prop != NULL && len == 0)) {
641208538Sraj
642208538Sraj		bzero(tmp, 10 * sizeof(char));
643208538Sraj		strcpy((char *)&tmp, "serial");
644208538Sraj		if (strlen(ptr) > 3)
645208538Sraj			/* Serial number too long */
646208538Sraj			return;
647208538Sraj
648208538Sraj		strncpy((char *)tmp + 6, ptr, 3);
649208538Sraj		sero = fdt_path_offset(fdtp, (const char *)tmp);
650208538Sraj		if (sero < 0)
651208538Sraj			/*
652208538Sraj			 * If serial device we're trying to assign
653208538Sraj			 * stdout to doesn't exist in DT -- return.
654208538Sraj			 */
655208538Sraj			return;
656208538Sraj
657208538Sraj		fdt_setprop(fdtp, no, "stdout", &tmp,
658208538Sraj		    strlen((char *)&tmp) + 1);
659208538Sraj		fdt_setprop(fdtp, no, "stdin", &tmp,
660208538Sraj		    strlen((char *)&tmp) + 1);
661208538Sraj	}
662208538Sraj}
663208538Sraj
664233230Sraj/*
665233230Sraj * Locate the blob, fix it up and return its location.
666233230Sraj */
667243693Sgonzostatic vm_offset_t
668208538Srajfdt_fixup(void)
669208538Sraj{
670208538Sraj	const char *env;
671208538Sraj	char *ethstr;
672208538Sraj	int chosen, err, eth_no, len;
673208538Sraj	struct sys_info *si;
674208538Sraj
675208538Sraj	env = NULL;
676208538Sraj	eth_no = 0;
677208538Sraj	ethstr = NULL;
678208538Sraj	len = 0;
679208538Sraj
680243693Sgonzo	if (fdtp == NULL) {
681243693Sgonzo		err = fdt_setup_fdtp();
682243693Sgonzo		if (err) {
683243693Sgonzo			sprintf(command_errbuf, "No valid device tree blob found!");
684243693Sgonzo			return (0);
685243693Sgonzo		}
686208538Sraj	}
687208538Sraj
688208538Sraj	/* Create /chosen node (if not exists) */
689208538Sraj	if ((chosen = fdt_subnode_offset(fdtp, 0, "chosen")) ==
690208538Sraj	    -FDT_ERR_NOTFOUND)
691208538Sraj		chosen = fdt_add_subnode(fdtp, 0, "chosen");
692208538Sraj
693208538Sraj	/* Value assigned to fixup-applied does not matter. */
694208538Sraj	if (fdt_getprop(fdtp, chosen, "fixup-applied", NULL))
695233230Sraj		goto success;
696208538Sraj
697208538Sraj	/* Acquire sys_info */
698208538Sraj	si = ub_get_sys_info();
699208538Sraj
700208538Sraj	while ((env = ub_env_enum(env)) != NULL) {
701208538Sraj		if (strncmp(env, "eth", 3) == 0 &&
702208538Sraj		    strncmp(env + (strlen(env) - 4), "addr", 4) == 0) {
703208538Sraj			/*
704208538Sraj			 * Handle Ethernet addrs: parse uboot env eth%daddr
705208538Sraj			 */
706208538Sraj
707208538Sraj			if (!eth_no) {
708208538Sraj				/*
709208538Sraj				 * Check how many chars we will need to store
710208538Sraj				 * maximal eth iface number.
711208538Sraj				 */
712208538Sraj				len = strlen(STRINGIFY(TMP_MAX_ETH)) +
713208538Sraj				    strlen("ethernet");
714208538Sraj
715208538Sraj				/*
716208538Sraj				 * Reserve mem for string "ethernet" and len
717208538Sraj				 * chars for iface no.
718208538Sraj				 */
719208538Sraj				ethstr = (char *)malloc(len * sizeof(char));
720208538Sraj				bzero(ethstr, len * sizeof(char));
721208538Sraj				strcpy(ethstr, "ethernet0");
722208538Sraj			}
723208538Sraj
724208538Sraj			/* Modify blob */
725208538Sraj			fixup_ethernet(env, ethstr, &eth_no, len);
726208538Sraj
727208538Sraj		} else if (strcmp(env, "consoledev") == 0)
728208538Sraj			fixup_stdout(env);
729208538Sraj	}
730208538Sraj
731208538Sraj	/* Modify cpu(s) and bus clock frequenties in /cpus node [Hz] */
732208538Sraj	fixup_cpubusfreqs(si->clk_cpu, si->clk_bus);
733208538Sraj
734208538Sraj	/* Fixup memory regions */
735208538Sraj	fixup_memory(si);
736208538Sraj
737208538Sraj	fdt_setprop(fdtp, chosen, "fixup-applied", NULL, 0);
738208538Sraj
739233230Srajsuccess:
740235529Skientzle	/* Overwrite the FDT with the fixed version. */
741235529Skientzle	COPYIN(fdtp, fdtp_va, fdtp_size);
742235529Skientzle	return (fdtp_va);
743208538Sraj}
744208538Sraj
745243693Sgonzo/*
746243693Sgonzo * Copy DTB blob to specified location and its return size
747243693Sgonzo */
748208538Srajint
749243693Sgonzofdt_copy(vm_offset_t va)
750243693Sgonzo{
751243693Sgonzo	int err;
752243693Sgonzo
753243693Sgonzo	if (fdtp == NULL) {
754243693Sgonzo		err = fdt_setup_fdtp();
755243693Sgonzo		if (err) {
756243693Sgonzo			printf("No valid device tree blob found!");
757243693Sgonzo			return (0);
758243693Sgonzo		}
759243693Sgonzo	}
760243693Sgonzo
761243693Sgonzo	if (fdt_fixup() == 0)
762243693Sgonzo		return (0);
763243693Sgonzo
764243693Sgonzo	COPYIN(fdtp, va, fdtp_size);
765243693Sgonzo	return (fdtp_size);
766243693Sgonzo}
767243693Sgonzo
768243693Sgonzo
769243693Sgonzo
770243693Sgonzoint
771208538Srajcommand_fdt_internal(int argc, char *argv[])
772208538Sraj{
773208538Sraj	cmdf_t *cmdh;
774243693Sgonzo	int flags;
775208538Sraj	char *cmd;
776208538Sraj	int i, err;
777208538Sraj
778208538Sraj	if (argc < 2) {
779208538Sraj		command_errmsg = "usage is 'fdt <command> [<args>]";
780208538Sraj		return (CMD_ERROR);
781208538Sraj	}
782208538Sraj
783208538Sraj	/*
784208538Sraj	 * Validate fdt <command>.
785208538Sraj	 */
786208538Sraj	cmd = strdup(argv[1]);
787208538Sraj	i = 0;
788208538Sraj	cmdh = NULL;
789208538Sraj	while (!(commands[i].name == NULL)) {
790208538Sraj		if (strcmp(cmd, commands[i].name) == 0) {
791208538Sraj			/* found it */
792208538Sraj			cmdh = commands[i].handler;
793243693Sgonzo			flags = commands[i].flags;
794208538Sraj			break;
795208538Sraj		}
796208538Sraj		i++;
797208538Sraj	}
798208538Sraj	if (cmdh == NULL) {
799208538Sraj		command_errmsg = "unknown command";
800208538Sraj		return (CMD_ERROR);
801208538Sraj	}
802208538Sraj
803243693Sgonzo	if (flags & CMD_REQUIRES_BLOB) {
804243693Sgonzo		/*
805243693Sgonzo		 * Check if uboot env vars were parsed already. If not, do it now.
806243693Sgonzo		 */
807243693Sgonzo		if (fdt_fixup() == 0)
808243693Sgonzo			return (CMD_ERROR);
809243693Sgonzo	}
810243693Sgonzo
811208538Sraj	/*
812208538Sraj	 * Call command handler.
813208538Sraj	 */
814208538Sraj	err = (*cmdh)(argc, argv);
815208538Sraj
816208538Sraj	return (err);
817208538Sraj}
818208538Sraj
819208538Srajstatic int
820243693Sgonzofdt_cmd_addr(int argc, char *argv[])
821243693Sgonzo{
822247201Skientzle	struct preloaded_file *fp;
823247045Skientzle	struct fdt_header *hdr;
824247201Skientzle	const char *addr;
825247201Skientzle	char *cp;
826243693Sgonzo
827247201Skientzle	fdt_to_load = NULL;
828247201Skientzle
829243693Sgonzo	if (argc > 2)
830243693Sgonzo		addr = argv[2];
831243693Sgonzo	else {
832243693Sgonzo		sprintf(command_errbuf, "no address specified");
833243693Sgonzo		return (CMD_ERROR);
834243693Sgonzo	}
835243693Sgonzo
836247201Skientzle	hdr = (struct fdt_header *)strtoul(addr, &cp, 16);
837243693Sgonzo	if (cp == addr) {
838243693Sgonzo		sprintf(command_errbuf, "Invalid address: %s", addr);
839243693Sgonzo		return (CMD_ERROR);
840243693Sgonzo	}
841243693Sgonzo
842247201Skientzle	while ((fp = file_findfile(NULL, "dtb")) != NULL) {
843247201Skientzle		file_discard(fp);
844247201Skientzle	}
845243693Sgonzo
846247201Skientzle	fdt_to_load = hdr;
847243693Sgonzo	return (CMD_OK);
848243693Sgonzo}
849243693Sgonzo
850243693Sgonzostatic int
851208538Srajfdt_cmd_cd(int argc, char *argv[])
852208538Sraj{
853208538Sraj	char *path;
854208538Sraj	char tmp[FDT_CWD_LEN];
855208538Sraj	int len, o;
856208538Sraj
857208538Sraj	path = (argc > 2) ? argv[2] : "/";
858208538Sraj
859208538Sraj	if (path[0] == '/') {
860208538Sraj		len = strlen(path);
861208538Sraj		if (len >= FDT_CWD_LEN)
862208538Sraj			goto fail;
863208538Sraj	} else {
864208538Sraj		/* Handle path specification relative to cwd */
865208538Sraj		len = strlen(cwd) + strlen(path) + 1;
866208538Sraj		if (len >= FDT_CWD_LEN)
867208538Sraj			goto fail;
868208538Sraj
869208538Sraj		strcpy(tmp, cwd);
870208538Sraj		strcat(tmp, "/");
871208538Sraj		strcat(tmp, path);
872208538Sraj		path = tmp;
873208538Sraj	}
874208538Sraj
875208538Sraj	o = fdt_path_offset(fdtp, path);
876208538Sraj	if (o < 0) {
877208538Sraj		sprintf(command_errbuf, "could not find node: '%s'", path);
878208538Sraj		return (CMD_ERROR);
879208538Sraj	}
880208538Sraj
881208538Sraj	strcpy(cwd, path);
882208538Sraj	return (CMD_OK);
883208538Sraj
884208538Srajfail:
885208538Sraj	sprintf(command_errbuf, "path too long: %d, max allowed: %d",
886208538Sraj	    len, FDT_CWD_LEN - 1);
887208538Sraj	return (CMD_ERROR);
888208538Sraj}
889208538Sraj
890208538Srajstatic int
891208538Srajfdt_cmd_hdr(int argc __unused, char *argv[] __unused)
892208538Sraj{
893208538Sraj	char line[80];
894208538Sraj	int ver;
895208538Sraj
896208538Sraj	if (fdtp == NULL) {
897208538Sraj		command_errmsg = "no device tree blob pointer?!";
898208538Sraj		return (CMD_ERROR);
899208538Sraj	}
900208538Sraj
901208538Sraj	ver = fdt_version(fdtp);
902208538Sraj	pager_open();
903208538Sraj	sprintf(line, "\nFlattened device tree header (%p):\n", fdtp);
904208538Sraj	pager_output(line);
905208538Sraj	sprintf(line, " magic                   = 0x%08x\n", fdt_magic(fdtp));
906208538Sraj	pager_output(line);
907208538Sraj	sprintf(line, " size                    = %d\n", fdt_totalsize(fdtp));
908208538Sraj	pager_output(line);
909208538Sraj	sprintf(line, " off_dt_struct           = 0x%08x\n",
910208538Sraj	    fdt_off_dt_struct(fdtp));
911208538Sraj	pager_output(line);
912208538Sraj	sprintf(line, " off_dt_strings          = 0x%08x\n",
913208538Sraj	    fdt_off_dt_strings(fdtp));
914208538Sraj	pager_output(line);
915208538Sraj	sprintf(line, " off_mem_rsvmap          = 0x%08x\n",
916208538Sraj	    fdt_off_mem_rsvmap(fdtp));
917208538Sraj	pager_output(line);
918208538Sraj	sprintf(line, " version                 = %d\n", ver);
919208538Sraj	pager_output(line);
920208538Sraj	sprintf(line, " last compatible version = %d\n",
921208538Sraj	    fdt_last_comp_version(fdtp));
922208538Sraj	pager_output(line);
923208538Sraj	if (ver >= 2) {
924208538Sraj		sprintf(line, " boot_cpuid              = %d\n",
925208538Sraj		    fdt_boot_cpuid_phys(fdtp));
926208538Sraj		pager_output(line);
927208538Sraj	}
928208538Sraj	if (ver >= 3) {
929208538Sraj		sprintf(line, " size_dt_strings         = %d\n",
930208538Sraj		    fdt_size_dt_strings(fdtp));
931208538Sraj		pager_output(line);
932208538Sraj	}
933208538Sraj	if (ver >= 17) {
934208538Sraj		sprintf(line, " size_dt_struct          = %d\n",
935208538Sraj		    fdt_size_dt_struct(fdtp));
936208538Sraj		pager_output(line);
937208538Sraj	}
938208538Sraj	pager_close();
939208538Sraj
940208538Sraj	return (CMD_OK);
941208538Sraj}
942208538Sraj
943208538Srajstatic int
944208538Srajfdt_cmd_ls(int argc, char *argv[])
945208538Sraj{
946208538Sraj	const char *prevname[FDT_MAX_DEPTH] = { NULL };
947208538Sraj	const char *name;
948208538Sraj	char *path;
949208538Sraj	int i, o, depth, len;
950208538Sraj
951208538Sraj	path = (argc > 2) ? argv[2] : NULL;
952208538Sraj	if (path == NULL)
953208538Sraj		path = cwd;
954208538Sraj
955208538Sraj	o = fdt_path_offset(fdtp, path);
956208538Sraj	if (o < 0) {
957208538Sraj		sprintf(command_errbuf, "could not find node: '%s'", path);
958208538Sraj		return (CMD_ERROR);
959208538Sraj	}
960208538Sraj
961208538Sraj	for (depth = 0;
962208538Sraj	    (o >= 0) && (depth >= 0);
963208538Sraj	    o = fdt_next_node(fdtp, o, &depth)) {
964208538Sraj
965208538Sraj		name = fdt_get_name(fdtp, o, &len);
966208538Sraj
967208538Sraj		if (depth > FDT_MAX_DEPTH) {
968208538Sraj			printf("max depth exceeded: %d\n", depth);
969208538Sraj			continue;
970208538Sraj		}
971208538Sraj
972208538Sraj		prevname[depth] = name;
973208538Sraj
974208538Sraj		/* Skip root (i = 1) when printing devices */
975208538Sraj		for (i = 1; i <= depth; i++) {
976208538Sraj			if (prevname[i] == NULL)
977208538Sraj				break;
978208538Sraj
979208538Sraj			if (strcmp(cwd, "/") == 0)
980208538Sraj				printf("/");
981208538Sraj			printf("%s", prevname[i]);
982208538Sraj		}
983208538Sraj		printf("\n");
984208538Sraj	}
985208538Sraj
986208538Sraj	return (CMD_OK);
987208538Sraj}
988208538Sraj
989208538Srajstatic __inline int
990208538Srajisprint(int c)
991208538Sraj{
992208538Sraj
993208538Sraj	return (c >= ' ' && c <= 0x7e);
994208538Sraj}
995208538Sraj
996208538Srajstatic int
997208538Srajfdt_isprint(const void *data, int len, int *count)
998208538Sraj{
999208538Sraj	const char *d;
1000208538Sraj	char ch;
1001208538Sraj	int yesno, i;
1002208538Sraj
1003208538Sraj	if (len == 0)
1004208538Sraj		return (0);
1005208538Sraj
1006208538Sraj	d = (const char *)data;
1007208538Sraj	if (d[len - 1] != '\0')
1008208538Sraj		return (0);
1009208538Sraj
1010208538Sraj	*count = 0;
1011208538Sraj	yesno = 1;
1012208538Sraj	for (i = 0; i < len; i++) {
1013208538Sraj		ch = *(d + i);
1014208538Sraj		if (isprint(ch) || (ch == '\0' && i > 0)) {
1015208538Sraj			/* Count strings */
1016208538Sraj			if (ch == '\0')
1017208538Sraj				(*count)++;
1018208538Sraj			continue;
1019208538Sraj		}
1020208538Sraj
1021208538Sraj		yesno = 0;
1022208538Sraj		break;
1023208538Sraj	}
1024208538Sraj
1025208538Sraj	return (yesno);
1026208538Sraj}
1027208538Sraj
1028208538Srajstatic int
1029208538Srajfdt_data_str(const void *data, int len, int count, char **buf)
1030208538Sraj{
1031233323Sraj	char *b, *tmp;
1032208538Sraj	const char *d;
1033233323Sraj	int buf_len, i, l;
1034208538Sraj
1035208538Sraj	/*
1036208538Sraj	 * Calculate the length for the string and allocate memory.
1037208538Sraj	 *
1038233323Sraj	 * Note that 'len' already includes at least one terminator.
1039208538Sraj	 */
1040233323Sraj	buf_len = len;
1041208538Sraj	if (count > 1) {
1042208538Sraj		/*
1043208538Sraj		 * Each token had already a terminator buried in 'len', but we
1044208538Sraj		 * only need one eventually, don't count space for these.
1045208538Sraj		 */
1046233323Sraj		buf_len -= count - 1;
1047208538Sraj
1048208538Sraj		/* Each consecutive token requires a ", " separator. */
1049233323Sraj		buf_len += count * 2;
1050208538Sraj	}
1051208538Sraj
1052233323Sraj	/* Add some space for surrounding double quotes. */
1053233323Sraj	buf_len += count * 2;
1054233323Sraj
1055233323Sraj	/* Note that string being put in 'tmp' may be as big as 'buf_len'. */
1056233323Sraj	b = (char *)malloc(buf_len);
1057233323Sraj	tmp = (char *)malloc(buf_len);
1058208538Sraj	if (b == NULL)
1059233323Sraj		goto error;
1060233323Sraj
1061233323Sraj	if (tmp == NULL) {
1062233323Sraj		free(b);
1063233323Sraj		goto error;
1064233323Sraj	}
1065233323Sraj
1066208538Sraj	b[0] = '\0';
1067208538Sraj
1068208538Sraj	/*
1069208538Sraj	 * Now that we have space, format the string.
1070208538Sraj	 */
1071208538Sraj	i = 0;
1072208538Sraj	do {
1073208538Sraj		d = (const char *)data + i;
1074208538Sraj		l = strlen(d) + 1;
1075208538Sraj
1076208538Sraj		sprintf(tmp, "\"%s\"%s", d,
1077208538Sraj		    (i + l) < len ?  ", " : "");
1078208538Sraj		strcat(b, tmp);
1079208538Sraj
1080208538Sraj		i += l;
1081208538Sraj
1082208538Sraj	} while (i < len);
1083208538Sraj	*buf = b;
1084208538Sraj
1085233323Sraj	free(tmp);
1086233323Sraj
1087208538Sraj	return (0);
1088233323Srajerror:
1089233323Sraj	return (1);
1090208538Sraj}
1091208538Sraj
1092208538Srajstatic int
1093208538Srajfdt_data_cell(const void *data, int len, char **buf)
1094208538Sraj{
1095233323Sraj	char *b, *tmp;
1096208538Sraj	const uint32_t *c;
1097208538Sraj	int count, i, l;
1098208538Sraj
1099208538Sraj	/* Number of cells */
1100208538Sraj	count = len / 4;
1101208538Sraj
1102208538Sraj	/*
1103208538Sraj	 * Calculate the length for the string and allocate memory.
1104208538Sraj	 */
1105208538Sraj
1106208538Sraj	/* Each byte translates to 2 output characters */
1107208538Sraj	l = len * 2;
1108208538Sraj	if (count > 1) {
1109208538Sraj		/* Each consecutive cell requires a " " separator. */
1110208538Sraj		l += (count - 1) * 1;
1111208538Sraj	}
1112208538Sraj	/* Each cell will have a "0x" prefix */
1113208538Sraj	l += count * 2;
1114208538Sraj	/* Space for surrounding <> and terminator */
1115208538Sraj	l += 3;
1116208538Sraj
1117208538Sraj	b = (char *)malloc(l);
1118233323Sraj	tmp = (char *)malloc(l);
1119208538Sraj	if (b == NULL)
1120233323Sraj		goto error;
1121208538Sraj
1122233323Sraj	if (tmp == NULL) {
1123233323Sraj		free(b);
1124233323Sraj		goto error;
1125233323Sraj	}
1126233323Sraj
1127208538Sraj	b[0] = '\0';
1128208538Sraj	strcat(b, "<");
1129208538Sraj
1130208538Sraj	for (i = 0; i < len; i += 4) {
1131208538Sraj		c = (const uint32_t *)((const uint8_t *)data + i);
1132208538Sraj		sprintf(tmp, "0x%08x%s", fdt32_to_cpu(*c),
1133208538Sraj		    i < (len - 4) ? " " : "");
1134208538Sraj		strcat(b, tmp);
1135208538Sraj	}
1136208538Sraj	strcat(b, ">");
1137208538Sraj	*buf = b;
1138208538Sraj
1139233323Sraj	free(tmp);
1140233323Sraj
1141208538Sraj	return (0);
1142233323Srajerror:
1143233323Sraj	return (1);
1144208538Sraj}
1145208538Sraj
1146208538Srajstatic int
1147208538Srajfdt_data_bytes(const void *data, int len, char **buf)
1148208538Sraj{
1149233323Sraj	char *b, *tmp;
1150208538Sraj	const char *d;
1151208538Sraj	int i, l;
1152208538Sraj
1153208538Sraj	/*
1154208538Sraj	 * Calculate the length for the string and allocate memory.
1155208538Sraj	 */
1156208538Sraj
1157208538Sraj	/* Each byte translates to 2 output characters */
1158208538Sraj	l = len * 2;
1159208538Sraj	if (len > 1)
1160208538Sraj		/* Each consecutive byte requires a " " separator. */
1161208538Sraj		l += (len - 1) * 1;
1162208538Sraj	/* Each byte will have a "0x" prefix */
1163208538Sraj	l += len * 2;
1164208538Sraj	/* Space for surrounding [] and terminator. */
1165208538Sraj	l += 3;
1166208538Sraj
1167208538Sraj	b = (char *)malloc(l);
1168233323Sraj	tmp = (char *)malloc(l);
1169208538Sraj	if (b == NULL)
1170233323Sraj		goto error;
1171208538Sraj
1172233323Sraj	if (tmp == NULL) {
1173233323Sraj		free(b);
1174233323Sraj		goto error;
1175233323Sraj	}
1176233323Sraj
1177208538Sraj	b[0] = '\0';
1178208538Sraj	strcat(b, "[");
1179208538Sraj
1180208538Sraj	for (i = 0, d = data; i < len; i++) {
1181208538Sraj		sprintf(tmp, "0x%02x%s", d[i], i < len - 1 ? " " : "");
1182208538Sraj		strcat(b, tmp);
1183208538Sraj	}
1184208538Sraj	strcat(b, "]");
1185208538Sraj	*buf = b;
1186208538Sraj
1187233323Sraj	free(tmp);
1188233323Sraj
1189208538Sraj	return (0);
1190233323Srajerror:
1191233323Sraj	return (1);
1192208538Sraj}
1193208538Sraj
1194208538Srajstatic int
1195208538Srajfdt_data_fmt(const void *data, int len, char **buf)
1196208538Sraj{
1197208538Sraj	int count;
1198208538Sraj
1199208538Sraj	if (len == 0) {
1200208538Sraj		*buf = NULL;
1201208538Sraj		return (1);
1202208538Sraj	}
1203208538Sraj
1204208538Sraj	if (fdt_isprint(data, len, &count))
1205208538Sraj		return (fdt_data_str(data, len, count, buf));
1206208538Sraj
1207208538Sraj	else if ((len % 4) == 0)
1208208538Sraj		return (fdt_data_cell(data, len, buf));
1209208538Sraj
1210208538Sraj	else
1211208538Sraj		return (fdt_data_bytes(data, len, buf));
1212208538Sraj}
1213208538Sraj
1214208538Srajstatic int
1215208538Srajfdt_prop(int offset)
1216208538Sraj{
1217208538Sraj	char *line, *buf;
1218208538Sraj	const struct fdt_property *prop;
1219208538Sraj	const char *name;
1220208538Sraj	const void *data;
1221208538Sraj	int len, rv;
1222208538Sraj
1223208538Sraj	line = NULL;
1224208538Sraj	prop = fdt_offset_ptr(fdtp, offset, sizeof(*prop));
1225208538Sraj	if (prop == NULL)
1226208538Sraj		return (1);
1227208538Sraj
1228208538Sraj	name = fdt_string(fdtp, fdt32_to_cpu(prop->nameoff));
1229208538Sraj	len = fdt32_to_cpu(prop->len);
1230208538Sraj
1231208538Sraj	rv = 0;
1232208538Sraj	buf = NULL;
1233208538Sraj	if (len == 0) {
1234208538Sraj		/* Property without value */
1235208538Sraj		line = (char *)malloc(strlen(name) + 2);
1236208538Sraj		if (line == NULL) {
1237208538Sraj			rv = 2;
1238208538Sraj			goto out2;
1239208538Sraj		}
1240208538Sraj		sprintf(line, "%s\n", name);
1241208538Sraj		goto out1;
1242208538Sraj	}
1243208538Sraj
1244208538Sraj	/*
1245208538Sraj	 * Process property with value
1246208538Sraj	 */
1247208538Sraj	data = prop->data;
1248208538Sraj
1249208538Sraj	if (fdt_data_fmt(data, len, &buf) != 0) {
1250208538Sraj		rv = 3;
1251208538Sraj		goto out2;
1252208538Sraj	}
1253208538Sraj
1254208538Sraj	line = (char *)malloc(strlen(name) + strlen(FDT_PROP_SEP) +
1255208538Sraj	    strlen(buf) + 2);
1256208538Sraj	if (line == NULL) {
1257208538Sraj		sprintf(command_errbuf, "could not allocate space for string");
1258208538Sraj		rv = 4;
1259208538Sraj		goto out2;
1260208538Sraj	}
1261208538Sraj
1262208538Sraj	sprintf(line, "%s" FDT_PROP_SEP "%s\n", name, buf);
1263208538Sraj
1264208538Srajout1:
1265208538Sraj	pager_open();
1266208538Sraj	pager_output(line);
1267208538Sraj	pager_close();
1268208538Sraj
1269208538Srajout2:
1270208538Sraj	if (buf)
1271208538Sraj		free(buf);
1272208538Sraj
1273208538Sraj	if (line)
1274208538Sraj		free(line);
1275208538Sraj
1276208538Sraj	return (rv);
1277208538Sraj}
1278208538Sraj
1279208538Srajstatic int
1280208538Srajfdt_modprop(int nodeoff, char *propname, void *value, char mode)
1281208538Sraj{
1282208538Sraj	uint32_t cells[100];
1283208538Sraj	char *buf;
1284208538Sraj	int len, rv;
1285208538Sraj	const struct fdt_property *p;
1286208538Sraj
1287208538Sraj	p = fdt_get_property(fdtp, nodeoff, propname, NULL);
1288208538Sraj
1289208538Sraj	if (p != NULL) {
1290208538Sraj		if (mode == 1) {
1291208538Sraj			 /* Adding inexistant value in mode 1 is forbidden */
1292208538Sraj			sprintf(command_errbuf, "property already exists!");
1293208538Sraj			return (CMD_ERROR);
1294208538Sraj		}
1295208538Sraj	} else if (mode == 0) {
1296208538Sraj		sprintf(command_errbuf, "property does not exist!");
1297208538Sraj		return (CMD_ERROR);
1298208538Sraj	}
1299208538Sraj	len = strlen(value);
1300208538Sraj	rv = 0;
1301208538Sraj	buf = (char *)value;
1302208538Sraj
1303208538Sraj	switch (*buf) {
1304208538Sraj	case '&':
1305208538Sraj		/* phandles */
1306208538Sraj		break;
1307208538Sraj	case '<':
1308208538Sraj		/* Data cells */
1309208538Sraj		len = fdt_strtovect(buf, (void *)&cells, 100,
1310208538Sraj		    sizeof(uint32_t));
1311208538Sraj
1312208538Sraj		rv = fdt_setprop(fdtp, nodeoff, propname, &cells,
1313208538Sraj		    len * sizeof(uint32_t));
1314208538Sraj		break;
1315208538Sraj	case '[':
1316208538Sraj		/* Data bytes */
1317208538Sraj		len = fdt_strtovect(buf, (void *)&cells, 100,
1318208538Sraj		    sizeof(uint8_t));
1319208538Sraj
1320208538Sraj		rv = fdt_setprop(fdtp, nodeoff, propname, &cells,
1321208538Sraj		    len * sizeof(uint8_t));
1322208538Sraj		break;
1323208538Sraj	case '"':
1324208538Sraj	default:
1325208538Sraj		/* Default -- string */
1326208538Sraj		rv = fdt_setprop_string(fdtp, nodeoff, propname, value);
1327208538Sraj		break;
1328208538Sraj	}
1329208538Sraj
1330233323Sraj	if (rv != 0) {
1331233323Sraj		if (rv == -FDT_ERR_NOSPACE)
1332233323Sraj			sprintf(command_errbuf,
1333233323Sraj			    "Device tree blob is too small!\n");
1334233323Sraj		else
1335233323Sraj			sprintf(command_errbuf,
1336233323Sraj			    "Could not add/modify property!\n");
1337235529Skientzle	} else {
1338235529Skientzle		COPYIN(fdtp, fdtp_va, fdtp_size);
1339233323Sraj	}
1340208538Sraj	return (rv);
1341208538Sraj}
1342208538Sraj
1343208538Sraj/* Merge strings from argv into a single string */
1344208538Srajstatic int
1345208538Srajfdt_merge_strings(int argc, char *argv[], int start, char **buffer)
1346208538Sraj{
1347208538Sraj	char *buf;
1348208538Sraj	int i, idx, sz;
1349208538Sraj
1350208538Sraj	*buffer = NULL;
1351208538Sraj	sz = 0;
1352208538Sraj
1353208538Sraj	for (i = start; i < argc; i++)
1354208538Sraj		sz += strlen(argv[i]);
1355208538Sraj
1356208538Sraj	/* Additional bytes for whitespaces between args */
1357208538Sraj	sz += argc - start;
1358208538Sraj
1359208538Sraj	buf = (char *)malloc(sizeof(char) * sz);
1360208538Sraj	bzero(buf, sizeof(char) * sz);
1361208538Sraj
1362208538Sraj	if (buf == NULL) {
1363208538Sraj		sprintf(command_errbuf, "could not allocate space "
1364208538Sraj		    "for string");
1365208538Sraj		return (1);
1366208538Sraj	}
1367208538Sraj
1368208538Sraj	idx = 0;
1369208538Sraj	for (i = start, idx = 0; i < argc; i++) {
1370208538Sraj		strcpy(buf + idx, argv[i]);
1371208538Sraj		idx += strlen(argv[i]);
1372208538Sraj		buf[idx] = ' ';
1373208538Sraj		idx++;
1374208538Sraj	}
1375208538Sraj	buf[sz - 1] = '\0';
1376208538Sraj	*buffer = buf;
1377208538Sraj	return (0);
1378208538Sraj}
1379208538Sraj
1380208538Sraj/* Extract offset and name of node/property from a given path */
1381208538Srajstatic int
1382208538Srajfdt_extract_nameloc(char **pathp, char **namep, int *nodeoff)
1383208538Sraj{
1384208538Sraj	int o;
1385208538Sraj	char *path = *pathp, *name = NULL, *subpath = NULL;
1386208538Sraj
1387208538Sraj	subpath = strrchr(path, '/');
1388208538Sraj	if (subpath == NULL) {
1389208538Sraj		o = fdt_path_offset(fdtp, cwd);
1390208538Sraj		name = path;
1391208538Sraj		path = (char *)&cwd;
1392208538Sraj	} else {
1393208538Sraj		*subpath = '\0';
1394208538Sraj		if (strlen(path) == 0)
1395208538Sraj			path = cwd;
1396208538Sraj
1397208538Sraj		name = subpath + 1;
1398208538Sraj		o = fdt_path_offset(fdtp, path);
1399208538Sraj	}
1400208538Sraj
1401208538Sraj	if (strlen(name) == 0) {
1402208538Sraj		sprintf(command_errbuf, "name not specified");
1403208538Sraj		return (1);
1404208538Sraj	}
1405208538Sraj	if (o < 0) {
1406208538Sraj		sprintf(command_errbuf, "could not find node: '%s'", path);
1407208538Sraj		return (1);
1408208538Sraj	}
1409208538Sraj	*namep = name;
1410208538Sraj	*nodeoff = o;
1411208538Sraj	*pathp = path;
1412208538Sraj	return (0);
1413208538Sraj}
1414208538Sraj
1415208538Srajstatic int
1416208538Srajfdt_cmd_prop(int argc, char *argv[])
1417208538Sraj{
1418208538Sraj	char *path, *propname, *value;
1419208538Sraj	int o, next, depth, rv;
1420208538Sraj	uint32_t tag;
1421208538Sraj
1422208538Sraj	path = (argc > 2) ? argv[2] : NULL;
1423208538Sraj
1424208538Sraj	value = NULL;
1425208538Sraj
1426208538Sraj	if (argc > 3) {
1427208538Sraj		/* Merge property value strings into one */
1428208538Sraj		if (fdt_merge_strings(argc, argv, 3, &value) != 0)
1429208538Sraj			return (CMD_ERROR);
1430208538Sraj	} else
1431208538Sraj		value = NULL;
1432208538Sraj
1433208538Sraj	if (path == NULL)
1434208538Sraj		path = cwd;
1435208538Sraj
1436208538Sraj	rv = CMD_OK;
1437208538Sraj
1438208538Sraj	if (value) {
1439208538Sraj		/* If value is specified -- try to modify prop. */
1440208538Sraj		if (fdt_extract_nameloc(&path, &propname, &o) != 0)
1441208538Sraj			return (CMD_ERROR);
1442208538Sraj
1443208538Sraj		rv = fdt_modprop(o, propname, value, 0);
1444208538Sraj		if (rv)
1445208538Sraj			return (CMD_ERROR);
1446208538Sraj		return (CMD_OK);
1447208538Sraj
1448208538Sraj	}
1449208538Sraj	/* User wants to display properties */
1450208538Sraj	o = fdt_path_offset(fdtp, path);
1451208538Sraj
1452208538Sraj	if (o < 0) {
1453208538Sraj		sprintf(command_errbuf, "could not find node: '%s'", path);
1454208538Sraj		rv = CMD_ERROR;
1455208538Sraj		goto out;
1456208538Sraj	}
1457208538Sraj
1458208538Sraj	depth = 0;
1459208538Sraj	while (depth >= 0) {
1460208538Sraj		tag = fdt_next_tag(fdtp, o, &next);
1461208538Sraj		switch (tag) {
1462208538Sraj		case FDT_NOP:
1463208538Sraj			break;
1464208538Sraj		case FDT_PROP:
1465208538Sraj			if (depth > 1)
1466208538Sraj				/* Don't process properties of nested nodes */
1467208538Sraj				break;
1468208538Sraj
1469208538Sraj			if (fdt_prop(o) != 0) {
1470208538Sraj				sprintf(command_errbuf, "could not process "
1471208538Sraj				    "property");
1472208538Sraj				rv = CMD_ERROR;
1473208538Sraj				goto out;
1474208538Sraj			}
1475208538Sraj			break;
1476208538Sraj		case FDT_BEGIN_NODE:
1477208538Sraj			depth++;
1478208538Sraj			if (depth > FDT_MAX_DEPTH) {
1479208538Sraj				printf("warning: nesting too deep: %d\n",
1480208538Sraj				    depth);
1481208538Sraj				goto out;
1482208538Sraj			}
1483208538Sraj			break;
1484208538Sraj		case FDT_END_NODE:
1485208538Sraj			depth--;
1486208538Sraj			if (depth == 0)
1487208538Sraj				/*
1488208538Sraj				 * This is the end of our starting node, force
1489208538Sraj				 * the loop finish.
1490208538Sraj				 */
1491208538Sraj				depth--;
1492208538Sraj			break;
1493208538Sraj		}
1494208538Sraj		o = next;
1495208538Sraj	}
1496208538Srajout:
1497208538Sraj	return (rv);
1498208538Sraj}
1499208538Sraj
1500208538Srajstatic int
1501208538Srajfdt_cmd_mkprop(int argc, char *argv[])
1502208538Sraj{
1503208538Sraj	int o;
1504208538Sraj	char *path, *propname, *value;
1505208538Sraj
1506208538Sraj	path = (argc > 2) ? argv[2] : NULL;
1507208538Sraj
1508208538Sraj	value = NULL;
1509208538Sraj
1510208538Sraj	if (argc > 3) {
1511208538Sraj		/* Merge property value strings into one */
1512208538Sraj		if (fdt_merge_strings(argc, argv, 3, &value) != 0)
1513208538Sraj			return (CMD_ERROR);
1514208538Sraj	} else
1515208538Sraj		value = NULL;
1516208538Sraj
1517208538Sraj	if (fdt_extract_nameloc(&path, &propname, &o) != 0)
1518208538Sraj		return (CMD_ERROR);
1519208538Sraj
1520208538Sraj	if (fdt_modprop(o, propname, value, 1))
1521208538Sraj		return (CMD_ERROR);
1522208538Sraj
1523247045Skientzle	COPYIN(fdtp, fdtp_va, fdtp_size);
1524208538Sraj	return (CMD_OK);
1525208538Sraj}
1526208538Sraj
1527208538Srajstatic int
1528208538Srajfdt_cmd_rm(int argc, char *argv[])
1529208538Sraj{
1530208538Sraj	int o, rv;
1531208538Sraj	char *path = NULL, *propname;
1532208538Sraj
1533208538Sraj	if (argc > 2)
1534208538Sraj		path = argv[2];
1535208538Sraj	else {
1536208538Sraj		sprintf(command_errbuf, "no node/property name specified");
1537208538Sraj		return (CMD_ERROR);
1538208538Sraj	}
1539208538Sraj
1540208538Sraj	o = fdt_path_offset(fdtp, path);
1541208538Sraj	if (o < 0) {
1542208538Sraj		/* If node not found -- try to find & delete property */
1543208538Sraj		if (fdt_extract_nameloc(&path, &propname, &o) != 0)
1544208538Sraj			return (CMD_ERROR);
1545208538Sraj
1546208538Sraj		if ((rv = fdt_delprop(fdtp, o, propname)) != 0) {
1547208538Sraj			sprintf(command_errbuf, "could not delete"
1548208538Sraj			    "%s\n", (rv == -FDT_ERR_NOTFOUND) ?
1549208538Sraj			    "(property/node does not exist)" : "");
1550208538Sraj			return (CMD_ERROR);
1551208538Sraj
1552208538Sraj		} else
1553208538Sraj			return (CMD_OK);
1554208538Sraj	}
1555208538Sraj	/* If node exists -- remove node */
1556208538Sraj	rv = fdt_del_node(fdtp, o);
1557208538Sraj	if (rv) {
1558208538Sraj		sprintf(command_errbuf, "could not delete node");
1559208538Sraj		return (CMD_ERROR);
1560235529Skientzle	} else {
1561235529Skientzle		COPYIN(fdtp, fdtp_va, fdtp_size);
1562208538Sraj	}
1563208538Sraj	return (CMD_OK);
1564208538Sraj}
1565208538Sraj
1566208538Srajstatic int
1567208538Srajfdt_cmd_mknode(int argc, char *argv[])
1568208538Sraj{
1569208538Sraj	int o, rv;
1570208538Sraj	char *path = NULL, *nodename = NULL;
1571208538Sraj
1572208538Sraj	if (argc > 2)
1573208538Sraj		path = argv[2];
1574208538Sraj	else {
1575208538Sraj		sprintf(command_errbuf, "no node name specified");
1576208538Sraj		return (CMD_ERROR);
1577208538Sraj	}
1578208538Sraj
1579208538Sraj	if (fdt_extract_nameloc(&path, &nodename, &o) != 0)
1580208538Sraj		return (CMD_ERROR);
1581208538Sraj
1582208538Sraj	rv = fdt_add_subnode(fdtp, o, nodename);
1583208538Sraj
1584208538Sraj	if (rv < 0) {
1585233323Sraj		if (rv == -FDT_ERR_NOSPACE)
1586233323Sraj			sprintf(command_errbuf,
1587233323Sraj			    "Device tree blob is too small!\n");
1588233323Sraj		else
1589233323Sraj			sprintf(command_errbuf,
1590233323Sraj			    "Could not add node!\n");
1591208538Sraj		return (CMD_ERROR);
1592235529Skientzle	} else {
1593235529Skientzle		COPYIN(fdtp, fdtp_va, fdtp_size);
1594208538Sraj	}
1595208538Sraj	return (CMD_OK);
1596208538Sraj}
1597208538Sraj
1598208538Srajstatic int
1599208538Srajfdt_cmd_pwd(int argc, char *argv[])
1600208538Sraj{
1601233323Sraj	char line[FDT_CWD_LEN];
1602208538Sraj
1603208538Sraj	pager_open();
1604208538Sraj	sprintf(line, "%s\n", cwd);
1605208538Sraj	pager_output(line);
1606208538Sraj	pager_close();
1607208538Sraj	return (CMD_OK);
1608208538Sraj}
1609208538Sraj
1610208538Srajstatic int
1611243693Sgonzofdt_cmd_mres(int argc, char *argv[])
1612243693Sgonzo{
1613243693Sgonzo	uint64_t start, size;
1614243693Sgonzo	int i, total;
1615243693Sgonzo	char line[80];
1616243693Sgonzo
1617243693Sgonzo	pager_open();
1618243693Sgonzo	total = fdt_num_mem_rsv(fdtp);
1619243693Sgonzo	if (total > 0) {
1620243693Sgonzo		pager_output("Reserved memory regions:\n");
1621243693Sgonzo		for (i = 0; i < total; i++) {
1622243693Sgonzo			fdt_get_mem_rsv(fdtp, i, &start, &size);
1623243693Sgonzo			sprintf(line, "reg#%d: (start: 0x%jx, size: 0x%jx)\n",
1624243693Sgonzo			    i, start, size);
1625243693Sgonzo			pager_output(line);
1626243693Sgonzo		}
1627243693Sgonzo	} else
1628243693Sgonzo		pager_output("No reserved memory regions\n");
1629243693Sgonzo	pager_close();
1630243693Sgonzo
1631243693Sgonzo	return (CMD_OK);
1632243693Sgonzo}
1633243693Sgonzo
1634243693Sgonzostatic int
1635208538Srajfdt_cmd_nyi(int argc, char *argv[])
1636208538Sraj{
1637208538Sraj
1638208538Sraj	printf("command not yet implemented\n");
1639208538Sraj	return (CMD_ERROR);
1640208538Sraj}
1641