1 // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
3 * libfdt - Flat Device Tree manipulation
4 * Copyright (C) 2006 David Gibson, IBM Corporation.
6 #include "libfdt_env.h"
11 #include "libfdt_internal.h"
14 * Minimal sanity check for a read-only tree. fdt_ro_probe_() checks
15 * that the given buffer contains what appears to be a flattened
16 * device tree with sane information in its header.
18 int fdt_ro_probe_(const void *fdt
)
20 if (fdt_magic(fdt
) == FDT_MAGIC
) {
22 if (fdt_version(fdt
) < FDT_FIRST_SUPPORTED_VERSION
)
23 return -FDT_ERR_BADVERSION
;
24 if (fdt_last_comp_version(fdt
) > FDT_LAST_SUPPORTED_VERSION
)
25 return -FDT_ERR_BADVERSION
;
26 } else if (fdt_magic(fdt
) == FDT_SW_MAGIC
) {
27 /* Unfinished sequential-write blob */
28 if (fdt_size_dt_struct(fdt
) == 0)
29 return -FDT_ERR_BADSTATE
;
31 return -FDT_ERR_BADMAGIC
;
37 static int check_off_(uint32_t hdrsize
, uint32_t totalsize
, uint32_t off
)
39 return (off
>= hdrsize
) && (off
<= totalsize
);
42 static int check_block_(uint32_t hdrsize
, uint32_t totalsize
,
43 uint32_t base
, uint32_t size
)
45 if (!check_off_(hdrsize
, totalsize
, base
))
46 return 0; /* block start out of bounds */
47 if ((base
+ size
) < base
)
48 return 0; /* overflow */
49 if (!check_off_(hdrsize
, totalsize
, base
+ size
))
50 return 0; /* block end out of bounds */
54 size_t fdt_header_size_(uint32_t version
)
58 else if (version
<= 2)
60 else if (version
<= 3)
62 else if (version
<= 16)
68 int fdt_check_header(const void *fdt
)
72 if (fdt_magic(fdt
) != FDT_MAGIC
)
73 return -FDT_ERR_BADMAGIC
;
74 hdrsize
= fdt_header_size(fdt
);
75 if ((fdt_version(fdt
) < FDT_FIRST_SUPPORTED_VERSION
)
76 || (fdt_last_comp_version(fdt
) > FDT_LAST_SUPPORTED_VERSION
))
77 return -FDT_ERR_BADVERSION
;
78 if (fdt_version(fdt
) < fdt_last_comp_version(fdt
))
79 return -FDT_ERR_BADVERSION
;
81 if ((fdt_totalsize(fdt
) < hdrsize
)
82 || (fdt_totalsize(fdt
) > INT_MAX
))
83 return -FDT_ERR_TRUNCATED
;
85 /* Bounds check memrsv block */
86 if (!check_off_(hdrsize
, fdt_totalsize(fdt
), fdt_off_mem_rsvmap(fdt
)))
87 return -FDT_ERR_TRUNCATED
;
89 /* Bounds check structure block */
90 if (fdt_version(fdt
) < 17) {
91 if (!check_off_(hdrsize
, fdt_totalsize(fdt
),
92 fdt_off_dt_struct(fdt
)))
93 return -FDT_ERR_TRUNCATED
;
95 if (!check_block_(hdrsize
, fdt_totalsize(fdt
),
96 fdt_off_dt_struct(fdt
),
97 fdt_size_dt_struct(fdt
)))
98 return -FDT_ERR_TRUNCATED
;
101 /* Bounds check strings block */
102 if (!check_block_(hdrsize
, fdt_totalsize(fdt
),
103 fdt_off_dt_strings(fdt
), fdt_size_dt_strings(fdt
)))
104 return -FDT_ERR_TRUNCATED
;
109 const void *fdt_offset_ptr(const void *fdt
, int offset
, unsigned int len
)
111 unsigned absoffset
= offset
+ fdt_off_dt_struct(fdt
);
113 if ((absoffset
< offset
)
114 || ((absoffset
+ len
) < absoffset
)
115 || (absoffset
+ len
) > fdt_totalsize(fdt
))
118 if (fdt_version(fdt
) >= 0x11)
119 if (((offset
+ len
) < offset
)
120 || ((offset
+ len
) > fdt_size_dt_struct(fdt
)))
123 return fdt_offset_ptr_(fdt
, offset
);
126 uint32_t fdt_next_tag(const void *fdt
, int startoffset
, int *nextoffset
)
128 const fdt32_t
*tagp
, *lenp
;
130 int offset
= startoffset
;
133 *nextoffset
= -FDT_ERR_TRUNCATED
;
134 tagp
= fdt_offset_ptr(fdt
, offset
, FDT_TAGSIZE
);
136 return FDT_END
; /* premature end */
137 tag
= fdt32_to_cpu(*tagp
);
138 offset
+= FDT_TAGSIZE
;
140 *nextoffset
= -FDT_ERR_BADSTRUCTURE
;
145 p
= fdt_offset_ptr(fdt
, offset
++, 1);
146 } while (p
&& (*p
!= '\0'));
148 return FDT_END
; /* premature end */
152 lenp
= fdt_offset_ptr(fdt
, offset
, sizeof(*lenp
));
154 return FDT_END
; /* premature end */
155 /* skip-name offset, length and value */
156 offset
+= sizeof(struct fdt_property
) - FDT_TAGSIZE
157 + fdt32_to_cpu(*lenp
);
158 if (fdt_version(fdt
) < 0x10 && fdt32_to_cpu(*lenp
) >= 8 &&
159 ((offset
- fdt32_to_cpu(*lenp
)) % 8) != 0)
172 if (!fdt_offset_ptr(fdt
, startoffset
, offset
- startoffset
))
173 return FDT_END
; /* premature end */
175 *nextoffset
= FDT_TAGALIGN(offset
);
179 int fdt_check_node_offset_(const void *fdt
, int offset
)
181 if ((offset
< 0) || (offset
% FDT_TAGSIZE
)
182 || (fdt_next_tag(fdt
, offset
, &offset
) != FDT_BEGIN_NODE
))
183 return -FDT_ERR_BADOFFSET
;
188 int fdt_check_prop_offset_(const void *fdt
, int offset
)
190 if ((offset
< 0) || (offset
% FDT_TAGSIZE
)
191 || (fdt_next_tag(fdt
, offset
, &offset
) != FDT_PROP
))
192 return -FDT_ERR_BADOFFSET
;
197 int fdt_next_node(const void *fdt
, int offset
, int *depth
)
203 if ((nextoffset
= fdt_check_node_offset_(fdt
, offset
)) < 0)
208 tag
= fdt_next_tag(fdt
, offset
, &nextoffset
);
221 if (depth
&& ((--(*depth
)) < 0))
226 if ((nextoffset
>= 0)
227 || ((nextoffset
== -FDT_ERR_TRUNCATED
) && !depth
))
228 return -FDT_ERR_NOTFOUND
;
232 } while (tag
!= FDT_BEGIN_NODE
);
237 int fdt_first_subnode(const void *fdt
, int offset
)
241 offset
= fdt_next_node(fdt
, offset
, &depth
);
242 if (offset
< 0 || depth
!= 1)
243 return -FDT_ERR_NOTFOUND
;
248 int fdt_next_subnode(const void *fdt
, int offset
)
253 * With respect to the parent, the depth of the next subnode will be
254 * the same as the last.
257 offset
= fdt_next_node(fdt
, offset
, &depth
);
258 if (offset
< 0 || depth
< 1)
259 return -FDT_ERR_NOTFOUND
;
265 const char *fdt_find_string_(const char *strtab
, int tabsize
, const char *s
)
267 int len
= strlen(s
) + 1;
268 const char *last
= strtab
+ tabsize
- len
;
271 for (p
= strtab
; p
<= last
; p
++)
272 if (memcmp(p
, s
, len
) == 0)
277 int fdt_move(const void *fdt
, void *buf
, int bufsize
)
281 if (fdt_totalsize(fdt
) > bufsize
)
282 return -FDT_ERR_NOSPACE
;
284 memmove(buf
, fdt
, fdt_totalsize(fdt
));