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