2 * libfdt - Flat Device Tree manipulation
3 * Copyright (C) 2006 David Gibson, IBM Corporation.
4 * SPDX-License-Identifier: GPL-2.0+ BSD-2-Clause
6 #include <libfdt_env.h>
15 #include "libfdt_internal.h"
17 int fdt_check_header(const void *fdt
)
19 if (fdt_magic(fdt
) == FDT_MAGIC
) {
21 if (fdt_version(fdt
) < FDT_FIRST_SUPPORTED_VERSION
)
22 return -FDT_ERR_BADVERSION
;
23 if (fdt_last_comp_version(fdt
) > FDT_LAST_SUPPORTED_VERSION
)
24 return -FDT_ERR_BADVERSION
;
25 } else if (fdt_magic(fdt
) == FDT_SW_MAGIC
) {
26 /* Unfinished sequential-write blob */
27 if (fdt_size_dt_struct(fdt
) == 0)
28 return -FDT_ERR_BADSTATE
;
30 return -FDT_ERR_BADMAGIC
;
36 const void *fdt_offset_ptr(const void *fdt
, int offset
, unsigned int len
)
40 if (fdt_version(fdt
) >= 0x11)
41 if (((offset
+ len
) < offset
)
42 || ((offset
+ len
) > fdt_size_dt_struct(fdt
)))
45 p
= _fdt_offset_ptr(fdt
, offset
);
52 uint32_t fdt_next_tag(const void *fdt
, int startoffset
, int *nextoffset
)
54 const fdt32_t
*tagp
, *lenp
;
56 int offset
= startoffset
;
59 *nextoffset
= -FDT_ERR_TRUNCATED
;
60 tagp
= fdt_offset_ptr(fdt
, offset
, FDT_TAGSIZE
);
62 return FDT_END
; /* premature end */
63 tag
= fdt32_to_cpu(*tagp
);
64 offset
+= FDT_TAGSIZE
;
66 *nextoffset
= -FDT_ERR_BADSTRUCTURE
;
71 p
= fdt_offset_ptr(fdt
, offset
++, 1);
72 } while (p
&& (*p
!= '\0'));
74 return FDT_END
; /* premature end */
78 lenp
= fdt_offset_ptr(fdt
, offset
, sizeof(*lenp
));
80 return FDT_END
; /* premature end */
81 /* skip-name offset, length and value */
82 offset
+= sizeof(struct fdt_property
) - FDT_TAGSIZE
83 + fdt32_to_cpu(*lenp
);
95 if (!fdt_offset_ptr(fdt
, startoffset
, offset
- startoffset
))
96 return FDT_END
; /* premature end */
98 *nextoffset
= FDT_TAGALIGN(offset
);
102 int _fdt_check_node_offset(const void *fdt
, int offset
)
104 if ((offset
< 0) || (offset
% FDT_TAGSIZE
)
105 || (fdt_next_tag(fdt
, offset
, &offset
) != FDT_BEGIN_NODE
))
106 return -FDT_ERR_BADOFFSET
;
111 int _fdt_check_prop_offset(const void *fdt
, int offset
)
113 if ((offset
< 0) || (offset
% FDT_TAGSIZE
)
114 || (fdt_next_tag(fdt
, offset
, &offset
) != FDT_PROP
))
115 return -FDT_ERR_BADOFFSET
;
120 int fdt_next_node(const void *fdt
, int offset
, int *depth
)
126 if ((nextoffset
= _fdt_check_node_offset(fdt
, offset
)) < 0)
131 tag
= fdt_next_tag(fdt
, offset
, &nextoffset
);
144 if (depth
&& ((--(*depth
)) < 0))
149 if ((nextoffset
>= 0)
150 || ((nextoffset
== -FDT_ERR_TRUNCATED
) && !depth
))
151 return -FDT_ERR_NOTFOUND
;
155 } while (tag
!= FDT_BEGIN_NODE
);
160 int fdt_first_subnode(const void *fdt
, int offset
)
164 offset
= fdt_next_node(fdt
, offset
, &depth
);
165 if (offset
< 0 || depth
!= 1)
166 return -FDT_ERR_NOTFOUND
;
171 int fdt_next_subnode(const void *fdt
, int offset
)
176 * With respect to the parent, the depth of the next subnode will be
177 * the same as the last.
180 offset
= fdt_next_node(fdt
, offset
, &depth
);
181 if (offset
< 0 || depth
< 1)
182 return -FDT_ERR_NOTFOUND
;
188 const char *_fdt_find_string(const char *strtab
, int tabsize
, const char *s
)
190 int len
= strlen(s
) + 1;
191 const char *last
= strtab
+ tabsize
- len
;
194 for (p
= strtab
; p
<= last
; p
++)
195 if (memcmp(p
, s
, len
) == 0)
200 int fdt_move(const void *fdt
, void *buf
, int bufsize
)
202 FDT_CHECK_HEADER(fdt
);
204 if (fdt_totalsize(fdt
) > bufsize
)
205 return -FDT_ERR_NOSPACE
;
207 memmove(buf
, fdt
, fdt_totalsize(fdt
));