1
2
3
4
5
6
7
8#include <libfdt_env.h>
9
10#ifndef USE_HOSTCC
11#include <fdt.h>
12#include <libfdt.h>
13#else
14#include "fdt_host.h"
15#endif
16
17#include "libfdt_internal.h"
18
19
20
21
22
23
24
25
26
27
28
29static int fdt_add_region(struct fdt_region_state *info, int offset, int size)
30{
31 struct fdt_region *reg;
32
33 reg = info->region ? &info->region[info->count - 1] : NULL;
34 if (info->can_merge && info->count &&
35 info->count <= info->max_regions &&
36 reg && offset <= reg->offset + reg->size) {
37 reg->size = offset + size - reg->offset;
38 } else if (info->count++ < info->max_regions) {
39 if (reg) {
40 reg++;
41 reg->offset = offset;
42 reg->size = size;
43 }
44 } else {
45 return -1;
46 }
47
48 return 0;
49}
50
51static int region_list_contains_offset(struct fdt_region_state *info,
52 const void *fdt, int target)
53{
54 struct fdt_region *reg;
55 int num;
56
57 target += fdt_off_dt_struct(fdt);
58 for (reg = info->region, num = 0; num < info->count; reg++, num++) {
59 if (target >= reg->offset && target < reg->offset + reg->size)
60 return 1;
61 }
62
63 return 0;
64}
65
66int fdt_add_alias_regions(const void *fdt, struct fdt_region *region, int count,
67 int max_regions, struct fdt_region_state *info)
68{
69 int base = fdt_off_dt_struct(fdt);
70 int node, node_end, offset;
71 int did_alias_header;
72
73 node = fdt_subnode_offset(fdt, 0, "aliases");
74 if (node < 0)
75 return -FDT_ERR_NOTFOUND;
76
77
78 node_end = fdt_next_subnode(fdt, node);
79 if (node_end <= 0)
80 return -FDT_ERR_BADLAYOUT;
81 node_end -= sizeof(fdt32_t);
82
83 did_alias_header = 0;
84 info->region = region;
85 info->count = count;
86 info->can_merge = 0;
87 info->max_regions = max_regions;
88
89 for (offset = fdt_first_property_offset(fdt, node);
90 offset >= 0;
91 offset = fdt_next_property_offset(fdt, offset)) {
92 const struct fdt_property *prop;
93 const char *name;
94 int target, next;
95
96 prop = fdt_get_property_by_offset(fdt, offset, NULL);
97 name = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
98 target = fdt_path_offset(fdt, name);
99 if (!region_list_contains_offset(info, fdt, target))
100 continue;
101 next = fdt_next_property_offset(fdt, offset);
102 if (next < 0)
103 next = node_end;
104
105 if (!did_alias_header) {
106 fdt_add_region(info, base + node, 12);
107 did_alias_header = 1;
108 }
109 fdt_add_region(info, base + offset, next - offset);
110 }
111
112
113 if (did_alias_header)
114 fdt_add_region(info, base + node_end, sizeof(fdt32_t));
115
116 return info->count < max_regions ? info->count : -FDT_ERR_NOSPACE;
117}
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136static int fdt_include_supernodes(struct fdt_region_state *info, int depth)
137{
138 int base = fdt_off_dt_struct(info->fdt);
139 int start, stop_at;
140 int i;
141
142
143
144
145
146
147
148 for (i = 0; i <= depth; i++) {
149 if (!info->stack[i].included) {
150 start = info->stack[i].offset;
151
152
153 fdt_next_tag(info->fdt, start, &stop_at);
154 if (fdt_add_region(info, base + start, stop_at - start))
155 return -1;
156
157
158 info->stack[i].included = 1;
159 info->can_merge = 1;
160 }
161
162
163 if (!info->stack[i].want)
164 info->stack[i].want = WANT_NODES_ONLY;
165 }
166
167 return 0;
168}
169
170enum {
171 FDT_DONE_NOTHING,
172 FDT_DONE_MEM_RSVMAP,
173 FDT_DONE_STRUCT,
174 FDT_DONE_END,
175 FDT_DONE_STRINGS,
176 FDT_DONE_ALL,
177};
178
179int fdt_first_region(const void *fdt,
180 int (*h_include)(void *priv, const void *fdt, int offset,
181 int type, const char *data, int size),
182 void *priv, struct fdt_region *region,
183 char *path, int path_len, int flags,
184 struct fdt_region_state *info)
185{
186 struct fdt_region_ptrs *p = &info->ptrs;
187
188
189 info->fdt = fdt;
190 info->can_merge = 1;
191 info->max_regions = 1;
192 info->start = -1;
193 p->want = WANT_NOTHING;
194 p->end = path;
195 *p->end = '\0';
196 p->nextoffset = 0;
197 p->depth = -1;
198 p->done = FDT_DONE_NOTHING;
199
200 return fdt_next_region(fdt, h_include, priv, region,
201 path, path_len, flags, info);
202}
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276int fdt_next_region(const void *fdt,
277 int (*h_include)(void *priv, const void *fdt, int offset,
278 int type, const char *data, int size),
279 void *priv, struct fdt_region *region,
280 char *path, int path_len, int flags,
281 struct fdt_region_state *info)
282{
283 int base = fdt_off_dt_struct(fdt);
284 int last_node = 0;
285 const char *str;
286
287 info->region = region;
288 info->count = 0;
289 if (info->ptrs.done < FDT_DONE_MEM_RSVMAP &&
290 (flags & FDT_REG_ADD_MEM_RSVMAP)) {
291
292 if (fdt_add_region(info, fdt_off_mem_rsvmap(fdt),
293 fdt_off_dt_struct(fdt) -
294 fdt_off_mem_rsvmap(fdt)))
295 return 0;
296 info->can_merge = 0;
297 info->ptrs.done = FDT_DONE_MEM_RSVMAP;
298 }
299
300
301
302
303
304
305
306
307 while (info->ptrs.done < FDT_DONE_STRUCT) {
308 const struct fdt_property *prop;
309 struct fdt_region_ptrs p;
310 const char *name;
311 int include = 0;
312 int stop_at = 0;
313 uint32_t tag;
314 int offset;
315 int val;
316 int len;
317
318
319
320
321
322
323
324 p = info->ptrs;
325
326
327
328
329
330
331 offset = p.nextoffset;
332 tag = fdt_next_tag(fdt, offset, &p.nextoffset);
333 stop_at = p.nextoffset;
334
335 switch (tag) {
336 case FDT_PROP:
337 stop_at = offset;
338 prop = fdt_get_property_by_offset(fdt, offset, NULL);
339 str = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
340 val = h_include(priv, fdt, last_node, FDT_IS_PROP, str,
341 strlen(str) + 1);
342 if (val == -1) {
343 include = p.want >= WANT_NODES_AND_PROPS;
344 } else {
345 include = val;
346
347
348
349
350
351
352
353 if ((flags & FDT_REG_SUPERNODES) && val &&
354 !p.want)
355 p.want = WANT_NODES_ONLY;
356 }
357
358
359 break;
360
361 case FDT_NOP:
362 include = p.want >= WANT_NODES_AND_PROPS;
363 stop_at = offset;
364 break;
365
366 case FDT_BEGIN_NODE:
367 last_node = offset;
368 p.depth++;
369 if (p.depth == FDT_MAX_DEPTH)
370 return -FDT_ERR_TOODEEP;
371 name = fdt_get_name(fdt, offset, &len);
372 if (p.end - path + 2 + len >= path_len)
373 return -FDT_ERR_NOSPACE;
374
375
376 if (p.end != path + 1)
377 *p.end++ = '/';
378 strcpy(p.end, name);
379 p.end += len;
380 info->stack[p.depth].want = p.want;
381 info->stack[p.depth].offset = offset;
382
383
384
385
386
387 if (p.want == WANT_NODES_ONLY ||
388 !(flags & (FDT_REG_DIRECT_SUBNODES |
389 FDT_REG_ALL_SUBNODES))) {
390 stop_at = offset;
391 p.want = WANT_NOTHING;
392 }
393 val = h_include(priv, fdt, offset, FDT_IS_NODE, path,
394 p.end - path + 1);
395
396
397 if (val) {
398 p.want = (flags & FDT_REG_ALL_SUBNODES) ?
399 WANT_ALL_NODES_AND_PROPS :
400 WANT_NODES_AND_PROPS;
401 }
402
403
404 else if (p.want) {
405 if (p.want != WANT_ALL_NODES_AND_PROPS)
406 p.want--;
407
408
409 } else {
410 stop_at = offset;
411 }
412
413
414
415
416
417 include = p.want;
418 info->stack[p.depth].included = include;
419 break;
420
421 case FDT_END_NODE:
422 include = p.want;
423 if (p.depth < 0)
424 return -FDT_ERR_BADSTRUCTURE;
425
426
427
428
429
430 if (!p.want && !(flags & FDT_REG_DIRECT_SUBNODES))
431 stop_at = offset;
432 p.want = info->stack[p.depth].want;
433 p.depth--;
434 while (p.end > path && *--p.end != '/')
435 ;
436 *p.end = '\0';
437 break;
438
439 case FDT_END:
440
441 include = 1;
442 p.done = FDT_DONE_STRUCT;
443 break;
444 }
445
446
447 if (include && info->start == -1) {
448
449 if (flags & FDT_REG_SUPERNODES) {
450 if (fdt_include_supernodes(info, p.depth))
451 return 0;
452 }
453 info->start = offset;
454 }
455
456
457
458
459
460 if (!include && info->start != -1) {
461 if (fdt_add_region(info, base + info->start,
462 stop_at - info->start))
463 return 0;
464 info->start = -1;
465 info->can_merge = 1;
466 }
467
468
469 info->ptrs = p;
470 }
471
472
473 if (info->ptrs.done < FDT_DONE_END) {
474 if (info->ptrs.nextoffset != fdt_size_dt_struct(fdt))
475 return -FDT_ERR_BADSTRUCTURE;
476
477 if (fdt_add_region(info, base + info->start,
478 info->ptrs.nextoffset - info->start))
479 return 0;
480 info->ptrs.done++;
481 }
482 if (info->ptrs.done < FDT_DONE_STRINGS) {
483 if (flags & FDT_REG_ADD_STRING_TAB) {
484 info->can_merge = 0;
485 if (fdt_off_dt_strings(fdt) <
486 base + info->ptrs.nextoffset)
487 return -FDT_ERR_BADLAYOUT;
488 if (fdt_add_region(info, fdt_off_dt_strings(fdt),
489 fdt_size_dt_strings(fdt)))
490 return 0;
491 }
492 info->ptrs.done++;
493 }
494
495 return info->count > 0 ? 0 : -FDT_ERR_NOTFOUND;
496}
497