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 int32_t fdt_ro_probe_(const void *fdt
)
20 uint32_t totalsize
= fdt_totalsize(fdt
);
22 if (can_assume(VALID_DTB
))
25 if (fdt_magic(fdt
) == FDT_MAGIC
) {
27 if (!can_assume(LATEST
)) {
28 if (fdt_version(fdt
) < FDT_FIRST_SUPPORTED_VERSION
)
29 return -FDT_ERR_BADVERSION
;
30 if (fdt_last_comp_version(fdt
) >
31 FDT_LAST_SUPPORTED_VERSION
)
32 return -FDT_ERR_BADVERSION
;
34 } else if (fdt_magic(fdt
) == FDT_SW_MAGIC
) {
35 /* Unfinished sequential-write blob */
36 if (!can_assume(VALID_INPUT
) && fdt_size_dt_struct(fdt
) == 0)
37 return -FDT_ERR_BADSTATE
;
39 return -FDT_ERR_BADMAGIC
;
42 if (totalsize
< INT32_MAX
)
45 return -FDT_ERR_TRUNCATED
;
48 static int check_off_(uint32_t hdrsize
, uint32_t totalsize
, uint32_t off
)
50 return (off
>= hdrsize
) && (off
<= totalsize
);
53 static int check_block_(uint32_t hdrsize
, uint32_t totalsize
,
54 uint32_t base
, uint32_t size
)
56 if (!check_off_(hdrsize
, totalsize
, base
))
57 return 0; /* block start out of bounds */
58 if ((base
+ size
) < base
)
59 return 0; /* overflow */
60 if (!check_off_(hdrsize
, totalsize
, base
+ size
))
61 return 0; /* block end out of bounds */
65 size_t fdt_header_size_(uint32_t version
)
69 else if (version
<= 2)
71 else if (version
<= 3)
73 else if (version
<= 16)
79 size_t fdt_header_size(const void *fdt
)
81 return can_assume(LATEST
) ? FDT_V17_SIZE
:
82 fdt_header_size_(fdt_version(fdt
));
85 int fdt_check_header(const void *fdt
)
89 if (fdt_magic(fdt
) != FDT_MAGIC
)
90 return -FDT_ERR_BADMAGIC
;
91 if (!can_assume(LATEST
)) {
92 if ((fdt_version(fdt
) < FDT_FIRST_SUPPORTED_VERSION
)
93 || (fdt_last_comp_version(fdt
) >
94 FDT_LAST_SUPPORTED_VERSION
))
95 return -FDT_ERR_BADVERSION
;
96 if (fdt_version(fdt
) < fdt_last_comp_version(fdt
))
97 return -FDT_ERR_BADVERSION
;
99 hdrsize
= fdt_header_size(fdt
);
100 if (!can_assume(VALID_DTB
)) {
102 if ((fdt_totalsize(fdt
) < hdrsize
)
103 || (fdt_totalsize(fdt
) > INT_MAX
))
104 return -FDT_ERR_TRUNCATED
;
106 /* Bounds check memrsv block */
107 if (!check_off_(hdrsize
, fdt_totalsize(fdt
),
108 fdt_off_mem_rsvmap(fdt
)))
109 return -FDT_ERR_TRUNCATED
;
112 if (!can_assume(VALID_DTB
)) {
113 /* Bounds check structure block */
114 if (!can_assume(LATEST
) && fdt_version(fdt
) < 17) {
115 if (!check_off_(hdrsize
, fdt_totalsize(fdt
),
116 fdt_off_dt_struct(fdt
)))
117 return -FDT_ERR_TRUNCATED
;
119 if (!check_block_(hdrsize
, fdt_totalsize(fdt
),
120 fdt_off_dt_struct(fdt
),
121 fdt_size_dt_struct(fdt
)))
122 return -FDT_ERR_TRUNCATED
;
125 /* Bounds check strings block */
126 if (!check_block_(hdrsize
, fdt_totalsize(fdt
),
127 fdt_off_dt_strings(fdt
),
128 fdt_size_dt_strings(fdt
)))
129 return -FDT_ERR_TRUNCATED
;
135 const void *fdt_offset_ptr(const void *fdt
, int offset
, unsigned int len
)
137 unsigned int uoffset
= offset
;
138 unsigned int absoffset
= offset
+ fdt_off_dt_struct(fdt
);
143 if (!can_assume(VALID_INPUT
))
144 if ((absoffset
< uoffset
)
145 || ((absoffset
+ len
) < absoffset
)
146 || (absoffset
+ len
) > fdt_totalsize(fdt
))
149 if (can_assume(LATEST
) || fdt_version(fdt
) >= 0x11)
150 if (((uoffset
+ len
) < uoffset
)
151 || ((offset
+ len
) > fdt_size_dt_struct(fdt
)))
154 return fdt_offset_ptr_(fdt
, offset
);
157 uint32_t fdt_next_tag(const void *fdt
, int startoffset
, int *nextoffset
)
159 const fdt32_t
*tagp
, *lenp
;
161 int offset
= startoffset
;
164 *nextoffset
= -FDT_ERR_TRUNCATED
;
165 tagp
= fdt_offset_ptr(fdt
, offset
, FDT_TAGSIZE
);
166 if (!can_assume(VALID_DTB
) && !tagp
)
167 return FDT_END
; /* premature end */
168 tag
= fdt32_to_cpu(*tagp
);
169 offset
+= FDT_TAGSIZE
;
171 *nextoffset
= -FDT_ERR_BADSTRUCTURE
;
176 p
= fdt_offset_ptr(fdt
, offset
++, 1);
177 } while (p
&& (*p
!= '\0'));
178 if (!can_assume(VALID_DTB
) && !p
)
179 return FDT_END
; /* premature end */
183 lenp
= fdt_offset_ptr(fdt
, offset
, sizeof(*lenp
));
184 if (!can_assume(VALID_DTB
) && !lenp
)
185 return FDT_END
; /* premature end */
186 /* skip-name offset, length and value */
187 offset
+= sizeof(struct fdt_property
) - FDT_TAGSIZE
188 + fdt32_to_cpu(*lenp
);
189 if (!can_assume(LATEST
) &&
190 fdt_version(fdt
) < 0x10 && fdt32_to_cpu(*lenp
) >= 8 &&
191 ((offset
- fdt32_to_cpu(*lenp
)) % 8) != 0)
204 if (!fdt_offset_ptr(fdt
, startoffset
, offset
- startoffset
))
205 return FDT_END
; /* premature end */
207 *nextoffset
= FDT_TAGALIGN(offset
);
211 int fdt_check_node_offset_(const void *fdt
, int offset
)
213 if (!can_assume(VALID_INPUT
)
214 && ((offset
< 0) || (offset
% FDT_TAGSIZE
)))
215 return -FDT_ERR_BADOFFSET
;
217 if (fdt_next_tag(fdt
, offset
, &offset
) != FDT_BEGIN_NODE
)
218 return -FDT_ERR_BADOFFSET
;
223 int fdt_check_prop_offset_(const void *fdt
, int offset
)
225 if (!can_assume(VALID_INPUT
)
226 && ((offset
< 0) || (offset
% FDT_TAGSIZE
)))
227 return -FDT_ERR_BADOFFSET
;
229 if (fdt_next_tag(fdt
, offset
, &offset
) != FDT_PROP
)
230 return -FDT_ERR_BADOFFSET
;
235 int fdt_next_node(const void *fdt
, int offset
, int *depth
)
241 if ((nextoffset
= fdt_check_node_offset_(fdt
, offset
)) < 0)
246 tag
= fdt_next_tag(fdt
, offset
, &nextoffset
);
259 if (depth
&& ((--(*depth
)) < 0))
264 if ((nextoffset
>= 0)
265 || ((nextoffset
== -FDT_ERR_TRUNCATED
) && !depth
))
266 return -FDT_ERR_NOTFOUND
;
270 } while (tag
!= FDT_BEGIN_NODE
);
275 int fdt_first_subnode(const void *fdt
, int offset
)
279 offset
= fdt_next_node(fdt
, offset
, &depth
);
280 if (offset
< 0 || depth
!= 1)
281 return -FDT_ERR_NOTFOUND
;
286 int fdt_next_subnode(const void *fdt
, int offset
)
291 * With respect to the parent, the depth of the next subnode will be
292 * the same as the last.
295 offset
= fdt_next_node(fdt
, offset
, &depth
);
296 if (offset
< 0 || depth
< 1)
297 return -FDT_ERR_NOTFOUND
;
303 const char *fdt_find_string_(const char *strtab
, int tabsize
, const char *s
)
305 int len
= strlen(s
) + 1;
306 const char *last
= strtab
+ tabsize
- len
;
309 for (p
= strtab
; p
<= last
; p
++)
310 if (memcmp(p
, s
, len
) == 0)
315 int fdt_move(const void *fdt
, void *buf
, int bufsize
)
317 if (!can_assume(VALID_INPUT
) && bufsize
< 0)
318 return -FDT_ERR_NOSPACE
;
322 if (fdt_totalsize(fdt
) > (unsigned int)bufsize
)
323 return -FDT_ERR_NOSPACE
;
325 memmove(buf
, fdt
, fdt_totalsize(fdt
));