1// See LICENSE for license details. 2 3#include <stdbool.h> 4#include <stdint.h> 5#include <string.h> 6#include "config.h" 7#include "fdt.h" 8#include "mtrap.h" 9 10static inline uint32_t bswap(uint32_t x) 11{ 12 uint32_t y = (x & 0x00FF00FF) << 8 | (x & 0xFF00FF00) >> 8; 13 uint32_t z = (y & 0x0000FFFF) << 16 | (y & 0xFFFF0000) >> 16; 14 return z; 15} 16 17static inline int isstring(char c) 18{ 19 if (c >= 'A' && c <= 'Z') 20 return 1; 21 if (c >= 'a' && c <= 'z') 22 return 1; 23 if (c >= '0' && c <= '9') 24 return 1; 25 if (c == '\0' || c == ' ' || c == ',' || c == '-') 26 return 1; 27 return 0; 28} 29 30static uint32_t *fdt_scan_helper( 31 uint32_t *lex, 32 const char *strings, 33 struct fdt_scan_node *node, 34 const struct fdt_cb *cb) 35{ 36 struct fdt_scan_node child; 37 struct fdt_scan_prop prop; 38 int last = 0; 39 40 child.parent = node; 41 // these are the default cell counts, as per the FDT spec 42 child.address_cells = 2; 43 child.size_cells = 1; 44 prop.node = node; 45 46 while (1) { 47 switch (bswap(lex[0])) { 48 case FDT_NOP: { 49 lex += 1; 50 break; 51 } 52 case FDT_PROP: { 53 assert (!last); 54 prop.name = strings + bswap(lex[2]); 55 prop.len = bswap(lex[1]); 56 prop.value = lex + 3; 57 if (node && !strcmp(prop.name, "#address-cells")) { node->address_cells = bswap(lex[3]); } 58 if (node && !strcmp(prop.name, "#size-cells")) { node->size_cells = bswap(lex[3]); } 59 lex += 3 + (prop.len+3)/4; 60 cb->prop(&prop, cb->extra); 61 break; 62 } 63 case FDT_BEGIN_NODE: { 64 uint32_t *lex_next; 65 if (!last && node && cb->done) cb->done(node, cb->extra); 66 last = 1; 67 child.name = (const char *)(lex+1); 68 if (cb->open) cb->open(&child, cb->extra); 69 lex_next = fdt_scan_helper( 70 lex + 2 + strlen(child.name)/4, 71 strings, &child, cb); 72 if (cb->close && cb->close(&child, cb->extra) == -1) 73 while (lex != lex_next) *lex++ = bswap(FDT_NOP); 74 lex = lex_next; 75 break; 76 } 77 case FDT_END_NODE: { 78 if (!last && node && cb->done) cb->done(node, cb->extra); 79 return lex + 1; 80 } 81 default: { // FDT_END 82 if (!last && node && cb->done) cb->done(node, cb->extra); 83 return lex; 84 } 85 } 86 } 87} 88 89void fdt_scan(uintptr_t fdt, const struct fdt_cb *cb) 90{ 91 struct fdt_header *header = (struct fdt_header *)fdt; 92 93 // Only process FDT that we understand 94 if (bswap(header->magic) != FDT_MAGIC || 95 bswap(header->last_comp_version) > FDT_VERSION) return; 96 97 const char *strings = (const char *)(fdt + bswap(header->off_dt_strings)); 98 uint32_t *lex = (uint32_t *)(fdt + bswap(header->off_dt_struct)); 99 100 fdt_scan_helper(lex, strings, 0, cb); 101} 102 103uint32_t fdt_size(uintptr_t fdt) 104{ 105 struct fdt_header *header = (struct fdt_header *)fdt; 106 107 // Only process FDT that we understand 108 if (bswap(header->magic) != FDT_MAGIC || 109 bswap(header->last_comp_version) > FDT_VERSION) return 0; 110 return bswap(header->totalsize); 111} 112 113const uint32_t *fdt_get_address(const struct fdt_scan_node *node, const uint32_t *value, uint64_t *result) 114{ 115 *result = 0; 116 for (int cells = node->address_cells; cells > 0; --cells) 117 *result = (*result << 32) + bswap(*value++); 118 return value; 119} 120 121const uint32_t *fdt_get_size(const struct fdt_scan_node *node, const uint32_t *value, uint64_t *result) 122{ 123 *result = 0; 124 for (int cells = node->size_cells; cells > 0; --cells) 125 *result = (*result << 32) + bswap(*value++); 126 return value; 127} 128 129int fdt_string_list_index(const struct fdt_scan_prop *prop, const char *str) 130{ 131 const char *list = (const char *)prop->value; 132 const char *end = list + prop->len; 133 int index = 0; 134 while (end - list > 0) { 135 if (!strcmp(list, str)) return index; 136 ++index; 137 list += strlen(list) + 1; 138 } 139 return -1; 140} 141 142const uint32_t *fdt_get_value(const uint32_t *value, uint32_t *result) 143{ 144 *result = bswap(*value++); 145 return value; 146} 147//////////////////////////////////////////// MEMORY SCAN ///////////////////////////////////////// 148 149struct mem_scan { 150 int memory; 151 const uint32_t *reg_value; 152 int reg_len; 153}; 154 155static void mem_open(const struct fdt_scan_node *node, void *extra) 156{ 157 struct mem_scan *scan = (struct mem_scan *)extra; 158 memset(scan, 0, sizeof(*scan)); 159} 160 161static void mem_prop(const struct fdt_scan_prop *prop, void *extra) 162{ 163 struct mem_scan *scan = (struct mem_scan *)extra; 164 if (!strcmp(prop->name, "device_type") && !strcmp((const char*)prop->value, "memory")) { 165 scan->memory = 1; 166 } else if (!strcmp(prop->name, "reg")) { 167 scan->reg_value = prop->value; 168 scan->reg_len = prop->len; 169 } 170} 171 172static void mem_done(const struct fdt_scan_node *node, void *extra) 173{ 174 struct mem_scan *scan = (struct mem_scan *)extra; 175 const uint32_t *value = scan->reg_value; 176 const uint32_t *end = value + scan->reg_len/4; 177 uintptr_t self = (uintptr_t)mem_done; 178 179 if (!scan->memory) return; 180 assert (scan->reg_value && scan->reg_len % 4 == 0); 181 182 while (end - value > 0) { 183 uint64_t base, size; 184 value = fdt_get_address(node->parent, value, &base); 185 value = fdt_get_size (node->parent, value, &size); 186 if (base <= self && self <= base + size) { mem_size = size; } 187 } 188 assert (end == value); 189} 190 191void query_mem(uintptr_t fdt) 192{ 193 struct fdt_cb cb; 194 struct mem_scan scan; 195 196 memset(&cb, 0, sizeof(cb)); 197 cb.open = mem_open; 198 cb.prop = mem_prop; 199 cb.done = mem_done; 200 cb.extra = &scan; 201 202 mem_size = 0; 203 fdt_scan(fdt, &cb); 204 assert (mem_size > 0); 205} 206 207///////////////////////////////////////////// HART SCAN ////////////////////////////////////////// 208 209static uint32_t hart_phandles[MAX_HARTS]; 210uint64_t hart_mask; 211 212struct hart_scan { 213 const struct fdt_scan_node *cpu; 214 int hart; 215 const struct fdt_scan_node *controller; 216 int cells; 217 uint32_t phandle; 218}; 219 220static void hart_open(const struct fdt_scan_node *node, void *extra) 221{ 222 struct hart_scan *scan = (struct hart_scan *)extra; 223 if (!scan->cpu) { 224 scan->hart = -1; 225 } 226 if (!scan->controller) { 227 scan->cells = 0; 228 scan->phandle = 0; 229 } 230} 231 232static void hart_prop(const struct fdt_scan_prop *prop, void *extra) 233{ 234 struct hart_scan *scan = (struct hart_scan *)extra; 235 if (!strcmp(prop->name, "device_type") && !strcmp((const char*)prop->value, "cpu")) { 236 assert (!scan->cpu); 237 scan->cpu = prop->node; 238 } else if (!strcmp(prop->name, "interrupt-controller")) { 239 assert (!scan->controller); 240 scan->controller = prop->node; 241 } else if (!strcmp(prop->name, "#interrupt-cells")) { 242 scan->cells = bswap(prop->value[0]); 243 } else if (!strcmp(prop->name, "phandle")) { 244 scan->phandle = bswap(prop->value[0]); 245 } else if (!strcmp(prop->name, "reg")) { 246 uint64_t reg; 247 fdt_get_address(prop->node->parent, prop->value, ®); 248 scan->hart = reg; 249 } 250} 251 252static void hart_done(const struct fdt_scan_node *node, void *extra) 253{ 254 struct hart_scan *scan = (struct hart_scan *)extra; 255 256 if (scan->cpu == node) { 257 assert (scan->hart >= 0); 258 } 259 260 if (scan->controller == node && scan->cpu) { 261 assert (scan->phandle > 0); 262 assert (scan->cells == 1); 263 264 if (scan->hart < MAX_HARTS) { 265 hart_phandles[scan->hart] = scan->phandle; 266 hart_mask |= 1 << scan->hart; 267 hls_init(scan->hart); 268 } 269 } 270} 271 272static int hart_close(const struct fdt_scan_node *node, void *extra) 273{ 274 struct hart_scan *scan = (struct hart_scan *)extra; 275 if (scan->cpu == node) scan->cpu = 0; 276 if (scan->controller == node) scan->controller = 0; 277 return 0; 278} 279 280void query_harts(uintptr_t fdt) 281{ 282 struct fdt_cb cb; 283 struct hart_scan scan; 284 285 memset(&cb, 0, sizeof(cb)); 286 memset(&scan, 0, sizeof(scan)); 287 cb.open = hart_open; 288 cb.prop = hart_prop; 289 cb.done = hart_done; 290 cb.close= hart_close; 291 cb.extra = &scan; 292 293 fdt_scan(fdt, &cb); 294 295 // The current hart should have been detected 296 assert ((hart_mask >> read_csr(mhartid)) != 0); 297} 298 299///////////////////////////////////////////// CLINT SCAN ///////////////////////////////////////// 300 301struct clint_scan 302{ 303 int compat; 304 uint64_t reg; 305 const uint32_t *int_value; 306 int int_len; 307 int done; 308}; 309 310static void clint_open(const struct fdt_scan_node *node, void *extra) 311{ 312 struct clint_scan *scan = (struct clint_scan *)extra; 313 scan->compat = 0; 314 scan->reg = 0; 315 scan->int_value = 0; 316} 317 318static void clint_prop(const struct fdt_scan_prop *prop, void *extra) 319{ 320 struct clint_scan *scan = (struct clint_scan *)extra; 321 if (!strcmp(prop->name, "compatible") && fdt_string_list_index(prop, "riscv,clint0") >= 0) { 322 scan->compat = 1; 323 } else if (!strcmp(prop->name, "reg")) { 324 fdt_get_address(prop->node->parent, prop->value, &scan->reg); 325 } else if (!strcmp(prop->name, "interrupts-extended")) { 326 scan->int_value = prop->value; 327 scan->int_len = prop->len; 328 } 329} 330 331static void clint_done(const struct fdt_scan_node *node, void *extra) 332{ 333 struct clint_scan *scan = (struct clint_scan *)extra; 334 const uint32_t *value = scan->int_value; 335 const uint32_t *end = value + scan->int_len/4; 336 337 if (!scan->compat) return; 338 assert (scan->reg != 0); 339 assert (scan->int_value && scan->int_len % 16 == 0); 340 assert (!scan->done); // only one clint 341 342 scan->done = 1; 343 mtime = (void*)((uintptr_t)scan->reg + 0xbff8); 344 345 for (int index = 0; end - value > 0; ++index) { 346 uint32_t phandle = bswap(value[0]); 347 int hart; 348 for (hart = 0; hart < MAX_HARTS; ++hart) 349 if (hart_phandles[hart] == phandle) 350 break; 351 if (hart < MAX_HARTS) { 352 hls_t *hls = OTHER_HLS(hart); 353 hls->ipi = (void*)((uintptr_t)scan->reg + index * 4); 354 hls->timecmp = (void*)((uintptr_t)scan->reg + 0x4000 + (index * 8)); 355 } 356 value += 4; 357 } 358} 359 360void query_clint(uintptr_t fdt) 361{ 362 struct fdt_cb cb; 363 struct clint_scan scan; 364 365 memset(&cb, 0, sizeof(cb)); 366 cb.open = clint_open; 367 cb.prop = clint_prop; 368 cb.done = clint_done; 369 cb.extra = &scan; 370 371 scan.done = 0; 372 fdt_scan(fdt, &cb); 373 assert (scan.done); 374} 375 376///////////////////////////////////////////// PLIC SCAN ///////////////////////////////////////// 377 378struct plic_scan 379{ 380 int compat; 381 uint64_t reg; 382 uint32_t *int_value; 383 int int_len; 384 int done; 385 int ndev; 386}; 387 388static void plic_open(const struct fdt_scan_node *node, void *extra) 389{ 390 struct plic_scan *scan = (struct plic_scan *)extra; 391 scan->compat = 0; 392 scan->reg = 0; 393 scan->int_value = 0; 394} 395 396static void plic_prop(const struct fdt_scan_prop *prop, void *extra) 397{ 398 struct plic_scan *scan = (struct plic_scan *)extra; 399 if (!strcmp(prop->name, "compatible") && fdt_string_list_index(prop, "riscv,plic0") >= 0) { 400 scan->compat = 1; 401 } else if (!strcmp(prop->name, "reg")) { 402 fdt_get_address(prop->node->parent, prop->value, &scan->reg); 403 } else if (!strcmp(prop->name, "interrupts-extended")) { 404 scan->int_value = prop->value; 405 scan->int_len = prop->len; 406 } else if (!strcmp(prop->name, "riscv,ndev")) { 407 scan->ndev = bswap(prop->value[0]); 408 } 409} 410 411#define HART_BASE 0x200000 412#define HART_SIZE 0x1000 413#define ENABLE_BASE 0x2000 414#define ENABLE_SIZE 0x80 415 416static void plic_done(const struct fdt_scan_node *node, void *extra) 417{ 418 struct plic_scan *scan = (struct plic_scan *)extra; 419 const uint32_t *value = scan->int_value; 420 const uint32_t *end = value + scan->int_len/4; 421 422 if (!scan->compat) return; 423 assert (scan->reg != 0); 424 assert (scan->int_value && scan->int_len % 8 == 0); 425 assert (scan->ndev >= 0 && scan->ndev < 1024); 426 assert (!scan->done); // only one plic 427 428 scan->done = 1; 429 plic_priorities = (uint32_t*)(uintptr_t)scan->reg; 430 plic_ndevs = scan->ndev; 431 432 for (int index = 0; end - value > 0; ++index) { 433 uint32_t phandle = bswap(value[0]); 434 uint32_t cpu_int = bswap(value[1]); 435 int hart; 436 for (hart = 0; hart < MAX_HARTS; ++hart) 437 if (hart_phandles[hart] == phandle) 438 break; 439 if (hart < MAX_HARTS) { 440 hls_t *hls = OTHER_HLS(hart); 441 if (cpu_int == IRQ_M_EXT) { 442 hls->plic_m_ie = (uintptr_t*)((uintptr_t)scan->reg + ENABLE_BASE + ENABLE_SIZE * index); 443 hls->plic_m_thresh = (uint32_t*) ((uintptr_t)scan->reg + HART_BASE + HART_SIZE * index); 444 } else if (cpu_int == IRQ_S_EXT) { 445 hls->plic_s_ie = (uintptr_t*)((uintptr_t)scan->reg + ENABLE_BASE + ENABLE_SIZE * index); 446 hls->plic_s_thresh = (uint32_t*) ((uintptr_t)scan->reg + HART_BASE + HART_SIZE * index); 447 } else { 448 printm("PLIC wired hart %d to wrong interrupt %d", hart, cpu_int); 449 } 450 } 451 value += 2; 452 } 453#if 0 454 printm("PLIC: prio %x devs %d\r\n", (uint32_t)(uintptr_t)plic_priorities, plic_ndevs); 455 for (int i = 0; i < MAX_HARTS; ++i) { 456 hls_t *hls = OTHER_HLS(i); 457 printm("CPU %d: %x %x %x %x\r\n", i, (uint32_t)(uintptr_t)hls->plic_m_ie, (uint32_t)(uintptr_t)hls->plic_m_thresh, (uint32_t)(uintptr_t)hls->plic_s_ie, (uint32_t)(uintptr_t)hls->plic_s_thresh); 458 } 459#endif 460} 461 462void query_plic(uintptr_t fdt) 463{ 464 struct fdt_cb cb; 465 struct plic_scan scan; 466 467 memset(&cb, 0, sizeof(cb)); 468 cb.open = plic_open; 469 cb.prop = plic_prop; 470 cb.done = plic_done; 471 cb.extra = &scan; 472 473 scan.done = 0; 474 fdt_scan(fdt, &cb); 475} 476 477static void plic_redact(const struct fdt_scan_node *node, void *extra) 478{ 479 struct plic_scan *scan = (struct plic_scan *)extra; 480 uint32_t *value = scan->int_value; 481 uint32_t *end = value + scan->int_len/4; 482 483 if (!scan->compat) return; 484 scan->done = 1; 485 486 while (end - value > 0) { 487 if (bswap(value[1]) == IRQ_M_EXT) value[1] = bswap(-1); 488 value += 2; 489 } 490} 491 492void filter_plic(uintptr_t fdt) 493{ 494 struct fdt_cb cb; 495 struct plic_scan scan; 496 497 memset(&cb, 0, sizeof(cb)); 498 cb.open = plic_open; 499 cb.prop = plic_prop; 500 cb.done = plic_redact; 501 cb.extra = &scan; 502 503 scan.done = 0; 504 fdt_scan(fdt, &cb); 505} 506 507//////////////////////////////////////////// COMPAT SCAN //////////////////////////////////////// 508 509struct compat_scan 510{ 511 const char *compat; 512 int depth; 513 int kill; 514}; 515 516static void compat_open(const struct fdt_scan_node *node, void *extra) 517{ 518 struct compat_scan *scan = (struct compat_scan *)extra; 519 ++scan->depth; 520} 521 522static void compat_prop(const struct fdt_scan_prop *prop, void *extra) 523{ 524 struct compat_scan *scan = (struct compat_scan *)extra; 525 if (!strcmp(prop->name, "compatible") && fdt_string_list_index(prop, scan->compat) >= 0) 526 if (scan->depth < scan->kill) 527 scan->kill = scan->depth; 528} 529 530static int compat_close(const struct fdt_scan_node *node, void *extra) 531{ 532 struct compat_scan *scan = (struct compat_scan *)extra; 533 if (scan->kill == scan->depth--) { 534 scan->kill = 999; 535 return -1; 536 } else { 537 return 0; 538 } 539} 540 541void filter_compat(uintptr_t fdt, const char *compat) 542{ 543 struct fdt_cb cb; 544 struct compat_scan scan; 545 546 memset(&cb, 0, sizeof(cb)); 547 cb.open = compat_open; 548 cb.prop = compat_prop; 549 cb.close = compat_close; 550 cb.extra = &scan; 551 552 scan.compat = compat; 553 scan.depth = 0; 554 scan.kill = 999; 555 fdt_scan(fdt, &cb); 556} 557 558//////////////////////////////////////////// CHOSEN SCAN //////////////////////////////////////// 559 560struct chosen_scan { 561 const struct fdt_scan_node *chosen; 562 void* kernel_start; 563 void* kernel_end; 564}; 565 566static void chosen_open(const struct fdt_scan_node *node, void *extra) 567{ 568 struct chosen_scan *scan = (struct chosen_scan *)extra; 569 if (!strcmp(node->name, "chosen")) { 570 scan->chosen = node; 571 } 572} 573 574static int chosen_close(const struct fdt_scan_node *node, void *extra) 575{ 576 struct chosen_scan *scan = (struct chosen_scan *)extra; 577 if (scan->chosen && scan->chosen == node) { 578 scan->chosen = NULL; 579 } 580 return 0; 581} 582 583static void chosen_prop(const struct fdt_scan_prop *prop, void *extra) 584{ 585 struct chosen_scan *scan = (struct chosen_scan *)extra; 586 uint64_t val; 587 if (!scan->chosen) return; 588 if (!strcmp(prop->name, "riscv,kernel-start")) { 589 fdt_get_address(prop->node->parent, prop->value, &val); 590 scan->kernel_start = (void*)(uintptr_t)val; 591 } else if (!strcmp(prop->name, "riscv,kernel-end")) { 592 fdt_get_address(prop->node->parent, prop->value, &val); 593 scan->kernel_end = (void*)(uintptr_t)val; 594 } 595} 596 597void query_chosen(uintptr_t fdt) 598{ 599 struct fdt_cb cb; 600 struct chosen_scan chosen; 601 602 memset(&cb, 0, sizeof(cb)); 603 cb.open = chosen_open; 604 cb.close = chosen_close; 605 cb.prop = chosen_prop; 606 607 memset(&chosen, 0, sizeof(chosen)); 608 cb.extra = &chosen; 609 610 fdt_scan(fdt, &cb); 611 kernel_start = chosen.kernel_start; 612 kernel_end = chosen.kernel_end; 613} 614 615//////////////////////////////////////////// HART FILTER //////////////////////////////////////// 616 617struct hart_filter { 618 int compat; 619 int hart; 620 char *status; 621 char *mmu_type; 622 long *disabled_hart_mask; 623}; 624 625static void hart_filter_open(const struct fdt_scan_node *node, void *extra) 626{ 627 struct hart_filter *filter = (struct hart_filter *)extra; 628 filter->status = NULL; 629 filter->mmu_type = NULL; 630 filter->compat = 0; 631 filter->hart = -1; 632} 633 634static void hart_filter_prop(const struct fdt_scan_prop *prop, void *extra) 635{ 636 struct hart_filter *filter = (struct hart_filter *)extra; 637 if (!strcmp(prop->name, "device_type") && !strcmp((const char*)prop->value, "cpu")) { 638 filter->compat = 1; 639 } else if (!strcmp(prop->name, "reg")) { 640 uint64_t reg; 641 fdt_get_address(prop->node->parent, prop->value, ®); 642 filter->hart = reg; 643 } else if (!strcmp(prop->name, "status")) { 644 filter->status = (char*)prop->value; 645 } else if (!strcmp(prop->name, "mmu-type")) { 646 filter->mmu_type = (char*)prop->value; 647 } 648} 649 650static bool hart_filter_mask(const struct hart_filter *filter) 651{ 652 if (filter->mmu_type == NULL) return true; 653 if (strcmp(filter->status, "okay")) return true; 654 if (!strcmp(filter->mmu_type, "riscv,sv32")) return false; 655 if (!strcmp(filter->mmu_type, "riscv,sv39")) return false; 656 if (!strcmp(filter->mmu_type, "riscv,sv48")) return false; 657 printm("hart_filter_mask saw unknown hart type: status=\"%s\", mmu_type=\"%s\"\n", 658 filter->status, filter->mmu_type); 659 return true; 660} 661 662static void hart_filter_done(const struct fdt_scan_node *node, void *extra) 663{ 664 struct hart_filter *filter = (struct hart_filter *)extra; 665 666 if (!filter->compat) return; 667 assert (filter->status); 668 assert (filter->hart >= 0); 669 670 if (hart_filter_mask(filter)) { 671 strcpy(filter->status, "masked"); 672 uint32_t *len = (uint32_t*)filter->status; 673 len[-2] = bswap(strlen("masked")+1); 674 *filter->disabled_hart_mask |= (1 << filter->hart); 675 } 676} 677 678void filter_harts(uintptr_t fdt, long *disabled_hart_mask) 679{ 680 struct fdt_cb cb; 681 struct hart_filter filter; 682 683 memset(&cb, 0, sizeof(cb)); 684 cb.open = hart_filter_open; 685 cb.prop = hart_filter_prop; 686 cb.done = hart_filter_done; 687 cb.extra = &filter; 688 689 filter.disabled_hart_mask = disabled_hart_mask; 690 *disabled_hart_mask = 0; 691 fdt_scan(fdt, &cb); 692} 693 694//////////////////////////////////////////// PRINT ////////////////////////////////////////////// 695 696#ifdef PK_PRINT_DEVICE_TREE 697#define FDT_PRINT_MAX_DEPTH 32 698 699struct fdt_print_info { 700 int depth; 701 const struct fdt_scan_node *stack[FDT_PRINT_MAX_DEPTH]; 702}; 703 704void fdt_print_printm(struct fdt_print_info *info, const char *format, ...) 705{ 706 va_list vl; 707 708 for (int i = 0; i < info->depth; ++i) 709 printm(" "); 710 711 va_start(vl, format); 712 vprintm(format, vl); 713 va_end(vl); 714} 715 716static void fdt_print_open(const struct fdt_scan_node *node, void *extra) 717{ 718 struct fdt_print_info *info = (struct fdt_print_info *)extra; 719 720 while (node->parent != NULL && info->stack[info->depth-1] != node->parent) { 721 info->depth--; 722 fdt_print_printm(info, "}\r\n"); 723 } 724 725 fdt_print_printm(info, "%s {\r\n", node->name); 726 info->stack[info->depth] = node; 727 info->depth++; 728} 729 730static void fdt_print_prop(const struct fdt_scan_prop *prop, void *extra) 731{ 732 struct fdt_print_info *info = (struct fdt_print_info *)extra; 733 int asstring = 1; 734 char *char_data = (char *)(prop->value); 735 736 fdt_print_printm(info, "%s", prop->name); 737 738 if (prop->len == 0) { 739 printm(";\r\n"); 740 return; 741 } else { 742 printm(" = "); 743 } 744 745 /* It appears that dtc uses a hueristic to detect strings so I'm using a 746 * similar one here. */ 747 for (int i = 0; i < prop->len; ++i) { 748 if (!isstring(char_data[i])) 749 asstring = 0; 750 if (i > 0 && char_data[i] == '\0' && char_data[i-1] == '\0') 751 asstring = 0; 752 } 753 754 if (asstring) { 755 for (size_t i = 0; i < prop->len; i += strlen(char_data + i) + 1) { 756 if (i != 0) 757 printm(", "); 758 printm("\"%s\"", char_data + i); 759 } 760 } else { 761 printm("<"); 762 for (size_t i = 0; i < prop->len/4; ++i) { 763 if (i != 0) 764 printm(" "); 765 printm("0x%08x", bswap(prop->value[i])); 766 } 767 printm(">"); 768 } 769 770 printm(";\r\n"); 771} 772 773static void fdt_print_done(const struct fdt_scan_node *node, void *extra) 774{ 775 struct fdt_print_info *info = (struct fdt_print_info *)extra; 776} 777 778static int fdt_print_close(const struct fdt_scan_node *node, void *extra) 779{ 780 struct fdt_print_info *info = (struct fdt_print_info *)extra; 781 return 0; 782} 783 784void fdt_print(uintptr_t fdt) 785{ 786 struct fdt_print_info info; 787 struct fdt_cb cb; 788 789 info.depth = 0; 790 791 memset(&cb, 0, sizeof(cb)); 792 cb.open = fdt_print_open; 793 cb.prop = fdt_print_prop; 794 cb.done = fdt_print_done; 795 cb.close = fdt_print_close; 796 cb.extra = &info; 797 798 fdt_scan(fdt, &cb); 799 800 while (info.depth > 0) { 801 info.depth--; 802 fdt_print_printm(&info, "}\r\n"); 803 } 804} 805#endif 806