1 1.1 skrll /* $NetBSD: fdt_overlay.c,v 1.1.1.2 2019/12/22 12:30:38 skrll Exp $ */ 2 1.1 skrll 3 1.1.1.2 skrll // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) 4 1.1.1.2 skrll /* 5 1.1.1.2 skrll * libfdt - Flat Device Tree manipulation 6 1.1.1.2 skrll * Copyright (C) 2016 Free Electrons 7 1.1.1.2 skrll * Copyright (C) 2016 NextThing Co. 8 1.1.1.2 skrll */ 9 1.1 skrll #include "libfdt_env.h" 10 1.1 skrll 11 1.1 skrll #include <fdt.h> 12 1.1 skrll #include <libfdt.h> 13 1.1 skrll 14 1.1 skrll #include "libfdt_internal.h" 15 1.1 skrll 16 1.1 skrll /** 17 1.1 skrll * overlay_get_target_phandle - retrieves the target phandle of a fragment 18 1.1 skrll * @fdto: pointer to the device tree overlay blob 19 1.1 skrll * @fragment: node offset of the fragment in the overlay 20 1.1 skrll * 21 1.1 skrll * overlay_get_target_phandle() retrieves the target phandle of an 22 1.1 skrll * overlay fragment when that fragment uses a phandle (target 23 1.1 skrll * property) instead of a path (target-path property). 24 1.1 skrll * 25 1.1 skrll * returns: 26 1.1 skrll * the phandle pointed by the target property 27 1.1 skrll * 0, if the phandle was not found 28 1.1 skrll * -1, if the phandle was malformed 29 1.1 skrll */ 30 1.1 skrll static uint32_t overlay_get_target_phandle(const void *fdto, int fragment) 31 1.1 skrll { 32 1.1 skrll const fdt32_t *val; 33 1.1 skrll int len; 34 1.1 skrll 35 1.1 skrll val = fdt_getprop(fdto, fragment, "target", &len); 36 1.1 skrll if (!val) 37 1.1 skrll return 0; 38 1.1 skrll 39 1.1 skrll if ((len != sizeof(*val)) || (fdt32_to_cpu(*val) == (uint32_t)-1)) 40 1.1 skrll return (uint32_t)-1; 41 1.1 skrll 42 1.1 skrll return fdt32_to_cpu(*val); 43 1.1 skrll } 44 1.1 skrll 45 1.1 skrll /** 46 1.1 skrll * overlay_get_target - retrieves the offset of a fragment's target 47 1.1 skrll * @fdt: Base device tree blob 48 1.1 skrll * @fdto: Device tree overlay blob 49 1.1 skrll * @fragment: node offset of the fragment in the overlay 50 1.1.1.2 skrll * @pathp: pointer which receives the path of the target (or NULL) 51 1.1 skrll * 52 1.1 skrll * overlay_get_target() retrieves the target offset in the base 53 1.1.1.2 skrll * device tree of a fragment, no matter how the actual targeting is 54 1.1 skrll * done (through a phandle or a path) 55 1.1 skrll * 56 1.1 skrll * returns: 57 1.1.1.2 skrll * the targeted node offset in the base device tree 58 1.1 skrll * Negative error code on error 59 1.1 skrll */ 60 1.1 skrll static int overlay_get_target(const void *fdt, const void *fdto, 61 1.1.1.2 skrll int fragment, char const **pathp) 62 1.1 skrll { 63 1.1 skrll uint32_t phandle; 64 1.1.1.2 skrll const char *path = NULL; 65 1.1.1.2 skrll int path_len = 0, ret; 66 1.1 skrll 67 1.1 skrll /* Try first to do a phandle based lookup */ 68 1.1 skrll phandle = overlay_get_target_phandle(fdto, fragment); 69 1.1 skrll if (phandle == (uint32_t)-1) 70 1.1 skrll return -FDT_ERR_BADPHANDLE; 71 1.1 skrll 72 1.1.1.2 skrll /* no phandle, try path */ 73 1.1.1.2 skrll if (!phandle) { 74 1.1.1.2 skrll /* And then a path based lookup */ 75 1.1.1.2 skrll path = fdt_getprop(fdto, fragment, "target-path", &path_len); 76 1.1.1.2 skrll if (path) 77 1.1.1.2 skrll ret = fdt_path_offset(fdt, path); 78 1.1.1.2 skrll else 79 1.1.1.2 skrll ret = path_len; 80 1.1.1.2 skrll } else 81 1.1.1.2 skrll ret = fdt_node_offset_by_phandle(fdt, phandle); 82 1.1 skrll 83 1.1.1.2 skrll /* 84 1.1.1.2 skrll * If we haven't found either a target or a 85 1.1.1.2 skrll * target-path property in a node that contains a 86 1.1.1.2 skrll * __overlay__ subnode (we wouldn't be called 87 1.1.1.2 skrll * otherwise), consider it a improperly written 88 1.1.1.2 skrll * overlay 89 1.1.1.2 skrll */ 90 1.1.1.2 skrll if (ret < 0 && path_len == -FDT_ERR_NOTFOUND) 91 1.1.1.2 skrll ret = -FDT_ERR_BADOVERLAY; 92 1.1 skrll 93 1.1.1.2 skrll /* return on error */ 94 1.1.1.2 skrll if (ret < 0) 95 1.1.1.2 skrll return ret; 96 1.1.1.2 skrll 97 1.1.1.2 skrll /* return pointer to path (if available) */ 98 1.1.1.2 skrll if (pathp) 99 1.1.1.2 skrll *pathp = path ? path : NULL; 100 1.1 skrll 101 1.1.1.2 skrll return ret; 102 1.1 skrll } 103 1.1 skrll 104 1.1 skrll /** 105 1.1 skrll * overlay_phandle_add_offset - Increases a phandle by an offset 106 1.1 skrll * @fdt: Base device tree blob 107 1.1 skrll * @node: Device tree overlay blob 108 1.1 skrll * @name: Name of the property to modify (phandle or linux,phandle) 109 1.1 skrll * @delta: offset to apply 110 1.1 skrll * 111 1.1 skrll * overlay_phandle_add_offset() increments a node phandle by a given 112 1.1 skrll * offset. 113 1.1 skrll * 114 1.1 skrll * returns: 115 1.1 skrll * 0 on success. 116 1.1 skrll * Negative error code on error 117 1.1 skrll */ 118 1.1 skrll static int overlay_phandle_add_offset(void *fdt, int node, 119 1.1 skrll const char *name, uint32_t delta) 120 1.1 skrll { 121 1.1 skrll const fdt32_t *val; 122 1.1 skrll uint32_t adj_val; 123 1.1 skrll int len; 124 1.1 skrll 125 1.1 skrll val = fdt_getprop(fdt, node, name, &len); 126 1.1 skrll if (!val) 127 1.1 skrll return len; 128 1.1 skrll 129 1.1 skrll if (len != sizeof(*val)) 130 1.1 skrll return -FDT_ERR_BADPHANDLE; 131 1.1 skrll 132 1.1 skrll adj_val = fdt32_to_cpu(*val); 133 1.1 skrll if ((adj_val + delta) < adj_val) 134 1.1 skrll return -FDT_ERR_NOPHANDLES; 135 1.1 skrll 136 1.1 skrll adj_val += delta; 137 1.1 skrll if (adj_val == (uint32_t)-1) 138 1.1 skrll return -FDT_ERR_NOPHANDLES; 139 1.1 skrll 140 1.1 skrll return fdt_setprop_inplace_u32(fdt, node, name, adj_val); 141 1.1 skrll } 142 1.1 skrll 143 1.1 skrll /** 144 1.1 skrll * overlay_adjust_node_phandles - Offsets the phandles of a node 145 1.1 skrll * @fdto: Device tree overlay blob 146 1.1 skrll * @node: Offset of the node we want to adjust 147 1.1 skrll * @delta: Offset to shift the phandles of 148 1.1 skrll * 149 1.1 skrll * overlay_adjust_node_phandles() adds a constant to all the phandles 150 1.1 skrll * of a given node. This is mainly use as part of the overlay 151 1.1 skrll * application process, when we want to update all the overlay 152 1.1 skrll * phandles to not conflict with the overlays of the base device tree. 153 1.1 skrll * 154 1.1 skrll * returns: 155 1.1 skrll * 0 on success 156 1.1 skrll * Negative error code on failure 157 1.1 skrll */ 158 1.1 skrll static int overlay_adjust_node_phandles(void *fdto, int node, 159 1.1 skrll uint32_t delta) 160 1.1 skrll { 161 1.1 skrll int child; 162 1.1 skrll int ret; 163 1.1 skrll 164 1.1 skrll ret = overlay_phandle_add_offset(fdto, node, "phandle", delta); 165 1.1 skrll if (ret && ret != -FDT_ERR_NOTFOUND) 166 1.1 skrll return ret; 167 1.1 skrll 168 1.1 skrll ret = overlay_phandle_add_offset(fdto, node, "linux,phandle", delta); 169 1.1 skrll if (ret && ret != -FDT_ERR_NOTFOUND) 170 1.1 skrll return ret; 171 1.1 skrll 172 1.1 skrll fdt_for_each_subnode(child, fdto, node) { 173 1.1 skrll ret = overlay_adjust_node_phandles(fdto, child, delta); 174 1.1 skrll if (ret) 175 1.1 skrll return ret; 176 1.1 skrll } 177 1.1 skrll 178 1.1 skrll return 0; 179 1.1 skrll } 180 1.1 skrll 181 1.1 skrll /** 182 1.1 skrll * overlay_adjust_local_phandles - Adjust the phandles of a whole overlay 183 1.1 skrll * @fdto: Device tree overlay blob 184 1.1 skrll * @delta: Offset to shift the phandles of 185 1.1 skrll * 186 1.1 skrll * overlay_adjust_local_phandles() adds a constant to all the 187 1.1 skrll * phandles of an overlay. This is mainly use as part of the overlay 188 1.1 skrll * application process, when we want to update all the overlay 189 1.1 skrll * phandles to not conflict with the overlays of the base device tree. 190 1.1 skrll * 191 1.1 skrll * returns: 192 1.1 skrll * 0 on success 193 1.1 skrll * Negative error code on failure 194 1.1 skrll */ 195 1.1 skrll static int overlay_adjust_local_phandles(void *fdto, uint32_t delta) 196 1.1 skrll { 197 1.1 skrll /* 198 1.1 skrll * Start adjusting the phandles from the overlay root 199 1.1 skrll */ 200 1.1 skrll return overlay_adjust_node_phandles(fdto, 0, delta); 201 1.1 skrll } 202 1.1 skrll 203 1.1 skrll /** 204 1.1 skrll * overlay_update_local_node_references - Adjust the overlay references 205 1.1 skrll * @fdto: Device tree overlay blob 206 1.1 skrll * @tree_node: Node offset of the node to operate on 207 1.1 skrll * @fixup_node: Node offset of the matching local fixups node 208 1.1 skrll * @delta: Offset to shift the phandles of 209 1.1 skrll * 210 1.1 skrll * overlay_update_local_nodes_references() update the phandles 211 1.1 skrll * pointing to a node within the device tree overlay by adding a 212 1.1 skrll * constant delta. 213 1.1 skrll * 214 1.1 skrll * This is mainly used as part of a device tree application process, 215 1.1 skrll * where you want the device tree overlays phandles to not conflict 216 1.1 skrll * with the ones from the base device tree before merging them. 217 1.1 skrll * 218 1.1 skrll * returns: 219 1.1 skrll * 0 on success 220 1.1 skrll * Negative error code on failure 221 1.1 skrll */ 222 1.1 skrll static int overlay_update_local_node_references(void *fdto, 223 1.1 skrll int tree_node, 224 1.1 skrll int fixup_node, 225 1.1 skrll uint32_t delta) 226 1.1 skrll { 227 1.1 skrll int fixup_prop; 228 1.1 skrll int fixup_child; 229 1.1 skrll int ret; 230 1.1 skrll 231 1.1 skrll fdt_for_each_property_offset(fixup_prop, fdto, fixup_node) { 232 1.1 skrll const fdt32_t *fixup_val; 233 1.1 skrll const char *tree_val; 234 1.1 skrll const char *name; 235 1.1 skrll int fixup_len; 236 1.1 skrll int tree_len; 237 1.1 skrll int i; 238 1.1 skrll 239 1.1 skrll fixup_val = fdt_getprop_by_offset(fdto, fixup_prop, 240 1.1 skrll &name, &fixup_len); 241 1.1 skrll if (!fixup_val) 242 1.1 skrll return fixup_len; 243 1.1 skrll 244 1.1 skrll if (fixup_len % sizeof(uint32_t)) 245 1.1 skrll return -FDT_ERR_BADOVERLAY; 246 1.1 skrll 247 1.1 skrll tree_val = fdt_getprop(fdto, tree_node, name, &tree_len); 248 1.1 skrll if (!tree_val) { 249 1.1 skrll if (tree_len == -FDT_ERR_NOTFOUND) 250 1.1 skrll return -FDT_ERR_BADOVERLAY; 251 1.1 skrll 252 1.1 skrll return tree_len; 253 1.1 skrll } 254 1.1 skrll 255 1.1 skrll for (i = 0; i < (fixup_len / sizeof(uint32_t)); i++) { 256 1.1 skrll fdt32_t adj_val; 257 1.1 skrll uint32_t poffset; 258 1.1 skrll 259 1.1 skrll poffset = fdt32_to_cpu(fixup_val[i]); 260 1.1 skrll 261 1.1 skrll /* 262 1.1 skrll * phandles to fixup can be unaligned. 263 1.1 skrll * 264 1.1 skrll * Use a memcpy for the architectures that do 265 1.1 skrll * not support unaligned accesses. 266 1.1 skrll */ 267 1.1 skrll memcpy(&adj_val, tree_val + poffset, sizeof(adj_val)); 268 1.1 skrll 269 1.1 skrll adj_val = cpu_to_fdt32(fdt32_to_cpu(adj_val) + delta); 270 1.1 skrll 271 1.1 skrll ret = fdt_setprop_inplace_namelen_partial(fdto, 272 1.1 skrll tree_node, 273 1.1 skrll name, 274 1.1 skrll strlen(name), 275 1.1 skrll poffset, 276 1.1 skrll &adj_val, 277 1.1 skrll sizeof(adj_val)); 278 1.1 skrll if (ret == -FDT_ERR_NOSPACE) 279 1.1 skrll return -FDT_ERR_BADOVERLAY; 280 1.1 skrll 281 1.1 skrll if (ret) 282 1.1 skrll return ret; 283 1.1 skrll } 284 1.1 skrll } 285 1.1 skrll 286 1.1 skrll fdt_for_each_subnode(fixup_child, fdto, fixup_node) { 287 1.1 skrll const char *fixup_child_name = fdt_get_name(fdto, fixup_child, 288 1.1 skrll NULL); 289 1.1 skrll int tree_child; 290 1.1 skrll 291 1.1 skrll tree_child = fdt_subnode_offset(fdto, tree_node, 292 1.1 skrll fixup_child_name); 293 1.1 skrll if (tree_child == -FDT_ERR_NOTFOUND) 294 1.1 skrll return -FDT_ERR_BADOVERLAY; 295 1.1 skrll if (tree_child < 0) 296 1.1 skrll return tree_child; 297 1.1 skrll 298 1.1 skrll ret = overlay_update_local_node_references(fdto, 299 1.1 skrll tree_child, 300 1.1 skrll fixup_child, 301 1.1 skrll delta); 302 1.1 skrll if (ret) 303 1.1 skrll return ret; 304 1.1 skrll } 305 1.1 skrll 306 1.1 skrll return 0; 307 1.1 skrll } 308 1.1 skrll 309 1.1 skrll /** 310 1.1 skrll * overlay_update_local_references - Adjust the overlay references 311 1.1 skrll * @fdto: Device tree overlay blob 312 1.1 skrll * @delta: Offset to shift the phandles of 313 1.1 skrll * 314 1.1 skrll * overlay_update_local_references() update all the phandles pointing 315 1.1 skrll * to a node within the device tree overlay by adding a constant 316 1.1 skrll * delta to not conflict with the base overlay. 317 1.1 skrll * 318 1.1 skrll * This is mainly used as part of a device tree application process, 319 1.1 skrll * where you want the device tree overlays phandles to not conflict 320 1.1 skrll * with the ones from the base device tree before merging them. 321 1.1 skrll * 322 1.1 skrll * returns: 323 1.1 skrll * 0 on success 324 1.1 skrll * Negative error code on failure 325 1.1 skrll */ 326 1.1 skrll static int overlay_update_local_references(void *fdto, uint32_t delta) 327 1.1 skrll { 328 1.1 skrll int fixups; 329 1.1 skrll 330 1.1 skrll fixups = fdt_path_offset(fdto, "/__local_fixups__"); 331 1.1 skrll if (fixups < 0) { 332 1.1 skrll /* There's no local phandles to adjust, bail out */ 333 1.1 skrll if (fixups == -FDT_ERR_NOTFOUND) 334 1.1 skrll return 0; 335 1.1 skrll 336 1.1 skrll return fixups; 337 1.1 skrll } 338 1.1 skrll 339 1.1 skrll /* 340 1.1 skrll * Update our local references from the root of the tree 341 1.1 skrll */ 342 1.1 skrll return overlay_update_local_node_references(fdto, 0, fixups, 343 1.1 skrll delta); 344 1.1 skrll } 345 1.1 skrll 346 1.1 skrll /** 347 1.1 skrll * overlay_fixup_one_phandle - Set an overlay phandle to the base one 348 1.1 skrll * @fdt: Base Device Tree blob 349 1.1 skrll * @fdto: Device tree overlay blob 350 1.1 skrll * @symbols_off: Node offset of the symbols node in the base device tree 351 1.1 skrll * @path: Path to a node holding a phandle in the overlay 352 1.1 skrll * @path_len: number of path characters to consider 353 1.1 skrll * @name: Name of the property holding the phandle reference in the overlay 354 1.1 skrll * @name_len: number of name characters to consider 355 1.1 skrll * @poffset: Offset within the overlay property where the phandle is stored 356 1.1 skrll * @label: Label of the node referenced by the phandle 357 1.1 skrll * 358 1.1 skrll * overlay_fixup_one_phandle() resolves an overlay phandle pointing to 359 1.1 skrll * a node in the base device tree. 360 1.1 skrll * 361 1.1 skrll * This is part of the device tree overlay application process, when 362 1.1 skrll * you want all the phandles in the overlay to point to the actual 363 1.1 skrll * base dt nodes. 364 1.1 skrll * 365 1.1 skrll * returns: 366 1.1 skrll * 0 on success 367 1.1 skrll * Negative error code on failure 368 1.1 skrll */ 369 1.1 skrll static int overlay_fixup_one_phandle(void *fdt, void *fdto, 370 1.1 skrll int symbols_off, 371 1.1 skrll const char *path, uint32_t path_len, 372 1.1 skrll const char *name, uint32_t name_len, 373 1.1 skrll int poffset, const char *label) 374 1.1 skrll { 375 1.1 skrll const char *symbol_path; 376 1.1 skrll uint32_t phandle; 377 1.1 skrll fdt32_t phandle_prop; 378 1.1 skrll int symbol_off, fixup_off; 379 1.1 skrll int prop_len; 380 1.1 skrll 381 1.1 skrll if (symbols_off < 0) 382 1.1 skrll return symbols_off; 383 1.1 skrll 384 1.1 skrll symbol_path = fdt_getprop(fdt, symbols_off, label, 385 1.1 skrll &prop_len); 386 1.1 skrll if (!symbol_path) 387 1.1 skrll return prop_len; 388 1.1 skrll 389 1.1 skrll symbol_off = fdt_path_offset(fdt, symbol_path); 390 1.1 skrll if (symbol_off < 0) 391 1.1 skrll return symbol_off; 392 1.1 skrll 393 1.1 skrll phandle = fdt_get_phandle(fdt, symbol_off); 394 1.1 skrll if (!phandle) 395 1.1 skrll return -FDT_ERR_NOTFOUND; 396 1.1 skrll 397 1.1 skrll fixup_off = fdt_path_offset_namelen(fdto, path, path_len); 398 1.1 skrll if (fixup_off == -FDT_ERR_NOTFOUND) 399 1.1 skrll return -FDT_ERR_BADOVERLAY; 400 1.1 skrll if (fixup_off < 0) 401 1.1 skrll return fixup_off; 402 1.1 skrll 403 1.1 skrll phandle_prop = cpu_to_fdt32(phandle); 404 1.1 skrll return fdt_setprop_inplace_namelen_partial(fdto, fixup_off, 405 1.1 skrll name, name_len, poffset, 406 1.1 skrll &phandle_prop, 407 1.1 skrll sizeof(phandle_prop)); 408 1.1 skrll }; 409 1.1 skrll 410 1.1 skrll /** 411 1.1 skrll * overlay_fixup_phandle - Set an overlay phandle to the base one 412 1.1 skrll * @fdt: Base Device Tree blob 413 1.1 skrll * @fdto: Device tree overlay blob 414 1.1 skrll * @symbols_off: Node offset of the symbols node in the base device tree 415 1.1 skrll * @property: Property offset in the overlay holding the list of fixups 416 1.1 skrll * 417 1.1 skrll * overlay_fixup_phandle() resolves all the overlay phandles pointed 418 1.1 skrll * to in a __fixups__ property, and updates them to match the phandles 419 1.1 skrll * in use in the base device tree. 420 1.1 skrll * 421 1.1 skrll * This is part of the device tree overlay application process, when 422 1.1 skrll * you want all the phandles in the overlay to point to the actual 423 1.1 skrll * base dt nodes. 424 1.1 skrll * 425 1.1 skrll * returns: 426 1.1 skrll * 0 on success 427 1.1 skrll * Negative error code on failure 428 1.1 skrll */ 429 1.1 skrll static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off, 430 1.1 skrll int property) 431 1.1 skrll { 432 1.1 skrll const char *value; 433 1.1 skrll const char *label; 434 1.1 skrll int len; 435 1.1 skrll 436 1.1 skrll value = fdt_getprop_by_offset(fdto, property, 437 1.1 skrll &label, &len); 438 1.1 skrll if (!value) { 439 1.1 skrll if (len == -FDT_ERR_NOTFOUND) 440 1.1 skrll return -FDT_ERR_INTERNAL; 441 1.1 skrll 442 1.1 skrll return len; 443 1.1 skrll } 444 1.1 skrll 445 1.1 skrll do { 446 1.1 skrll const char *path, *name, *fixup_end; 447 1.1 skrll const char *fixup_str = value; 448 1.1 skrll uint32_t path_len, name_len; 449 1.1 skrll uint32_t fixup_len; 450 1.1 skrll char *sep, *endptr; 451 1.1 skrll int poffset, ret; 452 1.1 skrll 453 1.1 skrll fixup_end = memchr(value, '\0', len); 454 1.1 skrll if (!fixup_end) 455 1.1 skrll return -FDT_ERR_BADOVERLAY; 456 1.1 skrll fixup_len = fixup_end - fixup_str; 457 1.1 skrll 458 1.1 skrll len -= fixup_len + 1; 459 1.1 skrll value += fixup_len + 1; 460 1.1 skrll 461 1.1 skrll path = fixup_str; 462 1.1 skrll sep = memchr(fixup_str, ':', fixup_len); 463 1.1 skrll if (!sep || *sep != ':') 464 1.1 skrll return -FDT_ERR_BADOVERLAY; 465 1.1 skrll 466 1.1 skrll path_len = sep - path; 467 1.1 skrll if (path_len == (fixup_len - 1)) 468 1.1 skrll return -FDT_ERR_BADOVERLAY; 469 1.1 skrll 470 1.1 skrll fixup_len -= path_len + 1; 471 1.1 skrll name = sep + 1; 472 1.1 skrll sep = memchr(name, ':', fixup_len); 473 1.1 skrll if (!sep || *sep != ':') 474 1.1 skrll return -FDT_ERR_BADOVERLAY; 475 1.1 skrll 476 1.1 skrll name_len = sep - name; 477 1.1 skrll if (!name_len) 478 1.1 skrll return -FDT_ERR_BADOVERLAY; 479 1.1 skrll 480 1.1 skrll poffset = strtoul(sep + 1, &endptr, 10); 481 1.1 skrll if ((*endptr != '\0') || (endptr <= (sep + 1))) 482 1.1 skrll return -FDT_ERR_BADOVERLAY; 483 1.1 skrll 484 1.1 skrll ret = overlay_fixup_one_phandle(fdt, fdto, symbols_off, 485 1.1 skrll path, path_len, name, name_len, 486 1.1 skrll poffset, label); 487 1.1 skrll if (ret) 488 1.1 skrll return ret; 489 1.1 skrll } while (len > 0); 490 1.1 skrll 491 1.1 skrll return 0; 492 1.1 skrll } 493 1.1 skrll 494 1.1 skrll /** 495 1.1 skrll * overlay_fixup_phandles - Resolve the overlay phandles to the base 496 1.1 skrll * device tree 497 1.1 skrll * @fdt: Base Device Tree blob 498 1.1 skrll * @fdto: Device tree overlay blob 499 1.1 skrll * 500 1.1 skrll * overlay_fixup_phandles() resolves all the overlay phandles pointing 501 1.1 skrll * to nodes in the base device tree. 502 1.1 skrll * 503 1.1 skrll * This is one of the steps of the device tree overlay application 504 1.1 skrll * process, when you want all the phandles in the overlay to point to 505 1.1 skrll * the actual base dt nodes. 506 1.1 skrll * 507 1.1 skrll * returns: 508 1.1 skrll * 0 on success 509 1.1 skrll * Negative error code on failure 510 1.1 skrll */ 511 1.1 skrll static int overlay_fixup_phandles(void *fdt, void *fdto) 512 1.1 skrll { 513 1.1 skrll int fixups_off, symbols_off; 514 1.1 skrll int property; 515 1.1 skrll 516 1.1 skrll /* We can have overlays without any fixups */ 517 1.1 skrll fixups_off = fdt_path_offset(fdto, "/__fixups__"); 518 1.1 skrll if (fixups_off == -FDT_ERR_NOTFOUND) 519 1.1 skrll return 0; /* nothing to do */ 520 1.1 skrll if (fixups_off < 0) 521 1.1 skrll return fixups_off; 522 1.1 skrll 523 1.1 skrll /* And base DTs without symbols */ 524 1.1 skrll symbols_off = fdt_path_offset(fdt, "/__symbols__"); 525 1.1 skrll if ((symbols_off < 0 && (symbols_off != -FDT_ERR_NOTFOUND))) 526 1.1 skrll return symbols_off; 527 1.1 skrll 528 1.1 skrll fdt_for_each_property_offset(property, fdto, fixups_off) { 529 1.1 skrll int ret; 530 1.1 skrll 531 1.1 skrll ret = overlay_fixup_phandle(fdt, fdto, symbols_off, property); 532 1.1 skrll if (ret) 533 1.1 skrll return ret; 534 1.1 skrll } 535 1.1 skrll 536 1.1 skrll return 0; 537 1.1 skrll } 538 1.1 skrll 539 1.1 skrll /** 540 1.1 skrll * overlay_apply_node - Merges a node into the base device tree 541 1.1 skrll * @fdt: Base Device Tree blob 542 1.1 skrll * @target: Node offset in the base device tree to apply the fragment to 543 1.1 skrll * @fdto: Device tree overlay blob 544 1.1 skrll * @node: Node offset in the overlay holding the changes to merge 545 1.1 skrll * 546 1.1 skrll * overlay_apply_node() merges a node into a target base device tree 547 1.1 skrll * node pointed. 548 1.1 skrll * 549 1.1 skrll * This is part of the final step in the device tree overlay 550 1.1 skrll * application process, when all the phandles have been adjusted and 551 1.1 skrll * resolved and you just have to merge overlay into the base device 552 1.1 skrll * tree. 553 1.1 skrll * 554 1.1 skrll * returns: 555 1.1 skrll * 0 on success 556 1.1 skrll * Negative error code on failure 557 1.1 skrll */ 558 1.1 skrll static int overlay_apply_node(void *fdt, int target, 559 1.1 skrll void *fdto, int node) 560 1.1 skrll { 561 1.1 skrll int property; 562 1.1 skrll int subnode; 563 1.1 skrll 564 1.1 skrll fdt_for_each_property_offset(property, fdto, node) { 565 1.1 skrll const char *name; 566 1.1 skrll const void *prop; 567 1.1 skrll int prop_len; 568 1.1 skrll int ret; 569 1.1 skrll 570 1.1 skrll prop = fdt_getprop_by_offset(fdto, property, &name, 571 1.1 skrll &prop_len); 572 1.1 skrll if (prop_len == -FDT_ERR_NOTFOUND) 573 1.1 skrll return -FDT_ERR_INTERNAL; 574 1.1 skrll if (prop_len < 0) 575 1.1 skrll return prop_len; 576 1.1 skrll 577 1.1 skrll ret = fdt_setprop(fdt, target, name, prop, prop_len); 578 1.1 skrll if (ret) 579 1.1 skrll return ret; 580 1.1 skrll } 581 1.1 skrll 582 1.1 skrll fdt_for_each_subnode(subnode, fdto, node) { 583 1.1 skrll const char *name = fdt_get_name(fdto, subnode, NULL); 584 1.1 skrll int nnode; 585 1.1 skrll int ret; 586 1.1 skrll 587 1.1 skrll nnode = fdt_add_subnode(fdt, target, name); 588 1.1 skrll if (nnode == -FDT_ERR_EXISTS) { 589 1.1 skrll nnode = fdt_subnode_offset(fdt, target, name); 590 1.1 skrll if (nnode == -FDT_ERR_NOTFOUND) 591 1.1 skrll return -FDT_ERR_INTERNAL; 592 1.1 skrll } 593 1.1 skrll 594 1.1 skrll if (nnode < 0) 595 1.1 skrll return nnode; 596 1.1 skrll 597 1.1 skrll ret = overlay_apply_node(fdt, nnode, fdto, subnode); 598 1.1 skrll if (ret) 599 1.1 skrll return ret; 600 1.1 skrll } 601 1.1 skrll 602 1.1 skrll return 0; 603 1.1 skrll } 604 1.1 skrll 605 1.1 skrll /** 606 1.1 skrll * overlay_merge - Merge an overlay into its base device tree 607 1.1 skrll * @fdt: Base Device Tree blob 608 1.1 skrll * @fdto: Device tree overlay blob 609 1.1 skrll * 610 1.1 skrll * overlay_merge() merges an overlay into its base device tree. 611 1.1 skrll * 612 1.1.1.2 skrll * This is the next to last step in the device tree overlay application 613 1.1 skrll * process, when all the phandles have been adjusted and resolved and 614 1.1 skrll * you just have to merge overlay into the base device tree. 615 1.1 skrll * 616 1.1 skrll * returns: 617 1.1 skrll * 0 on success 618 1.1 skrll * Negative error code on failure 619 1.1 skrll */ 620 1.1 skrll static int overlay_merge(void *fdt, void *fdto) 621 1.1 skrll { 622 1.1 skrll int fragment; 623 1.1 skrll 624 1.1 skrll fdt_for_each_subnode(fragment, fdto, 0) { 625 1.1 skrll int overlay; 626 1.1 skrll int target; 627 1.1 skrll int ret; 628 1.1 skrll 629 1.1 skrll /* 630 1.1 skrll * Each fragments will have an __overlay__ node. If 631 1.1 skrll * they don't, it's not supposed to be merged 632 1.1 skrll */ 633 1.1 skrll overlay = fdt_subnode_offset(fdto, fragment, "__overlay__"); 634 1.1 skrll if (overlay == -FDT_ERR_NOTFOUND) 635 1.1 skrll continue; 636 1.1 skrll 637 1.1 skrll if (overlay < 0) 638 1.1 skrll return overlay; 639 1.1 skrll 640 1.1.1.2 skrll target = overlay_get_target(fdt, fdto, fragment, NULL); 641 1.1 skrll if (target < 0) 642 1.1 skrll return target; 643 1.1 skrll 644 1.1 skrll ret = overlay_apply_node(fdt, target, fdto, overlay); 645 1.1 skrll if (ret) 646 1.1 skrll return ret; 647 1.1 skrll } 648 1.1 skrll 649 1.1 skrll return 0; 650 1.1 skrll } 651 1.1 skrll 652 1.1.1.2 skrll static int get_path_len(const void *fdt, int nodeoffset) 653 1.1.1.2 skrll { 654 1.1.1.2 skrll int len = 0, namelen; 655 1.1.1.2 skrll const char *name; 656 1.1.1.2 skrll 657 1.1.1.2 skrll FDT_RO_PROBE(fdt); 658 1.1.1.2 skrll 659 1.1.1.2 skrll for (;;) { 660 1.1.1.2 skrll name = fdt_get_name(fdt, nodeoffset, &namelen); 661 1.1.1.2 skrll if (!name) 662 1.1.1.2 skrll return namelen; 663 1.1.1.2 skrll 664 1.1.1.2 skrll /* root? we're done */ 665 1.1.1.2 skrll if (namelen == 0) 666 1.1.1.2 skrll break; 667 1.1.1.2 skrll 668 1.1.1.2 skrll nodeoffset = fdt_parent_offset(fdt, nodeoffset); 669 1.1.1.2 skrll if (nodeoffset < 0) 670 1.1.1.2 skrll return nodeoffset; 671 1.1.1.2 skrll len += namelen + 1; 672 1.1.1.2 skrll } 673 1.1.1.2 skrll 674 1.1.1.2 skrll /* in case of root pretend it's "/" */ 675 1.1.1.2 skrll if (len == 0) 676 1.1.1.2 skrll len++; 677 1.1.1.2 skrll return len; 678 1.1.1.2 skrll } 679 1.1.1.2 skrll 680 1.1.1.2 skrll /** 681 1.1.1.2 skrll * overlay_symbol_update - Update the symbols of base tree after a merge 682 1.1.1.2 skrll * @fdt: Base Device Tree blob 683 1.1.1.2 skrll * @fdto: Device tree overlay blob 684 1.1.1.2 skrll * 685 1.1.1.2 skrll * overlay_symbol_update() updates the symbols of the base tree with the 686 1.1.1.2 skrll * symbols of the applied overlay 687 1.1.1.2 skrll * 688 1.1.1.2 skrll * This is the last step in the device tree overlay application 689 1.1.1.2 skrll * process, allowing the reference of overlay symbols by subsequent 690 1.1.1.2 skrll * overlay operations. 691 1.1.1.2 skrll * 692 1.1.1.2 skrll * returns: 693 1.1.1.2 skrll * 0 on success 694 1.1.1.2 skrll * Negative error code on failure 695 1.1.1.2 skrll */ 696 1.1.1.2 skrll static int overlay_symbol_update(void *fdt, void *fdto) 697 1.1.1.2 skrll { 698 1.1.1.2 skrll int root_sym, ov_sym, prop, path_len, fragment, target; 699 1.1.1.2 skrll int len, frag_name_len, ret, rel_path_len; 700 1.1.1.2 skrll const char *s, *e; 701 1.1.1.2 skrll const char *path; 702 1.1.1.2 skrll const char *name; 703 1.1.1.2 skrll const char *frag_name; 704 1.1.1.2 skrll const char *rel_path; 705 1.1.1.2 skrll const char *target_path; 706 1.1.1.2 skrll char *buf; 707 1.1.1.2 skrll void *p; 708 1.1.1.2 skrll 709 1.1.1.2 skrll ov_sym = fdt_subnode_offset(fdto, 0, "__symbols__"); 710 1.1.1.2 skrll 711 1.1.1.2 skrll /* if no overlay symbols exist no problem */ 712 1.1.1.2 skrll if (ov_sym < 0) 713 1.1.1.2 skrll return 0; 714 1.1.1.2 skrll 715 1.1.1.2 skrll root_sym = fdt_subnode_offset(fdt, 0, "__symbols__"); 716 1.1.1.2 skrll 717 1.1.1.2 skrll /* it no root symbols exist we should create them */ 718 1.1.1.2 skrll if (root_sym == -FDT_ERR_NOTFOUND) 719 1.1.1.2 skrll root_sym = fdt_add_subnode(fdt, 0, "__symbols__"); 720 1.1.1.2 skrll 721 1.1.1.2 skrll /* any error is fatal now */ 722 1.1.1.2 skrll if (root_sym < 0) 723 1.1.1.2 skrll return root_sym; 724 1.1.1.2 skrll 725 1.1.1.2 skrll /* iterate over each overlay symbol */ 726 1.1.1.2 skrll fdt_for_each_property_offset(prop, fdto, ov_sym) { 727 1.1.1.2 skrll path = fdt_getprop_by_offset(fdto, prop, &name, &path_len); 728 1.1.1.2 skrll if (!path) 729 1.1.1.2 skrll return path_len; 730 1.1.1.2 skrll 731 1.1.1.2 skrll /* verify it's a string property (terminated by a single \0) */ 732 1.1.1.2 skrll if (path_len < 1 || memchr(path, '\0', path_len) != &path[path_len - 1]) 733 1.1.1.2 skrll return -FDT_ERR_BADVALUE; 734 1.1.1.2 skrll 735 1.1.1.2 skrll /* keep end marker to avoid strlen() */ 736 1.1.1.2 skrll e = path + path_len; 737 1.1.1.2 skrll 738 1.1.1.2 skrll if (*path != '/') 739 1.1.1.2 skrll return -FDT_ERR_BADVALUE; 740 1.1.1.2 skrll 741 1.1.1.2 skrll /* get fragment name first */ 742 1.1.1.2 skrll s = strchr(path + 1, '/'); 743 1.1.1.2 skrll if (!s) { 744 1.1.1.2 skrll /* Symbol refers to something that won't end 745 1.1.1.2 skrll * up in the target tree */ 746 1.1.1.2 skrll continue; 747 1.1.1.2 skrll } 748 1.1.1.2 skrll 749 1.1.1.2 skrll frag_name = path + 1; 750 1.1.1.2 skrll frag_name_len = s - path - 1; 751 1.1.1.2 skrll 752 1.1.1.2 skrll /* verify format; safe since "s" lies in \0 terminated prop */ 753 1.1.1.2 skrll len = sizeof("/__overlay__/") - 1; 754 1.1.1.2 skrll if ((e - s) > len && (memcmp(s, "/__overlay__/", len) == 0)) { 755 1.1.1.2 skrll /* /<fragment-name>/__overlay__/<relative-subnode-path> */ 756 1.1.1.2 skrll rel_path = s + len; 757 1.1.1.2 skrll rel_path_len = e - rel_path; 758 1.1.1.2 skrll } else if ((e - s) == len 759 1.1.1.2 skrll && (memcmp(s, "/__overlay__", len - 1) == 0)) { 760 1.1.1.2 skrll /* /<fragment-name>/__overlay__ */ 761 1.1.1.2 skrll rel_path = ""; 762 1.1.1.2 skrll rel_path_len = 0; 763 1.1.1.2 skrll } else { 764 1.1.1.2 skrll /* Symbol refers to something that won't end 765 1.1.1.2 skrll * up in the target tree */ 766 1.1.1.2 skrll continue; 767 1.1.1.2 skrll } 768 1.1.1.2 skrll 769 1.1.1.2 skrll /* find the fragment index in which the symbol lies */ 770 1.1.1.2 skrll ret = fdt_subnode_offset_namelen(fdto, 0, frag_name, 771 1.1.1.2 skrll frag_name_len); 772 1.1.1.2 skrll /* not found? */ 773 1.1.1.2 skrll if (ret < 0) 774 1.1.1.2 skrll return -FDT_ERR_BADOVERLAY; 775 1.1.1.2 skrll fragment = ret; 776 1.1.1.2 skrll 777 1.1.1.2 skrll /* an __overlay__ subnode must exist */ 778 1.1.1.2 skrll ret = fdt_subnode_offset(fdto, fragment, "__overlay__"); 779 1.1.1.2 skrll if (ret < 0) 780 1.1.1.2 skrll return -FDT_ERR_BADOVERLAY; 781 1.1.1.2 skrll 782 1.1.1.2 skrll /* get the target of the fragment */ 783 1.1.1.2 skrll ret = overlay_get_target(fdt, fdto, fragment, &target_path); 784 1.1.1.2 skrll if (ret < 0) 785 1.1.1.2 skrll return ret; 786 1.1.1.2 skrll target = ret; 787 1.1.1.2 skrll 788 1.1.1.2 skrll /* if we have a target path use */ 789 1.1.1.2 skrll if (!target_path) { 790 1.1.1.2 skrll ret = get_path_len(fdt, target); 791 1.1.1.2 skrll if (ret < 0) 792 1.1.1.2 skrll return ret; 793 1.1.1.2 skrll len = ret; 794 1.1.1.2 skrll } else { 795 1.1.1.2 skrll len = strlen(target_path); 796 1.1.1.2 skrll } 797 1.1.1.2 skrll 798 1.1.1.2 skrll ret = fdt_setprop_placeholder(fdt, root_sym, name, 799 1.1.1.2 skrll len + (len > 1) + rel_path_len + 1, &p); 800 1.1.1.2 skrll if (ret < 0) 801 1.1.1.2 skrll return ret; 802 1.1.1.2 skrll 803 1.1.1.2 skrll if (!target_path) { 804 1.1.1.2 skrll /* again in case setprop_placeholder changed it */ 805 1.1.1.2 skrll ret = overlay_get_target(fdt, fdto, fragment, &target_path); 806 1.1.1.2 skrll if (ret < 0) 807 1.1.1.2 skrll return ret; 808 1.1.1.2 skrll target = ret; 809 1.1.1.2 skrll } 810 1.1.1.2 skrll 811 1.1.1.2 skrll buf = p; 812 1.1.1.2 skrll if (len > 1) { /* target is not root */ 813 1.1.1.2 skrll if (!target_path) { 814 1.1.1.2 skrll ret = fdt_get_path(fdt, target, buf, len + 1); 815 1.1.1.2 skrll if (ret < 0) 816 1.1.1.2 skrll return ret; 817 1.1.1.2 skrll } else 818 1.1.1.2 skrll memcpy(buf, target_path, len + 1); 819 1.1.1.2 skrll 820 1.1.1.2 skrll } else 821 1.1.1.2 skrll len--; 822 1.1.1.2 skrll 823 1.1.1.2 skrll buf[len] = '/'; 824 1.1.1.2 skrll memcpy(buf + len + 1, rel_path, rel_path_len); 825 1.1.1.2 skrll buf[len + 1 + rel_path_len] = '\0'; 826 1.1.1.2 skrll } 827 1.1.1.2 skrll 828 1.1.1.2 skrll return 0; 829 1.1.1.2 skrll } 830 1.1.1.2 skrll 831 1.1 skrll int fdt_overlay_apply(void *fdt, void *fdto) 832 1.1 skrll { 833 1.1.1.2 skrll uint32_t delta; 834 1.1 skrll int ret; 835 1.1 skrll 836 1.1.1.2 skrll FDT_RO_PROBE(fdt); 837 1.1.1.2 skrll FDT_RO_PROBE(fdto); 838 1.1.1.2 skrll 839 1.1.1.2 skrll ret = fdt_find_max_phandle(fdt, &delta); 840 1.1.1.2 skrll if (ret) 841 1.1.1.2 skrll goto err; 842 1.1 skrll 843 1.1 skrll ret = overlay_adjust_local_phandles(fdto, delta); 844 1.1 skrll if (ret) 845 1.1 skrll goto err; 846 1.1 skrll 847 1.1 skrll ret = overlay_update_local_references(fdto, delta); 848 1.1 skrll if (ret) 849 1.1 skrll goto err; 850 1.1 skrll 851 1.1 skrll ret = overlay_fixup_phandles(fdt, fdto); 852 1.1 skrll if (ret) 853 1.1 skrll goto err; 854 1.1 skrll 855 1.1 skrll ret = overlay_merge(fdt, fdto); 856 1.1 skrll if (ret) 857 1.1 skrll goto err; 858 1.1 skrll 859 1.1.1.2 skrll ret = overlay_symbol_update(fdt, fdto); 860 1.1.1.2 skrll if (ret) 861 1.1.1.2 skrll goto err; 862 1.1.1.2 skrll 863 1.1 skrll /* 864 1.1 skrll * The overlay has been damaged, erase its magic. 865 1.1 skrll */ 866 1.1 skrll fdt_set_magic(fdto, ~0); 867 1.1 skrll 868 1.1 skrll return 0; 869 1.1 skrll 870 1.1 skrll err: 871 1.1 skrll /* 872 1.1 skrll * The overlay might have been damaged, erase its magic. 873 1.1 skrll */ 874 1.1 skrll fdt_set_magic(fdto, ~0); 875 1.1 skrll 876 1.1 skrll /* 877 1.1 skrll * The base device tree might have been damaged, erase its 878 1.1 skrll * magic. 879 1.1 skrll */ 880 1.1 skrll fdt_set_magic(fdt, ~0); 881 1.1 skrll 882 1.1 skrll return ret; 883 1.1 skrll } 884