xref: /netbsd-src/sys/external/bsd/libfdt/dist/fdt_ro.c (revision 5a485aa93ac82c3d325292e0224456d0b90f9a60)
1*5a485aa9Sskrll /*	$NetBSD: fdt_ro.c,v 1.1.1.3 2019/12/22 12:30:36 skrll Exp $	*/
2fc885a42Sskrll 
3*5a485aa9Sskrll // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
46233fbe7Smacallan /*
56233fbe7Smacallan  * libfdt - Flat Device Tree manipulation
66233fbe7Smacallan  * Copyright (C) 2006 David Gibson, IBM Corporation.
76233fbe7Smacallan  */
86233fbe7Smacallan #include "libfdt_env.h"
96233fbe7Smacallan 
106233fbe7Smacallan #include <fdt.h>
116233fbe7Smacallan #include <libfdt.h>
126233fbe7Smacallan 
136233fbe7Smacallan #include "libfdt_internal.h"
146233fbe7Smacallan 
fdt_nodename_eq_(const void * fdt,int offset,const char * s,int len)15*5a485aa9Sskrll static int fdt_nodename_eq_(const void *fdt, int offset,
166233fbe7Smacallan 			    const char *s, int len)
176233fbe7Smacallan {
18*5a485aa9Sskrll 	int olen;
19*5a485aa9Sskrll 	const char *p = fdt_get_name(fdt, offset, &olen);
206233fbe7Smacallan 
21*5a485aa9Sskrll 	if (!p || olen < len)
226233fbe7Smacallan 		/* short match */
236233fbe7Smacallan 		return 0;
246233fbe7Smacallan 
256233fbe7Smacallan 	if (memcmp(p, s, len) != 0)
266233fbe7Smacallan 		return 0;
276233fbe7Smacallan 
286233fbe7Smacallan 	if (p[len] == '\0')
296233fbe7Smacallan 		return 1;
306233fbe7Smacallan 	else if (!memchr(s, '@', len) && (p[len] == '@'))
316233fbe7Smacallan 		return 1;
326233fbe7Smacallan 	else
336233fbe7Smacallan 		return 0;
346233fbe7Smacallan }
356233fbe7Smacallan 
fdt_get_string(const void * fdt,int stroffset,int * lenp)36*5a485aa9Sskrll const char *fdt_get_string(const void *fdt, int stroffset, int *lenp)
37*5a485aa9Sskrll {
38*5a485aa9Sskrll 	int32_t totalsize = fdt_ro_probe_(fdt);
39*5a485aa9Sskrll 	uint32_t absoffset = stroffset + fdt_off_dt_strings(fdt);
40*5a485aa9Sskrll 	size_t len;
41*5a485aa9Sskrll 	int err;
42*5a485aa9Sskrll 	const char *s, *n;
43*5a485aa9Sskrll 
44*5a485aa9Sskrll 	err = totalsize;
45*5a485aa9Sskrll 	if (totalsize < 0)
46*5a485aa9Sskrll 		goto fail;
47*5a485aa9Sskrll 
48*5a485aa9Sskrll 	err = -FDT_ERR_BADOFFSET;
49*5a485aa9Sskrll 	if (absoffset >= totalsize)
50*5a485aa9Sskrll 		goto fail;
51*5a485aa9Sskrll 	len = totalsize - absoffset;
52*5a485aa9Sskrll 
53*5a485aa9Sskrll 	if (fdt_magic(fdt) == FDT_MAGIC) {
54*5a485aa9Sskrll 		if (stroffset < 0)
55*5a485aa9Sskrll 			goto fail;
56*5a485aa9Sskrll 		if (fdt_version(fdt) >= 17) {
57*5a485aa9Sskrll 			if (stroffset >= fdt_size_dt_strings(fdt))
58*5a485aa9Sskrll 				goto fail;
59*5a485aa9Sskrll 			if ((fdt_size_dt_strings(fdt) - stroffset) < len)
60*5a485aa9Sskrll 				len = fdt_size_dt_strings(fdt) - stroffset;
61*5a485aa9Sskrll 		}
62*5a485aa9Sskrll 	} else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
63*5a485aa9Sskrll 		if ((stroffset >= 0)
64*5a485aa9Sskrll 		    || (stroffset < -fdt_size_dt_strings(fdt)))
65*5a485aa9Sskrll 			goto fail;
66*5a485aa9Sskrll 		if ((-stroffset) < len)
67*5a485aa9Sskrll 			len = -stroffset;
68*5a485aa9Sskrll 	} else {
69*5a485aa9Sskrll 		err = -FDT_ERR_INTERNAL;
70*5a485aa9Sskrll 		goto fail;
71*5a485aa9Sskrll 	}
72*5a485aa9Sskrll 
73*5a485aa9Sskrll 	s = (const char *)fdt + absoffset;
74*5a485aa9Sskrll 	n = memchr(s, '\0', len);
75*5a485aa9Sskrll 	if (!n) {
76*5a485aa9Sskrll 		/* missing terminating NULL */
77*5a485aa9Sskrll 		err = -FDT_ERR_TRUNCATED;
78*5a485aa9Sskrll 		goto fail;
79*5a485aa9Sskrll 	}
80*5a485aa9Sskrll 
81*5a485aa9Sskrll 	if (lenp)
82*5a485aa9Sskrll 		*lenp = n - s;
83*5a485aa9Sskrll 	return s;
84*5a485aa9Sskrll 
85*5a485aa9Sskrll fail:
86*5a485aa9Sskrll 	if (lenp)
87*5a485aa9Sskrll 		*lenp = err;
88*5a485aa9Sskrll 	return NULL;
89*5a485aa9Sskrll }
90*5a485aa9Sskrll 
fdt_string(const void * fdt,int stroffset)916233fbe7Smacallan const char *fdt_string(const void *fdt, int stroffset)
926233fbe7Smacallan {
93*5a485aa9Sskrll 	return fdt_get_string(fdt, stroffset, NULL);
946233fbe7Smacallan }
956233fbe7Smacallan 
fdt_string_eq_(const void * fdt,int stroffset,const char * s,int len)96*5a485aa9Sskrll static int fdt_string_eq_(const void *fdt, int stroffset,
976233fbe7Smacallan 			  const char *s, int len)
986233fbe7Smacallan {
99*5a485aa9Sskrll 	int slen;
100*5a485aa9Sskrll 	const char *p = fdt_get_string(fdt, stroffset, &slen);
1016233fbe7Smacallan 
102*5a485aa9Sskrll 	return p && (slen == len) && (memcmp(p, s, len) == 0);
1036233fbe7Smacallan }
1046233fbe7Smacallan 
fdt_find_max_phandle(const void * fdt,uint32_t * phandle)105*5a485aa9Sskrll int fdt_find_max_phandle(const void *fdt, uint32_t *phandle)
106fc885a42Sskrll {
107*5a485aa9Sskrll 	uint32_t max = 0;
108*5a485aa9Sskrll 	int offset = -1;
109fc885a42Sskrll 
110*5a485aa9Sskrll 	while (true) {
111*5a485aa9Sskrll 		uint32_t value;
112fc885a42Sskrll 
113*5a485aa9Sskrll 		offset = fdt_next_node(fdt, offset, NULL);
114*5a485aa9Sskrll 		if (offset < 0) {
115fc885a42Sskrll 			if (offset == -FDT_ERR_NOTFOUND)
116*5a485aa9Sskrll 				break;
117fc885a42Sskrll 
118*5a485aa9Sskrll 			return offset;
119fc885a42Sskrll 		}
120fc885a42Sskrll 
121*5a485aa9Sskrll 		value = fdt_get_phandle(fdt, offset);
122*5a485aa9Sskrll 
123*5a485aa9Sskrll 		if (value > max)
124*5a485aa9Sskrll 			max = value;
125*5a485aa9Sskrll 	}
126*5a485aa9Sskrll 
127*5a485aa9Sskrll 	if (phandle)
128*5a485aa9Sskrll 		*phandle = max;
129*5a485aa9Sskrll 
130fc885a42Sskrll 	return 0;
131fc885a42Sskrll }
132fc885a42Sskrll 
fdt_generate_phandle(const void * fdt,uint32_t * phandle)133*5a485aa9Sskrll int fdt_generate_phandle(const void *fdt, uint32_t *phandle)
134*5a485aa9Sskrll {
135*5a485aa9Sskrll 	uint32_t max;
136*5a485aa9Sskrll 	int err;
137*5a485aa9Sskrll 
138*5a485aa9Sskrll 	err = fdt_find_max_phandle(fdt, &max);
139*5a485aa9Sskrll 	if (err < 0)
140*5a485aa9Sskrll 		return err;
141*5a485aa9Sskrll 
142*5a485aa9Sskrll 	if (max == FDT_MAX_PHANDLE)
143*5a485aa9Sskrll 		return -FDT_ERR_NOPHANDLES;
144*5a485aa9Sskrll 
145*5a485aa9Sskrll 	if (phandle)
146*5a485aa9Sskrll 		*phandle = max + 1;
147*5a485aa9Sskrll 
148*5a485aa9Sskrll 	return 0;
149*5a485aa9Sskrll }
150*5a485aa9Sskrll 
fdt_mem_rsv(const void * fdt,int n)151*5a485aa9Sskrll static const struct fdt_reserve_entry *fdt_mem_rsv(const void *fdt, int n)
152*5a485aa9Sskrll {
153*5a485aa9Sskrll 	int offset = n * sizeof(struct fdt_reserve_entry);
154*5a485aa9Sskrll 	int absoffset = fdt_off_mem_rsvmap(fdt) + offset;
155*5a485aa9Sskrll 
156*5a485aa9Sskrll 	if (absoffset < fdt_off_mem_rsvmap(fdt))
157*5a485aa9Sskrll 		return NULL;
158*5a485aa9Sskrll 	if (absoffset > fdt_totalsize(fdt) - sizeof(struct fdt_reserve_entry))
159*5a485aa9Sskrll 		return NULL;
160*5a485aa9Sskrll 	return fdt_mem_rsv_(fdt, n);
161*5a485aa9Sskrll }
162*5a485aa9Sskrll 
fdt_get_mem_rsv(const void * fdt,int n,uint64_t * address,uint64_t * size)1636233fbe7Smacallan int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
1646233fbe7Smacallan {
165*5a485aa9Sskrll 	const struct fdt_reserve_entry *re;
166*5a485aa9Sskrll 
167*5a485aa9Sskrll 	FDT_RO_PROBE(fdt);
168*5a485aa9Sskrll 	re = fdt_mem_rsv(fdt, n);
169*5a485aa9Sskrll 	if (!re)
170*5a485aa9Sskrll 		return -FDT_ERR_BADOFFSET;
171*5a485aa9Sskrll 
172*5a485aa9Sskrll 	*address = fdt64_ld(&re->address);
173*5a485aa9Sskrll 	*size = fdt64_ld(&re->size);
1746233fbe7Smacallan 	return 0;
1756233fbe7Smacallan }
1766233fbe7Smacallan 
fdt_num_mem_rsv(const void * fdt)1776233fbe7Smacallan int fdt_num_mem_rsv(const void *fdt)
1786233fbe7Smacallan {
179*5a485aa9Sskrll 	int i;
180*5a485aa9Sskrll 	const struct fdt_reserve_entry *re;
1816233fbe7Smacallan 
182*5a485aa9Sskrll 	for (i = 0; (re = fdt_mem_rsv(fdt, i)) != NULL; i++) {
183*5a485aa9Sskrll 		if (fdt64_ld(&re->size) == 0)
1846233fbe7Smacallan 			return i;
1856233fbe7Smacallan 	}
186*5a485aa9Sskrll 	return -FDT_ERR_TRUNCATED;
187*5a485aa9Sskrll }
1886233fbe7Smacallan 
nextprop_(const void * fdt,int offset)189*5a485aa9Sskrll static int nextprop_(const void *fdt, int offset)
1906233fbe7Smacallan {
1916233fbe7Smacallan 	uint32_t tag;
1926233fbe7Smacallan 	int nextoffset;
1936233fbe7Smacallan 
1946233fbe7Smacallan 	do {
1956233fbe7Smacallan 		tag = fdt_next_tag(fdt, offset, &nextoffset);
1966233fbe7Smacallan 
1976233fbe7Smacallan 		switch (tag) {
1986233fbe7Smacallan 		case FDT_END:
1996233fbe7Smacallan 			if (nextoffset >= 0)
2006233fbe7Smacallan 				return -FDT_ERR_BADSTRUCTURE;
2016233fbe7Smacallan 			else
2026233fbe7Smacallan 				return nextoffset;
2036233fbe7Smacallan 
2046233fbe7Smacallan 		case FDT_PROP:
2056233fbe7Smacallan 			return offset;
2066233fbe7Smacallan 		}
2076233fbe7Smacallan 		offset = nextoffset;
2086233fbe7Smacallan 	} while (tag == FDT_NOP);
2096233fbe7Smacallan 
2106233fbe7Smacallan 	return -FDT_ERR_NOTFOUND;
2116233fbe7Smacallan }
2126233fbe7Smacallan 
fdt_subnode_offset_namelen(const void * fdt,int offset,const char * name,int namelen)2136233fbe7Smacallan int fdt_subnode_offset_namelen(const void *fdt, int offset,
2146233fbe7Smacallan 			       const char *name, int namelen)
2156233fbe7Smacallan {
2166233fbe7Smacallan 	int depth;
2176233fbe7Smacallan 
218*5a485aa9Sskrll 	FDT_RO_PROBE(fdt);
2196233fbe7Smacallan 
2206233fbe7Smacallan 	for (depth = 0;
2216233fbe7Smacallan 	     (offset >= 0) && (depth >= 0);
2226233fbe7Smacallan 	     offset = fdt_next_node(fdt, offset, &depth))
2236233fbe7Smacallan 		if ((depth == 1)
224*5a485aa9Sskrll 		    && fdt_nodename_eq_(fdt, offset, name, namelen))
2256233fbe7Smacallan 			return offset;
2266233fbe7Smacallan 
2276233fbe7Smacallan 	if (depth < 0)
2286233fbe7Smacallan 		return -FDT_ERR_NOTFOUND;
2296233fbe7Smacallan 	return offset; /* error */
2306233fbe7Smacallan }
2316233fbe7Smacallan 
fdt_subnode_offset(const void * fdt,int parentoffset,const char * name)2326233fbe7Smacallan int fdt_subnode_offset(const void *fdt, int parentoffset,
2336233fbe7Smacallan 		       const char *name)
2346233fbe7Smacallan {
2356233fbe7Smacallan 	return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name));
2366233fbe7Smacallan }
2376233fbe7Smacallan 
fdt_path_offset_namelen(const void * fdt,const char * path,int namelen)2386233fbe7Smacallan int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen)
2396233fbe7Smacallan {
2406233fbe7Smacallan 	const char *end = path + namelen;
2416233fbe7Smacallan 	const char *p = path;
2426233fbe7Smacallan 	int offset = 0;
2436233fbe7Smacallan 
244*5a485aa9Sskrll 	FDT_RO_PROBE(fdt);
2456233fbe7Smacallan 
2466233fbe7Smacallan 	/* see if we have an alias */
2476233fbe7Smacallan 	if (*path != '/') {
2486233fbe7Smacallan 		const char *q = memchr(path, '/', end - p);
2496233fbe7Smacallan 
2506233fbe7Smacallan 		if (!q)
2516233fbe7Smacallan 			q = end;
2526233fbe7Smacallan 
2536233fbe7Smacallan 		p = fdt_get_alias_namelen(fdt, p, q - p);
2546233fbe7Smacallan 		if (!p)
2556233fbe7Smacallan 			return -FDT_ERR_BADPATH;
2566233fbe7Smacallan 		offset = fdt_path_offset(fdt, p);
2576233fbe7Smacallan 
2586233fbe7Smacallan 		p = q;
2596233fbe7Smacallan 	}
2606233fbe7Smacallan 
2616233fbe7Smacallan 	while (p < end) {
2626233fbe7Smacallan 		const char *q;
2636233fbe7Smacallan 
2646233fbe7Smacallan 		while (*p == '/') {
2656233fbe7Smacallan 			p++;
2666233fbe7Smacallan 			if (p == end)
2676233fbe7Smacallan 				return offset;
2686233fbe7Smacallan 		}
2696233fbe7Smacallan 		q = memchr(p, '/', end - p);
2706233fbe7Smacallan 		if (! q)
2716233fbe7Smacallan 			q = end;
2726233fbe7Smacallan 
2736233fbe7Smacallan 		offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p);
2746233fbe7Smacallan 		if (offset < 0)
2756233fbe7Smacallan 			return offset;
2766233fbe7Smacallan 
2776233fbe7Smacallan 		p = q;
2786233fbe7Smacallan 	}
2796233fbe7Smacallan 
2806233fbe7Smacallan 	return offset;
2816233fbe7Smacallan }
2826233fbe7Smacallan 
fdt_path_offset(const void * fdt,const char * path)2836233fbe7Smacallan int fdt_path_offset(const void *fdt, const char *path)
2846233fbe7Smacallan {
2856233fbe7Smacallan 	return fdt_path_offset_namelen(fdt, path, strlen(path));
2866233fbe7Smacallan }
2876233fbe7Smacallan 
fdt_get_name(const void * fdt,int nodeoffset,int * len)2886233fbe7Smacallan const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
2896233fbe7Smacallan {
290*5a485aa9Sskrll 	const struct fdt_node_header *nh = fdt_offset_ptr_(fdt, nodeoffset);
291*5a485aa9Sskrll 	const char *nameptr;
2926233fbe7Smacallan 	int err;
2936233fbe7Smacallan 
294*5a485aa9Sskrll 	if (((err = fdt_ro_probe_(fdt)) < 0)
295*5a485aa9Sskrll 	    || ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0))
2966233fbe7Smacallan 			goto fail;
2976233fbe7Smacallan 
298*5a485aa9Sskrll 	nameptr = nh->name;
2996233fbe7Smacallan 
300*5a485aa9Sskrll 	if (fdt_version(fdt) < 0x10) {
301*5a485aa9Sskrll 		/*
302*5a485aa9Sskrll 		 * For old FDT versions, match the naming conventions of V16:
303*5a485aa9Sskrll 		 * give only the leaf name (after all /). The actual tree
304*5a485aa9Sskrll 		 * contents are loosely checked.
305*5a485aa9Sskrll 		 */
306*5a485aa9Sskrll 		const char *leaf;
307*5a485aa9Sskrll 		leaf = strrchr(nameptr, '/');
308*5a485aa9Sskrll 		if (leaf == NULL) {
309*5a485aa9Sskrll 			err = -FDT_ERR_BADSTRUCTURE;
310*5a485aa9Sskrll 			goto fail;
311*5a485aa9Sskrll 		}
312*5a485aa9Sskrll 		nameptr = leaf+1;
313*5a485aa9Sskrll 	}
314*5a485aa9Sskrll 
315*5a485aa9Sskrll 	if (len)
316*5a485aa9Sskrll 		*len = strlen(nameptr);
317*5a485aa9Sskrll 
318*5a485aa9Sskrll 	return nameptr;
3196233fbe7Smacallan 
3206233fbe7Smacallan  fail:
3216233fbe7Smacallan 	if (len)
3226233fbe7Smacallan 		*len = err;
3236233fbe7Smacallan 	return NULL;
3246233fbe7Smacallan }
3256233fbe7Smacallan 
fdt_first_property_offset(const void * fdt,int nodeoffset)3266233fbe7Smacallan int fdt_first_property_offset(const void *fdt, int nodeoffset)
3276233fbe7Smacallan {
3286233fbe7Smacallan 	int offset;
3296233fbe7Smacallan 
330*5a485aa9Sskrll 	if ((offset = fdt_check_node_offset_(fdt, nodeoffset)) < 0)
3316233fbe7Smacallan 		return offset;
3326233fbe7Smacallan 
333*5a485aa9Sskrll 	return nextprop_(fdt, offset);
3346233fbe7Smacallan }
3356233fbe7Smacallan 
fdt_next_property_offset(const void * fdt,int offset)3366233fbe7Smacallan int fdt_next_property_offset(const void *fdt, int offset)
3376233fbe7Smacallan {
338*5a485aa9Sskrll 	if ((offset = fdt_check_prop_offset_(fdt, offset)) < 0)
3396233fbe7Smacallan 		return offset;
3406233fbe7Smacallan 
341*5a485aa9Sskrll 	return nextprop_(fdt, offset);
3426233fbe7Smacallan }
3436233fbe7Smacallan 
fdt_get_property_by_offset_(const void * fdt,int offset,int * lenp)344*5a485aa9Sskrll static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt,
3456233fbe7Smacallan 						              int offset,
3466233fbe7Smacallan 						              int *lenp)
3476233fbe7Smacallan {
3486233fbe7Smacallan 	int err;
3496233fbe7Smacallan 	const struct fdt_property *prop;
3506233fbe7Smacallan 
351*5a485aa9Sskrll 	if ((err = fdt_check_prop_offset_(fdt, offset)) < 0) {
3526233fbe7Smacallan 		if (lenp)
3536233fbe7Smacallan 			*lenp = err;
3546233fbe7Smacallan 		return NULL;
3556233fbe7Smacallan 	}
3566233fbe7Smacallan 
357*5a485aa9Sskrll 	prop = fdt_offset_ptr_(fdt, offset);
3586233fbe7Smacallan 
3596233fbe7Smacallan 	if (lenp)
360*5a485aa9Sskrll 		*lenp = fdt32_ld(&prop->len);
3616233fbe7Smacallan 
3626233fbe7Smacallan 	return prop;
3636233fbe7Smacallan }
3646233fbe7Smacallan 
fdt_get_property_by_offset(const void * fdt,int offset,int * lenp)365*5a485aa9Sskrll const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
366*5a485aa9Sskrll 						      int offset,
367*5a485aa9Sskrll 						      int *lenp)
368*5a485aa9Sskrll {
369*5a485aa9Sskrll 	/* Prior to version 16, properties may need realignment
370*5a485aa9Sskrll 	 * and this API does not work. fdt_getprop_*() will, however. */
371*5a485aa9Sskrll 
372*5a485aa9Sskrll 	if (fdt_version(fdt) < 0x10) {
373*5a485aa9Sskrll 		if (lenp)
374*5a485aa9Sskrll 			*lenp = -FDT_ERR_BADVERSION;
375*5a485aa9Sskrll 		return NULL;
376*5a485aa9Sskrll 	}
377*5a485aa9Sskrll 
378*5a485aa9Sskrll 	return fdt_get_property_by_offset_(fdt, offset, lenp);
379*5a485aa9Sskrll }
380*5a485aa9Sskrll 
fdt_get_property_namelen_(const void * fdt,int offset,const char * name,int namelen,int * lenp,int * poffset)381*5a485aa9Sskrll static const struct fdt_property *fdt_get_property_namelen_(const void *fdt,
3826233fbe7Smacallan 						            int offset,
3836233fbe7Smacallan 						            const char *name,
384*5a485aa9Sskrll 						            int namelen,
385*5a485aa9Sskrll 							    int *lenp,
386*5a485aa9Sskrll 							    int *poffset)
3876233fbe7Smacallan {
3886233fbe7Smacallan 	for (offset = fdt_first_property_offset(fdt, offset);
3896233fbe7Smacallan 	     (offset >= 0);
3906233fbe7Smacallan 	     (offset = fdt_next_property_offset(fdt, offset))) {
3916233fbe7Smacallan 		const struct fdt_property *prop;
3926233fbe7Smacallan 
393*5a485aa9Sskrll 		if (!(prop = fdt_get_property_by_offset_(fdt, offset, lenp))) {
3946233fbe7Smacallan 			offset = -FDT_ERR_INTERNAL;
3956233fbe7Smacallan 			break;
3966233fbe7Smacallan 		}
397*5a485aa9Sskrll 		if (fdt_string_eq_(fdt, fdt32_ld(&prop->nameoff),
398*5a485aa9Sskrll 				   name, namelen)) {
399*5a485aa9Sskrll 			if (poffset)
400*5a485aa9Sskrll 				*poffset = offset;
4016233fbe7Smacallan 			return prop;
4026233fbe7Smacallan 		}
403*5a485aa9Sskrll 	}
4046233fbe7Smacallan 
4056233fbe7Smacallan 	if (lenp)
4066233fbe7Smacallan 		*lenp = offset;
4076233fbe7Smacallan 	return NULL;
4086233fbe7Smacallan }
4096233fbe7Smacallan 
410*5a485aa9Sskrll 
fdt_get_property_namelen(const void * fdt,int offset,const char * name,int namelen,int * lenp)411*5a485aa9Sskrll const struct fdt_property *fdt_get_property_namelen(const void *fdt,
412*5a485aa9Sskrll 						    int offset,
413*5a485aa9Sskrll 						    const char *name,
414*5a485aa9Sskrll 						    int namelen, int *lenp)
415*5a485aa9Sskrll {
416*5a485aa9Sskrll 	/* Prior to version 16, properties may need realignment
417*5a485aa9Sskrll 	 * and this API does not work. fdt_getprop_*() will, however. */
418*5a485aa9Sskrll 	if (fdt_version(fdt) < 0x10) {
419*5a485aa9Sskrll 		if (lenp)
420*5a485aa9Sskrll 			*lenp = -FDT_ERR_BADVERSION;
421*5a485aa9Sskrll 		return NULL;
422*5a485aa9Sskrll 	}
423*5a485aa9Sskrll 
424*5a485aa9Sskrll 	return fdt_get_property_namelen_(fdt, offset, name, namelen, lenp,
425*5a485aa9Sskrll 					 NULL);
426*5a485aa9Sskrll }
427*5a485aa9Sskrll 
428*5a485aa9Sskrll 
fdt_get_property(const void * fdt,int nodeoffset,const char * name,int * lenp)4296233fbe7Smacallan const struct fdt_property *fdt_get_property(const void *fdt,
4306233fbe7Smacallan 					    int nodeoffset,
4316233fbe7Smacallan 					    const char *name, int *lenp)
4326233fbe7Smacallan {
4336233fbe7Smacallan 	return fdt_get_property_namelen(fdt, nodeoffset, name,
4346233fbe7Smacallan 					strlen(name), lenp);
4356233fbe7Smacallan }
4366233fbe7Smacallan 
fdt_getprop_namelen(const void * fdt,int nodeoffset,const char * name,int namelen,int * lenp)4376233fbe7Smacallan const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
4386233fbe7Smacallan 				const char *name, int namelen, int *lenp)
4396233fbe7Smacallan {
440*5a485aa9Sskrll 	int poffset;
4416233fbe7Smacallan 	const struct fdt_property *prop;
4426233fbe7Smacallan 
443*5a485aa9Sskrll 	prop = fdt_get_property_namelen_(fdt, nodeoffset, name, namelen, lenp,
444*5a485aa9Sskrll 					 &poffset);
4456233fbe7Smacallan 	if (!prop)
4466233fbe7Smacallan 		return NULL;
4476233fbe7Smacallan 
448*5a485aa9Sskrll 	/* Handle realignment */
449*5a485aa9Sskrll 	if (fdt_version(fdt) < 0x10 && (poffset + sizeof(*prop)) % 8 &&
450*5a485aa9Sskrll 	    fdt32_ld(&prop->len) >= 8)
451*5a485aa9Sskrll 		return prop->data + 4;
4526233fbe7Smacallan 	return prop->data;
4536233fbe7Smacallan }
4546233fbe7Smacallan 
fdt_getprop_by_offset(const void * fdt,int offset,const char ** namep,int * lenp)4556233fbe7Smacallan const void *fdt_getprop_by_offset(const void *fdt, int offset,
4566233fbe7Smacallan 				  const char **namep, int *lenp)
4576233fbe7Smacallan {
4586233fbe7Smacallan 	const struct fdt_property *prop;
4596233fbe7Smacallan 
460*5a485aa9Sskrll 	prop = fdt_get_property_by_offset_(fdt, offset, lenp);
4616233fbe7Smacallan 	if (!prop)
4626233fbe7Smacallan 		return NULL;
463*5a485aa9Sskrll 	if (namep) {
464*5a485aa9Sskrll 		const char *name;
465*5a485aa9Sskrll 		int namelen;
466*5a485aa9Sskrll 		name = fdt_get_string(fdt, fdt32_ld(&prop->nameoff),
467*5a485aa9Sskrll 				      &namelen);
468*5a485aa9Sskrll 		if (!name) {
469*5a485aa9Sskrll 			if (lenp)
470*5a485aa9Sskrll 				*lenp = namelen;
471*5a485aa9Sskrll 			return NULL;
472*5a485aa9Sskrll 		}
473*5a485aa9Sskrll 		*namep = name;
474*5a485aa9Sskrll 	}
475*5a485aa9Sskrll 
476*5a485aa9Sskrll 	/* Handle realignment */
477*5a485aa9Sskrll 	if (fdt_version(fdt) < 0x10 && (offset + sizeof(*prop)) % 8 &&
478*5a485aa9Sskrll 	    fdt32_ld(&prop->len) >= 8)
479*5a485aa9Sskrll 		return prop->data + 4;
4806233fbe7Smacallan 	return prop->data;
4816233fbe7Smacallan }
4826233fbe7Smacallan 
fdt_getprop(const void * fdt,int nodeoffset,const char * name,int * lenp)4836233fbe7Smacallan const void *fdt_getprop(const void *fdt, int nodeoffset,
4846233fbe7Smacallan 			const char *name, int *lenp)
4856233fbe7Smacallan {
4866233fbe7Smacallan 	return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp);
4876233fbe7Smacallan }
4886233fbe7Smacallan 
fdt_get_phandle(const void * fdt,int nodeoffset)4896233fbe7Smacallan uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
4906233fbe7Smacallan {
4916233fbe7Smacallan 	const fdt32_t *php;
4926233fbe7Smacallan 	int len;
4936233fbe7Smacallan 
4946233fbe7Smacallan 	/* FIXME: This is a bit sub-optimal, since we potentially scan
4956233fbe7Smacallan 	 * over all the properties twice. */
4966233fbe7Smacallan 	php = fdt_getprop(fdt, nodeoffset, "phandle", &len);
4976233fbe7Smacallan 	if (!php || (len != sizeof(*php))) {
4986233fbe7Smacallan 		php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len);
4996233fbe7Smacallan 		if (!php || (len != sizeof(*php)))
5006233fbe7Smacallan 			return 0;
5016233fbe7Smacallan 	}
5026233fbe7Smacallan 
503*5a485aa9Sskrll 	return fdt32_ld(php);
5046233fbe7Smacallan }
5056233fbe7Smacallan 
fdt_get_alias_namelen(const void * fdt,const char * name,int namelen)5066233fbe7Smacallan const char *fdt_get_alias_namelen(const void *fdt,
5076233fbe7Smacallan 				  const char *name, int namelen)
5086233fbe7Smacallan {
5096233fbe7Smacallan 	int aliasoffset;
5106233fbe7Smacallan 
5116233fbe7Smacallan 	aliasoffset = fdt_path_offset(fdt, "/aliases");
5126233fbe7Smacallan 	if (aliasoffset < 0)
5136233fbe7Smacallan 		return NULL;
5146233fbe7Smacallan 
5156233fbe7Smacallan 	return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL);
5166233fbe7Smacallan }
5176233fbe7Smacallan 
fdt_get_alias(const void * fdt,const char * name)5186233fbe7Smacallan const char *fdt_get_alias(const void *fdt, const char *name)
5196233fbe7Smacallan {
5206233fbe7Smacallan 	return fdt_get_alias_namelen(fdt, name, strlen(name));
5216233fbe7Smacallan }
5226233fbe7Smacallan 
fdt_get_path(const void * fdt,int nodeoffset,char * buf,int buflen)5236233fbe7Smacallan int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
5246233fbe7Smacallan {
5256233fbe7Smacallan 	int pdepth = 0, p = 0;
5266233fbe7Smacallan 	int offset, depth, namelen;
5276233fbe7Smacallan 	const char *name;
5286233fbe7Smacallan 
529*5a485aa9Sskrll 	FDT_RO_PROBE(fdt);
5306233fbe7Smacallan 
5316233fbe7Smacallan 	if (buflen < 2)
5326233fbe7Smacallan 		return -FDT_ERR_NOSPACE;
5336233fbe7Smacallan 
5346233fbe7Smacallan 	for (offset = 0, depth = 0;
5356233fbe7Smacallan 	     (offset >= 0) && (offset <= nodeoffset);
5366233fbe7Smacallan 	     offset = fdt_next_node(fdt, offset, &depth)) {
5376233fbe7Smacallan 		while (pdepth > depth) {
5386233fbe7Smacallan 			do {
5396233fbe7Smacallan 				p--;
5406233fbe7Smacallan 			} while (buf[p-1] != '/');
5416233fbe7Smacallan 			pdepth--;
5426233fbe7Smacallan 		}
5436233fbe7Smacallan 
5446233fbe7Smacallan 		if (pdepth >= depth) {
5456233fbe7Smacallan 			name = fdt_get_name(fdt, offset, &namelen);
5466233fbe7Smacallan 			if (!name)
5476233fbe7Smacallan 				return namelen;
5486233fbe7Smacallan 			if ((p + namelen + 1) <= buflen) {
5496233fbe7Smacallan 				memcpy(buf + p, name, namelen);
5506233fbe7Smacallan 				p += namelen;
5516233fbe7Smacallan 				buf[p++] = '/';
5526233fbe7Smacallan 				pdepth++;
5536233fbe7Smacallan 			}
5546233fbe7Smacallan 		}
5556233fbe7Smacallan 
5566233fbe7Smacallan 		if (offset == nodeoffset) {
5576233fbe7Smacallan 			if (pdepth < (depth + 1))
5586233fbe7Smacallan 				return -FDT_ERR_NOSPACE;
5596233fbe7Smacallan 
5606233fbe7Smacallan 			if (p > 1) /* special case so that root path is "/", not "" */
5616233fbe7Smacallan 				p--;
5626233fbe7Smacallan 			buf[p] = '\0';
5636233fbe7Smacallan 			return 0;
5646233fbe7Smacallan 		}
5656233fbe7Smacallan 	}
5666233fbe7Smacallan 
5676233fbe7Smacallan 	if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
5686233fbe7Smacallan 		return -FDT_ERR_BADOFFSET;
5696233fbe7Smacallan 	else if (offset == -FDT_ERR_BADOFFSET)
5706233fbe7Smacallan 		return -FDT_ERR_BADSTRUCTURE;
5716233fbe7Smacallan 
5726233fbe7Smacallan 	return offset; /* error from fdt_next_node() */
5736233fbe7Smacallan }
5746233fbe7Smacallan 
fdt_supernode_atdepth_offset(const void * fdt,int nodeoffset,int supernodedepth,int * nodedepth)5756233fbe7Smacallan int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
5766233fbe7Smacallan 				 int supernodedepth, int *nodedepth)
5776233fbe7Smacallan {
5786233fbe7Smacallan 	int offset, depth;
5796233fbe7Smacallan 	int supernodeoffset = -FDT_ERR_INTERNAL;
5806233fbe7Smacallan 
581*5a485aa9Sskrll 	FDT_RO_PROBE(fdt);
5826233fbe7Smacallan 
5836233fbe7Smacallan 	if (supernodedepth < 0)
5846233fbe7Smacallan 		return -FDT_ERR_NOTFOUND;
5856233fbe7Smacallan 
5866233fbe7Smacallan 	for (offset = 0, depth = 0;
5876233fbe7Smacallan 	     (offset >= 0) && (offset <= nodeoffset);
5886233fbe7Smacallan 	     offset = fdt_next_node(fdt, offset, &depth)) {
5896233fbe7Smacallan 		if (depth == supernodedepth)
5906233fbe7Smacallan 			supernodeoffset = offset;
5916233fbe7Smacallan 
5926233fbe7Smacallan 		if (offset == nodeoffset) {
5936233fbe7Smacallan 			if (nodedepth)
5946233fbe7Smacallan 				*nodedepth = depth;
5956233fbe7Smacallan 
5966233fbe7Smacallan 			if (supernodedepth > depth)
5976233fbe7Smacallan 				return -FDT_ERR_NOTFOUND;
5986233fbe7Smacallan 			else
5996233fbe7Smacallan 				return supernodeoffset;
6006233fbe7Smacallan 		}
6016233fbe7Smacallan 	}
6026233fbe7Smacallan 
6036233fbe7Smacallan 	if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
6046233fbe7Smacallan 		return -FDT_ERR_BADOFFSET;
6056233fbe7Smacallan 	else if (offset == -FDT_ERR_BADOFFSET)
6066233fbe7Smacallan 		return -FDT_ERR_BADSTRUCTURE;
6076233fbe7Smacallan 
6086233fbe7Smacallan 	return offset; /* error from fdt_next_node() */
6096233fbe7Smacallan }
6106233fbe7Smacallan 
fdt_node_depth(const void * fdt,int nodeoffset)6116233fbe7Smacallan int fdt_node_depth(const void *fdt, int nodeoffset)
6126233fbe7Smacallan {
6136233fbe7Smacallan 	int nodedepth;
6146233fbe7Smacallan 	int err;
6156233fbe7Smacallan 
6166233fbe7Smacallan 	err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
6176233fbe7Smacallan 	if (err)
6186233fbe7Smacallan 		return (err < 0) ? err : -FDT_ERR_INTERNAL;
6196233fbe7Smacallan 	return nodedepth;
6206233fbe7Smacallan }
6216233fbe7Smacallan 
fdt_parent_offset(const void * fdt,int nodeoffset)6226233fbe7Smacallan int fdt_parent_offset(const void *fdt, int nodeoffset)
6236233fbe7Smacallan {
6246233fbe7Smacallan 	int nodedepth = fdt_node_depth(fdt, nodeoffset);
6256233fbe7Smacallan 
6266233fbe7Smacallan 	if (nodedepth < 0)
6276233fbe7Smacallan 		return nodedepth;
6286233fbe7Smacallan 	return fdt_supernode_atdepth_offset(fdt, nodeoffset,
6296233fbe7Smacallan 					    nodedepth - 1, NULL);
6306233fbe7Smacallan }
6316233fbe7Smacallan 
fdt_node_offset_by_prop_value(const void * fdt,int startoffset,const char * propname,const void * propval,int proplen)6326233fbe7Smacallan int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
6336233fbe7Smacallan 				  const char *propname,
6346233fbe7Smacallan 				  const void *propval, int proplen)
6356233fbe7Smacallan {
6366233fbe7Smacallan 	int offset;
6376233fbe7Smacallan 	const void *val;
6386233fbe7Smacallan 	int len;
6396233fbe7Smacallan 
640*5a485aa9Sskrll 	FDT_RO_PROBE(fdt);
6416233fbe7Smacallan 
6426233fbe7Smacallan 	/* FIXME: The algorithm here is pretty horrible: we scan each
6436233fbe7Smacallan 	 * property of a node in fdt_getprop(), then if that didn't
6446233fbe7Smacallan 	 * find what we want, we scan over them again making our way
6456233fbe7Smacallan 	 * to the next node.  Still it's the easiest to implement
6466233fbe7Smacallan 	 * approach; performance can come later. */
6476233fbe7Smacallan 	for (offset = fdt_next_node(fdt, startoffset, NULL);
6486233fbe7Smacallan 	     offset >= 0;
6496233fbe7Smacallan 	     offset = fdt_next_node(fdt, offset, NULL)) {
6506233fbe7Smacallan 		val = fdt_getprop(fdt, offset, propname, &len);
6516233fbe7Smacallan 		if (val && (len == proplen)
6526233fbe7Smacallan 		    && (memcmp(val, propval, len) == 0))
6536233fbe7Smacallan 			return offset;
6546233fbe7Smacallan 	}
6556233fbe7Smacallan 
6566233fbe7Smacallan 	return offset; /* error from fdt_next_node() */
6576233fbe7Smacallan }
6586233fbe7Smacallan 
fdt_node_offset_by_phandle(const void * fdt,uint32_t phandle)6596233fbe7Smacallan int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
6606233fbe7Smacallan {
6616233fbe7Smacallan 	int offset;
6626233fbe7Smacallan 
6636233fbe7Smacallan 	if ((phandle == 0) || (phandle == -1))
6646233fbe7Smacallan 		return -FDT_ERR_BADPHANDLE;
6656233fbe7Smacallan 
666*5a485aa9Sskrll 	FDT_RO_PROBE(fdt);
6676233fbe7Smacallan 
6686233fbe7Smacallan 	/* FIXME: The algorithm here is pretty horrible: we
6696233fbe7Smacallan 	 * potentially scan each property of a node in
6706233fbe7Smacallan 	 * fdt_get_phandle(), then if that didn't find what
6716233fbe7Smacallan 	 * we want, we scan over them again making our way to the next
6726233fbe7Smacallan 	 * node.  Still it's the easiest to implement approach;
6736233fbe7Smacallan 	 * performance can come later. */
6746233fbe7Smacallan 	for (offset = fdt_next_node(fdt, -1, NULL);
6756233fbe7Smacallan 	     offset >= 0;
6766233fbe7Smacallan 	     offset = fdt_next_node(fdt, offset, NULL)) {
6776233fbe7Smacallan 		if (fdt_get_phandle(fdt, offset) == phandle)
6786233fbe7Smacallan 			return offset;
6796233fbe7Smacallan 	}
6806233fbe7Smacallan 
6816233fbe7Smacallan 	return offset; /* error from fdt_next_node() */
6826233fbe7Smacallan }
6836233fbe7Smacallan 
fdt_stringlist_contains(const char * strlist,int listlen,const char * str)6846233fbe7Smacallan int fdt_stringlist_contains(const char *strlist, int listlen, const char *str)
6856233fbe7Smacallan {
6866233fbe7Smacallan 	int len = strlen(str);
6876233fbe7Smacallan 	const char *p;
6886233fbe7Smacallan 
6896233fbe7Smacallan 	while (listlen >= len) {
6906233fbe7Smacallan 		if (memcmp(str, strlist, len+1) == 0)
6916233fbe7Smacallan 			return 1;
6926233fbe7Smacallan 		p = memchr(strlist, '\0', listlen);
6936233fbe7Smacallan 		if (!p)
6946233fbe7Smacallan 			return 0; /* malformed strlist.. */
6956233fbe7Smacallan 		listlen -= (p-strlist) + 1;
6966233fbe7Smacallan 		strlist = p + 1;
6976233fbe7Smacallan 	}
6986233fbe7Smacallan 	return 0;
6996233fbe7Smacallan }
7006233fbe7Smacallan 
fdt_stringlist_count(const void * fdt,int nodeoffset,const char * property)7016233fbe7Smacallan int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property)
7026233fbe7Smacallan {
7036233fbe7Smacallan 	const char *list, *end;
7046233fbe7Smacallan 	int length, count = 0;
7056233fbe7Smacallan 
7066233fbe7Smacallan 	list = fdt_getprop(fdt, nodeoffset, property, &length);
7076233fbe7Smacallan 	if (!list)
708fc885a42Sskrll 		return length;
7096233fbe7Smacallan 
7106233fbe7Smacallan 	end = list + length;
7116233fbe7Smacallan 
7126233fbe7Smacallan 	while (list < end) {
7136233fbe7Smacallan 		length = strnlen(list, end - list) + 1;
7146233fbe7Smacallan 
7156233fbe7Smacallan 		/* Abort if the last string isn't properly NUL-terminated. */
7166233fbe7Smacallan 		if (list + length > end)
7176233fbe7Smacallan 			return -FDT_ERR_BADVALUE;
7186233fbe7Smacallan 
7196233fbe7Smacallan 		list += length;
7206233fbe7Smacallan 		count++;
7216233fbe7Smacallan 	}
7226233fbe7Smacallan 
7236233fbe7Smacallan 	return count;
7246233fbe7Smacallan }
7256233fbe7Smacallan 
fdt_stringlist_search(const void * fdt,int nodeoffset,const char * property,const char * string)7266233fbe7Smacallan int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property,
7276233fbe7Smacallan 			  const char *string)
7286233fbe7Smacallan {
7296233fbe7Smacallan 	int length, len, idx = 0;
7306233fbe7Smacallan 	const char *list, *end;
7316233fbe7Smacallan 
7326233fbe7Smacallan 	list = fdt_getprop(fdt, nodeoffset, property, &length);
7336233fbe7Smacallan 	if (!list)
734fc885a42Sskrll 		return length;
7356233fbe7Smacallan 
7366233fbe7Smacallan 	len = strlen(string) + 1;
7376233fbe7Smacallan 	end = list + length;
7386233fbe7Smacallan 
7396233fbe7Smacallan 	while (list < end) {
7406233fbe7Smacallan 		length = strnlen(list, end - list) + 1;
7416233fbe7Smacallan 
7426233fbe7Smacallan 		/* Abort if the last string isn't properly NUL-terminated. */
7436233fbe7Smacallan 		if (list + length > end)
7446233fbe7Smacallan 			return -FDT_ERR_BADVALUE;
7456233fbe7Smacallan 
7466233fbe7Smacallan 		if (length == len && memcmp(list, string, length) == 0)
7476233fbe7Smacallan 			return idx;
7486233fbe7Smacallan 
7496233fbe7Smacallan 		list += length;
7506233fbe7Smacallan 		idx++;
7516233fbe7Smacallan 	}
7526233fbe7Smacallan 
7536233fbe7Smacallan 	return -FDT_ERR_NOTFOUND;
7546233fbe7Smacallan }
7556233fbe7Smacallan 
fdt_stringlist_get(const void * fdt,int nodeoffset,const char * property,int idx,int * lenp)7566233fbe7Smacallan const char *fdt_stringlist_get(const void *fdt, int nodeoffset,
7576233fbe7Smacallan 			       const char *property, int idx,
7586233fbe7Smacallan 			       int *lenp)
7596233fbe7Smacallan {
7606233fbe7Smacallan 	const char *list, *end;
7616233fbe7Smacallan 	int length;
7626233fbe7Smacallan 
7636233fbe7Smacallan 	list = fdt_getprop(fdt, nodeoffset, property, &length);
7646233fbe7Smacallan 	if (!list) {
7656233fbe7Smacallan 		if (lenp)
7666233fbe7Smacallan 			*lenp = length;
7676233fbe7Smacallan 
7686233fbe7Smacallan 		return NULL;
7696233fbe7Smacallan 	}
7706233fbe7Smacallan 
7716233fbe7Smacallan 	end = list + length;
7726233fbe7Smacallan 
7736233fbe7Smacallan 	while (list < end) {
7746233fbe7Smacallan 		length = strnlen(list, end - list) + 1;
7756233fbe7Smacallan 
7766233fbe7Smacallan 		/* Abort if the last string isn't properly NUL-terminated. */
7776233fbe7Smacallan 		if (list + length > end) {
7786233fbe7Smacallan 			if (lenp)
7796233fbe7Smacallan 				*lenp = -FDT_ERR_BADVALUE;
7806233fbe7Smacallan 
7816233fbe7Smacallan 			return NULL;
7826233fbe7Smacallan 		}
7836233fbe7Smacallan 
7846233fbe7Smacallan 		if (idx == 0) {
7856233fbe7Smacallan 			if (lenp)
7866233fbe7Smacallan 				*lenp = length - 1;
7876233fbe7Smacallan 
7886233fbe7Smacallan 			return list;
7896233fbe7Smacallan 		}
7906233fbe7Smacallan 
7916233fbe7Smacallan 		list += length;
7926233fbe7Smacallan 		idx--;
7936233fbe7Smacallan 	}
7946233fbe7Smacallan 
7956233fbe7Smacallan 	if (lenp)
7966233fbe7Smacallan 		*lenp = -FDT_ERR_NOTFOUND;
7976233fbe7Smacallan 
7986233fbe7Smacallan 	return NULL;
7996233fbe7Smacallan }
8006233fbe7Smacallan 
fdt_node_check_compatible(const void * fdt,int nodeoffset,const char * compatible)8016233fbe7Smacallan int fdt_node_check_compatible(const void *fdt, int nodeoffset,
8026233fbe7Smacallan 			      const char *compatible)
8036233fbe7Smacallan {
8046233fbe7Smacallan 	const void *prop;
8056233fbe7Smacallan 	int len;
8066233fbe7Smacallan 
8076233fbe7Smacallan 	prop = fdt_getprop(fdt, nodeoffset, "compatible", &len);
8086233fbe7Smacallan 	if (!prop)
8096233fbe7Smacallan 		return len;
810fc885a42Sskrll 
811fc885a42Sskrll 	return !fdt_stringlist_contains(prop, len, compatible);
8126233fbe7Smacallan }
8136233fbe7Smacallan 
fdt_node_offset_by_compatible(const void * fdt,int startoffset,const char * compatible)8146233fbe7Smacallan int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
8156233fbe7Smacallan 				  const char *compatible)
8166233fbe7Smacallan {
8176233fbe7Smacallan 	int offset, err;
8186233fbe7Smacallan 
819*5a485aa9Sskrll 	FDT_RO_PROBE(fdt);
8206233fbe7Smacallan 
8216233fbe7Smacallan 	/* FIXME: The algorithm here is pretty horrible: we scan each
8226233fbe7Smacallan 	 * property of a node in fdt_node_check_compatible(), then if
8236233fbe7Smacallan 	 * that didn't find what we want, we scan over them again
8246233fbe7Smacallan 	 * making our way to the next node.  Still it's the easiest to
8256233fbe7Smacallan 	 * implement approach; performance can come later. */
8266233fbe7Smacallan 	for (offset = fdt_next_node(fdt, startoffset, NULL);
8276233fbe7Smacallan 	     offset >= 0;
8286233fbe7Smacallan 	     offset = fdt_next_node(fdt, offset, NULL)) {
8296233fbe7Smacallan 		err = fdt_node_check_compatible(fdt, offset, compatible);
8306233fbe7Smacallan 		if ((err < 0) && (err != -FDT_ERR_NOTFOUND))
8316233fbe7Smacallan 			return err;
8326233fbe7Smacallan 		else if (err == 0)
8336233fbe7Smacallan 			return offset;
8346233fbe7Smacallan 	}
8356233fbe7Smacallan 
8366233fbe7Smacallan 	return offset; /* error from fdt_next_node() */
8376233fbe7Smacallan }
838*5a485aa9Sskrll 
fdt_check_full(const void * fdt,size_t bufsize)839*5a485aa9Sskrll int fdt_check_full(const void *fdt, size_t bufsize)
840*5a485aa9Sskrll {
841*5a485aa9Sskrll 	int err;
842*5a485aa9Sskrll 	int num_memrsv;
843*5a485aa9Sskrll 	int offset, nextoffset = 0;
844*5a485aa9Sskrll 	uint32_t tag;
845*5a485aa9Sskrll 	unsigned depth = 0;
846*5a485aa9Sskrll 	const void *prop;
847*5a485aa9Sskrll 	const char *propname;
848*5a485aa9Sskrll 
849*5a485aa9Sskrll 	if (bufsize < FDT_V1_SIZE)
850*5a485aa9Sskrll 		return -FDT_ERR_TRUNCATED;
851*5a485aa9Sskrll 	err = fdt_check_header(fdt);
852*5a485aa9Sskrll 	if (err != 0)
853*5a485aa9Sskrll 		return err;
854*5a485aa9Sskrll 	if (bufsize < fdt_totalsize(fdt))
855*5a485aa9Sskrll 		return -FDT_ERR_TRUNCATED;
856*5a485aa9Sskrll 
857*5a485aa9Sskrll 	num_memrsv = fdt_num_mem_rsv(fdt);
858*5a485aa9Sskrll 	if (num_memrsv < 0)
859*5a485aa9Sskrll 		return num_memrsv;
860*5a485aa9Sskrll 
861*5a485aa9Sskrll 	while (1) {
862*5a485aa9Sskrll 		offset = nextoffset;
863*5a485aa9Sskrll 		tag = fdt_next_tag(fdt, offset, &nextoffset);
864*5a485aa9Sskrll 
865*5a485aa9Sskrll 		if (nextoffset < 0)
866*5a485aa9Sskrll 			return nextoffset;
867*5a485aa9Sskrll 
868*5a485aa9Sskrll 		switch (tag) {
869*5a485aa9Sskrll 		case FDT_NOP:
870*5a485aa9Sskrll 			break;
871*5a485aa9Sskrll 
872*5a485aa9Sskrll 		case FDT_END:
873*5a485aa9Sskrll 			if (depth != 0)
874*5a485aa9Sskrll 				return -FDT_ERR_BADSTRUCTURE;
875*5a485aa9Sskrll 			return 0;
876*5a485aa9Sskrll 
877*5a485aa9Sskrll 		case FDT_BEGIN_NODE:
878*5a485aa9Sskrll 			depth++;
879*5a485aa9Sskrll 			if (depth > INT_MAX)
880*5a485aa9Sskrll 				return -FDT_ERR_BADSTRUCTURE;
881*5a485aa9Sskrll 			break;
882*5a485aa9Sskrll 
883*5a485aa9Sskrll 		case FDT_END_NODE:
884*5a485aa9Sskrll 			if (depth == 0)
885*5a485aa9Sskrll 				return -FDT_ERR_BADSTRUCTURE;
886*5a485aa9Sskrll 			depth--;
887*5a485aa9Sskrll 			break;
888*5a485aa9Sskrll 
889*5a485aa9Sskrll 		case FDT_PROP:
890*5a485aa9Sskrll 			prop = fdt_getprop_by_offset(fdt, offset, &propname,
891*5a485aa9Sskrll 						     &err);
892*5a485aa9Sskrll 			if (!prop)
893*5a485aa9Sskrll 				return err;
894*5a485aa9Sskrll 			break;
895*5a485aa9Sskrll 
896*5a485aa9Sskrll 		default:
897*5a485aa9Sskrll 			return -FDT_ERR_INTERNAL;
898*5a485aa9Sskrll 		}
899*5a485aa9Sskrll 	}
900*5a485aa9Sskrll }
901