1 /* 2 * Copyright (c) 2018-2024, Arm Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 /* Helper functions to offer easier navigation of Device Tree Blob */ 8 9 #include <assert.h> 10 #include <errno.h> 11 #include <inttypes.h> 12 #include <stdint.h> 13 #include <string.h> 14 15 #include <libfdt.h> 16 17 #include <common/debug.h> 18 #include <common/fdt_wrappers.h> 19 #include <common/uuid.h> 20 21 /* 22 * Read cells from a given property of the given node. Any number of 32-bit 23 * cells of the property can be read. Returns 0 on success, or a negative 24 * FDT error value otherwise. 25 */ 26 int fdt_read_uint32_array(const void *dtb, int node, const char *prop_name, 27 unsigned int cells, uint32_t *value) 28 { 29 const fdt32_t *prop; 30 int value_len; 31 32 assert(dtb != NULL); 33 assert(prop_name != NULL); 34 assert(value != NULL); 35 assert(node >= 0); 36 37 /* Access property and obtain its length (in bytes) */ 38 prop = fdt_getprop(dtb, node, prop_name, &value_len); 39 if (prop == NULL) { 40 VERBOSE("Couldn't find property %s in dtb\n", prop_name); 41 return -FDT_ERR_NOTFOUND; 42 } 43 44 /* Verify that property length can fill the entire array. */ 45 if (NCELLS((unsigned int)value_len) < cells) { 46 WARN("Property length mismatch\n"); 47 return -FDT_ERR_BADVALUE; 48 } 49 50 for (unsigned int i = 0U; i < cells; i++) { 51 value[i] = fdt32_to_cpu(prop[i]); 52 } 53 54 return 0; 55 } 56 57 int fdt_read_uint32(const void *dtb, int node, const char *prop_name, 58 uint32_t *value) 59 { 60 return fdt_read_uint32_array(dtb, node, prop_name, 1, value); 61 } 62 63 uint32_t fdt_read_uint32_default(const void *dtb, int node, 64 const char *prop_name, uint32_t dflt_value) 65 { 66 uint32_t ret = dflt_value; 67 int err = fdt_read_uint32(dtb, node, prop_name, &ret); 68 69 if (err < 0) { 70 return dflt_value; 71 } 72 73 return ret; 74 } 75 76 int fdt_read_uint64(const void *dtb, int node, const char *prop_name, 77 uint64_t *value) 78 { 79 uint32_t array[2] = {0, 0}; 80 int ret; 81 82 ret = fdt_read_uint32_array(dtb, node, prop_name, 2, array); 83 if (ret < 0) { 84 return ret; 85 } 86 87 *value = ((uint64_t)array[0] << 32) | array[1]; 88 return 0; 89 } 90 91 uint64_t fdt_read_uint64_default(const void *dtb, int node, 92 const char *prop_name, uint64_t dflt_value) 93 { 94 uint64_t ret = dflt_value; 95 int err = fdt_read_uint64(dtb, node, prop_name, &ret); 96 97 if (err < 0) { 98 return dflt_value; 99 } 100 101 return ret; 102 } 103 104 /* 105 * Read bytes from a given property of the given node. Any number of 106 * bytes of the property can be read. The fdt pointer is updated. 107 * Returns 0 on success, and -1 on error. 108 */ 109 int fdtw_read_bytes(const void *dtb, int node, const char *prop, 110 unsigned int length, void *value) 111 { 112 const void *ptr; 113 int value_len; 114 115 assert(dtb != NULL); 116 assert(prop != NULL); 117 assert(value != NULL); 118 assert(node >= 0); 119 120 /* Access property and obtain its length (in bytes) */ 121 ptr = fdt_getprop_namelen(dtb, node, prop, (int)strlen(prop), 122 &value_len); 123 if (ptr == NULL) { 124 WARN("Couldn't find property %s in dtb\n", prop); 125 return -1; 126 } 127 128 /* Verify that property length is not less than number of bytes */ 129 if ((unsigned int)value_len < length) { 130 WARN("Property length mismatch\n"); 131 return -1; 132 } 133 134 (void)memcpy(value, ptr, length); 135 136 return 0; 137 } 138 139 /* 140 * Read string from a given property of the given node. Up to 'size - 1' 141 * characters are read, and a NUL terminator is added. Returns 0 on success, 142 * and -1 upon error. 143 */ 144 int fdtw_read_string(const void *dtb, int node, const char *prop, 145 char *str, size_t size) 146 { 147 const char *ptr; 148 size_t len; 149 150 assert(dtb != NULL); 151 assert(node >= 0); 152 assert(prop != NULL); 153 assert(str != NULL); 154 assert(size > 0U); 155 156 ptr = fdt_getprop_namelen(dtb, node, prop, (int)strlen(prop), NULL); 157 if (ptr == NULL) { 158 WARN("Couldn't find property %s in dtb\n", prop); 159 return -1; 160 } 161 162 len = strlcpy(str, ptr, size); 163 if (len >= size) { 164 WARN("String of property %s in dtb has been truncated\n", prop); 165 return -1; 166 } 167 168 return 0; 169 } 170 171 /* 172 * Read UUID from a given property of the given node. Returns 0 on success, 173 * and a negative value upon error. 174 */ 175 int fdtw_read_uuid(const void *dtb, int node, const char *prop, 176 unsigned int length, uint8_t *uuid) 177 { 178 /* Buffer for UUID string (plus NUL terminator) */ 179 char uuid_string[UUID_STRING_LENGTH + 1U]; 180 int err; 181 182 assert(dtb != NULL); 183 assert(prop != NULL); 184 assert(uuid != NULL); 185 assert(node >= 0); 186 187 if (length < UUID_BYTES_LENGTH) { 188 return -EINVAL; 189 } 190 191 err = fdtw_read_string(dtb, node, prop, uuid_string, 192 UUID_STRING_LENGTH + 1U); 193 if (err != 0) { 194 return err; 195 } 196 197 if (read_uuid(uuid, uuid_string) != 0) { 198 return -FDT_ERR_BADVALUE; 199 } 200 201 return 0; 202 } 203 204 /* 205 * Write cells in place to a given property of the given node. At most 2 cells 206 * of the property are written. Returns 0 on success, and -1 upon error. 207 */ 208 int fdtw_write_inplace_cells(void *dtb, int node, const char *prop, 209 unsigned int cells, void *value) 210 { 211 int err, len; 212 213 assert(dtb != NULL); 214 assert(prop != NULL); 215 assert(value != NULL); 216 assert(node >= 0); 217 218 /* We expect either 1 or 2 cell property */ 219 assert(cells <= 2U); 220 221 if (cells == 2U) 222 *(fdt64_t *)value = cpu_to_fdt64(*(uint64_t *)value); 223 else 224 *(fdt32_t *)value = cpu_to_fdt32(*(uint32_t *)value); 225 226 len = (int)cells * 4; 227 228 /* Set property value in place */ 229 err = fdt_setprop_inplace(dtb, node, prop, value, len); 230 if (err != 0) { 231 WARN("Modify property %s failed with error %d\n", prop, err); 232 return -1; 233 } 234 235 return 0; 236 } 237 238 /* 239 * Write bytes in place to a given property of the given node. 240 * Any number of bytes of the property can be written. 241 * Returns 0 on success, and < 0 on error. 242 */ 243 int fdtw_write_inplace_bytes(void *dtb, int node, const char *prop, 244 unsigned int length, const void *data) 245 { 246 const void *ptr; 247 int namelen, value_len, err; 248 249 assert(dtb != NULL); 250 assert(prop != NULL); 251 assert(data != NULL); 252 assert(node >= 0); 253 254 namelen = (int)strlen(prop); 255 256 /* Access property and obtain its length in bytes */ 257 ptr = fdt_getprop_namelen(dtb, node, prop, namelen, &value_len); 258 if (ptr == NULL) { 259 WARN("Couldn't find property %s in dtb\n", prop); 260 return -1; 261 } 262 263 /* Verify that property length is not less than number of bytes */ 264 if ((unsigned int)value_len < length) { 265 WARN("Property length mismatch\n"); 266 return -1; 267 } 268 269 /* Set property value in place */ 270 err = fdt_setprop_inplace_namelen_partial(dtb, node, prop, 271 namelen, 0, 272 data, (int)length); 273 if (err != 0) { 274 WARN("Set property %s failed with error %d\n", prop, err); 275 } 276 277 return err; 278 } 279 280 static uint64_t fdt_read_prop_cells(const fdt32_t *prop, int nr_cells) 281 { 282 uint64_t reg = fdt32_to_cpu(prop[0]); 283 284 if (nr_cells > 1) { 285 reg = (reg << 32) | fdt32_to_cpu(prop[1]); 286 } 287 288 return reg; 289 } 290 291 int fdt_get_reg_props_by_index(const void *dtb, int node, int index, 292 uintptr_t *base, size_t *size) 293 { 294 const fdt32_t *prop; 295 int parent, len; 296 int ac, sc; 297 int cell; 298 299 parent = fdt_parent_offset(dtb, node); 300 if (parent < 0) { 301 return -FDT_ERR_BADOFFSET; 302 } 303 304 ac = fdt_address_cells(dtb, parent); 305 sc = fdt_size_cells(dtb, parent); 306 307 cell = index * (ac + sc); 308 309 prop = fdt_getprop(dtb, node, "reg", &len); 310 if (prop == NULL) { 311 WARN("Couldn't find \"reg\" property in dtb\n"); 312 return -FDT_ERR_NOTFOUND; 313 } 314 315 if (((cell + ac + sc) * (int)sizeof(uint32_t)) > len) { 316 return -FDT_ERR_BADVALUE; 317 } 318 319 if (base != NULL) { 320 *base = (uintptr_t)fdt_read_prop_cells(&prop[cell], ac); 321 } 322 323 if (size != NULL) { 324 *size = (size_t)fdt_read_prop_cells(&prop[cell + ac], sc); 325 } 326 327 return 0; 328 } 329 330 /******************************************************************************* 331 * This function fills reg node info (base & size) with an index found by 332 * checking the reg-names node. 333 * Returns 0 on success and a negative FDT error code on failure. 334 ******************************************************************************/ 335 int fdt_get_reg_props_by_name(const void *dtb, int node, const char *name, 336 uintptr_t *base, size_t *size) 337 { 338 int index; 339 340 index = fdt_stringlist_search(dtb, node, "reg-names", name); 341 if (index < 0) { 342 return index; 343 } 344 345 return fdt_get_reg_props_by_index(dtb, node, index, base, size); 346 } 347 348 /******************************************************************************* 349 * This function gets the stdout path node. 350 * It reads the value indicated inside the device tree. 351 * Returns node offset on success and a negative FDT error code on failure. 352 ******************************************************************************/ 353 int fdt_get_stdout_node_offset(const void *dtb) 354 { 355 int node; 356 const char *prop, *path; 357 int len; 358 359 /* The /secure-chosen node takes precedence over the standard one. */ 360 node = fdt_path_offset(dtb, "/secure-chosen"); 361 if (node < 0) { 362 node = fdt_path_offset(dtb, "/chosen"); 363 if (node < 0) { 364 return -FDT_ERR_NOTFOUND; 365 } 366 } 367 368 prop = fdt_getprop(dtb, node, "stdout-path", NULL); 369 if (prop == NULL) { 370 return -FDT_ERR_NOTFOUND; 371 } 372 373 /* Determine the actual path length, as a colon terminates the path. */ 374 path = strchr(prop, ':'); 375 if (path == NULL) { 376 len = strlen(prop); 377 } else { 378 len = path - prop; 379 } 380 381 /* Aliases cannot start with a '/', so it must be the actual path. */ 382 if (prop[0] == '/') { 383 return fdt_path_offset_namelen(dtb, prop, len); 384 } 385 386 /* Lookup the alias, as this contains the actual path. */ 387 path = fdt_get_alias_namelen(dtb, prop, len); 388 if (path == NULL) { 389 return -FDT_ERR_NOTFOUND; 390 } 391 392 return fdt_path_offset(dtb, path); 393 } 394 395 396 /******************************************************************************* 397 * Only devices which are direct children of root node use CPU address domain. 398 * All other devices use addresses that are local to the device node and cannot 399 * directly used by CPU. Device tree provides an address translation mechanism 400 * through "ranges" property which provides mappings from local address space to 401 * parent address space. Since a device could be a child of a child node to the 402 * root node, there can be more than one level of address translation needed to 403 * map the device local address space to CPU address space. 404 * fdtw_translate_address() API performs address translation of a local address 405 * to a global address with help of various helper functions. 406 ******************************************************************************/ 407 408 static bool fdtw_xlat_hit(const fdt32_t *value, int child_addr_size, 409 int parent_addr_size, int range_size, uint64_t base_address, 410 uint64_t *translated_addr) 411 { 412 uint64_t local_address, parent_address, addr_range; 413 414 local_address = fdt_read_prop_cells(value, child_addr_size); 415 parent_address = fdt_read_prop_cells(value + child_addr_size, 416 parent_addr_size); 417 addr_range = fdt_read_prop_cells(value + child_addr_size + 418 parent_addr_size, 419 range_size); 420 VERBOSE("DT: Address %" PRIx64 " mapped to %" PRIx64 " with range %" PRIx64 "\n", 421 local_address, parent_address, addr_range); 422 423 /* Perform range check */ 424 if ((base_address < local_address) || 425 (base_address >= local_address + addr_range)) { 426 return false; 427 } 428 429 /* Found hit for the addr range that needs to be translated */ 430 *translated_addr = parent_address + (base_address - local_address); 431 VERBOSE("DT: child address %" PRIx64 "mapped to %" PRIx64 " in parent bus\n", 432 local_address, parent_address); 433 return true; 434 } 435 436 #define ILLEGAL_ADDR ULL(~0) 437 438 static uint64_t fdtw_search_all_xlat_entries(const void *dtb, 439 const struct fdt_property *ranges_prop, 440 int local_bus, uint64_t base_address) 441 { 442 uint64_t translated_addr; 443 const fdt32_t *next_entry; 444 int parent_bus_node, nxlat_entries, length; 445 int self_addr_cells, parent_addr_cells, self_size_cells, ncells_xlat; 446 447 /* 448 * The number of cells in one translation entry in ranges is the sum of 449 * the following values: 450 * self#address-cells + parent#address-cells + self#size-cells 451 * Ex: the iofpga ranges property has one translation entry with 4 cells 452 * They represent iofpga#addr-cells + motherboard#addr-cells + iofpga#size-cells 453 * = 1 + 2 + 1 454 */ 455 456 parent_bus_node = fdt_parent_offset(dtb, local_bus); 457 self_addr_cells = fdt_address_cells(dtb, local_bus); 458 self_size_cells = fdt_size_cells(dtb, local_bus); 459 parent_addr_cells = fdt_address_cells(dtb, parent_bus_node); 460 461 /* Number of cells per translation entry i.e., mapping */ 462 ncells_xlat = self_addr_cells + parent_addr_cells + self_size_cells; 463 464 assert(ncells_xlat > 0); 465 466 /* 467 * Find the number of translations(mappings) specified in the current 468 * `ranges` property. Note that length represents number of bytes and 469 * is stored in big endian mode. 470 */ 471 length = fdt32_to_cpu(ranges_prop->len); 472 nxlat_entries = (length/sizeof(uint32_t))/ncells_xlat; 473 474 assert(nxlat_entries > 0); 475 476 next_entry = (const fdt32_t *)ranges_prop->data; 477 478 /* Iterate over the entries in the "ranges" */ 479 for (int i = 0; i < nxlat_entries; i++) { 480 if (fdtw_xlat_hit(next_entry, self_addr_cells, 481 parent_addr_cells, self_size_cells, base_address, 482 &translated_addr)){ 483 return translated_addr; 484 } 485 next_entry = next_entry + ncells_xlat; 486 } 487 488 INFO("DT: No translation found for address %" PRIx64 " in node %s\n", 489 base_address, fdt_get_name(dtb, local_bus, NULL)); 490 return ILLEGAL_ADDR; 491 } 492 493 494 /******************************************************************************* 495 * address mapping needs to be done recursively starting from current node to 496 * root node through all intermediate parent nodes. 497 * Sample device tree is shown here: 498 499 smb@0,0 { 500 compatible = "simple-bus"; 501 502 #address-cells = <2>; 503 #size-cells = <1>; 504 ranges = <0 0 0 0x08000000 0x04000000>, 505 <1 0 0 0x14000000 0x04000000>, 506 <2 0 0 0x18000000 0x04000000>, 507 <3 0 0 0x1c000000 0x04000000>, 508 <4 0 0 0x0c000000 0x04000000>, 509 <5 0 0 0x10000000 0x04000000>; 510 511 motherboard { 512 arm,v2m-memory-map = "rs1"; 513 compatible = "arm,vexpress,v2m-p1", "simple-bus"; 514 #address-cells = <2>; 515 #size-cells = <1>; 516 ranges; 517 518 iofpga@3,00000000 { 519 compatible = "arm,amba-bus", "simple-bus"; 520 #address-cells = <1>; 521 #size-cells = <1>; 522 ranges = <0 3 0 0x200000>; 523 v2m_serial1: uart@a0000 { 524 compatible = "arm,pl011", "arm,primecell"; 525 reg = <0x0a0000 0x1000>; 526 interrupts = <0 6 4>; 527 clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>; 528 clock-names = "uartclk", "apb_pclk"; 529 }; 530 }; 531 }; 532 533 * As seen above, there are 3 levels of address translations needed. An empty 534 * `ranges` property denotes identity mapping (as seen in `motherboard` node). 535 * Each ranges property can map a set of child addresses to parent bus. Hence 536 * there can be more than 1 (translation) entry in the ranges property as seen 537 * in the `smb` node which has 6 translation entries. 538 ******************************************************************************/ 539 540 /* Recursive implementation */ 541 uint64_t fdtw_translate_address(const void *dtb, int node, 542 uint64_t base_address) 543 { 544 int length, local_bus_node; 545 const char *node_name; 546 uint64_t global_address; 547 548 local_bus_node = fdt_parent_offset(dtb, node); 549 node_name = fdt_get_name(dtb, local_bus_node, NULL); 550 551 /* 552 * In the example given above, starting from the leaf node: 553 * uart@a000 represents the current node 554 * iofpga@3,00000000 represents the local bus 555 * motherboard represents the parent bus 556 */ 557 558 /* Read the ranges property */ 559 const struct fdt_property *property = fdt_get_property(dtb, 560 local_bus_node, "ranges", &length); 561 562 if (property == NULL) { 563 if (local_bus_node == 0) { 564 /* 565 * root node doesn't have range property as addresses 566 * are in CPU address space. 567 */ 568 return base_address; 569 } 570 INFO("DT: Couldn't find ranges property in node %s\n", 571 node_name); 572 return ILLEGAL_ADDR; 573 } else if (length == 0) { 574 /* empty ranges indicates identity map to parent bus */ 575 return fdtw_translate_address(dtb, local_bus_node, base_address); 576 } 577 578 VERBOSE("DT: Translation lookup in node %s at offset %d\n", node_name, 579 local_bus_node); 580 global_address = fdtw_search_all_xlat_entries(dtb, property, 581 local_bus_node, base_address); 582 583 if (global_address == ILLEGAL_ADDR) { 584 return ILLEGAL_ADDR; 585 } 586 587 /* Translate the local device address recursively */ 588 return fdtw_translate_address(dtb, local_bus_node, global_address); 589 } 590 591 /* 592 * For every CPU node (`/cpus/cpu@n`) in an FDT, execute a callback passing a 593 * pointer to the FDT and the offset of the CPU node. If the return value of the 594 * callback is negative, it is treated as an error and the loop is aborted. In 595 * this situation, the value of the callback is returned from the function. 596 * 597 * Returns `0` on success, or a negative integer representing an error code. 598 */ 599 int fdtw_for_each_cpu(const void *dtb, 600 int (*callback)(const void *dtb, int node, uintptr_t mpidr)) 601 { 602 int ret = 0; 603 int parent, node = 0; 604 605 parent = fdt_path_offset(dtb, "/cpus"); 606 if (parent < 0) { 607 return parent; 608 } 609 610 fdt_for_each_subnode(node, dtb, parent) { 611 const char *name; 612 int len; 613 614 uintptr_t mpidr = 0U; 615 616 name = fdt_get_name(dtb, node, &len); 617 if (strncmp(name, "cpu@", 4) != 0) { 618 continue; 619 } 620 621 ret = fdt_get_reg_props_by_index(dtb, node, 0, &mpidr, NULL); 622 if (ret < 0) { 623 break; 624 } 625 626 ret = callback(dtb, node, mpidr); 627 if (ret < 0) { 628 break; 629 } 630 } 631 632 return ret; 633 } 634 635 /* 636 * Find a given node in device tree. If not present, add it. 637 * Returns offset of node found/added on success, and < 0 on error. 638 */ 639 int fdtw_find_or_add_subnode(void *fdt, int parentoffset, const char *name) 640 { 641 int offset; 642 643 offset = fdt_subnode_offset(fdt, parentoffset, name); 644 645 if (offset == -FDT_ERR_NOTFOUND) { 646 offset = fdt_add_subnode(fdt, parentoffset, name); 647 } 648 649 if (offset < 0) { 650 ERROR("%s: %s: %s\n", __func__, name, fdt_strerror(offset)); 651 } 652 653 return offset; 654 } 655