]> git.proxmox.com Git - mirror_edk2.git/blob - EmbeddedPkg/Library/FdtLib/fdt.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / EmbeddedPkg / Library / FdtLib / fdt.c
1 /*
2 * libfdt - Flat Device Tree manipulation
3 * Copyright (C) 2006 David Gibson, IBM Corporation.
4 *
5 * libfdt is dual licensed: you can use it either under the terms of
6 * the GPL, or the BSD license, at your option.
7 *
8 * a) This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public
19 * License along with this library; if not, write to the Free
20 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
21 * MA 02110-1301 USA
22 *
23 * Alternatively,
24 *
25 * b) Redistribution and use in source and binary forms, with or
26 * without modification, are permitted provided that the following
27 * conditions are met:
28 *
29 * 1. Redistributions of source code must retain the above
30 * copyright notice, this list of conditions and the following
31 * disclaimer.
32 * 2. Redistributions in binary form must reproduce the above
33 * copyright notice, this list of conditions and the following
34 * disclaimer in the documentation and/or other materials
35 * provided with the distribution.
36 *
37 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
38 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
39 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
40 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
41 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
42 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
43 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
44 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
45 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
46 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
47 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
48 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
49 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
50 */
51 #include "libfdt_env.h"
52
53 #include <fdt.h>
54 #include <libfdt.h>
55
56 #include "libfdt_internal.h"
57
58 int
59 fdt_check_header (
60 const void *fdt
61 )
62 {
63 if (fdt_magic (fdt) == FDT_MAGIC) {
64 /* Complete tree */
65 if (fdt_version (fdt) < FDT_FIRST_SUPPORTED_VERSION) {
66 return -FDT_ERR_BADVERSION;
67 }
68
69 if (fdt_last_comp_version (fdt) > FDT_LAST_SUPPORTED_VERSION) {
70 return -FDT_ERR_BADVERSION;
71 }
72 } else if (fdt_magic (fdt) == FDT_SW_MAGIC) {
73 /* Unfinished sequential-write blob */
74 if (fdt_size_dt_struct (fdt) == 0) {
75 return -FDT_ERR_BADSTATE;
76 }
77 } else {
78 return -FDT_ERR_BADMAGIC;
79 }
80
81 return 0;
82 }
83
84 const void *
85 fdt_offset_ptr (
86 const void *fdt,
87 int offset,
88 unsigned int len
89 )
90 {
91 unsigned absoffset = offset + fdt_off_dt_struct (fdt);
92
93 if ( (absoffset < offset)
94 || ((absoffset + len) < absoffset)
95 || ((absoffset + len) > fdt_totalsize (fdt)))
96 {
97 return NULL;
98 }
99
100 if (fdt_version (fdt) >= 0x11) {
101 if ( ((offset + len) < offset)
102 || ((offset + len) > fdt_size_dt_struct (fdt)))
103 {
104 return NULL;
105 }
106 }
107
108 return _fdt_offset_ptr (fdt, offset);
109 }
110
111 uint32_t
112 fdt_next_tag (
113 const void *fdt,
114 int startoffset,
115 int *nextoffset
116 )
117 {
118 const fdt32_t *tagp, *lenp;
119 uint32_t tag;
120 int offset = startoffset;
121 const char *p;
122
123 *nextoffset = -FDT_ERR_TRUNCATED;
124 tagp = fdt_offset_ptr (fdt, offset, FDT_TAGSIZE);
125 if (!tagp) {
126 return FDT_END; /* premature end */
127 }
128
129 tag = fdt32_to_cpu (*tagp);
130 offset += FDT_TAGSIZE;
131
132 *nextoffset = -FDT_ERR_BADSTRUCTURE;
133 switch (tag) {
134 case FDT_BEGIN_NODE:
135 /* skip name */
136 do {
137 p = fdt_offset_ptr (fdt, offset++, 1);
138 } while (p && (*p != '\0'));
139
140 if (!p) {
141 return FDT_END; /* premature end */
142 }
143
144 break;
145
146 case FDT_PROP:
147 lenp = fdt_offset_ptr (fdt, offset, sizeof (*lenp));
148 if (!lenp) {
149 return FDT_END; /* premature end */
150 }
151
152 /* skip-name offset, length and value */
153 offset += sizeof (struct fdt_property) - FDT_TAGSIZE
154 + fdt32_to_cpu (*lenp);
155 break;
156
157 case FDT_END:
158 case FDT_END_NODE:
159 case FDT_NOP:
160 break;
161
162 default:
163 return FDT_END;
164 }
165
166 if (!fdt_offset_ptr (fdt, startoffset, offset - startoffset)) {
167 return FDT_END; /* premature end */
168 }
169
170 *nextoffset = FDT_TAGALIGN (offset);
171 return tag;
172 }
173
174 int
175 _fdt_check_node_offset (
176 const void *fdt,
177 int offset
178 )
179 {
180 if ( (offset < 0) || (offset % FDT_TAGSIZE)
181 || (fdt_next_tag (fdt, offset, &offset) != FDT_BEGIN_NODE))
182 {
183 return -FDT_ERR_BADOFFSET;
184 }
185
186 return offset;
187 }
188
189 int
190 _fdt_check_prop_offset (
191 const void *fdt,
192 int offset
193 )
194 {
195 if ( (offset < 0) || (offset % FDT_TAGSIZE)
196 || (fdt_next_tag (fdt, offset, &offset) != FDT_PROP))
197 {
198 return -FDT_ERR_BADOFFSET;
199 }
200
201 return offset;
202 }
203
204 int
205 fdt_next_node (
206 const void *fdt,
207 int offset,
208 int *depth
209 )
210 {
211 int nextoffset = 0;
212 uint32_t tag;
213
214 if (offset >= 0) {
215 if ((nextoffset = _fdt_check_node_offset (fdt, offset)) < 0) {
216 return nextoffset;
217 }
218 }
219
220 do {
221 offset = nextoffset;
222 tag = fdt_next_tag (fdt, offset, &nextoffset);
223
224 switch (tag) {
225 case FDT_PROP:
226 case FDT_NOP:
227 break;
228
229 case FDT_BEGIN_NODE:
230 if (depth) {
231 (*depth)++;
232 }
233
234 break;
235
236 case FDT_END_NODE:
237 if (depth && ((--(*depth)) < 0)) {
238 return nextoffset;
239 }
240
241 break;
242
243 case FDT_END:
244 if ( (nextoffset >= 0)
245 || ((nextoffset == -FDT_ERR_TRUNCATED) && !depth))
246 {
247 return -FDT_ERR_NOTFOUND;
248 } else {
249 return nextoffset;
250 }
251 }
252 } while (tag != FDT_BEGIN_NODE);
253
254 return offset;
255 }
256
257 int
258 fdt_first_subnode (
259 const void *fdt,
260 int offset
261 )
262 {
263 int depth = 0;
264
265 offset = fdt_next_node (fdt, offset, &depth);
266 if ((offset < 0) || (depth != 1)) {
267 return -FDT_ERR_NOTFOUND;
268 }
269
270 return offset;
271 }
272
273 int
274 fdt_next_subnode (
275 const void *fdt,
276 int offset
277 )
278 {
279 int depth = 1;
280
281 /*
282 * With respect to the parent, the depth of the next subnode will be
283 * the same as the last.
284 */
285 do {
286 offset = fdt_next_node (fdt, offset, &depth);
287 if ((offset < 0) || (depth < 1)) {
288 return -FDT_ERR_NOTFOUND;
289 }
290 } while (depth > 1);
291
292 return offset;
293 }
294
295 const char *
296 _fdt_find_string (
297 const char *strtab,
298 int tabsize,
299 const char *s
300 )
301 {
302 int len = strlen (s) + 1;
303 const char *last = strtab + tabsize - len;
304 const char *p;
305
306 for (p = strtab; p <= last; p++) {
307 if (memcmp (p, s, len) == 0) {
308 return p;
309 }
310 }
311
312 return NULL;
313 }
314
315 int
316 fdt_move (
317 const void *fdt,
318 void *buf,
319 int bufsize
320 )
321 {
322 FDT_CHECK_HEADER (fdt);
323
324 if (fdt_totalsize (fdt) > bufsize) {
325 return -FDT_ERR_NOSPACE;
326 }
327
328 memmove (buf, fdt, fdt_totalsize (fdt));
329 return 0;
330 }