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