1/*
2Copyright (c) 2016-2019 Raspberry Pi (Trading) Ltd.
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are met:
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above copyright
10 notice, this list of conditions and the following disclaimer in the
11 documentation and/or other materials provided with the distribution.
12 * Neither the name of the copyright holder nor the
13 names of its contributors may be used to endorse or promote products
14 derived from this software without specific prior written permission.
15
16THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*/
27
28#include <stdio.h>
29#include <stdlib.h>
30#include <stdarg.h>
31#include <stdint.h>
32#include <libfdt.h>
33#include <assert.h>
34
35#include "dtoverlay.h"
36
37#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
38
39typedef enum
40{
41 FIXUP_ABSOLUTE,
42 FIXUP_RELATIVE
43} fixup_type_t;
44
45#define DTOVERRIDE_END 0
46#define DTOVERRIDE_INTEGER 1
47#define DTOVERRIDE_BOOLEAN 2
48#define DTOVERRIDE_BOOLEAN_INV 3
49#define DTOVERRIDE_STRING 4
50#define DTOVERRIDE_OVERLAY 5
51#define DTOVERRIDE_BYTE_STRING 6
52
53static int dtoverlay_extract_override(const char *override_name,
54 char *override_value, int value_size,
55 int *phandle_ptr,
56 const char **datap, const char *dataendp,
57 const char **namep, int *namelenp,
58 int *offp, int *sizep);
59
60static const char *dtoverlay_lookup_key(const char *lookup_string, const char *data_end,
61 const char *key, char *buf, int buf_len);
62
63static int dtoverlay_set_node_name(DTBLOB_T *dtb, int node_off,
64 const char *name);
65
66static void dtoverlay_stdio_logging(dtoverlay_logging_type_t type,
67 const char *fmt, va_list args);
68
69#define phandle_debug if (0) dtoverlay_debug
70
71static DTOVERLAY_LOGGING_FUNC *dtoverlay_logging_func = dtoverlay_stdio_logging;
72static int dtoverlay_debug_enabled = 0;
73
74static int strmemcmp(const char *mem, int mem_len, const char *str)
75{
76 int ret = strncmp(mem, str, mem_len);
77 if (ret == 0 && str[mem_len] != 0)
78 ret = 1;
79 return ret;
80}
81
82uint8_t dtoverlay_read_u8(const void *src, int off)
83{
84 const unsigned char *p = src;
85 return (p[off + 0] << 0);
86}
87
88uint16_t dtoverlay_read_u16(const void *src, int off)
89{
90 const unsigned char *p = src;
91 return (p[off + 0] << 8) | (p[off + 1] << 0);
92}
93
94uint32_t dtoverlay_read_u32(const void *src, int off)
95{
96 const unsigned char *p = src;
97 return (p[off + 0] << 24) | (p[off + 1] << 16) |
98 (p[off + 2] << 8) | (p[off + 3] << 0);
99}
100
101uint64_t dtoverlay_read_u64(const void *src, int off)
102{
103 const unsigned char *p = src;
104 return ((uint64_t)p[off + 0] << 56) | ((uint64_t)p[off + 1] << 48) |
105 ((uint64_t)p[off + 2] << 40) | ((uint64_t)p[off + 3] << 32) |
106 (p[off + 4] << 24) | (p[off + 5] << 16) |
107 (p[off + 6] << 8) | (p[off + 7] << 0);
108}
109
110void dtoverlay_write_u8(void *dst, int off, uint32_t val)
111{
112 unsigned char *p = dst;
113 p[off] = (val >> 0) & 0xff;
114}
115
116void dtoverlay_write_u16(void *dst, int off, uint32_t val)
117{
118 unsigned char *p = dst;
119 p[off + 0] = (val >> 8) & 0xff;
120 p[off + 1] = (val >> 0) & 0xff;
121}
122
123void dtoverlay_write_u32(void *dst, int off, uint32_t val)
124{
125 unsigned char *p = dst;
126 p[off + 0] = (val >> 24) & 0xff;
127 p[off + 1] = (val >> 16) & 0xff;
128 p[off + 2] = (val >> 8) & 0xff;
129 p[off + 3] = (val >> 0) & 0xff;
130}
131
132void dtoverlay_write_u64(void *dst, int off, uint64_t val)
133{
134 unsigned char *p = dst;
135 p[off + 0] = (val >> 56) & 0xff;
136 p[off + 1] = (val >> 48) & 0xff;
137 p[off + 2] = (val >> 40) & 0xff;
138 p[off + 3] = (val >> 32) & 0xff;
139 p[off + 4] = (val >> 24) & 0xff;
140 p[off + 5] = (val >> 16) & 0xff;
141 p[off + 6] = (val >> 8) & 0xff;
142 p[off + 7] = (val >> 0) & 0xff;
143}
144
145// Returns the offset of the node indicated by the absolute path, creating
146// it and any intermediates as necessary, or a negative error code.
147int dtoverlay_create_node(DTBLOB_T *dtb, const char *node_path, int path_len)
148{
149 const char *path_ptr;
150 const char *path_end;
151 int node_off = 0;
152
153 if (!path_len)
154 path_len = strlen(node_path);
155
156 path_ptr = node_path;
157 path_end = node_path + path_len;
158
159 if ((path_len > 0) && (path_ptr[path_len - 1] == '/'))
160 path_end--;
161
162 while (path_ptr < path_end)
163 {
164 const char *path_next;
165 int subnode_off;
166
167 if (*path_ptr != '/')
168 return -FDT_ERR_BADPATH;
169
170 // find the next path separator (or the end of the string)
171 path_ptr++;
172 for (path_next = path_ptr;
173 (path_next != path_end) && (*path_next != '/');
174 path_next++)
175 continue;
176
177 subnode_off = fdt_subnode_offset_namelen(dtb->fdt, node_off, path_ptr,
178 path_next - path_ptr);
179 if (subnode_off >= 0)
180 node_off = subnode_off;
181 else
182 node_off = fdt_add_subnode_namelen(dtb->fdt, node_off, path_ptr,
183 path_next - path_ptr);
184 if (node_off < 0)
185 break;
186
187 path_ptr = path_next;
188 }
189
190 if ((node_off >= 0) && (path_ptr != path_end))
191 return -FDT_ERR_BADPATH;
192
193 return node_off;
194}
195
196// Returns 0 on success, otherwise <0 error code
197int dtoverlay_delete_node(DTBLOB_T *dtb, const char *node_path, int path_len)
198{
199 int node_off = 0;
200 if (!path_len)
201 path_len = strlen(node_path);
202
203 dtoverlay_debug("delete_node(%.*s)", path_len, node_path);
204 node_off = fdt_path_offset_namelen(dtb->fdt, node_path, path_len);
205 if (node_off < 0)
206 return node_off;
207 return fdt_del_node(dtb->fdt, node_off);
208}
209
210// Returns the offset of the node indicated by the absolute path or a negative
211// error code.
212int dtoverlay_find_node(DTBLOB_T *dtb, const char *node_path, int path_len)
213{
214 if (!path_len)
215 path_len = strlen(node_path);
216 return fdt_path_offset_namelen(dtb->fdt, node_path, path_len);
217}
218
219// Returns 0 on success, otherwise <0 error code
220int dtoverlay_set_node_properties(DTBLOB_T *dtb, const char *node_path,
221 DTOVERLAY_PARAM_T *properties,
222 unsigned int num_properties)
223{
224 int err = 0;
225 int node_off;
226
227 node_off = fdt_path_offset(dtb->fdt, node_path);
228 if (node_off < 0)
229 node_off = dtoverlay_create_node(dtb, node_path, 0);
230 if (node_off >= 0)
231 {
232 int i;
233 for (i = 0; (i < num_properties) && (err == 0); i++)
234 {
235 DTOVERLAY_PARAM_T *p;
236
237 p = properties + i;
238 err = fdt_setprop(dtb->fdt, node_off, p->param, p->b, p->len);
239 }
240 }
241 else
242 err = node_off;
243 return err;
244}
245
246struct dynstring
247{
248 char *buf;
249 int size;
250 int len;
251};
252
253static void dynstring_init(struct dynstring *ds)
254{
255 ds->size = 0;
256 ds->len = 0;
257 ds->buf = NULL;
258}
259
260static int dynstring_init_size(struct dynstring *ds, int initial_size)
261{
262 if (initial_size < 32)
263 initial_size = 32;
264 ds->size = initial_size;
265 ds->len = 0;
266 ds->buf = malloc(initial_size);
267 if (!ds->buf)
268 {
269 dtoverlay_error(" out of memory");
270 return -FDT_ERR_NOSPACE;
271 }
272 return 0;
273}
274
275static int dynstring_set_size(struct dynstring *ds, int size)
276{
277 if (size > ds->size)
278 {
279 size = (size * 5)/4; // Add a 25% headroom
280 ds->buf = realloc(ds->buf, size);
281 if (!ds->buf)
282 {
283 dtoverlay_error(" out of memory");
284 return -FDT_ERR_NOSPACE;
285 }
286 ds->size = size;
287 }
288 return 0;
289}
290
291static int dynstring_dup(struct dynstring *ds, const char *src, int len)
292{
293 int err = 0;
294
295 if (!len)
296 len = strlen(src);
297
298 err = dynstring_set_size(ds, len + 1);
299 if (!err)
300 {
301 memcpy(ds->buf, src, len + 1);
302 ds->len = len;
303 }
304
305 return err;
306}
307
308static int dynstring_patch(struct dynstring *ds, int pos, int width,
309 const char *src, int len)
310{
311 int newlen = ds->len + (len - width);
312 int err = dynstring_set_size(ds, newlen + 1);
313 if (!err)
314 {
315 if (width != len)
316 {
317 // Move any data following the patch
318 memmove(ds->buf + pos + len, ds->buf + pos + width,
319 ds->len + 1 - (pos + width));
320 ds->len = newlen;
321 }
322 memcpy(ds->buf + pos, src, len);
323 }
324 return err;
325}
326
327static int dynstring_grow(struct dynstring *ds)
328{
329 return dynstring_set_size(ds, (3*ds->size)/2);
330}
331
332static void dynstring_free(struct dynstring *ds)
333{
334 free(ds->buf);
335 dynstring_init(ds);
336}
337
338static int dtoverlay_set_node_name(DTBLOB_T *dtb, int node_off,
339 const char *name)
340{
341 struct dynstring path_buf;
342 struct dynstring prop_buf;
343 char *old_path;
344 const char *old_name;
345 const char *fixup_nodes[] =
346 {
347 "/__fixups__",
348 "/__local_fixups__", // For old-style dtbos
349 "/__symbols__" // Just in case the kernel cares
350 };
351 int old_name_len;
352 int old_path_len; // All of it
353 int dir_len; // Excluding the node name, but with the trailling slash
354 int name_len;
355 int offset;
356 int fixup_idx;
357 int err = 0;
358
359 // Fixups and local-fixups both use node names, so this
360 // function must be patch them up when a node is renamed
361 // unless the fixups have already been applied.
362 // Calculating a node's name is expensive, so only do it if
363 // necessary. Since renaming a node can move things around,
364 // don't use node_off afterwards.
365 err = dynstring_init_size(&path_buf, 100);
366 if (err)
367 return err;
368
369 if (!dtb->fixups_applied)
370 {
371 while (1)
372 {
373 err = fdt_get_path(dtb->fdt, node_off, path_buf.buf, path_buf.size);
374 if (!err)
375 break;
376 if (err != -FDT_ERR_NOSPACE)
377 return err;
378 dynstring_grow(&path_buf);
379 }
380 }
381 old_path = path_buf.buf;
382
383 err = fdt_set_name(dtb->fdt, node_off, name);
384 if (err || dtb->fixups_applied)
385 goto clean_up;
386
387 // Find the node name in old_path
388 old_name = strrchr(old_path, '/');
389 assert(old_name);
390 if (!old_name)
391 return -FDT_ERR_INTERNAL;
392 old_name++;
393 old_name_len = strlen(old_name);
394 dir_len = old_name - old_path;
395 old_path_len = dir_len + old_name_len;
396
397 // Short-circuit the case where the name isn't changing
398 if (strcmp(name, old_name) == 0)
399 goto clean_up;
400
401 name_len = strlen(name);
402
403 // Search the fixups and symbols for the old path (including as
404 // a parent) and replace with the new name
405
406 dynstring_init(&prop_buf);
407 for (fixup_idx = 0; fixup_idx < ARRAY_SIZE(fixup_nodes); fixup_idx++)
408 {
409 int prop_off;
410
411 offset = fdt_path_offset(dtb->fdt, fixup_nodes[fixup_idx]);
412 if (offset > 0)
413 {
414
415 // Iterate through the properties
416 for (prop_off = fdt_first_property_offset(dtb->fdt, offset);
417 (prop_off >= 0) && (err == 0);
418 prop_off = fdt_next_property_offset(dtb->fdt, prop_off))
419 {
420 const char *prop_name;
421 const char *prop_val;
422 int prop_len;
423 int pos;
424 int changed = 0;
425
426 prop_val = fdt_getprop_by_offset(dtb->fdt, prop_off,
427 &prop_name, &prop_len);
428 err = dynstring_dup(&prop_buf, prop_val, prop_len);
429 if (err)
430 break;
431
432 // Scan each property for matching paths
433 pos = 0;
434 while (pos < prop_len)
435 {
436 if ((pos + old_path_len < prop_len) &&
437 (memcmp(prop_buf.buf + pos, old_path, old_path_len) == 0) &&
438 ((prop_buf.buf[pos + old_path_len] == ':') ||
439 (prop_buf.buf[pos + old_path_len] == '/') ||
440 (prop_buf.buf[pos + old_path_len] == '\0')))
441 {
442 // Patch the string, replacing old name with new
443 err = dynstring_patch(&prop_buf, pos + dir_len, old_name_len,
444 name, name_len);
445 if (err)
446 break;
447
448 prop_len += name_len - old_name_len;
449 changed = 1;
450 }
451 pos += strlen(prop_buf.buf + pos) + 1;
452 }
453
454 if (!err && changed)
455 {
456 // Caution - may change offsets, but only by shuffling everything
457 // afterwards, i.e. the offset to this node or property does not
458 // change.
459 err = fdt_setprop(dtb->fdt, offset, prop_name, prop_buf.buf,
460 prop_len);
461 }
462 }
463 }
464 }
465
466 dynstring_free(&prop_buf);
467
468 if (err)
469 goto clean_up;
470
471 // Then look for a "/__local_fixups__<old_path>" node, and rename
472 // that as well.
473 offset = fdt_path_offset(dtb->fdt, "/__local_fixups__");
474 if (offset > 0)
475 {
476 const char *p, *end;
477
478 p = old_path;
479 end = old_path + old_path_len;
480 while (p < end)
481 {
482 const char *q;
483
484 while (*p == '/') {
485 p++;
486 if (p == end)
487 break;
488 }
489 q = memchr(p, '/', end - p);
490 if (! q)
491 q = end;
492
493 offset = fdt_subnode_offset_namelen(dtb->fdt, offset, p, q-p);
494 if (offset < 0)
495 break;
496
497 p = q;
498 }
499
500 if (offset > 0)
501 err = fdt_set_name(dtb->fdt, offset, name);
502 }
503
504 // __overrides__ don't need patching because nodes are identified
505 // using phandles, which are unaffected by renaming and resizing nodes.
506
507clean_up:
508 dynstring_free(&path_buf);
509
510 return err;
511}
512
513// Returns 0 on success, otherwise <0 error code
514int dtoverlay_create_prop_fragment(DTBLOB_T *dtb, int idx, int target_phandle,
515 const char *prop_name, const void *prop_data,
516 int prop_len)
517{
518 char fragment_name[20];
519 int frag_off, ovl_off;
520 int ret;
521 snprintf(fragment_name, sizeof(fragment_name), "fragment-%u", idx);
522 frag_off = fdt_add_subnode(dtb->fdt, 0, fragment_name);
523 if (frag_off < 0)
524 return frag_off;
525 ret = fdt_setprop_u32(dtb->fdt, frag_off, "target", target_phandle);
526 if (ret < 0)
527 return ret;
528 ovl_off = fdt_add_subnode(dtb->fdt, frag_off, "__overlay__");
529 if (ovl_off < 0)
530 return ovl_off;
531 return fdt_setprop(dtb->fdt, ovl_off, prop_name, prop_data, prop_len);
532}
533
534// Returns 0 on success, otherwise <0 error code
535static int dtoverlay_merge_fragment(DTBLOB_T *base_dtb, int target_off,
536 const DTBLOB_T *overlay_dtb,
537 int overlay_off, int depth)
538{
539 int prop_off, subnode_off;
540 int err = 0;
541
542 if (dtoverlay_debug_enabled)
543 {
544 char base_path[256];
545 char overlay_path[256];
546 fdt_get_path(base_dtb->fdt, target_off, base_path, sizeof(base_path));
547 fdt_get_path(overlay_dtb->fdt, overlay_off, overlay_path,
548 sizeof(overlay_path));
549
550 dtoverlay_debug("merge_fragment(%s,%s)", base_path,
551 overlay_path);
552 }
553
554 // Merge each property of the node
555 for (prop_off = fdt_first_property_offset(overlay_dtb->fdt, overlay_off);
556 (prop_off >= 0) && (err == 0);
557 prop_off = fdt_next_property_offset(overlay_dtb->fdt, prop_off))
558 {
559 const char *prop_name;
560 const void *prop_val;
561 int prop_len;
562 struct fdt_property *target_prop;
563 int target_len;
564
565 prop_val = fdt_getprop_by_offset(overlay_dtb->fdt, prop_off,
566 &prop_name, &prop_len);
567
568 /* Skip these system properties (only phandles in the first level) */
569 if ((strcmp(prop_name, "name") == 0) ||
570 ((depth == 0) && ((strcmp(prop_name, "phandle") == 0) ||
571 (strcmp(prop_name, "linux,phandle") == 0))))
572 continue;
573
574 dtoverlay_debug(" +prop(%s)", prop_name);
575
576 if ((strcmp(prop_name, "bootargs") == 0) &&
577 ((target_prop = fdt_get_property_w(base_dtb->fdt, target_off, prop_name, &target_len)) != NULL) &&
578 (target_len > 0) && *target_prop->data)
579 {
580 target_prop->data[target_len - 1] = ' ';
581 err = fdt_appendprop(base_dtb->fdt, target_off, prop_name, prop_val, prop_len);
582 }
583 else
584 err = fdt_setprop(base_dtb->fdt, target_off, prop_name, prop_val, prop_len);
585 }
586
587 // Merge each subnode of the node
588 for (subnode_off = fdt_first_subnode(overlay_dtb->fdt, overlay_off);
589 (subnode_off >= 0) && (err == 0);
590 subnode_off = fdt_next_subnode(overlay_dtb->fdt, subnode_off))
591 {
592 const char *subnode_name;
593 int name_len;
594 int subtarget_off;
595
596 subnode_name = fdt_get_name(overlay_dtb->fdt, subnode_off, &name_len);
597
598 subtarget_off = fdt_subnode_offset_namelen(base_dtb->fdt, target_off,
599 subnode_name, name_len);
600 if (subtarget_off < 0)
601 subtarget_off = fdt_add_subnode_namelen(base_dtb->fdt, target_off,
602 subnode_name, name_len);
603
604 if (subtarget_off >= 0)
605 {
606 err = dtoverlay_merge_fragment(base_dtb, subtarget_off,
607 overlay_dtb, subnode_off,
608 depth + 1);
609 }
610 else
611 {
612 err = subtarget_off;
613 }
614 }
615
616 dtoverlay_debug("merge_fragment() end");
617
618 return err;
619}
620
621static int dtoverlay_phandle_relocate(DTBLOB_T *dtb, int node_off,
622 const char *prop_name,
623 uint32_t phandle_increment)
624{
625 int len;
626 const fdt32_t *prop_val = fdt_getprop(dtb->fdt, node_off, prop_name, &len);
627 int err = 0; // The absence of the property is not an error
628
629 if (prop_val)
630 {
631 uint32_t phandle;
632
633 if (len < 4)
634 {
635 dtoverlay_error("%s property too small", prop_name);
636 return -FDT_ERR_BADSTRUCTURE;
637 }
638
639 phandle = fdt32_to_cpu(*prop_val) + phandle_increment;
640 phandle_debug(" phandle_relocate %d->%d", fdt32_to_cpu(*prop_val), phandle);
641
642 err = fdt_setprop_inplace_u32(dtb->fdt, node_off, prop_name, phandle);
643 }
644
645 return err;
646}
647
648// Returns 0 on success, or an FDT error code
649static int dtoverlay_apply_fixups(DTBLOB_T *dtb, const char *fixups_stringlist,
650 uint32_t phandle, fixup_type_t type)
651{
652 // The fixups arrive as a sequence of NUL-terminated strings, of the form:
653 // "path:property:offset"
654 // Use an empty string as an end marker, since:
655 // 1) all tags begin 0x00 0x00 0x00,
656 // 2) all string properties must be followed by a tag,
657 // 3) an empty string is not a valid fixup, and
658 // 4) the code is simpler as a result.
659
660 const char *fixup = fixups_stringlist;
661
662 while (fixup[0])
663 {
664 const char *prop_name, *offset_str;
665 char *offset_end;
666 const void *prop_ptr;
667 int prop_len;
668 int node_off;
669 unsigned long offset;
670 uint32_t patch;
671
672 prop_name = strchr(fixup, ':');
673 if (!prop_name)
674 return -FDT_ERR_BADSTRUCTURE;
675 prop_name++;
676
677 offset_str = strchr(prop_name, ':');
678 if (!offset_str)
679 return -FDT_ERR_BADSTRUCTURE;
680 offset_str++;
681
682 offset = strtoul(offset_str, &offset_end, 10);
683 if ((offset_end == offset_str) || (offset_end[0] != 0))
684 return -FDT_ERR_BADSTRUCTURE;
685
686 node_off = fdt_path_offset_namelen(dtb->fdt, fixup, prop_name - 1 - fixup);
687 if (node_off < 0)
688 return node_off;
689
690 prop_ptr = fdt_getprop_namelen(dtb->fdt, node_off, prop_name,
691 offset_str - 1 - prop_name, &prop_len);
692 if (!prop_ptr)
693 return prop_len;
694 if (offset > (prop_len - 4))
695 return -FDT_ERR_BADSTRUCTURE;
696
697 // Now apply the patch. Yes, prop_ptr is a const void *, but the
698 // alternative (copying the whole property, patching, then updating as
699 // a whole) is ridiculous.
700 if (type == FIXUP_RELATIVE)
701 {
702 patch = phandle + dtoverlay_read_u32(prop_ptr, offset);
703 phandle_debug(" phandle fixup %d+%d->%d", phandle, patch - phandle, patch);
704 }
705 else
706 {
707 patch = phandle;
708 phandle_debug(" phandle ref '%s'->%d", prop_name, patch);
709 }
710
711 dtoverlay_write_u32((void *)prop_ptr, offset, patch);
712
713 fixup = offset_end + 1;
714 }
715
716 return 0;
717}
718
719// Returns 0 on success, or an FDT error code
720static int dtoverlay_apply_fixups_node(DTBLOB_T *dtb, int fix_off,
721 int target_off, uint32_t phandle_offset)
722{
723 // The fixups are arranged as a subtree mirroring the structure of the
724 // overall tree. Walk this tree in order. Each property is an array of cells
725 // containing offsets to patch within the corresponding node/property of
726 // the target tree.
727 int err = 0;
728 int prop_off;
729 int subfix_off;
730
731 // Merge each property of the node
732 for (prop_off = fdt_first_property_offset(dtb->fdt, fix_off);
733 (prop_off >= 0) && (err == 0);
734 prop_off = fdt_next_property_offset(dtb->fdt, prop_off))
735 {
736 const char *prop_name;
737 const void *prop_val;
738 int prop_len;
739 void *target_ptr;
740 int target_len;
741 int off;
742
743 prop_val = fdt_getprop_by_offset(dtb->fdt, prop_off,
744 &prop_name, &prop_len);
745 if (!prop_val)
746 return -FDT_ERR_INTERNAL;
747
748 target_ptr = fdt_getprop_w(dtb->fdt, target_off, prop_name, &target_len);
749 if (!target_ptr)
750 return -FDT_ERR_BADSTRUCTURE;
751
752 for (off = 0; (off + 4) <= prop_len; off += 4)
753 {
754 uint32_t patch;
755 int patch_offset = dtoverlay_read_u32(prop_val, off);
756 if ((patch_offset + 4) > target_len)
757 return -FDT_ERR_BADSTRUCTURE;
758
759 patch = phandle_offset + dtoverlay_read_u32(target_ptr, patch_offset);
760 phandle_debug(" phandle fixup %d+%d->%d", phandle_offset, patch - phandle_offset, patch);
761
762 dtoverlay_write_u32(target_ptr, patch_offset, patch);
763 }
764 }
765
766 // Merge each subnode of the node
767 for (subfix_off = fdt_first_subnode(dtb->fdt, fix_off);
768 (subfix_off >= 0) && (err == 0);
769 subfix_off = fdt_next_subnode(dtb->fdt, subfix_off))
770 {
771 const char *subnode_name;
772 int name_len;
773 int subtarget_off;
774
775 subnode_name = fdt_get_name(dtb->fdt, subfix_off, &name_len);
776
777 subtarget_off = fdt_subnode_offset_namelen(dtb->fdt, target_off,
778 subnode_name, name_len);
779
780 if (subtarget_off >= 0)
781 {
782 err = dtoverlay_apply_fixups_node(dtb, subfix_off, subtarget_off,
783 phandle_offset);
784 }
785 else
786 {
787 err = subtarget_off;
788 }
789 }
790
791 return err;
792}
793
794// Returns 0 on success, or a negative FDT error.
795static int dtoverlay_resolve_phandles(DTBLOB_T *base_dtb, DTBLOB_T *overlay_dtb)
796{
797 int local_fixups_off;
798 int node_off;
799 int err = 0;
800
801 // First find and update the phandles in the overlay
802
803 for (node_off = 0;
804 node_off >= 0;
805 node_off = fdt_next_node(overlay_dtb->fdt, node_off, NULL))
806 {
807 dtoverlay_phandle_relocate(overlay_dtb, node_off, "phandle",
808 base_dtb->max_phandle);
809 dtoverlay_phandle_relocate(overlay_dtb, node_off, "linux,phandle",
810 base_dtb->max_phandle);
811 }
812
813 local_fixups_off = fdt_path_offset(overlay_dtb->fdt, "/__local_fixups__");
814 if (local_fixups_off >= 0)
815 {
816 const char *fixups_stringlist;
817
818 // Update the references to local phandles using the local fixups.
819 // The property name is "fixup".
820 // The value is a NUL-separated stringlist of descriptors of the form:
821 // path:property:offset
822 fixups_stringlist =
823 fdt_getprop(overlay_dtb->fdt, local_fixups_off, "fixup", &err);
824 if (fixups_stringlist)
825 {
826 // Relocate the overlay phandle references
827 err = dtoverlay_apply_fixups(overlay_dtb, fixups_stringlist,
828 base_dtb->max_phandle, FIXUP_RELATIVE);
829 }
830 else
831 {
832 err = dtoverlay_apply_fixups_node(overlay_dtb, local_fixups_off,
833 0, base_dtb->max_phandle);
834 }
835 if (err < 0)
836 {
837 dtoverlay_error("error applying local fixups");
838 return err;
839 }
840 }
841
842 overlay_dtb->max_phandle += base_dtb->max_phandle;
843 phandle_debug(" +overlay max phandle +%d -> %d", base_dtb->max_phandle, overlay_dtb->max_phandle);
844
845 return err;
846}
847
848// Returns 0 on success, or an FDT error code
849static int dtoverlay_resolve_fixups(DTBLOB_T *base_dtb, DTBLOB_T *overlay_dtb)
850{
851 int fixups_off;
852 int err = 0;
853
854 fixups_off = fdt_path_offset(overlay_dtb->fdt, "/__fixups__");
855
856 if (fixups_off >= 0)
857 {
858 int fixup_off, symbols_off = -1;
859
860 fixup_off = fdt_first_property_offset(overlay_dtb->fdt, fixups_off);
861
862 if (fixup_off >= 0)
863 {
864 // Find the symbols, which will be needed to resolve the fixups
865 symbols_off = fdt_path_offset(base_dtb->fdt, "/__symbols__");
866
867 if (symbols_off < 0)
868 {
869 dtoverlay_error("No symbols found");
870 return -FDT_ERR_NOTFOUND;
871 }
872 }
873
874 for (;
875 fixup_off >= 0;
876 fixup_off = fdt_next_property_offset(overlay_dtb->fdt, fixup_off))
877 {
878 const char *fixups_stringlist, *symbol_name, *target_path;
879 const char *ref_type;
880 int target_off;
881 uint32_t target_phandle;
882
883 // The property name identifies a symbol (or alias) in the base.
884 // The value is a comma-separated list of descriptors of the form:
885 // path:property:offset
886 fixups_stringlist = fdt_getprop_by_offset(overlay_dtb->fdt, fixup_off,
887 &symbol_name, &err);
888 if (!fixups_stringlist)
889 {
890 dtoverlay_error("__fixups__ are borked");
891 break;
892 }
893
894 // 1) Find the target node.
895 if (symbol_name[0] == '/')
896 {
897 /* This is a new-style path reference */
898 target_path = symbol_name;
899 ref_type = "path";
900 }
901 else
902 {
903 target_path = fdt_getprop(base_dtb->fdt, symbols_off, symbol_name,
904 &err);
905 if (!target_path)
906 {
907 dtoverlay_error("can't find symbol '%s'", symbol_name);
908 break;
909 }
910
911 ref_type = "symbol";
912 }
913
914 target_off = fdt_path_offset(base_dtb->fdt, target_path);
915 if (target_off < 0)
916 {
917 dtoverlay_error("%s '%s' is invalid", ref_type, symbol_name);
918 err = target_off;
919 break;
920 }
921
922 // 2) Ensure that the target node has a phandle.
923 target_phandle = fdt_get_phandle(base_dtb->fdt, target_off);
924 if (!target_phandle)
925 {
926 // It doesn't, so give it one
927 fdt32_t temp;
928 target_phandle = ++base_dtb->max_phandle;
929 temp = cpu_to_fdt32(target_phandle);
930
931 err = fdt_setprop(base_dtb->fdt, target_off, "phandle",
932 &temp, 4);
933
934 if (err != 0)
935 {
936 dtoverlay_error("failed to add a phandle");
937 break;
938 }
939 phandle_debug(" phandle '%s'->%d", target_path, target_phandle);
940
941 // The symbols may have moved, so recalculate
942 symbols_off = fdt_path_offset(base_dtb->fdt, "/__symbols__");
943 }
944
945 // Now apply the valid target_phandle to the items in the fixup string
946
947 err = dtoverlay_apply_fixups(overlay_dtb, fixups_stringlist,
948 target_phandle, FIXUP_ABSOLUTE);
949 if (err)
950 break;
951 }
952 }
953
954 return err;
955}
956
957// Returns 0 on success, -ve for fatal errors and +ve for non-fatal errors
958int dtoverlay_merge_overlay(DTBLOB_T *base_dtb, DTBLOB_T *overlay_dtb)
959{
960 // Merge each fragment node
961 int frag_off;
962
963 for (frag_off = fdt_first_subnode(overlay_dtb->fdt, 0);
964 frag_off >= 0;
965 frag_off = fdt_next_subnode(overlay_dtb->fdt, frag_off))
966 {
967 const char *node_name, *target_path;
968 const char *frag_name;
969 int target_off, overlay_off;
970 int len, err;
971
972 node_name = fdt_get_name(overlay_dtb->fdt, frag_off, NULL);
973
974 if (strncmp(node_name, "fragment@", 9) != 0 &&
975 strncmp(node_name, "fragment-", 9) != 0)
976 continue;
977 frag_name = node_name + 9;
978
979 dtoverlay_debug("Found fragment %s (offset %d)", frag_name, frag_off);
980
981 // Find the target and overlay nodes
982 overlay_off = fdt_subnode_offset(overlay_dtb->fdt, frag_off, "__overlay__");
983 if (overlay_off < 0)
984 {
985 if (fdt_subnode_offset(overlay_dtb->fdt, frag_off, "__dormant__"))
986 dtoverlay_debug("fragment %s disabled", frag_name);
987 else
988 dtoverlay_error("no overlay in fragment %s", frag_name);
989 continue;
990 }
991
992 target_path = fdt_getprop(overlay_dtb->fdt, frag_off, "target-path", &len);
993 if (target_path)
994 {
995 if (len && (target_path[len - 1] == '\0'))
996 len--;
997 target_off = fdt_path_offset_namelen(base_dtb->fdt, target_path, len);
998 if (target_off < 0)
999 {
1000 dtoverlay_error("invalid target-path '%.*s'", len, target_path);
1001 return NON_FATAL(target_off);
1002 }
1003 }
1004 else
1005 {
1006 const void *target_prop;
1007 target_prop = fdt_getprop(overlay_dtb->fdt, frag_off, "target", &len);
1008 if (!target_prop)
1009 {
1010 dtoverlay_error("no target or target-path");
1011 return NON_FATAL(len);
1012 }
1013
1014 if (len != 4)
1015 return NON_FATAL(FDT_ERR_BADSTRUCTURE);
1016
1017 target_off =
1018 fdt_node_offset_by_phandle(base_dtb->fdt,
1019 fdt32_to_cpu(*(fdt32_t *)target_prop));
1020 if (target_off < 0)
1021 {
1022 dtoverlay_error("invalid target");
1023 return NON_FATAL(target_off);
1024 }
1025 }
1026
1027 // Now do the merge
1028 err = dtoverlay_merge_fragment(base_dtb, target_off, overlay_dtb,
1029 overlay_off, 0);
1030 if (err != 0)
1031 {
1032 dtoverlay_error("merge failed");
1033 return err;
1034 }
1035 }
1036
1037 base_dtb->max_phandle = overlay_dtb->max_phandle;
1038
1039 return 0;
1040}
1041
1042// Returns 0 on success, -ve for fatal errors and +ve for non-fatal errors
1043int dtoverlay_fixup_overlay(DTBLOB_T *base_dtb, DTBLOB_T *overlay_dtb)
1044{
1045 int err;
1046
1047 // To do: Check the "compatible" string?
1048
1049 err = dtoverlay_resolve_fixups(base_dtb, overlay_dtb);
1050
1051 if (err >= 0)
1052 err = dtoverlay_resolve_phandles(base_dtb, overlay_dtb);
1053
1054 overlay_dtb->fixups_applied = 1;
1055
1056 return NON_FATAL(err);
1057}
1058
1059// Returns 0 on success, -ve for fatal errors and +ve for non-fatal errors
1060int dtoverlay_merge_params(DTBLOB_T *dtb, const DTOVERLAY_PARAM_T *params,
1061 unsigned int num_params)
1062{
1063 int err = 0;
1064 unsigned int i;
1065
1066 for (i=0; (i<num_params) && (err == 0); i++) {
1067 const DTOVERLAY_PARAM_T *p;
1068 const char *node_name, *slash;
1069 int node_off, path_len;
1070
1071 p = params + i;
1072 node_name = p->param;
1073 slash = strrchr(node_name, '/');
1074
1075 if (!slash)
1076 {
1077 err = NON_FATAL(FDT_ERR_BADPATH);
1078 break;
1079 }
1080
1081 // Ensure that root properties ("/xxx") work
1082 if (slash == node_name)
1083 path_len = 1;
1084 else
1085 path_len = slash - node_name;
1086
1087 // find node, create if it does not exist yet
1088 node_off = dtoverlay_create_node(dtb, node_name, path_len);
1089 if (node_off >= 0)
1090 {
1091 const char *prop_name = slash + 1;
1092 int prop_len;
1093 struct fdt_property *prop;
1094
1095 if ((strcmp(prop_name, "bootargs") == 0) &&
1096 ((prop = fdt_get_property_w(dtb->fdt, node_off, prop_name, &prop_len)) != NULL) &&
1097 (prop_len > 0) && *prop->data)
1098 {
1099 prop->data[prop_len - 1] = ' ';
1100 err = fdt_appendprop(dtb->fdt, node_off, prop_name, p->b, p->len);
1101 }
1102 else
1103 err = fdt_setprop(dtb->fdt, node_off, prop_name, p->b, p->len);
1104 }
1105 else
1106 err = node_off;
1107 }
1108
1109 return err;
1110}
1111
1112/* Returns a pointer to the override data and (through data_len) its length.
1113 On error, sets *data_len to be the error code. */
1114const char *dtoverlay_find_override(DTBLOB_T *dtb, const char *override_name,
1115 int *data_len)
1116{
1117 int overrides_off;
1118 const char *data;
1119 int len;
1120
1121 // Find the table of overrides
1122 overrides_off = fdt_path_offset(dtb->fdt, "/__overrides__");
1123
1124 if (overrides_off < 0)
1125 {
1126 dtoverlay_debug("/__overrides__ node not found");
1127 *data_len = overrides_off;
1128 return NULL;
1129 }
1130
1131 // Locate the property
1132 data = fdt_getprop(dtb->fdt, overrides_off, override_name, &len);
1133 *data_len = len;
1134 if (data)
1135 dtoverlay_debug("Found override %s", override_name);
1136 else
1137 dtoverlay_debug("/__overrides__ has no %s property", override_name);
1138
1139 return data;
1140}
1141
1142int hex_digit(char c)
1143{
1144 if (c >= '0' && c <= '9')
1145 return c - '0';
1146 else if (c >= 'A' && c <= 'F')
1147 return 10 + c - 'A';
1148 else if (c >= 'a' && c <= 'f')
1149 return 10 + c - 'a';
1150 else
1151 return -1;
1152}
1153
1154int dtoverlay_override_one_target(int override_type,
1155 const char *override_value,
1156 DTBLOB_T *dtb, int node_off,
1157 const char *prop_name, int target_phandle,
1158 int target_off, int target_size,
1159 void *callback_state)
1160{
1161 int err = 0;
1162
1163 if (override_type == DTOVERRIDE_STRING)
1164 {
1165 char *prop_val;
1166 int prop_len;
1167
1168 /* Replace the whole property with the string */
1169 if ((strcmp(prop_name, "bootargs") == 0) &&
1170 ((prop_val = fdt_getprop_w(dtb->fdt, node_off, prop_name,
1171 &prop_len)) != NULL) &&
1172 (prop_len > 0) && prop_val[0])
1173 {
1174 prop_val[prop_len - 1] = ' ';
1175 err = fdt_appendprop_string(dtb->fdt, node_off, prop_name, override_value);
1176 }
1177 else if (strcmp(prop_name, "name") == 0) // "name" is a pseudo-property
1178 {
1179 err = dtoverlay_set_node_name(dtb, node_off, override_value);
1180 }
1181 else
1182 err = fdt_setprop_string(dtb->fdt, node_off, prop_name, override_value);
1183 }
1184 else if (override_type == DTOVERRIDE_BYTE_STRING)
1185 {
1186 /* Replace the whole property with the byte string */
1187 uint8_t bytes_buf[32]; // For efficiency/laziness, place a limit on the length
1188 const char *p = override_value;
1189 int byte_count = 0;
1190
1191 while (*p)
1192 {
1193 int nib1, nib2;
1194 // whitespace and colons are legal separators
1195 if (*p == ':' || *p == ' ' || *p == '\t')
1196 {
1197 p++;
1198 continue;
1199 }
1200 nib1 = hex_digit(*p++);
1201 nib2 = hex_digit(*p++);
1202 if (nib1 < 0 || nib2 < 0)
1203 {
1204 dtoverlay_error("invalid bytestring '%s'", override_value);
1205 return NON_FATAL(FDT_ERR_BADVALUE);
1206 }
1207 if (byte_count == sizeof(bytes_buf))
1208 {
1209 dtoverlay_error("bytestring '%s' too long", override_value);
1210 return NON_FATAL(FDT_ERR_BADVALUE);
1211 }
1212 bytes_buf[byte_count++] = (nib1 << 4) | nib2;
1213 }
1214
1215 err = fdt_setprop(dtb->fdt, node_off, prop_name, bytes_buf, byte_count);
1216 }
1217 else if (override_type != DTOVERRIDE_END)
1218 {
1219 const char *p;
1220 char *end;
1221 char *prop_val;
1222 void *prop_buf = NULL;
1223 int prop_len;
1224 int new_prop_len;
1225 uint64_t override_int;
1226 uint32_t frag_num;
1227
1228 /* Parse as an integer */
1229 override_int = strtoull(override_value, &end, 0);
1230 if (end[0] != '\0')
1231 {
1232 if ((strcmp(override_value, "y") == 0) ||
1233 (strcmp(override_value, "yes") == 0) ||
1234 (strcmp(override_value, "on") == 0) ||
1235 (strcmp(override_value, "true") == 0) ||
1236 (strcmp(override_value, "down") == 0))
1237 override_int = 1;
1238 else if ((strcmp(override_value, "n") == 0) ||
1239 (strcmp(override_value, "no") == 0) ||
1240 (strcmp(override_value, "off") == 0) ||
1241 (strcmp(override_value, "false") == 0))
1242 override_int = 0;
1243 else if (strcmp(override_value, "up") == 0)
1244 override_int = 2;
1245 else
1246 {
1247 dtoverlay_error("invalid override value '%s' - ignored",
1248 override_value);
1249 return NON_FATAL(FDT_ERR_INTERNAL);
1250 }
1251 }
1252
1253 switch (override_type)
1254 {
1255 case DTOVERRIDE_INTEGER:
1256 /* Patch a word within the property */
1257 prop_val = (void *)fdt_getprop(dtb->fdt, node_off, prop_name,
1258 &prop_len);
1259 new_prop_len = target_off + target_size;
1260 if (prop_len < new_prop_len)
1261 {
1262 /* This property either doesn't exist or isn't long enough.
1263 Create a buffer containing any existing property data
1264 with zero padding, which will later be patched and written
1265 back. */
1266 prop_buf = calloc(1, new_prop_len);
1267 if (!prop_buf)
1268 {
1269 dtoverlay_error(" out of memory");
1270 return NON_FATAL(FDT_ERR_NOSPACE);
1271 }
1272 if (prop_len > 0)
1273 memcpy(prop_buf, prop_val, prop_len);
1274 prop_val = prop_buf;
1275 }
1276
1277 switch (target_size)
1278 {
1279 case 1:
1280 dtoverlay_write_u8(prop_val, target_off, (uint32_t)override_int);
1281 break;
1282 case 2:
1283 dtoverlay_write_u16(prop_val, target_off, (uint32_t)override_int);
1284 break;
1285 case 4:
1286 dtoverlay_write_u32(prop_val, target_off, (uint32_t)override_int);
1287 break;
1288 case 8:
1289 dtoverlay_write_u64(prop_val, target_off, override_int);
1290 break;
1291 default:
1292 break;
1293 }
1294
1295 if (prop_buf)
1296 {
1297 /* Add/extend the property by setting it */
1298 if (strcmp(prop_name, "reg") != 0) // Don't create or extend "reg" - it must be a pseudo-property
1299 err = fdt_setprop(dtb->fdt, node_off, prop_name, prop_buf, new_prop_len);
1300 free(prop_buf);
1301 }
1302
1303 if (strcmp(prop_name, "reg") == 0 && target_off == 0)
1304 {
1305 const char *old_name = fdt_get_name(dtb->fdt, node_off, NULL);
1306 const char *atpos = strchr(old_name, '@');
1307 if (atpos)
1308 {
1309 int name_len = (atpos - old_name);
1310 char *new_name = malloc(name_len + 1 + 16 + 1);
1311 if (!new_name)
1312 return -FDT_ERR_NOSPACE;
1313 sprintf(new_name, "%.*s@%x", name_len, old_name, (uint32_t)override_int);
1314 err = dtoverlay_set_node_name(dtb, node_off, new_name);
1315 free(new_name);
1316 }
1317 }
1318 break;
1319
1320 case DTOVERRIDE_BOOLEAN:
1321 case DTOVERRIDE_BOOLEAN_INV:
1322 /* This is a boolean property (present->true, absent->false) */
1323 if (override_int ^ (override_type == DTOVERRIDE_BOOLEAN_INV))
1324 err = fdt_setprop(dtb->fdt, node_off, prop_name, NULL, 0);
1325 else
1326 {
1327 err = fdt_delprop(dtb->fdt, node_off, prop_name);
1328 if (err == -FDT_ERR_NOTFOUND)
1329 err = 0;
1330 }
1331 break;
1332
1333 case DTOVERRIDE_OVERLAY:
1334 /* Apply the overlay-wide override. The supported options are (<frag> is a fragment number):
1335 +<frag> Enable a fragment
1336 -<frag> Disable a fragment
1337 =<frag> Enable/disable the fragment according to the override value
1338 !<frag> Disable/enable the fragment according to the inverse of the override value */
1339 p = prop_name;
1340 while (*p && !err)
1341 {
1342 char type = *p;
1343 int frag_off;
1344 switch (type)
1345 {
1346 case '+':
1347 case '-':
1348 case '=':
1349 case '!':
1350 frag_num = strtoul(p + 1, &end, 0);
1351 if (end != p)
1352 {
1353 /* Change fragment@<frag_num>/__overlay__<->__dormant__ as necessary */
1354 const char *states[2] = { "__dormant__", "__overlay__" };
1355 char node_name[24];
1356 int active = (type == '+') ||
1357 ((type == '=') && (override_int != 0)) ||
1358 ((type == '!') && (override_int == 0));
1359 snprintf(node_name, sizeof(node_name), "/fragment@%u", frag_num);
1360 frag_off = fdt_path_offset(dtb->fdt, node_name);
1361 if (frag_off < 0)
1362 {
1363 snprintf(node_name, sizeof(node_name), "/fragment-%u", frag_num);
1364 frag_off = fdt_path_offset(dtb->fdt, node_name);
1365 }
1366 if (frag_off >= 0)
1367 {
1368 frag_off = fdt_subnode_offset(dtb->fdt, frag_off, states[!active]);
1369 if (frag_off >= 0)
1370 (void)dtoverlay_set_node_name(dtb, frag_off, states[active]);
1371 }
1372 else
1373 {
1374 dtoverlay_error(" fragment %u not found", frag_num);
1375 err = NON_FATAL(frag_off);
1376 }
1377 p = end;
1378 }
1379 else
1380 {
1381 dtoverlay_error(" invalid overlay override '%s'", prop_name);
1382 err = NON_FATAL(FDT_ERR_BADVALUE);
1383 }
1384 break;
1385 }
1386 }
1387 break;
1388 }
1389 }
1390
1391 return err;
1392}
1393
1394/*
1395 The problem is the split between inline string values and inline
1396 cell values passed to the callback. For strings properties the
1397 returned data is strings; no conversion from cells is required. The
1398 special handling for "status" is performed before the callback. For
1399 all other property types the returned values are binary/opaque data.
1400 Any string data should have been converted to binary data already in
1401 the framework.
1402
1403Translation:
1404 1. The override value (the value assigned to the parameter) is always a string.
1405 2. Strings are converted according to type of the parameter at the point of use.
1406 3. A single override value can result in multiple different values being assigned
1407 to properties as the result of type conversions and set lookups.
1408 4. Cell literals have a binary value.
1409 5. Lookups convert strings to either a string or a cell literal.
1410 6. Cell literals are primarily (only?) useful for label references, which are
1411 really just integers. There is nothing stopping them (or other integers) being
1412 converted to strings.
1413 7. Therefore dtoverlay_extract_override always returns a string value, either the
1414 input override value, a literal, or the result of a lookup.
1415*/
1416
1417// Returns 0 on success, -ve for fatal errors and +ve for non-fatal errors
1418// After calling this, assume all node offsets are no longer valid
1419int dtoverlay_foreach_override_target(DTBLOB_T *dtb, const char *override_name,
1420 const char *override_data, int data_len,
1421 const char *override_value,
1422 override_callback_t callback,
1423 void *callback_state)
1424{
1425 int err = 0;
1426 int target_phandle = 0;
1427 char *data_buf, *data, *data_end;
1428
1429 /* Short-circuit the degenerate case of an empty parameter, avoiding an
1430 apparent memory allocation failure. */
1431 if (!data_len)
1432 return 0;
1433
1434 /* Copy the override data in case it moves */
1435 data_buf = malloc(data_len);
1436 if (!data_buf)
1437 {
1438 dtoverlay_error(" out of memory");
1439 return NON_FATAL(FDT_ERR_NOSPACE);
1440 }
1441
1442 memcpy(data_buf, override_data, data_len);
1443 data = data_buf;
1444 data_end = data + data_len;
1445
1446 while (err == 0)
1447 {
1448 const char *target_prop = NULL;
1449 static char prop_name[256];
1450 static char target_value[256];
1451 int name_len = 0;
1452 int target_off = 0;
1453 int target_size = 0;
1454 int override_type;
1455 int node_off = 0;
1456
1457 strcpy(target_value, override_value);
1458 override_type = dtoverlay_extract_override(override_name,
1459 target_value, sizeof(target_value),
1460 &target_phandle,
1461 (const char **)&data, data_end,
1462 &target_prop, &name_len,
1463 &target_off, &target_size);
1464
1465 if (override_type < 0)
1466 {
1467 err = override_type;
1468 break;
1469 }
1470 /* Pass DTOVERRIDE_END to the callback, in case it is interested */
1471
1472 if (target_phandle != 0)
1473 {
1474 node_off = fdt_node_offset_by_phandle(dtb->fdt, target_phandle);
1475 if (node_off < 0)
1476 {
1477 dtoverlay_error(" phandle %d not found", target_phandle);
1478 err = NON_FATAL(node_off);
1479 break;
1480 }
1481 }
1482
1483 /* Sadly there are no '_namelen' setprop variants, so copies are required */
1484 if (target_prop)
1485 {
1486 memcpy(prop_name, target_prop, name_len);
1487 prop_name[name_len] = '\0';
1488 }
1489
1490 err = callback(override_type, target_value, dtb, node_off, prop_name,
1491 target_phandle, target_off, target_size, callback_state);
1492
1493 if (override_type == DTOVERRIDE_END)
1494 break;
1495 }
1496
1497 free(data_buf);
1498
1499 return err;
1500}
1501
1502// Returns 0 on success, -ve for fatal errors and +ve for non-fatal errors
1503int dtoverlay_apply_override(DTBLOB_T *dtb, const char *override_name,
1504 const char *override_data, int data_len,
1505 const char *override_value)
1506{
1507 return dtoverlay_foreach_override_target(dtb, override_name,
1508 override_data, data_len,
1509 override_value,
1510 dtoverlay_override_one_target,
1511 NULL);
1512}
1513
1514/* Returns an override type (DTOVERRIDE_INTEGER, DTOVERRIDE_BOOLEAN, DTOVERRIDE_STRING, DTOVERRIDE_OVERLAY),
1515 DTOVERRIDE_END (0) at the end, or an error code (< 0) */
1516static int dtoverlay_extract_override(const char *override_name,
1517 char *override_value, int value_size,
1518 int *phandle_ptr,
1519 const char **datap, const char *data_end,
1520 const char **namep, int *namelenp,
1521 int *offp, int *sizep)
1522{
1523 const char *data;
1524 const char *prop_name, *override_end;
1525 int len, override_len, name_len, target_len, phandle;
1526 const char *offset_seps = ".;:#?![{=";
1527 const char *literal_value = NULL;
1528 char literal_type = '?';
1529 int type;
1530
1531 data = *datap;
1532 len = data_end - data;
1533 if (len <= 0)
1534 {
1535 if (len < 0)
1536 return len;
1537 *phandle_ptr = 0;
1538 *namep = NULL;
1539 return DTOVERRIDE_END;
1540 }
1541
1542 // Check for space for a phandle, a terminating NUL and at least one char
1543 if (len < (sizeof(fdt32_t) + 1 + 1))
1544 {
1545 dtoverlay_error(" override %s: data is truncated or mangled",
1546 override_name);
1547 return -FDT_ERR_BADSTRUCTURE;
1548 }
1549
1550 phandle = dtoverlay_read_u32(data, 0);
1551 *phandle_ptr = phandle;
1552
1553 data += sizeof(fdt32_t);
1554 len -= sizeof(fdt32_t);
1555
1556 override_end = memchr(data, 0, len);
1557 if (!override_end)
1558 {
1559 dtoverlay_error(" override %s: string is not NUL-terminated",
1560 override_name);
1561 return -FDT_ERR_BADSTRUCTURE;
1562 }
1563
1564 prop_name = data;
1565
1566 override_len = override_end - prop_name;
1567 data += (override_len + 1);
1568 *datap = data;
1569
1570 if (phandle <= 0)
1571 {
1572 if (phandle < 0)
1573 return -FDT_ERR_BADPHANDLE;
1574 /* This is an "overlay" override, signalled using <0> as the phandle. */
1575 *namep = prop_name;
1576 *namelenp = override_len;
1577 return DTOVERRIDE_OVERLAY;
1578 }
1579
1580 target_len = strcspn(prop_name, "={");
1581 name_len = strcspn(prop_name, offset_seps);
1582
1583 *namep = prop_name;
1584 *namelenp = name_len;
1585
1586 if (target_len < override_len)
1587 {
1588 /* Literal assignment or lookup table
1589 * Can't have '=' and '{' (or at least, don't need to support it.
1590 * = is an override value replacement
1591 * { is an override value transformation
1592 */
1593 literal_type = prop_name[target_len];
1594 literal_value = prop_name + target_len + 1;
1595 }
1596
1597 if (name_len < target_len)
1598 {
1599 /* There is a separator specified */
1600 char sep = prop_name[name_len];
1601 if (sep == '?')
1602 {
1603 /* The target is a boolean parameter (present->true, absent->false) */
1604 *offp = 0;
1605 *sizep = 0;
1606 type = DTOVERRIDE_BOOLEAN;
1607 dtoverlay_debug(" override %s: boolean target %.*s",
1608 override_name, name_len, prop_name);
1609 }
1610 else if (sep == '!')
1611 {
1612 /* The target is a boolean parameter (present->true, absent->false),
1613 * but the sense of the value is inverted */
1614 *offp = 0;
1615 *sizep = 0;
1616 type = DTOVERRIDE_BOOLEAN_INV;
1617 dtoverlay_debug(" override %s: inverted boolean target %.*s",
1618 override_name, name_len, prop_name);
1619 }
1620 else if (sep == '[')
1621 {
1622 /* The target is a byte-string */
1623 *offp = -1;
1624 *sizep = 0;
1625 type = DTOVERRIDE_BYTE_STRING;
1626 dtoverlay_debug(" override %s: byte-string target %.*s",
1627 override_name, name_len, prop_name);
1628 }
1629 else
1630 {
1631 /* The target is a cell/integer */
1632 *offp = atoi(prop_name + name_len + 1);
1633 *sizep = 1 << (strchr(offset_seps, sep) - offset_seps);
1634 type = DTOVERRIDE_INTEGER;
1635 dtoverlay_debug(" override %s: cell target %.*s @ offset %d (size %d)",
1636 override_name, name_len, prop_name, *offp, *sizep);
1637 }
1638 }
1639 else
1640 {
1641 *offp = -1;
1642 *sizep = 0;
1643 type = DTOVERRIDE_STRING;
1644 dtoverlay_debug(" override %s: string target '%.*s'",
1645 override_name, name_len, prop_name);
1646 }
1647
1648 if (literal_value)
1649 {
1650 if (literal_type == '=')
1651 {
1652 /* Immediate value */
1653 if (type == DTOVERRIDE_STRING ||
1654 type == DTOVERRIDE_BYTE_STRING ||
1655 literal_value[0])
1656 {
1657 /* String */
1658 strcpy(override_value, literal_value);
1659 }
1660 else
1661 {
1662 /* Cell */
1663 sprintf(override_value, "%d", dtoverlay_read_u32(data, 0));
1664 *datap = data + 4;
1665 }
1666 }
1667 else if (literal_type == '{')
1668 {
1669 /* Lookup */
1670 data = dtoverlay_lookup_key(literal_value, data_end,
1671 override_value, override_value, value_size);
1672 *datap = data;
1673 if (!data)
1674 return -FDT_ERR_BADSTRUCTURE;
1675 }
1676 else
1677 {
1678 return -FDT_ERR_INTERNAL;
1679 }
1680 }
1681
1682 if ((type == DTOVERRIDE_STRING) &&
1683 (strmemcmp(prop_name, name_len, "status") == 0))
1684 {
1685 /* Convert booleans to okay/disabled */
1686 if ((strcmp(override_value, "y") == 0) ||
1687 (strcmp(override_value, "yes") == 0) ||
1688 (strcmp(override_value, "on") == 0) ||
1689 (strcmp(override_value, "true") == 0) ||
1690 (strcmp(override_value, "enable") == 0) ||
1691 (strcmp(override_value, "1") == 0))
1692 strcpy(override_value, "okay");
1693 else if ((strcmp(override_value, "n") == 0) ||
1694 (strcmp(override_value, "no") == 0) ||
1695 (strcmp(override_value, "off") == 0) ||
1696 (strcmp(override_value, "false") == 0) ||
1697 (strcmp(override_value, "0") == 0))
1698 strcpy(override_value, "disabled");
1699 }
1700
1701 return type;
1702}
1703
1704/* Read the string or (if permitted) cell value, storing the result in buf. Returns a pointer
1705 to the first byte after the successfully parsed immediate, or NULL on error. */
1706static const char *dtoverlay_extract_immediate(const char *data, const char *data_end,
1707 char *buf, int buf_len)
1708{
1709 if ((data + 1) < data_end && !data[0])
1710 {
1711 uint32_t val;
1712 data++;
1713 if (data + 4 > data_end)
1714 {
1715 dtoverlay_error(" truncated cell immediate");
1716 return NULL;
1717 }
1718 val = dtoverlay_read_u32(data, 0);
1719 if (buf)
1720 snprintf(buf, buf_len, "%d", val);
1721 data += 4;
1722 }
1723 else if (data[0] == '\'')
1724 {
1725 // Continue to closing "'", error on end-of-string
1726 int len;
1727 data++;
1728 len = strcspn(data, "'");
1729 if (!data[len])
1730 {
1731 dtoverlay_error(" unterminated quoted string: '%s", data);
1732 return NULL;
1733 }
1734 if (len >= buf_len)
1735 {
1736 dtoverlay_error(" immediate string too long: '%s", data);
1737 return NULL;
1738 }
1739 if (buf)
1740 {
1741 memcpy(buf, data, len);
1742 buf[len] = '\0';
1743 }
1744 data += len + 1;
1745 if (*data == ',') // Skip a comma, preserve a brace
1746 data++;
1747 }
1748 else
1749 {
1750 // Continue to a comma, right brace or end-of-string NUL
1751 int len = strcspn(data, ",}");
1752 if (len >= buf_len)
1753 {
1754 dtoverlay_error(" immediate string too long: '%s", data);
1755 return NULL;
1756 }
1757 if (buf)
1758 {
1759 memcpy(buf, data, len);
1760 buf[len] = '\0';
1761 }
1762 data += len;
1763 if (*data == ',') // Skip a comma, preserve a brace
1764 data++;
1765 }
1766
1767 return data;
1768}
1769
1770static const char *dtoverlay_lookup_key(const char *lookup_string, const char *data_end,
1771 const char *key, char *buf, int buf_len)
1772{
1773 const char *p = lookup_string;
1774 int found = 0;
1775
1776 while (p < data_end && *p && *p != '}')
1777 {
1778 int key_len = strcspn(p, "=,}");
1779 char *q = NULL;
1780 char sep = p[key_len];
1781
1782 if (!key_len)
1783 {
1784 if (sep) // default value
1785 {
1786 if (!found)
1787 {
1788 q = buf;
1789 found = 2;
1790 }
1791 }
1792 }
1793 else
1794 {
1795 if (found != 1 && strmemcmp(p, key_len, key) == 0)
1796 {
1797 q = buf;
1798 found = 1;
1799 }
1800 }
1801
1802 p += key_len;
1803
1804 if (sep == '=')
1805 {
1806 p = dtoverlay_extract_immediate(p + 1, data_end, q, buf_len);
1807 }
1808 else
1809 {
1810 if (q && q != key)
1811 {
1812 strncpy(q, key, buf_len);
1813 q[buf_len - 1] = 0;
1814 }
1815 if (sep == ',')
1816 p++;
1817 }
1818 }
1819
1820 if (!found)
1821 {
1822 dtoverlay_error("lookup -> no match for '%s'", key);
1823 return NULL;
1824 }
1825
1826 if (p == data_end)
1827 return p;
1828
1829 if (!*p)
1830 {
1831 dtoverlay_error(" malformed lookup");
1832 return NULL;
1833 }
1834
1835 assert(p[0] != 0 && p[1] == 0);
1836 return p + 2;
1837}
1838
1839int dtoverlay_set_synonym(DTBLOB_T *dtb, const char *dst, const char *src)
1840{
1841 /* Add/update all aliases, symbols and overrides named dst
1842 to be equivalent to those named src.
1843 An absent src is ignored.
1844 */
1845 int err;
1846
1847 err = dtoverlay_dup_property(dtb, "/aliases", dst, src);
1848 if (err == 0)
1849 err = dtoverlay_dup_property(dtb, "/__symbols__", dst, src);
1850 if (err == 0)
1851 dtoverlay_dup_property(dtb, "/__overrides__", dst, src);
1852 return err;
1853}
1854
1855int dtoverlay_dup_property(DTBLOB_T *dtb, const char *node_name,
1856 const char *dst, const char *src)
1857{
1858 /* Find the node and src property */
1859 const DTBLOB_T *src_prop;
1860 int node_off;
1861 int prop_len = 0;
1862 int err = 0;
1863
1864 node_off = fdt_path_offset(dtb->fdt, node_name);
1865 if (node_off < 0)
1866 return 0;
1867
1868 src_prop = fdt_getprop(dtb->fdt, node_off, src, &prop_len);
1869 if (!src_prop)
1870 return 0;
1871
1872 err = fdt_setprop_inplace(dtb->fdt, node_off, dst, src_prop, prop_len);
1873 if (err != 0)
1874 {
1875 void *prop_data;
1876 /* Copy the src property, just in case things move */
1877 prop_data = malloc(prop_len);
1878 memcpy(prop_data, src_prop, prop_len);
1879
1880 err = fdt_setprop(dtb->fdt, node_off, dst, prop_data, prop_len);
1881
1882 free(prop_data);
1883 }
1884
1885 if (err == 0)
1886 dtoverlay_debug("%s:%s=%s", node_name, dst, src);
1887 return err;
1888}
1889
1890int dtoverlay_find_pins_for_device(DTBLOB_T *dtb, const char *symbol,
1891 PIN_ITER_T *iter)
1892{
1893 int pos = dtoverlay_find_symbol(dtb, symbol);
1894
1895 memset(iter, 0, sizeof(*iter));
1896
1897 if (pos < 0)
1898 return pos;
1899
1900 iter->dtb = dtb;
1901
1902 if (dtoverlay_node_is_enabled(dtb, pos))
1903 iter->pinctrl = dtoverlay_get_property(dtb, pos, "pinctrl-0", &iter->pinctrl_len);
1904
1905 return 0;
1906}
1907
1908int dtoverlay_next_pin(PIN_ITER_T *iter, int *pin, int *func, int *pull)
1909{
1910 if (pin)
1911 *pin = -1;
1912 if (func)
1913 *func = -1;
1914 if (pull)
1915 *pull = -1;
1916
1917 while (1)
1918 {
1919 int phandle, pos;
1920
1921 if ((iter->pin_off) + 4 <= iter->pins_len)
1922 {
1923 int off = iter->pin_off;
1924 *pin = GETBE4(iter->pins, off);
1925 if (func && iter->funcs_len)
1926 *func = GETBE4(iter->funcs, (iter->funcs_len > 4) ? off : 0);
1927 if (pull && iter->pulls_len)
1928 *pull = GETBE4(iter->pulls, (iter->pulls_len > 4) ? off : 0);
1929 iter->pin_off = off + 4;
1930 return 1;
1931 }
1932
1933 if ((iter->pinctrl_off + 4) > iter->pinctrl_len)
1934 break;
1935
1936 phandle = GETBE4(iter->pinctrl, iter->pinctrl_off);
1937 iter->pinctrl_off += 4;
1938 pos = dtoverlay_find_phandle(iter->dtb, phandle);
1939 iter->pins = dtoverlay_get_property(iter->dtb, pos, "brcm,pins", &iter->pins_len);
1940 iter->funcs = dtoverlay_get_property(iter->dtb, pos, "brcm,function", &iter->funcs_len);
1941 iter->pulls = dtoverlay_get_property(iter->dtb, pos, "brcm,pull", &iter->pulls_len);
1942 iter->pin_off = 0;
1943 }
1944
1945 return 0;
1946}
1947
1948DTBLOB_T *dtoverlay_create_dtb(int max_size)
1949{
1950 DTBLOB_T *dtb = NULL;
1951 void *fdt = NULL;
1952
1953 fdt = malloc(max_size);
1954 if (!fdt)
1955 {
1956 dtoverlay_error("out of memory");
1957 goto error_exit;
1958 }
1959
1960 if (fdt_create_empty_tree(fdt, max_size) != 0)
1961 {
1962 dtoverlay_error("failed to create empty dtb");
1963 goto error_exit;
1964 }
1965
1966 dtb = calloc(1, sizeof(DTBLOB_T));
1967 if (!dtb)
1968 {
1969 dtoverlay_error("out of memory");
1970 goto error_exit;
1971 }
1972
1973 dtb->fdt = fdt;
1974 dtb->max_phandle = 0; // Not a valid phandle
1975
1976 return dtb;
1977
1978error_exit:
1979 free(fdt);
1980 if (dtb)
1981 free(dtb->trailer);
1982 free(dtb);
1983 return NULL;
1984
1985}
1986
1987DTBLOB_T *dtoverlay_load_dtb_from_fp(FILE *fp, int max_size)
1988{
1989 DTBLOB_T *dtb = NULL;
1990 void *fdt = NULL;
1991
1992 if (fp)
1993 {
1994 long len;
1995 long bytes_read;
1996 int dtb_len;
1997
1998 fseek(fp, 0, SEEK_END);
1999 len = ftell(fp);
2000 fseek(fp, 0, SEEK_SET);
2001 if (max_size > 0)
2002 {
2003 if (max_size < len)
2004 {
2005 dtoverlay_error("file too large (%d bytes) for max_size", len);
2006 goto error_exit;
2007 }
2008 }
2009 else if (max_size < 0)
2010 {
2011 max_size = len - max_size;
2012 }
2013 else
2014 {
2015 max_size = len;
2016 }
2017
2018 fdt = malloc(max_size);
2019 if (!fdt)
2020 {
2021 dtoverlay_error("out of memory");
2022 goto error_exit;
2023 }
2024
2025 bytes_read = fread(fdt, 1, len, fp);
2026 fclose(fp);
2027
2028 if (bytes_read != len)
2029 {
2030 dtoverlay_error("fread failed");
2031 goto error_exit;
2032 }
2033
2034 // Record the total size before any expansion
2035 dtb_len = fdt_totalsize(fdt);
2036
2037 dtb = dtoverlay_import_fdt(fdt, max_size);
2038 if (!dtb)
2039 goto error_exit;
2040
2041 dtb->fdt_is_malloced = 1;
2042
2043 if (len > dtb_len)
2044 {
2045 /* Load the trailer */
2046 dtb->trailer_len = len - dtb_len;
2047 dtb->trailer = malloc(dtb->trailer_len);
2048 if (!dtb->trailer)
2049 {
2050 dtoverlay_error("out of memory");
2051 goto error_exit;
2052 }
2053 dtb->trailer_is_malloced = 1;
2054 memcpy(dtb->trailer, (char *)fdt + dtb_len, dtb->trailer_len);
2055 }
2056 }
2057
2058 return dtb;
2059
2060error_exit:
2061 free(fdt);
2062 if (dtb)
2063 free(dtb->trailer);
2064 free(dtb);
2065 return NULL;
2066}
2067
2068DTBLOB_T *dtoverlay_load_dtb(const char *filename, int max_size)
2069{
2070 FILE *fp = fopen(filename, "rb");
2071 if (fp)
2072 return dtoverlay_load_dtb_from_fp(fp, max_size);
2073 dtoverlay_error("Failed to open '%s'", filename);
2074 return NULL;
2075}
2076
2077DTBLOB_T *dtoverlay_import_fdt(void *fdt, int buf_size)
2078{
2079 DTBLOB_T *dtb = NULL;
2080 int node_off;
2081 int dtb_len;
2082 int err;
2083
2084 err = fdt_check_header(fdt);
2085 if (err != 0)
2086 {
2087 dtoverlay_error("not a valid FDT - err %d", err);
2088 goto error_exit;
2089 }
2090
2091 dtb_len = fdt_totalsize(fdt);
2092
2093 if (buf_size < dtb_len)
2094 {
2095 dtoverlay_error("fdt is too large");
2096 err = -FDT_ERR_NOSPACE;
2097 goto error_exit;
2098 }
2099
2100 if (buf_size > dtb_len)
2101 fdt_set_totalsize(fdt, buf_size);
2102
2103 dtb = calloc(1, sizeof(DTBLOB_T));
2104 if (!dtb)
2105 {
2106 dtoverlay_error("out of memory");
2107 goto error_exit;
2108 }
2109
2110 dtb->fdt = fdt;
2111 dtb->max_phandle = 0; // Not a valid phandle
2112
2113 // Find the minimum and maximum phandles, in case it is necessary to
2114 // relocate existing ones or create new ones.
2115
2116 for (node_off = 0;
2117 node_off >= 0;
2118 node_off = fdt_next_node(fdt, node_off, NULL))
2119 {
2120 uint32_t phandle = fdt_get_phandle(fdt, node_off);
2121 if (phandle > dtb->max_phandle)
2122 dtb->max_phandle = phandle;
2123 }
2124
2125error_exit:
2126 return dtb;
2127}
2128
2129int dtoverlay_save_dtb(const DTBLOB_T *dtb, const char *filename)
2130{
2131 FILE *fp = fopen(filename, "wb");
2132 int err = 0;
2133
2134 if (fp)
2135 {
2136 long len = fdt_totalsize(dtb->fdt);
2137 if (len != fwrite(dtb->fdt, 1, len, fp))
2138 {
2139 dtoverlay_error("fwrite failed");
2140 err = -2;
2141 goto error_exit;
2142 }
2143 if (dtb->trailer_len &&
2144 (fwrite(dtb->trailer, 1, dtb->trailer_len, fp) != dtb->trailer_len))
2145 {
2146 dtoverlay_error("fwrite failed");
2147 err = -2;
2148 goto error_exit;
2149 }
2150
2151 dtoverlay_debug("Wrote %ld bytes to '%s'", len, filename);
2152 fclose(fp);
2153 }
2154 else
2155 {
2156 dtoverlay_debug("Failed to create '%s'", filename);
2157 err = -1;
2158 }
2159
2160error_exit:
2161 return err;
2162}
2163
2164int dtoverlay_extend_dtb(DTBLOB_T *dtb, int new_size)
2165{
2166 int size = fdt_totalsize(dtb->fdt);
2167 int err = 0;
2168
2169 if (new_size < 0)
2170 new_size = size - new_size;
2171
2172 if (new_size > size)
2173 {
2174 void *fdt;
2175 fdt = malloc(new_size);
2176 if (fdt)
2177 {
2178 memcpy(fdt, dtb->fdt, size);
2179 fdt_set_totalsize(fdt, new_size);
2180
2181 if (dtb->fdt_is_malloced)
2182 free(dtb->fdt);
2183
2184 dtb->fdt = fdt;
2185 dtb->fdt_is_malloced = 1;
2186 }
2187 else
2188 {
2189 err = -FDT_ERR_NOSPACE;
2190 }
2191 }
2192 else if (new_size < size)
2193 {
2194 /* Can't shrink it */
2195 err = -FDT_ERR_NOSPACE;
2196 }
2197
2198 return err;
2199}
2200
2201int dtoverlay_dtb_totalsize(DTBLOB_T *dtb)
2202{
2203 return fdt_totalsize(dtb->fdt);
2204}
2205
2206void dtoverlay_pack_dtb(DTBLOB_T *dtb)
2207{
2208 fdt_pack(dtb->fdt);
2209}
2210
2211void dtoverlay_free_dtb(DTBLOB_T *dtb)
2212{
2213 if (dtb)
2214 {
2215 if (dtb->fdt_is_malloced)
2216 free(dtb->fdt);
2217 if (dtb->trailer_is_malloced)
2218 free(dtb->trailer);
2219 free(dtb);
2220 }
2221}
2222
2223int dtoverlay_find_phandle(DTBLOB_T *dtb, int phandle)
2224{
2225 return fdt_node_offset_by_phandle(dtb->fdt, phandle);
2226}
2227
2228int dtoverlay_find_symbol(DTBLOB_T *dtb, const char *symbol_name)
2229{
2230 int symbols_off, path_len;
2231 const char *node_path;
2232
2233 node_path = dtoverlay_get_alias(dtb, symbol_name);
2234
2235 if (node_path)
2236 {
2237 path_len = strlen(node_path);
2238 }
2239 else
2240 {
2241 symbols_off = fdt_path_offset(dtb->fdt, "/__symbols__");
2242
2243 if (symbols_off < 0)
2244 {
2245 dtoverlay_error("No symbols found");
2246 return -FDT_ERR_NOTFOUND;
2247 }
2248
2249 node_path = fdt_getprop(dtb->fdt, symbols_off, symbol_name, &path_len);
2250 if (path_len < 0)
2251 return -FDT_ERR_NOTFOUND;
2252
2253 //Ensure we don't have trailing NULLs
2254 if (path_len > strnlen(node_path, path_len))
2255 path_len = strnlen(node_path, path_len);
2256 }
2257
2258 return fdt_path_offset_namelen(dtb->fdt, node_path, path_len);
2259}
2260
2261int dtoverlay_find_matching_node(DTBLOB_T *dtb, const char **node_names,
2262 int pos)
2263{
2264 while (1)
2265 {
2266 const char *node_name;
2267 pos = fdt_next_node(dtb->fdt, pos, NULL);
2268 if (pos < 0)
2269 break;
2270 node_name = fdt_get_name(dtb->fdt, pos, NULL);
2271 if (node_name)
2272 {
2273 int i;
2274 for (i = 0; node_names[i]; i++)
2275 {
2276 const char *node = node_names[i];
2277 int matchlen = strlen(node);
2278 if ((strncmp(node_name, node, matchlen) == 0) &&
2279 ((node[matchlen] == '\0') ||
2280 (node[matchlen] == '@')))
2281 return pos;
2282 }
2283 }
2284 }
2285 return -1;
2286}
2287
2288int dtoverlay_node_is_enabled(DTBLOB_T *dtb, int pos)
2289{
2290 if (pos >= 0)
2291 {
2292 const void *prop = dtoverlay_get_property(dtb, pos, "status", NULL);
2293 if (prop &&
2294 ((strcmp((const char *)prop, "okay") == 0) ||
2295 (strcmp((const char *)prop, "ok") == 0)))
2296 return 1;
2297 }
2298 return 0;
2299}
2300
2301const void *dtoverlay_get_property(DTBLOB_T *dtb, int pos, const char *prop_name, int *prop_len)
2302{
2303 return fdt_getprop(dtb->fdt, pos, prop_name, prop_len);
2304}
2305
2306int dtoverlay_set_property(DTBLOB_T *dtb, int pos,
2307 const char *prop_name, const void *prop, int prop_len)
2308{
2309 int err = fdt_setprop(dtb->fdt, pos, prop_name, prop, prop_len);
2310 if (err < 0)
2311 dtoverlay_error("Failed to set property '%s'", prop_name);
2312 return err;
2313}
2314
2315const char *dtoverlay_get_alias(DTBLOB_T *dtb, const char *alias_name)
2316{
2317 int node_off;
2318 int prop_len;
2319 const char *alias;
2320
2321 node_off = fdt_path_offset(dtb->fdt, "/aliases");
2322
2323 alias = fdt_getprop(dtb->fdt, node_off, alias_name, &prop_len);
2324 if (alias && !prop_len)
2325 alias = "";
2326 return alias;
2327}
2328
2329int dtoverlay_set_alias(DTBLOB_T *dtb, const char *alias_name, const char *value)
2330{
2331 int node_off;
2332
2333 node_off = fdt_path_offset(dtb->fdt, "/aliases");
2334 if (node_off < 0)
2335 node_off = fdt_add_subnode(dtb->fdt, 0, "aliases");
2336
2337 return fdt_setprop_string(dtb->fdt, node_off, alias_name, value);
2338}
2339
2340void dtoverlay_set_logging_func(DTOVERLAY_LOGGING_FUNC *func)
2341{
2342 dtoverlay_logging_func = func;
2343}
2344
2345void dtoverlay_enable_debug(int enable)
2346{
2347 dtoverlay_debug_enabled = enable;
2348}
2349
2350void dtoverlay_error(const char *fmt, ...)
2351{
2352 va_list args;
2353 va_start(args, fmt);
2354 (*dtoverlay_logging_func)(DTOVERLAY_ERROR, fmt, args);
2355 va_end(args);
2356}
2357
2358void dtoverlay_debug(const char *fmt, ...)
2359{
2360 va_list args;
2361 if (dtoverlay_debug_enabled)
2362 {
2363 va_start(args, fmt);
2364 (*dtoverlay_logging_func)(DTOVERLAY_DEBUG, fmt, args);
2365 va_end(args);
2366 }
2367}
2368
2369static void dtoverlay_stdio_logging(dtoverlay_logging_type_t type,
2370 const char *fmt, va_list args)
2371{
2372 const char *type_str;
2373
2374 switch (type)
2375 {
2376 case DTOVERLAY_ERROR:
2377 type_str = "error";
2378 break;
2379
2380 case DTOVERLAY_DEBUG:
2381 type_str = "debug";
2382 break;
2383
2384 default:
2385 type_str = "?";
2386 }
2387
2388 fprintf(stderr, "DTOVERLAY[%s]: ", type_str);
2389 vfprintf(stderr, fmt, args);
2390 fprintf(stderr, "\n");
2391}
2392