fdt_loader_cmd.c revision 233323
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 233323 2012-03-22 20:34:26Z raj $");
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#define DEBUG
44208538Sraj
45208538Sraj#ifdef DEBUG
46208538Sraj#define debugf(fmt, args...) do { printf("%s(): ", __func__);	\
47208538Sraj    printf(fmt,##args); } while (0)
48208538Sraj#else
49208538Sraj#define debugf(fmt, args...)
50208538Sraj#endif
51208538Sraj
52208538Sraj#define FDT_CWD_LEN	256
53208538Sraj#define FDT_MAX_DEPTH	6
54208538Sraj
55208538Sraj#define FDT_PROP_SEP	" = "
56208538Sraj
57208538Sraj#define STR(number) #number
58208538Sraj#define STRINGIFY(number) STR(number)
59208538Sraj
60233230Sraj#define COPYOUT(s,d,l)	archsw.arch_copyout((vm_offset_t)(s), d, l)
61233230Sraj
62233230Sraj#define FDT_STATIC_DTB_SYMBOL	"fdt_static_dtb"
63233230Sraj
64208538Srajstatic struct fdt_header *fdtp = NULL;
65208538Sraj
66208538Srajstatic int fdt_cmd_nyi(int argc, char *argv[]);
67208538Sraj
68208538Srajstatic int fdt_cmd_mkprop(int argc, char *argv[]);
69208538Srajstatic int fdt_cmd_cd(int argc, char *argv[]);
70208538Srajstatic int fdt_cmd_hdr(int argc, char *argv[]);
71208538Srajstatic int fdt_cmd_ls(int argc, char *argv[]);
72208538Srajstatic int fdt_cmd_prop(int argc, char *argv[]);
73208538Srajstatic int fdt_cmd_pwd(int argc, char *argv[]);
74208538Srajstatic int fdt_cmd_rm(int argc, char *argv[]);
75208538Srajstatic int fdt_cmd_mknode(int argc, char *argv[]);
76208538Sraj
77208538Srajtypedef int cmdf_t(int, char *[]);
78208538Sraj
79208538Srajstruct cmdtab {
80208538Sraj	char	*name;
81208538Sraj	cmdf_t	*handler;
82208538Sraj};
83208538Sraj
84208538Srajstatic const struct cmdtab commands[] = {
85208538Sraj	{ "alias", &fdt_cmd_nyi },
86208538Sraj	{ "cd", &fdt_cmd_cd },
87208538Sraj	{ "header", &fdt_cmd_hdr },
88208538Sraj	{ "ls", &fdt_cmd_ls },
89208538Sraj	{ "mknode", &fdt_cmd_mknode },
90208538Sraj	{ "mkprop", &fdt_cmd_mkprop },
91208538Sraj	{ "mres", &fdt_cmd_nyi },
92208538Sraj	{ "prop", &fdt_cmd_prop },
93208538Sraj	{ "pwd", &fdt_cmd_pwd },
94208538Sraj	{ "rm", &fdt_cmd_rm },
95208538Sraj	{ NULL, NULL }
96208538Sraj};
97208538Sraj
98208538Srajstatic char cwd[FDT_CWD_LEN] = "/";
99208538Sraj
100233230Srajstatic vm_offset_t
101233230Srajfdt_find_static_dtb(void)
102233230Sraj{
103233230Sraj	Elf_Sym sym;
104233230Sraj	vm_offset_t dyntab, esym;
105233230Sraj	uint64_t offs;
106233230Sraj	struct preloaded_file *kfp;
107233230Sraj	struct file_metadata *md;
108233230Sraj	Elf_Sym *symtab;
109233230Sraj	Elf_Dyn *dyn;
110233230Sraj	char *strtab, *strp;
111233323Sraj	int i, sym_count;
112233230Sraj
113233323Sraj	symtab = NULL;
114233323Sraj	dyntab = esym = 0;
115233323Sraj	strtab = strp = NULL;
116233230Sraj
117233230Sraj	offs = __elfN(relocation_offset);
118233230Sraj
119233230Sraj	kfp = file_findfile(NULL, NULL);
120233230Sraj	if (kfp == NULL)
121233230Sraj		return (0);
122233230Sraj
123233230Sraj	md = file_findmetadata(kfp, MODINFOMD_ESYM);
124233230Sraj	if (md == NULL)
125233230Sraj		return (0);
126233230Sraj	COPYOUT(md->md_data, &esym, sizeof(esym));
127233230Sraj
128233230Sraj	md = file_findmetadata(kfp, MODINFOMD_DYNAMIC);
129233230Sraj	if (md == NULL)
130233230Sraj		return (0);
131233230Sraj	COPYOUT(md->md_data, &dyntab, sizeof(dyntab));
132233323Sraj
133233230Sraj	dyntab += offs;
134233230Sraj
135233230Sraj	/* Locate STRTAB and DYNTAB */
136233230Sraj	for (dyn = (Elf_Dyn *)dyntab; dyn->d_tag != DT_NULL; dyn++) {
137233230Sraj		if (dyn->d_tag == DT_STRTAB) {
138233230Sraj			strtab = (char *)(uintptr_t)(dyn->d_un.d_ptr + offs);
139233230Sraj			continue;
140233230Sraj		} else if (dyn->d_tag == DT_SYMTAB) {
141233230Sraj			symtab = (Elf_Sym *)(uintptr_t)
142233230Sraj			    (dyn->d_un.d_ptr + offs);
143233230Sraj			continue;
144233230Sraj		}
145233230Sraj	}
146233230Sraj
147233230Sraj	if (symtab == NULL || strtab == NULL) {
148233230Sraj		/*
149233230Sraj		 * No symtab? No strtab? That should not happen here,
150233230Sraj		 * and should have been verified during __elfN(loadimage).
151233230Sraj		 * This must be some kind of a bug.
152233230Sraj		 */
153233230Sraj		return (0);
154233230Sraj	}
155233230Sraj
156233323Sraj	sym_count = (int)((Elf_Sym *)esym - symtab) / sizeof(Elf_Sym);
157233323Sraj
158233230Sraj	/*
159233230Sraj	 * The most efficent way to find a symbol would be to calculate a
160233230Sraj	 * hash, find proper bucket and chain, and thus find a symbol.
161233230Sraj	 * However, that would involve code duplication (e.g. for hash
162233230Sraj	 * function). So we're using simpler and a bit slower way: we're
163233230Sraj	 * iterating through symbols, searching for the one which name is
164233230Sraj	 * 'equal' to 'fdt_static_dtb'. To speed up the process a little bit,
165233230Sraj	 * we are eliminating symbols type of which is not STT_NOTYPE, or(and)
166233230Sraj	 * those which binding attribute is not STB_GLOBAL.
167233230Sraj	 */
168233323Sraj	for (i = 0; i < sym_count; i++) {
169233230Sraj		COPYOUT(symtab + i, &sym, sizeof(sym));
170233230Sraj		if (ELF_ST_BIND(sym.st_info) != STB_GLOBAL ||
171233230Sraj		    ELF_ST_TYPE(sym.st_info) != STT_NOTYPE)
172233230Sraj			continue;
173233230Sraj
174233230Sraj		strp = strdupout((vm_offset_t)(strtab + sym.st_name));
175233230Sraj		if (strcmp(strp, FDT_STATIC_DTB_SYMBOL) == 0) {
176233230Sraj			/* Found a match ! */
177233230Sraj			free(strp);
178233230Sraj			return ((vm_offset_t)(sym.st_value + offs));
179233230Sraj		}
180233230Sraj		free(strp);
181233230Sraj	}
182233230Sraj	return (0);
183233230Sraj}
184233230Sraj
185208538Srajstatic int
186208538Srajfdt_setup_fdtp()
187208538Sraj{
188208538Sraj	struct preloaded_file *bfp;
189208538Sraj	int err;
190208538Sraj
191208538Sraj	/*
192208538Sraj	 * Find the device tree blob.
193208538Sraj	 */
194208538Sraj	bfp = file_findfile(NULL, "dtb");
195208538Sraj	if (bfp == NULL) {
196233323Sraj		if ((fdtp = (struct fdt_header *)fdt_find_static_dtb()) == 0) {
197233230Sraj			command_errmsg = "no device tree blob found!";
198233230Sraj			return (CMD_ERROR);
199233230Sraj		}
200233230Sraj	} else {
201233230Sraj		/* Dynamic blob has precedence over static. */
202233230Sraj		fdtp = (struct fdt_header *)bfp->f_addr;
203208538Sraj	}
204208538Sraj
205208538Sraj	/*
206208538Sraj	 * Validate the blob.
207208538Sraj	 */
208208538Sraj	err = fdt_check_header(fdtp);
209208538Sraj	if (err < 0) {
210208538Sraj		if (err == -FDT_ERR_BADVERSION)
211208538Sraj			sprintf(command_errbuf,
212208538Sraj			    "incompatible blob version: %d, should be: %d",
213208538Sraj			    fdt_version(fdtp), FDT_LAST_SUPPORTED_VERSION);
214208538Sraj
215208538Sraj		else
216208538Sraj			sprintf(command_errbuf, "error validating blob: %s",
217208538Sraj			    fdt_strerror(err));
218208538Sraj		return (CMD_ERROR);
219208538Sraj	}
220208538Sraj	return (CMD_OK);
221208538Sraj}
222208538Sraj
223208538Sraj#define fdt_strtovect(str, cellbuf, lim, cellsize) _fdt_strtovect((str), \
224208538Sraj    (cellbuf), (lim), (cellsize), 0);
225208538Sraj
226208538Sraj/* Force using base 16 */
227208538Sraj#define fdt_strtovectx(str, cellbuf, lim, cellsize) _fdt_strtovect((str), \
228208538Sraj    (cellbuf), (lim), (cellsize), 16);
229208538Sraj
230208538Srajstatic int
231208538Sraj_fdt_strtovect(char *str, void *cellbuf, int lim, unsigned char cellsize,
232208538Sraj    uint8_t base)
233208538Sraj{
234208538Sraj	char *buf = str;
235208538Sraj	char *end = str + strlen(str) - 2;
236208538Sraj	uint32_t *u32buf = NULL;
237208538Sraj	uint8_t *u8buf = NULL;
238208538Sraj	int cnt = 0;
239208538Sraj
240208538Sraj	if (cellsize == sizeof(uint32_t))
241208538Sraj		u32buf = (uint32_t *)cellbuf;
242208538Sraj	else
243208538Sraj		u8buf = (uint8_t *)cellbuf;
244208538Sraj
245208538Sraj	if (lim == 0)
246208538Sraj		return (0);
247208538Sraj
248208538Sraj	while (buf < end) {
249208538Sraj
250208538Sraj		/* Skip white whitespace(s)/separators */
251208538Sraj		while (!isxdigit(*buf) && buf < end)
252208538Sraj			buf++;
253208538Sraj
254208538Sraj		if (u32buf != NULL)
255208538Sraj			u32buf[cnt] =
256208538Sraj			    cpu_to_fdt32((uint32_t)strtol(buf, NULL, base));
257208538Sraj
258208538Sraj		else
259208538Sraj			u8buf[cnt] = (uint8_t)strtol(buf, NULL, base);
260208538Sraj
261208538Sraj		if (cnt + 1 <= lim - 1)
262208538Sraj			cnt++;
263208538Sraj		else
264208538Sraj			break;
265208538Sraj		buf++;
266208538Sraj		/* Find another number */
267208538Sraj		while ((isxdigit(*buf) || *buf == 'x') && buf < end)
268208538Sraj			buf++;
269208538Sraj	}
270208538Sraj	return (cnt);
271208538Sraj}
272208538Sraj
273208538Sraj#define	TMP_MAX_ETH	8
274208538Sraj
275208538Srajvoid
276208538Srajfixup_ethernet(const char *env, char *ethstr, int *eth_no, int len)
277208538Sraj{
278208538Sraj	char *end, *str;
279208538Sraj	uint8_t tmp_addr[6];
280208538Sraj	int i, n;
281208538Sraj
282208538Sraj	/* Extract interface number */
283208538Sraj	i = strtol(env + 3, &end, 10);
284208538Sraj	if (end == (env + 3))
285208538Sraj		/* 'ethaddr' means interface 0 address */
286208538Sraj		n = 0;
287208538Sraj	else
288208538Sraj		n = i;
289208538Sraj
290208538Sraj	if (n > TMP_MAX_ETH)
291208538Sraj		return;
292208538Sraj
293208538Sraj	str = ub_env_get(env);
294208538Sraj
295208538Sraj	/* Convert macaddr string into a vector of uints */
296208538Sraj	fdt_strtovectx(str, &tmp_addr, 6, sizeof(uint8_t));
297208538Sraj	if (n != 0) {
298208538Sraj		i = strlen(env) - 7;
299208538Sraj		strncpy(ethstr + 8, env + 3, i);
300208538Sraj	}
301208538Sraj	/* Set actual property to a value from vect */
302208538Sraj	fdt_setprop(fdtp, fdt_path_offset(fdtp, ethstr),
303208538Sraj	    "local-mac-address", &tmp_addr, 6 * sizeof(uint8_t));
304208538Sraj
305208538Sraj	/* Clear ethernet..XXXX.. string */
306208538Sraj	bzero(ethstr + 8, len - 8);
307208538Sraj
308208538Sraj	if (n + 1 > *eth_no)
309208538Sraj		*eth_no = n + 1;
310208538Sraj}
311208538Sraj
312208538Srajvoid
313208538Srajfixup_cpubusfreqs(unsigned long cpufreq, unsigned long busfreq)
314208538Sraj{
315208538Sraj	int lo, o = 0, o2, maxo = 0, depth;
316208538Sraj	const uint32_t zero = 0;
317208538Sraj
318208538Sraj	/* We want to modify every subnode of /cpus */
319208538Sraj	o = fdt_path_offset(fdtp, "/cpus");
320208538Sraj
321208538Sraj	/* maxo should contain offset of node next to /cpus */
322208538Sraj	depth = 0;
323208538Sraj	maxo = o;
324208538Sraj	while (depth != -1)
325208538Sraj		maxo = fdt_next_node(fdtp, maxo, &depth);
326208538Sraj
327208538Sraj	/* Find CPU frequency properties */
328208538Sraj	o = fdt_node_offset_by_prop_value(fdtp, o, "clock-frequency",
329208538Sraj	    &zero, sizeof(uint32_t));
330208538Sraj
331208538Sraj	o2 = fdt_node_offset_by_prop_value(fdtp, o, "bus-frequency", &zero,
332208538Sraj	    sizeof(uint32_t));
333208538Sraj
334208538Sraj	lo = MIN(o, o2);
335208538Sraj
336208538Sraj	while (o != -FDT_ERR_NOTFOUND && o2 != -FDT_ERR_NOTFOUND) {
337208538Sraj
338208538Sraj		o = fdt_node_offset_by_prop_value(fdtp, lo,
339208538Sraj		    "clock-frequency", &zero, sizeof(uint32_t));
340208538Sraj
341208538Sraj		o2 = fdt_node_offset_by_prop_value(fdtp, lo, "bus-frequency",
342208538Sraj		    &zero, sizeof(uint32_t));
343208538Sraj
344208538Sraj		/* We're only interested in /cpus subnode(s) */
345208538Sraj		if (lo > maxo)
346208538Sraj			break;
347208538Sraj
348208538Sraj		fdt_setprop_inplace_cell(fdtp, lo, "clock-frequency",
349208538Sraj		    (uint32_t)cpufreq);
350208538Sraj
351208538Sraj		fdt_setprop_inplace_cell(fdtp, lo, "bus-frequency",
352208538Sraj		    (uint32_t)busfreq);
353208538Sraj
354208538Sraj		lo = MIN(o, o2);
355208538Sraj	}
356208538Sraj}
357208538Sraj
358208538Srajint
359208538Srajfdt_reg_valid(uint32_t *reg, int len, int addr_cells, int size_cells)
360208538Sraj{
361208538Sraj	int cells_in_tuple, i, tuples, tuple_size;
362208538Sraj	uint32_t cur_start, cur_size;
363208538Sraj
364208538Sraj	cells_in_tuple = (addr_cells + size_cells);
365208538Sraj	tuple_size = cells_in_tuple * sizeof(uint32_t);
366208538Sraj	tuples = len / tuple_size;
367208538Sraj	if (tuples == 0)
368208538Sraj		return (EINVAL);
369208538Sraj
370208538Sraj	for (i = 0; i < tuples; i++) {
371208538Sraj		if (addr_cells == 2)
372208538Sraj			cur_start = fdt64_to_cpu(reg[i * cells_in_tuple]);
373208538Sraj		else
374208538Sraj			cur_start = fdt32_to_cpu(reg[i * cells_in_tuple]);
375208538Sraj
376208538Sraj		if (size_cells == 2)
377208538Sraj			cur_size = fdt64_to_cpu(reg[i * cells_in_tuple + 2]);
378208538Sraj		else
379208538Sraj			cur_size = fdt32_to_cpu(reg[i * cells_in_tuple + 1]);
380208538Sraj
381208538Sraj		if (cur_size == 0)
382208538Sraj			return (EINVAL);
383208538Sraj
384208538Sraj		debugf(" reg#%d (start: 0x%0x size: 0x%0x) valid!\n",
385208538Sraj		    i, cur_start, cur_size);
386208538Sraj	}
387208538Sraj	return (0);
388208538Sraj}
389208538Sraj
390208538Srajvoid
391208538Srajfixup_memory(struct sys_info *si)
392208538Sraj{
393208538Sraj	struct mem_region *curmr;
394208538Sraj	uint32_t addr_cells, size_cells;
395208538Sraj	uint32_t *addr_cellsp, *reg,  *size_cellsp;
396208538Sraj	int err, i, len, memory, realmrno, root;
397208538Sraj	uint8_t *buf, *sb;
398208538Sraj
399208538Sraj	root = fdt_path_offset(fdtp, "/");
400208538Sraj	if (root < 0) {
401208538Sraj		sprintf(command_errbuf, "Could not find root node !");
402208538Sraj		return;
403208538Sraj	}
404208538Sraj
405208538Sraj	memory = fdt_path_offset(fdtp, "/memory");
406208538Sraj	if (memory <= 0) {
407208538Sraj		/* Create proper '/memory' node. */
408208538Sraj		memory = fdt_add_subnode(fdtp, root, "memory");
409208538Sraj		if (memory <= 0) {
410208538Sraj			sprintf(command_errbuf, "Could not fixup '/memory' "
411208538Sraj			    "node, error code : %d!\n", memory);
412208538Sraj			return;
413208538Sraj		}
414208538Sraj
415208538Sraj		err = fdt_setprop(fdtp, memory, "device_type", "memory",
416208538Sraj		    sizeof("memory"));
417208538Sraj
418208538Sraj		if (err < 0)
419208538Sraj			return;
420208538Sraj	}
421208538Sraj
422208538Sraj	addr_cellsp = (uint32_t *)fdt_getprop(fdtp, root, "#address-cells",
423208538Sraj	    NULL);
424208538Sraj	size_cellsp = (uint32_t *)fdt_getprop(fdtp, root, "#size-cells", NULL);
425208538Sraj
426208538Sraj	if (addr_cellsp == NULL || size_cellsp == NULL) {
427208538Sraj		sprintf(command_errbuf, "Could not fixup '/memory' node : "
428208538Sraj		    "%s %s property not found in root node!\n",
429208538Sraj		    (!addr_cellsp) ? "#address-cells" : "",
430208538Sraj		    (!size_cellsp) ? "#size-cells" : "");
431208538Sraj		return;
432208538Sraj	}
433208538Sraj
434208538Sraj	addr_cells = fdt32_to_cpu(*addr_cellsp);
435208538Sraj	size_cells = fdt32_to_cpu(*size_cellsp);
436208538Sraj
437208538Sraj	/* Count valid memory regions entries in sysinfo. */
438208538Sraj	realmrno = si->mr_no;
439208538Sraj	for (i = 0; i < si->mr_no; i++)
440208538Sraj		if (si->mr[i].start == 0 && si->mr[i].size == 0)
441208538Sraj			realmrno--;
442208538Sraj
443208538Sraj	if (realmrno == 0) {
444208538Sraj		sprintf(command_errbuf, "Could not fixup '/memory' node : "
445208538Sraj		    "sysinfo doesn't contain valid memory regions info!\n");
446208538Sraj		return;
447208538Sraj	}
448208538Sraj
449208538Sraj	if ((reg = (uint32_t *)fdt_getprop(fdtp, memory, "reg",
450208538Sraj	    &len)) != NULL) {
451208538Sraj
452208538Sraj		if (fdt_reg_valid(reg, len, addr_cells, size_cells) == 0)
453208538Sraj			/*
454208538Sraj			 * Do not apply fixup if existing 'reg' property
455208538Sraj			 * seems to be valid.
456208538Sraj			 */
457208538Sraj			return;
458208538Sraj	}
459208538Sraj
460208538Sraj	len = (addr_cells + size_cells) * realmrno * sizeof(uint32_t);
461208538Sraj	sb = buf = (uint8_t *)malloc(len);
462208538Sraj	if (!buf)
463208538Sraj		return;
464208538Sraj
465208538Sraj	bzero(buf, len);
466208538Sraj
467208538Sraj	for (i = 0; i < si->mr_no; i++) {
468208538Sraj		curmr = &si->mr[i];
469208538Sraj		if (curmr->size != 0) {
470208538Sraj			/* Ensure endianess, and put cells into a buffer */
471208538Sraj			if (addr_cells == 2)
472208538Sraj				*(uint64_t *)buf =
473208538Sraj				    cpu_to_fdt64(curmr->start);
474208538Sraj			else
475208538Sraj				*(uint32_t *)buf =
476208538Sraj				    cpu_to_fdt32(curmr->start);
477208538Sraj
478208538Sraj			buf += sizeof(uint32_t) * addr_cells;
479208538Sraj			if (size_cells == 2)
480208538Sraj				*(uint64_t *)buf =
481208538Sraj				    cpu_to_fdt64(curmr->size);
482208538Sraj			else
483208538Sraj				*(uint32_t *)buf =
484208538Sraj				    cpu_to_fdt32(curmr->size);
485208538Sraj
486208538Sraj			buf += sizeof(uint32_t) * size_cells;
487208538Sraj		}
488208538Sraj	}
489208538Sraj
490208538Sraj	/* Set property */
491208538Sraj	if ((err = fdt_setprop(fdtp, memory, "reg", sb, len)) < 0)
492208538Sraj		sprintf(command_errbuf, "Could not fixup '/memory' node.\n");
493208538Sraj}
494208538Sraj
495208538Srajvoid
496208538Srajfixup_stdout(const char *env)
497208538Sraj{
498208538Sraj	const char *str;
499208538Sraj	char *ptr;
500208538Sraj	int serialno;
501208538Sraj	int len, no, sero;
502208538Sraj	const struct fdt_property *prop;
503208538Sraj	char *tmp[10];
504208538Sraj
505208538Sraj	str = ub_env_get(env);
506208538Sraj	ptr = (char *)str + strlen(str) - 1;
507208538Sraj	while (ptr > str && isdigit(*(str - 1)))
508208538Sraj		str--;
509208538Sraj
510208538Sraj	if (ptr == str)
511208538Sraj		return;
512208538Sraj
513208538Sraj	serialno = (int)strtol(ptr, NULL, 0);
514208538Sraj	no = fdt_path_offset(fdtp, "/chosen");
515208538Sraj	if (no < 0)
516208538Sraj		return;
517208538Sraj
518208538Sraj	prop = fdt_get_property(fdtp, no, "stdout", &len);
519208538Sraj
520208538Sraj	/* If /chosen/stdout does not extist, create it */
521208538Sraj	if (prop == NULL || (prop != NULL && len == 0)) {
522208538Sraj
523208538Sraj		bzero(tmp, 10 * sizeof(char));
524208538Sraj		strcpy((char *)&tmp, "serial");
525208538Sraj		if (strlen(ptr) > 3)
526208538Sraj			/* Serial number too long */
527208538Sraj			return;
528208538Sraj
529208538Sraj		strncpy((char *)tmp + 6, ptr, 3);
530208538Sraj		sero = fdt_path_offset(fdtp, (const char *)tmp);
531208538Sraj		if (sero < 0)
532208538Sraj			/*
533208538Sraj			 * If serial device we're trying to assign
534208538Sraj			 * stdout to doesn't exist in DT -- return.
535208538Sraj			 */
536208538Sraj			return;
537208538Sraj
538208538Sraj		fdt_setprop(fdtp, no, "stdout", &tmp,
539208538Sraj		    strlen((char *)&tmp) + 1);
540208538Sraj		fdt_setprop(fdtp, no, "stdin", &tmp,
541208538Sraj		    strlen((char *)&tmp) + 1);
542208538Sraj	}
543208538Sraj}
544208538Sraj
545233230Sraj/*
546233230Sraj * Locate the blob, fix it up and return its location.
547233230Sraj */
548233230Srajvoid *
549208538Srajfdt_fixup(void)
550208538Sraj{
551208538Sraj	const char *env;
552208538Sraj	char *ethstr;
553208538Sraj	int chosen, err, eth_no, len;
554208538Sraj	struct sys_info *si;
555208538Sraj
556208538Sraj	env = NULL;
557208538Sraj	eth_no = 0;
558208538Sraj	ethstr = NULL;
559208538Sraj	len = 0;
560208538Sraj
561233230Sraj	err = fdt_setup_fdtp();
562233230Sraj	if (err) {
563233230Sraj		sprintf(command_errbuf, "No valid device tree blob found!");
564233230Sraj		return (NULL);
565208538Sraj	}
566208538Sraj
567208538Sraj	/* Create /chosen node (if not exists) */
568208538Sraj	if ((chosen = fdt_subnode_offset(fdtp, 0, "chosen")) ==
569208538Sraj	    -FDT_ERR_NOTFOUND)
570208538Sraj		chosen = fdt_add_subnode(fdtp, 0, "chosen");
571208538Sraj
572208538Sraj	/* Value assigned to fixup-applied does not matter. */
573208538Sraj	if (fdt_getprop(fdtp, chosen, "fixup-applied", NULL))
574233230Sraj		goto success;
575208538Sraj
576208538Sraj	/* Acquire sys_info */
577208538Sraj	si = ub_get_sys_info();
578208538Sraj
579208538Sraj	while ((env = ub_env_enum(env)) != NULL) {
580208538Sraj		if (strncmp(env, "eth", 3) == 0 &&
581208538Sraj		    strncmp(env + (strlen(env) - 4), "addr", 4) == 0) {
582208538Sraj			/*
583208538Sraj			 * Handle Ethernet addrs: parse uboot env eth%daddr
584208538Sraj			 */
585208538Sraj
586208538Sraj			if (!eth_no) {
587208538Sraj				/*
588208538Sraj				 * Check how many chars we will need to store
589208538Sraj				 * maximal eth iface number.
590208538Sraj				 */
591208538Sraj				len = strlen(STRINGIFY(TMP_MAX_ETH)) +
592208538Sraj				    strlen("ethernet");
593208538Sraj
594208538Sraj				/*
595208538Sraj				 * Reserve mem for string "ethernet" and len
596208538Sraj				 * chars for iface no.
597208538Sraj				 */
598208538Sraj				ethstr = (char *)malloc(len * sizeof(char));
599208538Sraj				bzero(ethstr, len * sizeof(char));
600208538Sraj				strcpy(ethstr, "ethernet0");
601208538Sraj			}
602208538Sraj
603208538Sraj			/* Modify blob */
604208538Sraj			fixup_ethernet(env, ethstr, &eth_no, len);
605208538Sraj
606208538Sraj		} else if (strcmp(env, "consoledev") == 0)
607208538Sraj			fixup_stdout(env);
608208538Sraj	}
609208538Sraj
610208538Sraj	/* Modify cpu(s) and bus clock frequenties in /cpus node [Hz] */
611208538Sraj	fixup_cpubusfreqs(si->clk_cpu, si->clk_bus);
612208538Sraj
613208538Sraj	/* Fixup memory regions */
614208538Sraj	fixup_memory(si);
615208538Sraj
616208538Sraj	fdt_setprop(fdtp, chosen, "fixup-applied", NULL, 0);
617208538Sraj
618233230Srajsuccess:
619233230Sraj	return (fdtp);
620208538Sraj}
621208538Sraj
622208538Srajint
623208538Srajcommand_fdt_internal(int argc, char *argv[])
624208538Sraj{
625208538Sraj	cmdf_t *cmdh;
626208538Sraj	char *cmd;
627208538Sraj	int i, err;
628208538Sraj
629208538Sraj	if (argc < 2) {
630208538Sraj		command_errmsg = "usage is 'fdt <command> [<args>]";
631208538Sraj		return (CMD_ERROR);
632208538Sraj	}
633208538Sraj
634208538Sraj	/*
635208538Sraj	 * Check if uboot env vars were parsed already. If not, do it now.
636208538Sraj	 */
637233230Sraj	if (fdt_fixup() == NULL)
638233230Sraj		return (CMD_ERROR);
639208538Sraj
640208538Sraj	/*
641208538Sraj	 * Validate fdt <command>.
642208538Sraj	 */
643208538Sraj	cmd = strdup(argv[1]);
644208538Sraj	i = 0;
645208538Sraj	cmdh = NULL;
646208538Sraj	while (!(commands[i].name == NULL)) {
647208538Sraj		if (strcmp(cmd, commands[i].name) == 0) {
648208538Sraj			/* found it */
649208538Sraj			cmdh = commands[i].handler;
650208538Sraj			break;
651208538Sraj		}
652208538Sraj		i++;
653208538Sraj	}
654208538Sraj	if (cmdh == NULL) {
655208538Sraj		command_errmsg = "unknown command";
656208538Sraj		return (CMD_ERROR);
657208538Sraj	}
658208538Sraj
659208538Sraj	/*
660208538Sraj	 * Call command handler.
661208538Sraj	 */
662208538Sraj	err = (*cmdh)(argc, argv);
663208538Sraj
664208538Sraj	return (err);
665208538Sraj}
666208538Sraj
667208538Srajstatic int
668208538Srajfdt_cmd_cd(int argc, char *argv[])
669208538Sraj{
670208538Sraj	char *path;
671208538Sraj	char tmp[FDT_CWD_LEN];
672208538Sraj	int len, o;
673208538Sraj
674208538Sraj	path = (argc > 2) ? argv[2] : "/";
675208538Sraj
676208538Sraj	if (path[0] == '/') {
677208538Sraj		len = strlen(path);
678208538Sraj		if (len >= FDT_CWD_LEN)
679208538Sraj			goto fail;
680208538Sraj	} else {
681208538Sraj		/* Handle path specification relative to cwd */
682208538Sraj		len = strlen(cwd) + strlen(path) + 1;
683208538Sraj		if (len >= FDT_CWD_LEN)
684208538Sraj			goto fail;
685208538Sraj
686208538Sraj		strcpy(tmp, cwd);
687208538Sraj		strcat(tmp, "/");
688208538Sraj		strcat(tmp, path);
689208538Sraj		path = tmp;
690208538Sraj	}
691208538Sraj
692208538Sraj	o = fdt_path_offset(fdtp, path);
693208538Sraj	if (o < 0) {
694208538Sraj		sprintf(command_errbuf, "could not find node: '%s'", path);
695208538Sraj		return (CMD_ERROR);
696208538Sraj	}
697208538Sraj
698208538Sraj	strcpy(cwd, path);
699208538Sraj	return (CMD_OK);
700208538Sraj
701208538Srajfail:
702208538Sraj	sprintf(command_errbuf, "path too long: %d, max allowed: %d",
703208538Sraj	    len, FDT_CWD_LEN - 1);
704208538Sraj	return (CMD_ERROR);
705208538Sraj}
706208538Sraj
707208538Srajstatic int
708208538Srajfdt_cmd_hdr(int argc __unused, char *argv[] __unused)
709208538Sraj{
710208538Sraj	char line[80];
711208538Sraj	int ver;
712208538Sraj
713208538Sraj	if (fdtp == NULL) {
714208538Sraj		command_errmsg = "no device tree blob pointer?!";
715208538Sraj		return (CMD_ERROR);
716208538Sraj	}
717208538Sraj
718208538Sraj	ver = fdt_version(fdtp);
719208538Sraj	pager_open();
720208538Sraj	sprintf(line, "\nFlattened device tree header (%p):\n", fdtp);
721208538Sraj	pager_output(line);
722208538Sraj	sprintf(line, " magic                   = 0x%08x\n", fdt_magic(fdtp));
723208538Sraj	pager_output(line);
724208538Sraj	sprintf(line, " size                    = %d\n", fdt_totalsize(fdtp));
725208538Sraj	pager_output(line);
726208538Sraj	sprintf(line, " off_dt_struct           = 0x%08x\n",
727208538Sraj	    fdt_off_dt_struct(fdtp));
728208538Sraj	pager_output(line);
729208538Sraj	sprintf(line, " off_dt_strings          = 0x%08x\n",
730208538Sraj	    fdt_off_dt_strings(fdtp));
731208538Sraj	pager_output(line);
732208538Sraj	sprintf(line, " off_mem_rsvmap          = 0x%08x\n",
733208538Sraj	    fdt_off_mem_rsvmap(fdtp));
734208538Sraj	pager_output(line);
735208538Sraj	sprintf(line, " version                 = %d\n", ver);
736208538Sraj	pager_output(line);
737208538Sraj	sprintf(line, " last compatible version = %d\n",
738208538Sraj	    fdt_last_comp_version(fdtp));
739208538Sraj	pager_output(line);
740208538Sraj	if (ver >= 2) {
741208538Sraj		sprintf(line, " boot_cpuid              = %d\n",
742208538Sraj		    fdt_boot_cpuid_phys(fdtp));
743208538Sraj		pager_output(line);
744208538Sraj	}
745208538Sraj	if (ver >= 3) {
746208538Sraj		sprintf(line, " size_dt_strings         = %d\n",
747208538Sraj		    fdt_size_dt_strings(fdtp));
748208538Sraj		pager_output(line);
749208538Sraj	}
750208538Sraj	if (ver >= 17) {
751208538Sraj		sprintf(line, " size_dt_struct          = %d\n",
752208538Sraj		    fdt_size_dt_struct(fdtp));
753208538Sraj		pager_output(line);
754208538Sraj	}
755208538Sraj	pager_close();
756208538Sraj
757208538Sraj	return (CMD_OK);
758208538Sraj}
759208538Sraj
760208538Srajstatic int
761208538Srajfdt_cmd_ls(int argc, char *argv[])
762208538Sraj{
763208538Sraj	const char *prevname[FDT_MAX_DEPTH] = { NULL };
764208538Sraj	const char *name;
765208538Sraj	char *path;
766208538Sraj	int i, o, depth, len;
767208538Sraj
768208538Sraj	path = (argc > 2) ? argv[2] : NULL;
769208538Sraj	if (path == NULL)
770208538Sraj		path = cwd;
771208538Sraj
772208538Sraj	o = fdt_path_offset(fdtp, path);
773208538Sraj	if (o < 0) {
774208538Sraj		sprintf(command_errbuf, "could not find node: '%s'", path);
775208538Sraj		return (CMD_ERROR);
776208538Sraj	}
777208538Sraj
778208538Sraj	for (depth = 0;
779208538Sraj	    (o >= 0) && (depth >= 0);
780208538Sraj	    o = fdt_next_node(fdtp, o, &depth)) {
781208538Sraj
782208538Sraj		name = fdt_get_name(fdtp, o, &len);
783208538Sraj
784208538Sraj		if (depth > FDT_MAX_DEPTH) {
785208538Sraj			printf("max depth exceeded: %d\n", depth);
786208538Sraj			continue;
787208538Sraj		}
788208538Sraj
789208538Sraj		prevname[depth] = name;
790208538Sraj
791208538Sraj		/* Skip root (i = 1) when printing devices */
792208538Sraj		for (i = 1; i <= depth; i++) {
793208538Sraj			if (prevname[i] == NULL)
794208538Sraj				break;
795208538Sraj
796208538Sraj			if (strcmp(cwd, "/") == 0)
797208538Sraj				printf("/");
798208538Sraj			printf("%s", prevname[i]);
799208538Sraj		}
800208538Sraj		printf("\n");
801208538Sraj	}
802208538Sraj
803208538Sraj	return (CMD_OK);
804208538Sraj}
805208538Sraj
806208538Srajstatic __inline int
807208538Srajisprint(int c)
808208538Sraj{
809208538Sraj
810208538Sraj	return (c >= ' ' && c <= 0x7e);
811208538Sraj}
812208538Sraj
813208538Srajstatic int
814208538Srajfdt_isprint(const void *data, int len, int *count)
815208538Sraj{
816208538Sraj	const char *d;
817208538Sraj	char ch;
818208538Sraj	int yesno, i;
819208538Sraj
820208538Sraj	if (len == 0)
821208538Sraj		return (0);
822208538Sraj
823208538Sraj	d = (const char *)data;
824208538Sraj	if (d[len - 1] != '\0')
825208538Sraj		return (0);
826208538Sraj
827208538Sraj	*count = 0;
828208538Sraj	yesno = 1;
829208538Sraj	for (i = 0; i < len; i++) {
830208538Sraj		ch = *(d + i);
831208538Sraj		if (isprint(ch) || (ch == '\0' && i > 0)) {
832208538Sraj			/* Count strings */
833208538Sraj			if (ch == '\0')
834208538Sraj				(*count)++;
835208538Sraj			continue;
836208538Sraj		}
837208538Sraj
838208538Sraj		yesno = 0;
839208538Sraj		break;
840208538Sraj	}
841208538Sraj
842208538Sraj	return (yesno);
843208538Sraj}
844208538Sraj
845208538Srajstatic int
846208538Srajfdt_data_str(const void *data, int len, int count, char **buf)
847208538Sraj{
848233323Sraj	char *b, *tmp;
849208538Sraj	const char *d;
850233323Sraj	int buf_len, i, l;
851208538Sraj
852208538Sraj	/*
853208538Sraj	 * Calculate the length for the string and allocate memory.
854208538Sraj	 *
855233323Sraj	 * Note that 'len' already includes at least one terminator.
856208538Sraj	 */
857233323Sraj	buf_len = len;
858208538Sraj	if (count > 1) {
859208538Sraj		/*
860208538Sraj		 * Each token had already a terminator buried in 'len', but we
861208538Sraj		 * only need one eventually, don't count space for these.
862208538Sraj		 */
863233323Sraj		buf_len -= count - 1;
864208538Sraj
865208538Sraj		/* Each consecutive token requires a ", " separator. */
866233323Sraj		buf_len += count * 2;
867208538Sraj	}
868208538Sraj
869233323Sraj	/* Add some space for surrounding double quotes. */
870233323Sraj	buf_len += count * 2;
871233323Sraj
872233323Sraj	/* Note that string being put in 'tmp' may be as big as 'buf_len'. */
873233323Sraj	b = (char *)malloc(buf_len);
874233323Sraj	tmp = (char *)malloc(buf_len);
875208538Sraj	if (b == NULL)
876233323Sraj		goto error;
877233323Sraj
878233323Sraj	if (tmp == NULL) {
879233323Sraj		free(b);
880233323Sraj		goto error;
881233323Sraj	}
882233323Sraj
883208538Sraj	b[0] = '\0';
884208538Sraj
885208538Sraj	/*
886208538Sraj	 * Now that we have space, format the string.
887208538Sraj	 */
888208538Sraj	i = 0;
889208538Sraj	do {
890208538Sraj		d = (const char *)data + i;
891208538Sraj		l = strlen(d) + 1;
892208538Sraj
893208538Sraj		sprintf(tmp, "\"%s\"%s", d,
894208538Sraj		    (i + l) < len ?  ", " : "");
895208538Sraj		strcat(b, tmp);
896208538Sraj
897208538Sraj		i += l;
898208538Sraj
899208538Sraj	} while (i < len);
900208538Sraj	*buf = b;
901208538Sraj
902233323Sraj	free(tmp);
903233323Sraj
904208538Sraj	return (0);
905233323Srajerror:
906233323Sraj	return (1);
907208538Sraj}
908208538Sraj
909208538Srajstatic int
910208538Srajfdt_data_cell(const void *data, int len, char **buf)
911208538Sraj{
912233323Sraj	char *b, *tmp;
913208538Sraj	const uint32_t *c;
914208538Sraj	int count, i, l;
915208538Sraj
916208538Sraj	/* Number of cells */
917208538Sraj	count = len / 4;
918208538Sraj
919208538Sraj	/*
920208538Sraj	 * Calculate the length for the string and allocate memory.
921208538Sraj	 */
922208538Sraj
923208538Sraj	/* Each byte translates to 2 output characters */
924208538Sraj	l = len * 2;
925208538Sraj	if (count > 1) {
926208538Sraj		/* Each consecutive cell requires a " " separator. */
927208538Sraj		l += (count - 1) * 1;
928208538Sraj	}
929208538Sraj	/* Each cell will have a "0x" prefix */
930208538Sraj	l += count * 2;
931208538Sraj	/* Space for surrounding <> and terminator */
932208538Sraj	l += 3;
933208538Sraj
934208538Sraj	b = (char *)malloc(l);
935233323Sraj	tmp = (char *)malloc(l);
936208538Sraj	if (b == NULL)
937233323Sraj		goto error;
938208538Sraj
939233323Sraj	if (tmp == NULL) {
940233323Sraj		free(b);
941233323Sraj		goto error;
942233323Sraj	}
943233323Sraj
944208538Sraj	b[0] = '\0';
945208538Sraj	strcat(b, "<");
946208538Sraj
947208538Sraj	for (i = 0; i < len; i += 4) {
948208538Sraj		c = (const uint32_t *)((const uint8_t *)data + i);
949208538Sraj		sprintf(tmp, "0x%08x%s", fdt32_to_cpu(*c),
950208538Sraj		    i < (len - 4) ? " " : "");
951208538Sraj		strcat(b, tmp);
952208538Sraj	}
953208538Sraj	strcat(b, ">");
954208538Sraj	*buf = b;
955208538Sraj
956233323Sraj	free(tmp);
957233323Sraj
958208538Sraj	return (0);
959233323Srajerror:
960233323Sraj	return (1);
961208538Sraj}
962208538Sraj
963208538Srajstatic int
964208538Srajfdt_data_bytes(const void *data, int len, char **buf)
965208538Sraj{
966233323Sraj	char *b, *tmp;
967208538Sraj	const char *d;
968208538Sraj	int i, l;
969208538Sraj
970208538Sraj	/*
971208538Sraj	 * Calculate the length for the string and allocate memory.
972208538Sraj	 */
973208538Sraj
974208538Sraj	/* Each byte translates to 2 output characters */
975208538Sraj	l = len * 2;
976208538Sraj	if (len > 1)
977208538Sraj		/* Each consecutive byte requires a " " separator. */
978208538Sraj		l += (len - 1) * 1;
979208538Sraj	/* Each byte will have a "0x" prefix */
980208538Sraj	l += len * 2;
981208538Sraj	/* Space for surrounding [] and terminator. */
982208538Sraj	l += 3;
983208538Sraj
984208538Sraj	b = (char *)malloc(l);
985233323Sraj	tmp = (char *)malloc(l);
986208538Sraj	if (b == NULL)
987233323Sraj		goto error;
988208538Sraj
989233323Sraj	if (tmp == NULL) {
990233323Sraj		free(b);
991233323Sraj		goto error;
992233323Sraj	}
993233323Sraj
994208538Sraj	b[0] = '\0';
995208538Sraj	strcat(b, "[");
996208538Sraj
997208538Sraj	for (i = 0, d = data; i < len; i++) {
998208538Sraj		sprintf(tmp, "0x%02x%s", d[i], i < len - 1 ? " " : "");
999208538Sraj		strcat(b, tmp);
1000208538Sraj	}
1001208538Sraj	strcat(b, "]");
1002208538Sraj	*buf = b;
1003208538Sraj
1004233323Sraj	free(tmp);
1005233323Sraj
1006208538Sraj	return (0);
1007233323Srajerror:
1008233323Sraj	return (1);
1009208538Sraj}
1010208538Sraj
1011208538Srajstatic int
1012208538Srajfdt_data_fmt(const void *data, int len, char **buf)
1013208538Sraj{
1014208538Sraj	int count;
1015208538Sraj
1016208538Sraj	if (len == 0) {
1017208538Sraj		*buf = NULL;
1018208538Sraj		return (1);
1019208538Sraj	}
1020208538Sraj
1021208538Sraj	if (fdt_isprint(data, len, &count))
1022208538Sraj		return (fdt_data_str(data, len, count, buf));
1023208538Sraj
1024208538Sraj	else if ((len % 4) == 0)
1025208538Sraj		return (fdt_data_cell(data, len, buf));
1026208538Sraj
1027208538Sraj	else
1028208538Sraj		return (fdt_data_bytes(data, len, buf));
1029208538Sraj}
1030208538Sraj
1031208538Srajstatic int
1032208538Srajfdt_prop(int offset)
1033208538Sraj{
1034208538Sraj	char *line, *buf;
1035208538Sraj	const struct fdt_property *prop;
1036208538Sraj	const char *name;
1037208538Sraj	const void *data;
1038208538Sraj	int len, rv;
1039208538Sraj
1040208538Sraj	line = NULL;
1041208538Sraj	prop = fdt_offset_ptr(fdtp, offset, sizeof(*prop));
1042208538Sraj	if (prop == NULL)
1043208538Sraj		return (1);
1044208538Sraj
1045208538Sraj	name = fdt_string(fdtp, fdt32_to_cpu(prop->nameoff));
1046208538Sraj	len = fdt32_to_cpu(prop->len);
1047208538Sraj
1048208538Sraj	rv = 0;
1049208538Sraj	buf = NULL;
1050208538Sraj	if (len == 0) {
1051208538Sraj		/* Property without value */
1052208538Sraj		line = (char *)malloc(strlen(name) + 2);
1053208538Sraj		if (line == NULL) {
1054208538Sraj			rv = 2;
1055208538Sraj			goto out2;
1056208538Sraj		}
1057208538Sraj		sprintf(line, "%s\n", name);
1058208538Sraj		goto out1;
1059208538Sraj	}
1060208538Sraj
1061208538Sraj	/*
1062208538Sraj	 * Process property with value
1063208538Sraj	 */
1064208538Sraj	data = prop->data;
1065208538Sraj
1066208538Sraj	if (fdt_data_fmt(data, len, &buf) != 0) {
1067208538Sraj		rv = 3;
1068208538Sraj		goto out2;
1069208538Sraj	}
1070208538Sraj
1071208538Sraj	line = (char *)malloc(strlen(name) + strlen(FDT_PROP_SEP) +
1072208538Sraj	    strlen(buf) + 2);
1073208538Sraj	if (line == NULL) {
1074208538Sraj		sprintf(command_errbuf, "could not allocate space for string");
1075208538Sraj		rv = 4;
1076208538Sraj		goto out2;
1077208538Sraj	}
1078208538Sraj
1079208538Sraj	sprintf(line, "%s" FDT_PROP_SEP "%s\n", name, buf);
1080208538Sraj
1081208538Srajout1:
1082208538Sraj	pager_open();
1083208538Sraj	pager_output(line);
1084208538Sraj	pager_close();
1085208538Sraj
1086208538Srajout2:
1087208538Sraj	if (buf)
1088208538Sraj		free(buf);
1089208538Sraj
1090208538Sraj	if (line)
1091208538Sraj		free(line);
1092208538Sraj
1093208538Sraj	return (rv);
1094208538Sraj}
1095208538Sraj
1096208538Srajstatic int
1097208538Srajfdt_modprop(int nodeoff, char *propname, void *value, char mode)
1098208538Sraj{
1099208538Sraj	uint32_t cells[100];
1100208538Sraj	char *buf;
1101208538Sraj	int len, rv;
1102208538Sraj	const struct fdt_property *p;
1103208538Sraj
1104208538Sraj	p = fdt_get_property(fdtp, nodeoff, propname, NULL);
1105208538Sraj
1106208538Sraj	if (p != NULL) {
1107208538Sraj		if (mode == 1) {
1108208538Sraj			 /* Adding inexistant value in mode 1 is forbidden */
1109208538Sraj			sprintf(command_errbuf, "property already exists!");
1110208538Sraj			return (CMD_ERROR);
1111208538Sraj		}
1112208538Sraj	} else if (mode == 0) {
1113208538Sraj		sprintf(command_errbuf, "property does not exist!");
1114208538Sraj		return (CMD_ERROR);
1115208538Sraj	}
1116208538Sraj	len = strlen(value);
1117208538Sraj	rv = 0;
1118208538Sraj	buf = (char *)value;
1119208538Sraj
1120208538Sraj	switch (*buf) {
1121208538Sraj	case '&':
1122208538Sraj		/* phandles */
1123208538Sraj		break;
1124208538Sraj	case '<':
1125208538Sraj		/* Data cells */
1126208538Sraj		len = fdt_strtovect(buf, (void *)&cells, 100,
1127208538Sraj		    sizeof(uint32_t));
1128208538Sraj
1129208538Sraj		rv = fdt_setprop(fdtp, nodeoff, propname, &cells,
1130208538Sraj		    len * sizeof(uint32_t));
1131208538Sraj		break;
1132208538Sraj	case '[':
1133208538Sraj		/* Data bytes */
1134208538Sraj		len = fdt_strtovect(buf, (void *)&cells, 100,
1135208538Sraj		    sizeof(uint8_t));
1136208538Sraj
1137208538Sraj		rv = fdt_setprop(fdtp, nodeoff, propname, &cells,
1138208538Sraj		    len * sizeof(uint8_t));
1139208538Sraj		break;
1140208538Sraj	case '"':
1141208538Sraj	default:
1142208538Sraj		/* Default -- string */
1143208538Sraj		rv = fdt_setprop_string(fdtp, nodeoff, propname, value);
1144208538Sraj		break;
1145208538Sraj	}
1146208538Sraj
1147233323Sraj	if (rv != 0) {
1148233323Sraj		if (rv == -FDT_ERR_NOSPACE)
1149233323Sraj			sprintf(command_errbuf,
1150233323Sraj			    "Device tree blob is too small!\n");
1151233323Sraj		else
1152233323Sraj			sprintf(command_errbuf,
1153233323Sraj			    "Could not add/modify property!\n");
1154233323Sraj	}
1155208538Sraj	return (rv);
1156208538Sraj}
1157208538Sraj
1158208538Sraj/* Merge strings from argv into a single string */
1159208538Srajstatic int
1160208538Srajfdt_merge_strings(int argc, char *argv[], int start, char **buffer)
1161208538Sraj{
1162208538Sraj	char *buf;
1163208538Sraj	int i, idx, sz;
1164208538Sraj
1165208538Sraj	*buffer = NULL;
1166208538Sraj	sz = 0;
1167208538Sraj
1168208538Sraj	for (i = start; i < argc; i++)
1169208538Sraj		sz += strlen(argv[i]);
1170208538Sraj
1171208538Sraj	/* Additional bytes for whitespaces between args */
1172208538Sraj	sz += argc - start;
1173208538Sraj
1174208538Sraj	buf = (char *)malloc(sizeof(char) * sz);
1175208538Sraj	bzero(buf, sizeof(char) * sz);
1176208538Sraj
1177208538Sraj	if (buf == NULL) {
1178208538Sraj		sprintf(command_errbuf, "could not allocate space "
1179208538Sraj		    "for string");
1180208538Sraj		return (1);
1181208538Sraj	}
1182208538Sraj
1183208538Sraj	idx = 0;
1184208538Sraj	for (i = start, idx = 0; i < argc; i++) {
1185208538Sraj		strcpy(buf + idx, argv[i]);
1186208538Sraj		idx += strlen(argv[i]);
1187208538Sraj		buf[idx] = ' ';
1188208538Sraj		idx++;
1189208538Sraj	}
1190208538Sraj	buf[sz - 1] = '\0';
1191208538Sraj	*buffer = buf;
1192208538Sraj	return (0);
1193208538Sraj}
1194208538Sraj
1195208538Sraj/* Extract offset and name of node/property from a given path */
1196208538Srajstatic int
1197208538Srajfdt_extract_nameloc(char **pathp, char **namep, int *nodeoff)
1198208538Sraj{
1199208538Sraj	int o;
1200208538Sraj	char *path = *pathp, *name = NULL, *subpath = NULL;
1201208538Sraj
1202208538Sraj	subpath = strrchr(path, '/');
1203208538Sraj	if (subpath == NULL) {
1204208538Sraj		o = fdt_path_offset(fdtp, cwd);
1205208538Sraj		name = path;
1206208538Sraj		path = (char *)&cwd;
1207208538Sraj	} else {
1208208538Sraj		*subpath = '\0';
1209208538Sraj		if (strlen(path) == 0)
1210208538Sraj			path = cwd;
1211208538Sraj
1212208538Sraj		name = subpath + 1;
1213208538Sraj		o = fdt_path_offset(fdtp, path);
1214208538Sraj	}
1215208538Sraj
1216208538Sraj	if (strlen(name) == 0) {
1217208538Sraj		sprintf(command_errbuf, "name not specified");
1218208538Sraj		return (1);
1219208538Sraj	}
1220208538Sraj	if (o < 0) {
1221208538Sraj		sprintf(command_errbuf, "could not find node: '%s'", path);
1222208538Sraj		return (1);
1223208538Sraj	}
1224208538Sraj	*namep = name;
1225208538Sraj	*nodeoff = o;
1226208538Sraj	*pathp = path;
1227208538Sraj	return (0);
1228208538Sraj}
1229208538Sraj
1230208538Srajstatic int
1231208538Srajfdt_cmd_prop(int argc, char *argv[])
1232208538Sraj{
1233208538Sraj	char *path, *propname, *value;
1234208538Sraj	int o, next, depth, rv;
1235208538Sraj	uint32_t tag;
1236208538Sraj
1237208538Sraj	path = (argc > 2) ? argv[2] : NULL;
1238208538Sraj
1239208538Sraj	value = NULL;
1240208538Sraj
1241208538Sraj	if (argc > 3) {
1242208538Sraj		/* Merge property value strings into one */
1243208538Sraj		if (fdt_merge_strings(argc, argv, 3, &value) != 0)
1244208538Sraj			return (CMD_ERROR);
1245208538Sraj	} else
1246208538Sraj		value = NULL;
1247208538Sraj
1248208538Sraj	if (path == NULL)
1249208538Sraj		path = cwd;
1250208538Sraj
1251208538Sraj	rv = CMD_OK;
1252208538Sraj
1253208538Sraj	if (value) {
1254208538Sraj		/* If value is specified -- try to modify prop. */
1255208538Sraj		if (fdt_extract_nameloc(&path, &propname, &o) != 0)
1256208538Sraj			return (CMD_ERROR);
1257208538Sraj
1258208538Sraj		rv = fdt_modprop(o, propname, value, 0);
1259208538Sraj		if (rv)
1260208538Sraj			return (CMD_ERROR);
1261208538Sraj		return (CMD_OK);
1262208538Sraj
1263208538Sraj	}
1264208538Sraj	/* User wants to display properties */
1265208538Sraj	o = fdt_path_offset(fdtp, path);
1266208538Sraj
1267208538Sraj	if (o < 0) {
1268208538Sraj		sprintf(command_errbuf, "could not find node: '%s'", path);
1269208538Sraj		rv = CMD_ERROR;
1270208538Sraj		goto out;
1271208538Sraj	}
1272208538Sraj
1273208538Sraj	depth = 0;
1274208538Sraj	while (depth >= 0) {
1275208538Sraj		tag = fdt_next_tag(fdtp, o, &next);
1276208538Sraj		switch (tag) {
1277208538Sraj		case FDT_NOP:
1278208538Sraj			break;
1279208538Sraj		case FDT_PROP:
1280208538Sraj			if (depth > 1)
1281208538Sraj				/* Don't process properties of nested nodes */
1282208538Sraj				break;
1283208538Sraj
1284208538Sraj			if (fdt_prop(o) != 0) {
1285208538Sraj				sprintf(command_errbuf, "could not process "
1286208538Sraj				    "property");
1287208538Sraj				rv = CMD_ERROR;
1288208538Sraj				goto out;
1289208538Sraj			}
1290208538Sraj			break;
1291208538Sraj		case FDT_BEGIN_NODE:
1292208538Sraj			depth++;
1293208538Sraj			if (depth > FDT_MAX_DEPTH) {
1294208538Sraj				printf("warning: nesting too deep: %d\n",
1295208538Sraj				    depth);
1296208538Sraj				goto out;
1297208538Sraj			}
1298208538Sraj			break;
1299208538Sraj		case FDT_END_NODE:
1300208538Sraj			depth--;
1301208538Sraj			if (depth == 0)
1302208538Sraj				/*
1303208538Sraj				 * This is the end of our starting node, force
1304208538Sraj				 * the loop finish.
1305208538Sraj				 */
1306208538Sraj				depth--;
1307208538Sraj			break;
1308208538Sraj		}
1309208538Sraj		o = next;
1310208538Sraj	}
1311208538Srajout:
1312208538Sraj	return (rv);
1313208538Sraj}
1314208538Sraj
1315208538Srajstatic int
1316208538Srajfdt_cmd_mkprop(int argc, char *argv[])
1317208538Sraj{
1318208538Sraj	int o;
1319208538Sraj	char *path, *propname, *value;
1320208538Sraj
1321208538Sraj	path = (argc > 2) ? argv[2] : NULL;
1322208538Sraj
1323208538Sraj	value = NULL;
1324208538Sraj
1325208538Sraj	if (argc > 3) {
1326208538Sraj		/* Merge property value strings into one */
1327208538Sraj		if (fdt_merge_strings(argc, argv, 3, &value) != 0)
1328208538Sraj			return (CMD_ERROR);
1329208538Sraj	} else
1330208538Sraj		value = NULL;
1331208538Sraj
1332208538Sraj	if (fdt_extract_nameloc(&path, &propname, &o) != 0)
1333208538Sraj		return (CMD_ERROR);
1334208538Sraj
1335208538Sraj	if (fdt_modprop(o, propname, value, 1))
1336208538Sraj		return (CMD_ERROR);
1337208538Sraj
1338208538Sraj	return (CMD_OK);
1339208538Sraj}
1340208538Sraj
1341208538Srajstatic int
1342208538Srajfdt_cmd_rm(int argc, char *argv[])
1343208538Sraj{
1344208538Sraj	int o, rv;
1345208538Sraj	char *path = NULL, *propname;
1346208538Sraj
1347208538Sraj	if (argc > 2)
1348208538Sraj		path = argv[2];
1349208538Sraj	else {
1350208538Sraj		sprintf(command_errbuf, "no node/property name specified");
1351208538Sraj		return (CMD_ERROR);
1352208538Sraj	}
1353208538Sraj
1354208538Sraj	o = fdt_path_offset(fdtp, path);
1355208538Sraj	if (o < 0) {
1356208538Sraj		/* If node not found -- try to find & delete property */
1357208538Sraj		if (fdt_extract_nameloc(&path, &propname, &o) != 0)
1358208538Sraj			return (CMD_ERROR);
1359208538Sraj
1360208538Sraj		if ((rv = fdt_delprop(fdtp, o, propname)) != 0) {
1361208538Sraj			sprintf(command_errbuf, "could not delete"
1362208538Sraj			    "%s\n", (rv == -FDT_ERR_NOTFOUND) ?
1363208538Sraj			    "(property/node does not exist)" : "");
1364208538Sraj			return (CMD_ERROR);
1365208538Sraj
1366208538Sraj		} else
1367208538Sraj			return (CMD_OK);
1368208538Sraj	}
1369208538Sraj	/* If node exists -- remove node */
1370208538Sraj	rv = fdt_del_node(fdtp, o);
1371208538Sraj	if (rv) {
1372208538Sraj		sprintf(command_errbuf, "could not delete node");
1373208538Sraj		return (CMD_ERROR);
1374208538Sraj	}
1375208538Sraj	return (CMD_OK);
1376208538Sraj}
1377208538Sraj
1378208538Srajstatic int
1379208538Srajfdt_cmd_mknode(int argc, char *argv[])
1380208538Sraj{
1381208538Sraj	int o, rv;
1382208538Sraj	char *path = NULL, *nodename = NULL;
1383208538Sraj
1384208538Sraj	if (argc > 2)
1385208538Sraj		path = argv[2];
1386208538Sraj	else {
1387208538Sraj		sprintf(command_errbuf, "no node name specified");
1388208538Sraj		return (CMD_ERROR);
1389208538Sraj	}
1390208538Sraj
1391208538Sraj	if (fdt_extract_nameloc(&path, &nodename, &o) != 0)
1392208538Sraj		return (CMD_ERROR);
1393208538Sraj
1394208538Sraj	rv = fdt_add_subnode(fdtp, o, nodename);
1395208538Sraj
1396208538Sraj	if (rv < 0) {
1397233323Sraj		if (rv == -FDT_ERR_NOSPACE)
1398233323Sraj			sprintf(command_errbuf,
1399233323Sraj			    "Device tree blob is too small!\n");
1400233323Sraj		else
1401233323Sraj			sprintf(command_errbuf,
1402233323Sraj			    "Could not add node!\n");
1403208538Sraj		return (CMD_ERROR);
1404208538Sraj	}
1405208538Sraj	return (CMD_OK);
1406208538Sraj}
1407208538Sraj
1408208538Srajstatic int
1409208538Srajfdt_cmd_pwd(int argc, char *argv[])
1410208538Sraj{
1411233323Sraj	char line[FDT_CWD_LEN];
1412208538Sraj
1413208538Sraj	pager_open();
1414208538Sraj	sprintf(line, "%s\n", cwd);
1415208538Sraj	pager_output(line);
1416208538Sraj	pager_close();
1417208538Sraj	return (CMD_OK);
1418208538Sraj}
1419208538Sraj
1420208538Srajstatic int
1421208538Srajfdt_cmd_nyi(int argc, char *argv[])
1422208538Sraj{
1423208538Sraj
1424208538Sraj	printf("command not yet implemented\n");
1425208538Sraj	return (CMD_ERROR);
1426208538Sraj}
1427