blob: da261784300c1ca1990c124fb5a0449210b4d0bd [file] [log] [blame]
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +01001#include "fdt.h"
2
3#include <stdint.h>
4
5#include "dlog.h"
6#include "std.h"
7
8struct fdt_header {
9 uint32_t magic;
10 uint32_t totalsize;
11 uint32_t off_dt_struct;
12 uint32_t off_dt_strings;
13 uint32_t off_mem_rsvmap;
14 uint32_t version;
15 uint32_t last_comp_version;
16 uint32_t boot_cpuid_phys;
17 uint32_t size_dt_strings;
18 uint32_t size_dt_struct;
19};
20
21struct fdt_reserve_entry {
22 uint64_t address;
23 uint64_t size;
24};
25
26enum fdt_token {
27 FDT_BEGIN_NODE = 1,
28 FDT_END_NODE = 2,
29 FDT_PROP = 3,
30 FDT_NOP = 4,
31 FDT_END = 9,
32};
33
34struct fdt_tokenizer {
35 const char *cur;
36 const char *end;
37 const char *strs;
38};
39
40#define FDT_VERSION 17
41#define FDT_MAGIC 0xd00dfeed
42
43static void fdt_tokenizer_init(struct fdt_tokenizer *t, const char *strs,
44 const char *begin, const char *end)
45{
46 t->strs = strs;
47 t->cur = begin;
48 t->end = end;
49}
50
51static void fdt_tokenizer_align(struct fdt_tokenizer *t)
52{
53 t->cur = (char *)(((size_t)t->cur + 3) & ~3);
54}
55
56static bool fdt_tokenizer_uint32(struct fdt_tokenizer *t, uint32_t *res)
57{
58 const char *next = t->cur + sizeof(*res);
59 if (next > t->end)
60 return false;
61
62 *res = ntohl(*(uint32_t *)t->cur);
63 t->cur = next;
64
65 return true;
66}
67
68static bool fdt_tokenizer_token(struct fdt_tokenizer *t, uint32_t *res)
69{
70 uint32_t v;
71
72 while (fdt_tokenizer_uint32(t, &v)) {
73 if (v != FDT_NOP) {
74 *res = v;
75 return true;
76 }
77 }
78 return false;
79}
80
81static bool fdt_tokenizer_bytes(struct fdt_tokenizer *t,
82 const char **res, size_t size)
83{
84 const char *next = t->cur + size;
85 if (next > t->end)
86 return false;
87
88 *res = t->cur;
89 t->cur = next;
90 fdt_tokenizer_align(t);
91
92 return true;
93}
94
95static bool fdt_tokenizer_str(struct fdt_tokenizer *t, const char **res)
96{
97 const char *p;
98 for (p = t->cur; p < t->end; p++) {
99 if (!*p) {
100 /* Found the end of the string. */
101 *res = t->cur;
102 t->cur = p + 1;
103 fdt_tokenizer_align(t);
104 return true;
105 }
106 }
107
108 return false;
109}
110
111void fdt_root_node(struct fdt_node *node, const struct fdt_header *hdr)
112{
113 uint32_t max_ver;
114 uint32_t min_ver;
115 uint32_t begin = ntohl(hdr->off_dt_struct);
116 uint32_t size = ntohl(hdr->size_dt_struct);
117
118 memset(node, 0, sizeof(*node));
119
120 /* Check the magic number before anything else. */
121 if (hdr->magic != ntohl(FDT_MAGIC))
122 return;
123
124 /* Check the version. */
125 max_ver = ntohl(hdr->version);
126 min_ver = ntohl(hdr->last_comp_version);
127 if (FDT_VERSION < min_ver || FDT_VERSION > max_ver)
128 return;
129
130 /* TODO: Verify that it is all within the fdt. */
131 node->begin = (const char *)hdr + begin;
132 node->end = node->begin + size;
133
134 /* TODO: Verify strings as well. */
135 node->strs = (char *)hdr + ntohl(hdr->off_dt_strings);
136}
137
138static bool fdt_next_property(struct fdt_tokenizer *t, const char **name,
139 const char **buf, uint32_t *size)
140{
141 uint32_t token;
142 uint32_t nameoff;
143
144 if (!fdt_tokenizer_token(t, &token))
145 return false;
146
147 if (token != FDT_PROP) {
148 /* Rewind so that caller will get the same token. */
149 t->cur -= sizeof(uint32_t);
150 return false;
151 }
152
153 if (!fdt_tokenizer_uint32(t, size) ||
154 !fdt_tokenizer_uint32(t, &nameoff) ||
155 !fdt_tokenizer_bytes(t, buf, *size)) {
156 /*
157 * Move cursor to the end so that caller won't get any new
158 * tokens.
159 */
160 t->cur = t->end;
161 return false;
162 }
163
164 /* TODO: Need to verify the strings. */
165 *name = t->strs + nameoff;
166
167 return true;
168}
169
170static bool fdt_next_subnode(struct fdt_tokenizer *t, const char **name)
171{
172 uint32_t token;
173
174 if (!fdt_tokenizer_token(t, &token))
175 return false;
176
177 if (token != FDT_BEGIN_NODE) {
178 /* Rewind so that caller will get the same token. */
179 t->cur -= sizeof(uint32_t);
180 return false;
181 }
182
183 if (!fdt_tokenizer_str(t, name)) {
184 /*
185 * Move cursor to the end so that caller won't get any new
186 * tokens.
187 */
188 t->cur = t->end;
189 return false;
190 }
191
192 return true;
193}
194
195static void fdt_skip_properties(struct fdt_tokenizer *t)
196{
197 const char *name;
198 const char *buf;
199 uint32_t size;
200 while (fdt_next_property(t, &name, &buf, &size));
201}
202
203static bool fdt_skip_node(struct fdt_tokenizer *t)
204{
205 const char *name;
206 uint32_t token;
207 size_t pending = 1;
208
209 fdt_skip_properties(t);
210
211 do {
212 while (fdt_next_subnode(t, &name)) {
213 fdt_skip_properties(t);
214 pending++;
215 }
216
217 if (!fdt_tokenizer_token(t, &token))
218 return false;
219
220 if (token != FDT_END_NODE) {
221 t->cur = t->end;
222 return false;
223 }
224
225 pending--;
226 } while (pending);
227
228 return true;
229}
230
231bool fdt_read_property(const struct fdt_node *node, const char *name,
232 const char **buf, uint32_t *size)
233{
234 struct fdt_tokenizer t;
235 const char *prop_name;
236
237 fdt_tokenizer_init(&t, node->strs, node->begin, node->end);
238
239 while (fdt_next_property(&t, &prop_name, buf, size)) {
240 if (!strcmp(prop_name, name))
241 return true;
242 }
243
244 return false;
245}
246
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100247bool fdt_first_child(struct fdt_node *node, const char **child_name)
248{
249 struct fdt_tokenizer t;
250
251 fdt_tokenizer_init(&t, node->strs, node->begin, node->end);
252
253 fdt_skip_properties(&t);
254
255 if (!fdt_next_subnode(&t, child_name))
256 return false;
257
258 node->begin = t.cur;
259
260 return true;
261}
262
263bool fdt_next_sibling(struct fdt_node *node, const char **sibling_name)
264{
265 struct fdt_tokenizer t;
266
267 fdt_tokenizer_init(&t, node->strs, node->begin, node->end);
268
269 if (!fdt_skip_node(&t))
270 return false;
271
272 if (!fdt_next_subnode(&t, sibling_name))
273 return false;
274
275 node->begin = t.cur;
276
277 return true;
278}
279
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100280bool fdt_find_child(struct fdt_node *node, const char *child)
281{
282 struct fdt_tokenizer t;
283 const char *name;
284
285 fdt_tokenizer_init(&t, node->strs, node->begin, node->end);
286
287 fdt_skip_properties(&t);
288
289 while (fdt_next_subnode(&t, &name)) {
290 if (!strcmp(name, child)) {
291 node->begin = t.cur;
292 return true;
293 }
294
295 fdt_skip_node(&t);
296 }
297
298 return false;
299}
300
301void fdt_dump(struct fdt_header *hdr)
302{
303 uint32_t token;
304 size_t depth = 0;
305 const char *name;
306 struct fdt_tokenizer t;
307 struct fdt_node node;
308
309 /* Traverse the whole thing. */
310 fdt_root_node(&node, hdr);
311
312 fdt_tokenizer_init(&t, node.strs, node.begin, node.end);
313
314 do {
315 while (fdt_next_subnode(&t, &name)) {
316 const char *buf;
317 uint32_t size;
318
319 dlog("%*sNew node: \"%s\"\n", 2 * depth, "", name);
320 depth++;
321 while (fdt_next_property(&t, &name, &buf, &size)) {
322 size_t i;
323 dlog("%*sproperty: \"%s\" (", 2 * depth, "", name);
324 for (i = 0; i < size; i++)
325 dlog("%s%02x", i == 0 ? "" : " ", buf[i]);
326 dlog(")\n");
327 }
328 }
329
330 if (!fdt_tokenizer_token(&t, &token))
331 return;
332
333 if (token != FDT_END_NODE)
334 return;
335
336 depth--;
337 } while (depth);
338
339 dlog("fdt: off_mem_rsvmap=%u\n", ntohl(hdr->off_mem_rsvmap));
340 {
341 struct fdt_reserve_entry *e = (struct fdt_reserve_entry *)((size_t)hdr + ntohl(hdr->off_mem_rsvmap));
342 while (e->address || e->size) {
343 dlog("Entry: %p (0x%x bytes)\n", ntohll(e->address), ntohll(e->size));
344 e++;
345 }
346 }
347}
348
349void fdt_add_mem_reservation(struct fdt_header *hdr, size_t addr, size_t len)
350{
351 /* TODO: Clean this up. */
352 char *begin = (char *)hdr + ntohl(hdr->off_mem_rsvmap);
353 struct fdt_reserve_entry *e = (struct fdt_reserve_entry *)begin;
354 hdr->totalsize = htonl(ntohl(hdr->totalsize) + sizeof(struct fdt_reserve_entry));
355 hdr->off_dt_struct = htonl(ntohl(hdr->off_dt_struct) + sizeof(struct fdt_reserve_entry));
356 hdr->off_dt_strings = htonl(ntohl(hdr->off_dt_strings) + sizeof(struct fdt_reserve_entry));
357 memmove(begin + sizeof(struct fdt_reserve_entry), begin, ntohl(hdr->totalsize) - ntohl(hdr->off_mem_rsvmap));
358 e->address = htonll(addr);
359 e->size = htonll(len);
360}