2 * Copyright (c) 2015 Oleksandr Tymoshenko <gonzo@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
33 #include "fdt_overlay.h"
39 fdt_max_phandle(void *fdtp)
42 uint32_t max_phandle, phandle;
45 o = fdt_path_offset(fdtp, "/");
46 max_phandle = fdt_get_phandle(fdtp, o);
47 for (depth = 0; (o >= 0) && (depth >= 0); o = fdt_next_node(fdtp, o, &depth)) {
48 phandle = fdt_get_phandle(fdtp, o);
49 if (max_phandle < phandle)
50 max_phandle = phandle;
57 * Returns exact memory location specified by fixup in format
58 * /path/to/node:property:offset
61 fdt_get_fixup_location(void *fdtp, const char *fixup)
63 char *path, *prop, *offsetp, *endp;
64 int prop_offset, o, proplen;
70 prop = strchr(path, ':');
72 printf("missing property part in \"%s\"\n", fixup);
80 offsetp = strchr(prop, ':');
81 if (offsetp == NULL) {
82 printf("missing offset part in \"%s\"\n", fixup);
90 prop_offset = strtoul(offsetp, &endp, 10);
92 printf("\"%s\" is not valid number\n", offsetp);
97 o = fdt_path_offset(fdtp, path);
99 printf("path \"%s\" not found\n", path);
104 result = fdt_getprop_w(fdtp, o, prop, &proplen);
106 printf("property \"%s\" not found in \"%s\" node\n", prop, path);
111 if (proplen < prop_offset + sizeof(uint32_t)) {
112 printf("%s: property length is too small for fixup\n", fixup);
117 result = (char*)result + prop_offset;
125 * Process one entry in __fixups__ { } node
126 * @fixups is property value, array of NUL-terminated strings
127 * with fixup locations
128 * @fixups_len length of the fixups array in bytes
129 * @phandle is value for these locations
132 fdt_do_one_fixup(void *fdtp, const char *fixups, int fixups_len, int phandle)
137 val = cpu_to_fdt32(phandle);
139 while (fixups_len > 0) {
140 fixup_pos = fdt_get_fixup_location(fdtp, fixups);
141 if (fixup_pos != NULL)
142 memcpy(fixup_pos, &val, sizeof(val));
144 fixups_len -= strlen(fixups) + 1;
145 fixups += strlen(fixups) + 1;
152 * Increase u32 value at pos by offset
155 fdt_increase_u32(void *pos, uint32_t offset)
159 memcpy(&val, pos, sizeof(val));
160 val = cpu_to_fdt32(fdt32_to_cpu(val) + offset);
161 memcpy(pos, &val, sizeof(val));
165 * Process local fixups
166 * @fixups is property value, array of NUL-terminated strings
167 * with fixup locations
168 * @fixups_len length of the fixups array in bytes
169 * @offset value these locations should be increased by
172 fdt_do_local_fixup(void *fdtp, const char *fixups, int fixups_len, int offset)
176 while (fixups_len > 0) {
177 fixup_pos = fdt_get_fixup_location(fdtp, fixups);
178 if (fixup_pos != NULL)
179 fdt_increase_u32(fixup_pos, offset);
181 fixups_len -= strlen(fixups) + 1;
182 fixups += strlen(fixups) + 1;
189 * Increase node phandle by phandle_offset
192 fdt_increase_phandle(void *fdtp, int node_offset, uint32_t phandle_offset)
195 void *phandle_pos, *node_pos;
197 node_pos = (char*)fdtp + node_offset;
199 phandle_pos = fdt_getprop_w(fdtp, node_offset, "phandle", &proplen);
201 fdt_increase_u32(phandle_pos, phandle_offset);
202 phandle_pos = fdt_getprop_w(fdtp, node_offset, "linux,phandle", &proplen);
204 fdt_increase_u32(phandle_pos, phandle_offset);
208 * Increase all phandles by offset
211 fdt_increase_phandles(void *fdtp, uint32_t offset)
215 o = fdt_path_offset(fdtp, "/");
216 for (depth = 0; (o >= 0) && (depth >= 0); o = fdt_next_node(fdtp, o, &depth)) {
217 fdt_increase_phandle(fdtp, o, offset);
222 * Overlay one node defined by <overlay_fdtp, overlay_o> over <main_fdtp, target_o>
225 fdt_overlay_node(void *main_fdtp, int target_o, void *overlay_fdtp, int overlay_o)
230 int target_subnode_o;
232 /* Overlay properties */
233 for (o = fdt_first_property_offset(overlay_fdtp, overlay_o);
234 o >= 0; o = fdt_next_property_offset(overlay_fdtp, o)) {
235 val = fdt_getprop_by_offset(overlay_fdtp, o, &name, &len);
237 fdt_setprop(main_fdtp, target_o, name, val, len);
240 /* Now overlay nodes */
242 for (depth = 0; (o >= 0) && (depth >= 0);
243 o = fdt_next_node(overlay_fdtp, o, &depth)) {
246 /* Check if there is node with the same name */
247 name = fdt_get_name(overlay_fdtp, o, NULL);
248 target_subnode_o = fdt_subnode_offset(main_fdtp, target_o, name);
249 if (target_subnode_o < 0) {
250 /* create new subnode and run merge recursively */
251 target_subnode_o = fdt_add_subnode(main_fdtp, target_o, name);
252 if (target_subnode_o < 0) {
253 printf("failed to create subnode \"%s\": %d\n",
254 name, target_subnode_o);
259 fdt_overlay_node(main_fdtp, target_subnode_o,
265 * Apply one overlay fragment
268 fdt_apply_fragment(void *main_fdtp, void *overlay_fdtp, int fragment_o)
271 const char *target_path;
273 int target_node_o, overlay_node_o;
276 val = fdt_getprop(overlay_fdtp, fragment_o, "target", NULL);
278 memcpy(&target, val, sizeof(target));
279 target = fdt32_to_cpu(target);
280 target_node_o = fdt_node_offset_by_phandle(main_fdtp, target);
281 if (target_node_o < 0) {
282 printf("failed to find target %04x\n", target);
287 if (target_node_o < 0) {
288 target_path = fdt_getprop(overlay_fdtp, fragment_o, "target-path", NULL);
289 if (target_path == NULL)
292 target_node_o = fdt_path_offset(main_fdtp, target_path);
293 if (target_node_o < 0) {
294 printf("failed to find target-path %s\n", target_path);
299 if (target_node_o < 0)
302 overlay_node_o = fdt_subnode_offset(overlay_fdtp, fragment_o, "__overlay__");
303 if (overlay_node_o < 0) {
304 printf("missing __overlay__ sub-node\n");
308 fdt_overlay_node(main_fdtp, target_node_o, overlay_fdtp, overlay_node_o);
312 * Handle __fixups__ node in overlay DTB
315 fdt_overlay_do_fixups(void *main_fdtp, void *overlay_fdtp)
317 int main_symbols_o, symbol_o, overlay_fixups_o;
320 const char *fixups, *name;
321 const char *symbol_path;
324 main_symbols_o = fdt_path_offset(main_fdtp, "/__symbols__");
325 overlay_fixups_o = fdt_path_offset(overlay_fdtp, "/__fixups__");
327 if (main_symbols_o < 0)
329 if (overlay_fixups_o < 0)
332 for (fixup_prop_o = fdt_first_property_offset(overlay_fdtp, overlay_fixups_o);
334 fixup_prop_o = fdt_next_property_offset(overlay_fdtp, fixup_prop_o)) {
335 fixups = fdt_getprop_by_offset(overlay_fdtp, fixup_prop_o, &name, &len);
336 symbol_path = fdt_getprop(main_fdtp, main_symbols_o, name, NULL);
337 if (symbol_path == NULL) {
338 printf("couldn't find \"%s\" symbol in main dtb\n", name);
341 symbol_o = fdt_path_offset(main_fdtp, symbol_path);
343 printf("couldn't find \"%s\" path in main dtb\n", symbol_path);
346 phandle = fdt_get_phandle(main_fdtp, symbol_o);
347 if (fdt_do_one_fixup(overlay_fdtp, fixups, len, phandle) < 0)
355 * Handle __local_fixups__ node in overlay DTB
358 fdt_overlay_do_local_fixups(void *main_fdtp, void *overlay_fdtp)
360 int overlay_local_fixups_o;
363 uint32_t phandle_offset;
365 overlay_local_fixups_o = fdt_path_offset(overlay_fdtp, "/__local_fixups__");
367 if (overlay_local_fixups_o < 0)
370 phandle_offset = fdt_max_phandle(main_fdtp);
371 fdt_increase_phandles(overlay_fdtp, phandle_offset);
372 fixups = fdt_getprop_w(overlay_fdtp, overlay_local_fixups_o, "fixup", &len);
374 if (fdt_do_local_fixup(overlay_fdtp, fixups, len, phandle_offset) < 0)
382 * Apply all fragments to main DTB
385 fdt_overlay_apply_fragments(void *main_fdtp, void *overlay_fdtp)
389 o = fdt_path_offset(overlay_fdtp, "/");
390 for (depth = 0; (o >= 0) && (depth >= 0); o = fdt_next_node(overlay_fdtp, o, &depth)) {
394 fdt_apply_fragment(main_fdtp, overlay_fdtp, o);
401 fdt_overlay_apply(void *main_fdtp, void *overlay_fdtp, size_t overlay_length)
408 /* We modify overlay in-place, so we need writable copy */
409 overlay_copy = malloc(overlay_length);
410 if (overlay_copy == NULL) {
411 printf("failed to allocate memory for overlay copy\n");
415 memcpy(overlay_copy, overlay_fdtp, overlay_length);
417 if (fdt_overlay_do_fixups(main_fdtp, overlay_copy) < 0) {
418 printf("failed to perform fixups in overlay\n");
423 if (fdt_overlay_do_local_fixups(main_fdtp, overlay_copy) < 0) {
424 printf("failed to perform local fixups in overlay\n");
429 if (fdt_overlay_apply_fragments(main_fdtp, overlay_copy) < 0) {
430 printf("failed to apply fragments\n");