xref: /openbsd/sys/dev/ofw/fdt.c (revision 76d0caae)
1 /*	$OpenBSD: fdt.c,v 1.27 2021/05/06 19:45:16 kettenis Exp $	*/
2 
3 /*
4  * Copyright (c) 2009 Dariusz Swiderski <sfires@sfires.net>
5  * Copyright (c) 2009 Mark Kettenis <kettenis@sfires.net>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <sys/types.h>
21 #include <sys/systm.h>
22 #include <sys/malloc.h>
23 
24 #include <dev/ofw/fdt.h>
25 #include <dev/ofw/openfirm.h>
26 
27 unsigned int fdt_check_head(void *);
28 char	*fdt_get_str(u_int32_t);
29 void	*skip_property(u_int32_t *);
30 void	*skip_props(u_int32_t *);
31 void	*skip_node_name(u_int32_t *);
32 void	*skip_node(void *);
33 void	*skip_nops(u_int32_t *);
34 void	*fdt_parent_node_recurse(void *, void *);
35 void	*fdt_find_phandle_recurse(void *, uint32_t);
36 int	 fdt_node_property_int(void *, char *, int *);
37 int	 fdt_node_property_ints(void *, char *, int *, int);
38 int	 fdt_translate_reg(void *, struct fdt_reg *);
39 #ifdef DEBUG
40 void 	 fdt_print_node_recurse(void *, int);
41 #endif
42 
43 static int tree_inited = 0;
44 static struct fdt tree;
45 
46 unsigned int
47 fdt_check_head(void *fdt)
48 {
49 	struct fdt_head *fh;
50 	u_int32_t *ptr, *tok;
51 
52 	fh = fdt;
53 	ptr = (u_int32_t *)fdt;
54 
55 	if (betoh32(fh->fh_magic) != FDT_MAGIC)
56 		return 0;
57 
58 	if (betoh32(fh->fh_version) > FDT_CODE_VERSION)
59 		return 0;
60 
61 	tok = skip_nops(ptr + (betoh32(fh->fh_struct_off) / 4));
62 	if (betoh32(*tok) != FDT_NODE_BEGIN)
63 		return 0;
64 
65 	/* check for end signature on version 17 blob */
66 	if ((betoh32(fh->fh_version) >= 17) &&
67 	    (betoh32(*(ptr + (betoh32(fh->fh_struct_off) / 4) +
68 	    (betoh32(fh->fh_struct_size) / 4) - 1)) != FDT_END))
69 		return 0;
70 
71 	return betoh32(fh->fh_version);
72 }
73 
74 /*
75  * Initializes internal structures of module.
76  * Has to be called once, preferably in machdep.c.
77  */
78 int
79 fdt_init(void *fdt)
80 {
81 	int version;
82 
83 	bzero(&tree, sizeof(struct fdt));
84 	tree_inited = 0;
85 
86 	if (!fdt)
87 		return 0;
88 
89 	if (!(version = fdt_check_head(fdt)))
90 		return 0;
91 
92 	tree.header = (struct fdt_head *)fdt;
93 	tree.tree = (char *)fdt + betoh32(tree.header->fh_struct_off);
94 	tree.strings = (char *)fdt + betoh32(tree.header->fh_strings_off);
95 	tree.memory = (char *)fdt + betoh32(tree.header->fh_reserve_off);
96 	tree.end = (char *)fdt + betoh32(tree.header->fh_size);
97 	tree.version = version;
98 	tree.strings_size = betoh32(tree.header->fh_strings_size);
99 	if (tree.version >= 17)
100 		tree.struct_size = betoh32(tree.header->fh_struct_size);
101 	tree_inited = 1;
102 
103 	return version;
104 }
105 
106 void
107 fdt_finalize(void)
108 {
109 	char *start = (char *)tree.header;
110 
111 	tree.header->fh_size = htobe32(tree.end - start);
112 	tree.header->fh_struct_off = htobe32(tree.tree - start);
113 	tree.header->fh_strings_off = htobe32(tree.strings - start);
114 	tree.header->fh_reserve_off = htobe32(tree.memory - start);
115 	tree.header->fh_strings_size = htobe32(tree.strings_size);
116 	if (tree.version >= 17)
117 		tree.header->fh_struct_size = htobe32(tree.struct_size);
118 }
119 
120 /*
121  * Return the size of the FDT.
122  */
123 size_t
124 fdt_get_size(void *fdt)
125 {
126 	if (!fdt)
127 		return 0;
128 
129 	if (!fdt_check_head(fdt))
130 		return 0;
131 
132 	return betoh32(((struct fdt_head *)fdt)->fh_size);
133 }
134 
135 /*
136  * Retrieve string pointer from strings table.
137  */
138 char *
139 fdt_get_str(u_int32_t num)
140 {
141 	if (num > tree.strings_size)
142 		return NULL;
143 	return (tree.strings) ? (tree.strings + num) : NULL;
144 }
145 
146 int
147 fdt_add_str(char *name)
148 {
149 	size_t len = roundup(strlen(name) + 1, sizeof(uint32_t));
150 	char *end = tree.strings + tree.strings_size;
151 
152 	memmove(end + len, end, tree.end - end);
153 	tree.strings_size += len;
154 	if (tree.tree > tree.strings)
155 		tree.tree += len;
156 	if (tree.memory > tree.strings)
157 		tree.memory += len;
158 	tree.end += len;
159 	memset(end, 0, len);
160 	memcpy(end, name, strlen(name));
161 
162 	return (end - tree.strings);
163 }
164 
165 /*
166  * Utility functions for skipping parts of tree.
167  */
168 
169 void *
170 skip_nops(u_int32_t *ptr)
171 {
172 	while (betoh32(*ptr) == FDT_NOP)
173 		ptr++;
174 
175 	return ptr;
176 }
177 
178 void *
179 skip_property(u_int32_t *ptr)
180 {
181 	u_int32_t size;
182 
183 	size = betoh32(*(ptr + 1));
184 	/* move forward by magic + size + nameid + rounded up property size */
185 	ptr += 3 + roundup(size, sizeof(u_int32_t)) / sizeof(u_int32_t);
186 
187 	return skip_nops(ptr);
188 }
189 
190 void *
191 skip_props(u_int32_t *ptr)
192 {
193 	while (betoh32(*ptr) == FDT_PROPERTY) {
194 		ptr = skip_property(ptr);
195 	}
196 	return ptr;
197 }
198 
199 void *
200 skip_node_name(u_int32_t *ptr)
201 {
202 	/* skip name, aligned to 4 bytes, this is NULL term., so must add 1 */
203 	ptr += roundup(strlen((char *)ptr) + 1,
204 	    sizeof(u_int32_t)) / sizeof(u_int32_t);
205 
206 	return skip_nops(ptr);
207 }
208 
209 /*
210  * Retrieves node property, the returned pointer is inside the fdt tree,
211  * so we should not modify content pointed by it directly.
212  */
213 int
214 fdt_node_property(void *node, char *name, char **out)
215 {
216 	u_int32_t *ptr;
217 	u_int32_t nameid;
218 	char *tmp;
219 
220 	if (!tree_inited)
221 		return -1;
222 
223 	ptr = (u_int32_t *)node;
224 
225 	if (betoh32(*ptr) != FDT_NODE_BEGIN)
226 		return -1;
227 
228 	ptr = skip_node_name(ptr + 1);
229 
230 	while (betoh32(*ptr) == FDT_PROPERTY) {
231 		nameid = betoh32(*(ptr + 2)); /* id of name in strings table */
232 		tmp = fdt_get_str(nameid);
233 		if (!strcmp(name, tmp)) {
234 			*out = (char *)(ptr + 3); /* beginning of the value */
235 			return betoh32(*(ptr + 1)); /* size of value */
236 		}
237 		ptr = skip_property(ptr);
238 	}
239 	return -1;
240 }
241 
242 int
243 fdt_node_set_property(void *node, char *name, void *data, int len)
244 {
245 	uint32_t *ptr, *next;
246 	uint32_t nameid;
247 	uint32_t curlen;
248 	size_t delta;
249 	char *tmp;
250 
251 	if (!tree_inited)
252 		return 0;
253 
254 	ptr = (uint32_t *)node;
255 
256 	if (betoh32(*ptr) != FDT_NODE_BEGIN)
257 		return 0;
258 
259 	ptr = skip_node_name(ptr + 1);
260 
261 	while (betoh32(*ptr) == FDT_PROPERTY) {
262 		nameid = betoh32(*(ptr + 2)); /* id of name in strings table */
263 		tmp = fdt_get_str(nameid);
264 		next = skip_property(ptr);
265 		if (!strcmp(name, tmp)) {
266 			curlen = betoh32(*(ptr + 1));
267 			delta = roundup(len, sizeof(uint32_t)) -
268 			    roundup(curlen, sizeof(uint32_t));
269 			memmove((char *)next + delta, next,
270 			    tree.end - (char *)next);
271 			tree.struct_size += delta;
272 			if (tree.strings > tree.tree)
273 				tree.strings += delta;
274 			if (tree.memory > tree.tree)
275 				tree.memory += delta;
276 			tree.end += delta;
277 			*(ptr + 1) = htobe32(len);
278 			memcpy(ptr + 3, data, len);
279 			return 1;
280 		}
281 		ptr = next;
282 	}
283 	return 0;
284 }
285 
286 int
287 fdt_node_add_property(void *node, char *name, void *data, int len)
288 {
289 	char *dummy;
290 
291 	if (!tree_inited)
292 		return 0;
293 
294 	if (fdt_node_property(node, name, &dummy) == -1) {
295 		uint32_t *ptr = (uint32_t *)node;
296 
297 		if (betoh32(*ptr) != FDT_NODE_BEGIN)
298 			return 0;
299 
300 		ptr = skip_node_name(ptr + 1);
301 
302 		memmove(ptr + 3, ptr, tree.end - (char *)ptr);
303 		tree.struct_size += 3 * sizeof(uint32_t);
304 		if (tree.strings > tree.tree)
305 			tree.strings += 3 * sizeof(uint32_t);
306 		if (tree.memory > tree.tree)
307 			tree.memory += 3 * sizeof(uint32_t);
308 		tree.end += 3 * sizeof(uint32_t);
309 		*ptr++ = htobe32(FDT_PROPERTY);
310 		*ptr++ = htobe32(0);
311 		*ptr++ = htobe32(fdt_add_str(name));
312 	}
313 
314 	return fdt_node_set_property(node, name, data, len);
315 }
316 
317 /*
318  * Retrieves next node, skipping all the children nodes of the pointed node,
319  * returns pointer to next node, no matter if it exists or not.
320  */
321 void *
322 skip_node(void *node)
323 {
324 	u_int32_t *ptr = node;
325 
326 	ptr++;
327 
328 	ptr = skip_node_name(ptr);
329 	ptr = skip_props(ptr);
330 
331 	/* skip children */
332 	while (betoh32(*ptr) == FDT_NODE_BEGIN)
333 		ptr = skip_node(ptr);
334 
335 	return skip_nops(ptr + 1);
336 }
337 
338 /*
339  * Retrieves next node, skipping all the children nodes of the pointed node,
340  * returns pointer to next node if exists, otherwise returns NULL.
341  * If passed 0 will return first node of the tree (root).
342  */
343 void *
344 fdt_next_node(void *node)
345 {
346 	u_int32_t *ptr;
347 
348 	if (!tree_inited)
349 		return NULL;
350 
351 	ptr = node;
352 
353 	if (node == NULL) {
354 		ptr = skip_nops((uint32_t *)tree.tree);
355 		return (betoh32(*ptr) == FDT_NODE_BEGIN) ? ptr : NULL;
356 	}
357 
358 	if (betoh32(*ptr) != FDT_NODE_BEGIN)
359 		return NULL;
360 
361 	ptr++;
362 
363 	ptr = skip_node_name(ptr);
364 	ptr = skip_props(ptr);
365 
366 	/* skip children */
367 	while (betoh32(*ptr) == FDT_NODE_BEGIN)
368 		ptr = skip_node(ptr);
369 
370 	if (betoh32(*ptr) != FDT_NODE_END)
371 		return NULL;
372 
373 	ptr = skip_nops(ptr + 1);
374 
375 	if (betoh32(*ptr) != FDT_NODE_BEGIN)
376 		return NULL;
377 
378 	return ptr;
379 }
380 
381 int
382 fdt_next_property(void *node, char *name, char **nextname)
383 {
384 	u_int32_t *ptr;
385 	u_int32_t nameid;
386 
387 	if (!tree_inited)
388 		return 0;
389 
390 	ptr = (u_int32_t *)node;
391 
392 	if (betoh32(*ptr) != FDT_NODE_BEGIN)
393 		return 0;
394 
395 	ptr = skip_node_name(ptr + 1);
396 
397 	while (betoh32(*ptr) == FDT_PROPERTY) {
398 		nameid = betoh32(*(ptr + 2)); /* id of name in strings table */
399 		if (strcmp(name, "") == 0) {
400 			*nextname = fdt_get_str(nameid);
401 			return 1;
402 		}
403 		if (strcmp(name, fdt_get_str(nameid)) == 0) {
404 			ptr = skip_property(ptr);
405 			if (betoh32(*ptr) != FDT_PROPERTY)
406 				break;
407 			nameid = betoh32(*(ptr + 2));
408 			*nextname = fdt_get_str(nameid);
409 			return 1;
410 		}
411 		ptr = skip_property(ptr);
412 	}
413 	*nextname = "";
414 	return 1;
415 }
416 
417 /*
418  * Retrieves node property as integers and puts them in the given
419  * integer array.
420  */
421 int
422 fdt_node_property_ints(void *node, char *name, int *out, int outlen)
423 {
424 	int *data;
425 	int i, inlen;
426 
427 	inlen = fdt_node_property(node, name, (char **)&data) / sizeof(int);
428 	if (inlen <= 0)
429 		return -1;
430 
431 	for (i = 0; i < inlen && i < outlen; i++)
432 		out[i] = betoh32(data[i]);
433 
434 	return i;
435 }
436 
437 /*
438  * Retrieves node property as an integer.
439  */
440 int
441 fdt_node_property_int(void *node, char *name, int *out)
442 {
443 	return fdt_node_property_ints(node, name, out, 1);
444 }
445 
446 /*
447  * Retrieves next node, skipping all the children nodes of the pointed node
448  */
449 void *
450 fdt_child_node(void *node)
451 {
452 	u_int32_t *ptr;
453 
454 	if (!tree_inited)
455 		return NULL;
456 
457 	ptr = node;
458 
459 	if (betoh32(*ptr) != FDT_NODE_BEGIN)
460 		return NULL;
461 
462 	ptr++;
463 
464 	ptr = skip_node_name(ptr);
465 	ptr = skip_props(ptr);
466 	/* check if there is a child node */
467 	return (betoh32(*ptr) == FDT_NODE_BEGIN) ? (ptr) : NULL;
468 }
469 
470 /*
471  * Retrieves node name.
472  */
473 char *
474 fdt_node_name(void *node)
475 {
476 	u_int32_t *ptr;
477 
478 	if (!tree_inited)
479 		return NULL;
480 
481 	ptr = node;
482 
483 	if (betoh32(*ptr) != FDT_NODE_BEGIN)
484 		return NULL;
485 
486 	return (char *)(ptr + 1);
487 }
488 
489 void *
490 fdt_find_node(char *name)
491 {
492 	void *node = fdt_next_node(0);
493 	const char *p = name;
494 
495 	if (!tree_inited)
496 		return NULL;
497 
498 	if (*p != '/')
499 		return NULL;
500 
501 	while (*p) {
502 		void *child;
503 		const char *q;
504 
505 		while (*p == '/')
506 			p++;
507 		if (*p == 0)
508 			return node;
509 		q = strchr(p, '/');
510 		if (q == NULL)
511 			q = p + strlen(p);
512 
513 		for (child = fdt_child_node(node); child;
514 		     child = fdt_next_node(child)) {
515 			if (strncmp(p, fdt_node_name(child), q - p) == 0) {
516 				node = child;
517 				break;
518 			}
519 		}
520 
521 		if (child == NULL)
522 			return NULL; /* No match found. */
523 
524 		p = q;
525 	}
526 
527 	return node;
528 }
529 
530 void *
531 fdt_parent_node_recurse(void *pnode, void *child)
532 {
533 	void *node = fdt_child_node(pnode);
534 	void *tmp;
535 
536 	while (node && (node != child)) {
537 		if ((tmp = fdt_parent_node_recurse(node, child)))
538 			return tmp;
539 		node = fdt_next_node(node);
540 	}
541 	return (node) ? pnode : NULL;
542 }
543 
544 void *
545 fdt_parent_node(void *node)
546 {
547 	void *pnode = fdt_next_node(0);
548 
549 	if (!tree_inited)
550 		return NULL;
551 
552 	if (node == pnode)
553 		return NULL;
554 
555 	return fdt_parent_node_recurse(pnode, node);
556 }
557 
558 void *
559 fdt_find_phandle_recurse(void *node, uint32_t phandle)
560 {
561 	void *child;
562 	char *data;
563 	void *tmp;
564 	int len;
565 
566 	len = fdt_node_property(node, "phandle", &data);
567 	if (len < 0)
568 		len = fdt_node_property(node, "linux,phandle", &data);
569 
570 	if (len == sizeof(uint32_t) && bemtoh32(data) == phandle)
571 		return node;
572 
573 	for (child = fdt_child_node(node); child; child = fdt_next_node(child))
574 		if ((tmp = fdt_find_phandle_recurse(child, phandle)))
575 			return tmp;
576 
577 	return NULL;
578 }
579 
580 void *
581 fdt_find_phandle(uint32_t phandle)
582 {
583 	return fdt_find_phandle_recurse(fdt_next_node(0), phandle);
584 }
585 
586 void
587 fdt_get_cells(void *node, int *ac, int *sc)
588 {
589 	void *parent;
590 
591 	parent = fdt_parent_node(node);
592 	if (parent == NULL)
593 		*ac = *sc = 1;
594 	else
595 		fdt_get_cells(parent, ac, sc);
596 
597 	fdt_node_property_int(node, "#address-cells", ac);
598 	fdt_node_property_int(node, "#size-cells", sc);
599 }
600 
601 /*
602  * Translate memory address depending on parent's range.
603  *
604  * Ranges are a way of mapping one address to another.  This ranges attribute
605  * is set on a node's parent.  This means if a node does not have a parent,
606  * there's nothing to translate.  If it does have a parent and the parent does
607  * not have a ranges attribute, there's nothing to translate either.
608  *
609  * If the parent has a ranges attribute and the attribute is not empty, the
610  * node's memory address has to be in one of the given ranges.  This range is
611  * then used to translate the memory address.
612  *
613  * If the parent has a ranges attribute, but the attribute is empty, there's
614  * nothing to translate.  But it's not a translation barrier.  It can be treated
615  * as a simple 1:1 mapping.
616  *
617  * Translation does not end here.  We need to check if the parent's parent also
618  * has a ranges attribute and ask the same questions again.
619  */
620 int
621 fdt_translate_reg(void *node, struct fdt_reg *reg)
622 {
623 	void *parent;
624 	int pac, psc, ac, sc, rlen, rone, *range;
625 	uint64_t from, to, size;
626 
627 	/* No parent, no translation. */
628 	parent = fdt_parent_node(node);
629 	if (parent == NULL)
630 		return 0;
631 
632 	/* Extract ranges property from node. */
633 	rlen = fdt_node_property(node, "ranges", (char **)&range) / sizeof(int);
634 
635 	/* No ranges means translation barrier. Translation stops here. */
636 	if (range == NULL)
637 		return 0;
638 
639 	/* Empty ranges means 1:1 mapping. Continue translation on parent. */
640 	if (rlen <= 0)
641 		return fdt_translate_reg(parent, reg);
642 
643 	/*
644 	 * Get parent address/size width.  We only support 32-bit (1)
645 	 * and 64-bit (2) wide addresses and sizes here.
646 	 */
647 	fdt_get_cells(parent, &pac, &psc);
648 	if (pac <= 0 || pac > 2 || psc <= 0 || psc > 2)
649 		return EINVAL;
650 
651 	/*
652 	 * Get our own address/size width.  Again, we only support
653 	 * 32-bit (1) and 64-bit (2) wide addresses and sizes here.
654 	 */
655 	fdt_get_cells(node, &ac, &sc);
656 	if (ac <= 0 || ac > 2 || sc <= 0 || sc > 2)
657 		return EINVAL;
658 
659 	/* Must have at least one range. */
660 	rone = pac + ac + sc;
661 	if (rlen < rone)
662 		return ESRCH;
663 
664 	/* For each range. */
665 	for (; rlen >= rone; rlen -= rone, range += rone) {
666 		/* Extract from and size, so we can see if we fit. */
667 		from = betoh32(range[0]);
668 		if (ac == 2)
669 			from = (from << 32) + betoh32(range[1]);
670 		size = betoh32(range[ac + pac]);
671 		if (sc == 2)
672 			size = (size << 32) + betoh32(range[ac + pac + 1]);
673 
674 		/* Try next, if we're not in the range. */
675 		if (reg->addr < from || (reg->addr + reg->size) > (from + size))
676 			continue;
677 
678 		/* All good, extract to address and translate. */
679 		to = betoh32(range[ac]);
680 		if (pac == 2)
681 			to = (to << 32) + betoh32(range[ac + 1]);
682 
683 		reg->addr -= from;
684 		reg->addr += to;
685 		return fdt_translate_reg(parent, reg);
686 	}
687 
688 	/* To be successful, we must have returned in the for-loop. */
689 	return ESRCH;
690 }
691 
692 /*
693  * Parse the memory address and size of a node.
694  */
695 int
696 fdt_get_reg(void *node, int idx, struct fdt_reg *reg)
697 {
698 	void *parent;
699 	int ac, sc, off, *in, inlen;
700 
701 	if (node == NULL || reg == NULL)
702 		return EINVAL;
703 
704 	parent = fdt_parent_node(node);
705 	if (parent == NULL)
706 		return EINVAL;
707 
708 	/*
709 	 * Get parent address/size width.  We only support 32-bit (1)
710 	 * and 64-bit (2) wide addresses and sizes here.
711 	 */
712 	fdt_get_cells(parent, &ac, &sc);
713 	if (ac <= 0 || ac > 2 || sc <= 0 || sc > 2)
714 		return EINVAL;
715 
716 	inlen = fdt_node_property(node, "reg", (char **)&in) / sizeof(int);
717 	if (inlen < ((idx + 1) * (ac + sc)))
718 		return EINVAL;
719 
720 	off = idx * (ac + sc);
721 
722 	reg->addr = betoh32(in[off]);
723 	if (ac == 2)
724 		reg->addr = (reg->addr << 32) + betoh32(in[off + 1]);
725 
726 	reg->size = betoh32(in[off + ac]);
727 	if (sc == 2)
728 		reg->size = (reg->size << 32) + betoh32(in[off + ac + 1]);
729 
730 	return fdt_translate_reg(parent, reg);
731 }
732 
733 int
734 fdt_is_compatible(void *node, const char *name)
735 {
736 	char *data;
737 	int len;
738 
739 	len = fdt_node_property(node, "compatible", &data);
740 	while (len > 0) {
741 		if (strcmp(data, name) == 0)
742 			return 1;
743 		len -= strlen(data) + 1;
744 		data += strlen(data) + 1;
745 	}
746 
747 	return 0;
748 }
749 
750 #ifdef DEBUG
751 /*
752  * Debug methods for printing whole tree, particular odes and properies
753  */
754 void *
755 fdt_print_property(void *node, int level)
756 {
757 	u_int32_t *ptr;
758 	char *tmp, *value;
759 	int cnt;
760 	u_int32_t nameid, size;
761 
762 	ptr = (u_int32_t *)node;
763 
764 	if (!tree_inited)
765 		return NULL;
766 
767 	if (betoh32(*ptr) != FDT_PROPERTY)
768 		return ptr; /* should never happen */
769 
770 	/* extract property name_id and size */
771 	size = betoh32(*++ptr);
772 	nameid = betoh32(*++ptr);
773 
774 	for (cnt = 0; cnt < level; cnt++)
775 		printf("\t");
776 
777 	tmp = fdt_get_str(nameid);
778 	printf("\t%s : ", tmp ? tmp : "NO_NAME");
779 
780 	ptr++;
781 	value = (char *)ptr;
782 
783 	if (!strcmp(tmp, "device_type") || !strcmp(tmp, "compatible") ||
784 	    !strcmp(tmp, "model") || !strcmp(tmp, "bootargs") ||
785 	    !strcmp(tmp, "linux,stdout-path")) {
786 		printf("%s", value);
787 	} else if (!strcmp(tmp, "clock-frequency") ||
788 	    !strcmp(tmp, "timebase-frequency")) {
789 		printf("%d", betoh32(*((unsigned int *)value)));
790 	} else {
791 		for (cnt = 0; cnt < size; cnt++) {
792 			if ((cnt % sizeof(u_int32_t)) == 0)
793 				printf(" ");
794 			printf("%02x", value[cnt]);
795 		}
796 	}
797 	ptr += roundup(size, sizeof(u_int32_t)) / sizeof(u_int32_t);
798 	printf("\n");
799 
800 	return ptr;
801 }
802 
803 void
804 fdt_print_node(void *node, int level)
805 {
806 	u_int32_t *ptr;
807 	int cnt;
808 
809 	ptr = (u_int32_t *)node;
810 
811 	if (betoh32(*ptr) != FDT_NODE_BEGIN)
812 		return;
813 
814 	ptr++;
815 
816 	for (cnt = 0; cnt < level; cnt++)
817 		printf("\t");
818 	printf("%s :\n", fdt_node_name(node));
819 	ptr = skip_node_name(ptr);
820 
821 	while (betoh32(*ptr) == FDT_PROPERTY)
822 		ptr = fdt_print_property(ptr, level);
823 }
824 
825 void
826 fdt_print_node_recurse(void *node, int level)
827 {
828 	void *child;
829 
830 	fdt_print_node(node, level);
831 	for (child = fdt_child_node(node); child; child = fdt_next_node(child))
832 		fdt_print_node_recurse(child, level + 1);
833 }
834 
835 void
836 fdt_print_tree(void)
837 {
838 	fdt_print_node_recurse(fdt_next_node(0), 0);
839 }
840 #endif
841 
842 int
843 OF_peer(int handle)
844 {
845 	void *node = (char *)tree.header + handle;
846 
847 	if (handle == 0)
848 		node = fdt_find_node("/");
849 	else
850 		node = fdt_next_node(node);
851 	return node ? ((char *)node - (char *)tree.header) : 0;
852 }
853 
854 int
855 OF_child(int handle)
856 {
857 	void *node = (char *)tree.header + handle;
858 
859 	node = fdt_child_node(node);
860 	return node ? ((char *)node - (char *)tree.header) : 0;
861 }
862 
863 int
864 OF_parent(int handle)
865 {
866 	void *node = (char *)tree.header + handle;
867 
868 	node = fdt_parent_node(node);
869 	return node ? ((char *)node - (char *)tree.header) : 0;
870 }
871 
872 int
873 OF_finddevice(char *name)
874 {
875 	void *node;
876 
877 	node = fdt_find_node(name);
878 	return node ? ((char *)node - (char *)tree.header) : -1;
879 }
880 
881 int
882 OF_getnodebyname(int handle, const char *name)
883 {
884 	void *node = (char *)tree.header + handle;
885 
886 	if (handle == 0)
887 		node = fdt_find_node("/");
888 
889 	for (node = fdt_child_node(node); node; node = fdt_next_node(node)) {
890 		if (strcmp(name, fdt_node_name(node)) == 0)
891 			break;
892 	}
893 
894 	return node ? ((char *)node - (char *)tree.header) : 0;
895 }
896 
897 int
898 OF_getnodebyphandle(uint32_t phandle)
899 {
900 	void *node;
901 
902 	node = fdt_find_phandle(phandle);
903 	return node ? ((char *)node - (char *)tree.header) : 0;
904 }
905 
906 int
907 OF_getproplen(int handle, char *prop)
908 {
909 	void *node = (char *)tree.header + handle;
910 	char *data, *name;
911 	int len;
912 
913 	len = fdt_node_property(node, prop, &data);
914 
915 	/*
916 	 * The "name" property is optional since version 16 of the
917 	 * flattened device tree specification, so we synthesize one
918 	 * from the unit name of the node if it is missing.
919 	 */
920 	if (len < 0 && strcmp(prop, "name") == 0) {
921 		name = fdt_node_name(node);
922 		data = strchr(name, '@');
923 		if (data)
924 			len = data - name;
925 		else
926 			len = strlen(name);
927 		return len + 1;
928 	}
929 
930 	return len;
931 }
932 
933 int
934 OF_getprop(int handle, char *prop, void *buf, int buflen)
935 {
936 	void *node = (char *)tree.header + handle;
937 	char *data;
938 	int len;
939 
940 	len = fdt_node_property(node, prop, &data);
941 
942 	/*
943 	 * The "name" property is optional since version 16 of the
944 	 * flattened device tree specification, so we synthesize one
945 	 * from the unit name of the node if it is missing.
946 	 */
947 	if (len < 0 && strcmp(prop, "name") == 0) {
948 		data = fdt_node_name(node);
949 		if (data) {
950 			len = strlcpy(buf, data, buflen);
951 			data = strchr(buf, '@');
952 			if (data) {
953 				*data = 0;
954 				len = data - (char *)buf;
955 			}
956 			return len + 1;
957 		}
958 	}
959 
960 	if (len > 0)
961 		memcpy(buf, data, min(len, buflen));
962 	return len;
963 }
964 
965 int
966 OF_getpropbool(int handle, char *prop)
967 {
968 	void *node = (char *)tree.header + handle;
969 	char *data;
970 
971 	return (fdt_node_property(node, prop, &data) >= 0);
972 }
973 
974 uint32_t
975 OF_getpropint(int handle, char *prop, uint32_t defval)
976 {
977 	uint32_t val;
978 	int len;
979 
980 	len = OF_getprop(handle, prop, &val, sizeof(val));
981 	if (len != sizeof(val))
982 		return defval;
983 
984 	return betoh32(val);
985 }
986 
987 int
988 OF_getpropintarray(int handle, char *prop, uint32_t *buf, int buflen)
989 {
990 	int len;
991 	int i;
992 
993 	len = OF_getprop(handle, prop, buf, buflen);
994 	if (len < 0 || (len % sizeof(uint32_t)))
995 		return -1;
996 
997 	for (i = 0; i < len / sizeof(uint32_t); i++)
998 		buf[i] = betoh32(buf[i]);
999 
1000 	return len;
1001 }
1002 
1003 uint64_t
1004 OF_getpropint64(int handle, char *prop, uint64_t defval)
1005 {
1006 	uint64_t val;
1007 	int len;
1008 
1009 	len = OF_getprop(handle, prop, &val, sizeof(val));
1010 	if (len != sizeof(val))
1011 		return defval;
1012 
1013 	return betoh64(val);
1014 }
1015 
1016 int
1017 OF_getpropint64array(int handle, char *prop, uint64_t *buf, int buflen)
1018 {
1019 	int len;
1020 	int i;
1021 
1022 	len = OF_getprop(handle, prop, buf, buflen);
1023 	if (len < 0 || (len % sizeof(uint64_t)))
1024 		return -1;
1025 
1026 	for (i = 0; i < len / sizeof(uint64_t); i++)
1027 		buf[i] = betoh64(buf[i]);
1028 
1029 	return len;
1030 }
1031 
1032 int
1033 OF_nextprop(int handle, char *prop, void *nextprop)
1034 {
1035 	void *node = (char *)tree.header + handle;
1036 	char *data;
1037 
1038 	if (fdt_node_property(node, "name", &data) == -1) {
1039 		if (strcmp(prop, "") == 0)
1040 			return strlcpy(nextprop, "name", OFMAXPARAM);
1041 		if (strcmp(prop, "name") == 0)
1042 			prop = "";
1043 	}
1044 
1045 	if (fdt_next_property(node, prop, &data))
1046 		return strlcpy(nextprop, data, OFMAXPARAM);
1047 	return -1;
1048 }
1049 
1050 int
1051 OF_is_compatible(int handle, const char *name)
1052 {
1053 	void *node = (char *)tree.header + handle;
1054 	return (fdt_is_compatible(node, name));
1055 }
1056 
1057 int
1058 OF_getindex(int handle, const char *entry, const char *prop)
1059 {
1060 	char *names;
1061 	char *name;
1062 	char *end;
1063 	int idx = 0;
1064 	int len;
1065 
1066 	if (entry == NULL)
1067 		return 0;
1068 
1069 	len = OF_getproplen(handle, (char *)prop);
1070 	if (len <= 0)
1071 		return -1;
1072 
1073 	names = malloc(len, M_TEMP, M_WAITOK);
1074 	OF_getprop(handle, (char *)prop, names, len);
1075 	end = names + len;
1076 	name = names;
1077 	while (name < end) {
1078 		if (strcmp(name, entry) == 0) {
1079 			free(names, M_TEMP, len);
1080 			return idx;
1081 		}
1082 		name += strlen(name) + 1;
1083 		idx++;
1084 	}
1085 	free(names, M_TEMP, len);
1086 	return -1;
1087 }
1088