1 /* 2 * Copyright 2019-2022 Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Alexander von Gluck IV <kallisti5@unixzen.com> 7 */ 8 9 10 // TODO: split arch-depending code to per-arch source 11 12 #include <arch_cpu_defs.h> 13 #include <arch_dtb.h> 14 #include <arch_smp.h> 15 #include <arch/generic/debug_uart_8250.h> 16 #if defined(__riscv) 17 # include <arch/riscv64/arch_uart_sifive.h> 18 #elif defined(__ARM__) 19 # include <arch/arm/arch_uart_pl011.h> 20 #elif defined(__aarch64__) 21 # include <arch/arm/arch_uart_pl011.h> 22 # include <arch/arm64/arch_uart_linflex.h> 23 #endif 24 25 26 #include <boot/addr_range.h> 27 #include <boot/platform.h> 28 #include <boot/stage2.h> 29 #include <boot/uart.h> 30 #include <string.h> 31 #include <kernel/kernel.h> 32 33 #include <ByteOrder.h> 34 35 extern "C" { 36 #include <libfdt.h> 37 } 38 39 #include "efi_platform.h" 40 #include "serial.h" 41 42 43 #define GIC_INTERRUPT_CELL_TYPE 0 44 #define GIC_INTERRUPT_CELL_ID 1 45 #define GIC_INTERRUPT_CELL_FLAGS 2 46 #define GIC_INTERRUPT_TYPE_SPI 0 47 #define GIC_INTERRUPT_TYPE_PPI 1 48 #define GIC_INTERRUPT_BASE_SPI 32 49 #define GIC_INTERRUPT_BASE_PPI 16 50 51 52 //#define TRACE_DUMP_FDT 53 54 55 #define INFO(x...) dprintf("efi/fdt: " x) 56 #define ERROR(x...) dprintf("efi/fdt: " x) 57 58 59 static void* sDtbTable = NULL; 60 static uint32 sDtbSize = 0; 61 62 template <typename T> DebugUART* 63 get_uart(addr_t base, int64 clock) { 64 static char buffer[sizeof(T)]; 65 return new(buffer) T(base, clock); 66 } 67 68 69 const struct supported_uarts { 70 const char* dtb_compat; 71 const char* kind; 72 DebugUART* (*uart_driver_init)(addr_t base, int64 clock); 73 } kSupportedUarts[] = { 74 { "ns16550a", UART_KIND_8250, &get_uart<DebugUART8250> }, 75 { "ns16550", UART_KIND_8250, &get_uart<DebugUART8250> }, 76 #if defined(__riscv) 77 { "sifive,uart0", UART_KIND_SIFIVE, &get_uart<ArchUARTSifive> }, 78 #elif defined(__ARM__) 79 { "arm,pl011", UART_KIND_PL011, &get_uart<ArchUARTPL011> }, 80 { "snps,dw-apb-uart", UART_KIND_8250, &get_uart<DebugUART8250> }, 81 { "brcm,bcm2835-aux-uart", UART_KIND_8250, &get_uart<DebugUART8250> } 82 #elif defined(__aarch64__) 83 { "arm,pl011", UART_KIND_PL011, &get_uart<ArchUARTPL011> }, 84 { "fsl,s32-linflexuart", UART_KIND_LINFLEX, &get_uart<ArchUARTlinflex> }, 85 { "brcm,bcm2835-aux-uart", UART_KIND_8250, &get_uart<DebugUART8250> } 86 #endif 87 }; 88 89 90 #ifdef TRACE_DUMP_FDT 91 static void 92 write_string_list(const char* prop, size_t size) 93 { 94 bool first = true; 95 const char* propEnd = prop + size; 96 while (propEnd - prop > 0) { 97 if (first) 98 first = false; 99 else 100 dprintf(", "); 101 int curLen = strlen(prop); 102 dprintf("'%s'", prop); 103 prop += curLen + 1; 104 } 105 } 106 107 108 static void 109 dump_fdt(const void *fdt) 110 { 111 if (!fdt) 112 return; 113 114 int err = fdt_check_header(fdt); 115 if (err) { 116 dprintf("fdt error: %s\n", fdt_strerror(err)); 117 return; 118 } 119 120 dprintf("fdt tree:\n"); 121 122 int node = -1; 123 int depth = -1; 124 while ((node = fdt_next_node(fdt, node, &depth)) >= 0 && depth >= 0) { 125 for (int i = 0; i < depth; i++) 126 dprintf(" "); 127 // WriteInt(node); WriteString(", "); WriteInt(depth); WriteString(": "); 128 dprintf("node('%s')\n", fdt_get_name(fdt, node, NULL)); 129 depth++; 130 for (int prop = fdt_first_property_offset(fdt, node); prop >= 0; prop = fdt_next_property_offset(fdt, prop)) { 131 int len; 132 const struct fdt_property *property = fdt_get_property_by_offset(fdt, prop, &len); 133 if (property == NULL) { 134 for (int i = 0; i < depth; i++) 135 dprintf(" "); 136 dprintf("getting prop at %d: %s\n", prop, fdt_strerror(len)); 137 break; 138 } 139 for (int i = 0; i < depth; i++) 140 dprintf(" "); 141 dprintf("prop('%s'): ", fdt_string(fdt, fdt32_to_cpu(property->nameoff))); 142 if ( 143 strcmp(fdt_string(fdt, fdt32_to_cpu(property->nameoff)), "compatible") == 0 || 144 strcmp(fdt_string(fdt, fdt32_to_cpu(property->nameoff)), "model") == 0 || 145 strcmp(fdt_string(fdt, fdt32_to_cpu(property->nameoff)), "serial-number") == 0 || 146 strcmp(fdt_string(fdt, fdt32_to_cpu(property->nameoff)), "status") == 0 || 147 strcmp(fdt_string(fdt, fdt32_to_cpu(property->nameoff)), "device_type") == 0 || 148 strcmp(fdt_string(fdt, fdt32_to_cpu(property->nameoff)), "riscv,isa") == 0 || 149 strcmp(fdt_string(fdt, fdt32_to_cpu(property->nameoff)), "mmu-type") == 0 || 150 strcmp(fdt_string(fdt, fdt32_to_cpu(property->nameoff)), "format") == 0 || 151 strcmp(fdt_string(fdt, fdt32_to_cpu(property->nameoff)), "bootargs") == 0 || 152 strcmp(fdt_string(fdt, fdt32_to_cpu(property->nameoff)), "stdout-path") == 0 || 153 strcmp(fdt_string(fdt, fdt32_to_cpu(property->nameoff)), "reg-names") == 0 || 154 strcmp(fdt_string(fdt, fdt32_to_cpu(property->nameoff)), "reset-names") == 0 || 155 strcmp(fdt_string(fdt, fdt32_to_cpu(property->nameoff)), "clock-names") == 0 || 156 strcmp(fdt_string(fdt, fdt32_to_cpu(property->nameoff)), "clock-output-names") == 0 157 ) { 158 write_string_list((const char*)property->data, fdt32_to_cpu(property->len)); 159 } else if (strcmp(fdt_string(fdt, fdt32_to_cpu(property->nameoff)), "reg") == 0) { 160 for (uint64_t *it = (uint64_t*)property->data; (uint8_t*)it - (uint8_t*)property->data < fdt32_to_cpu(property->len); it += 2) { 161 if (it != (uint64_t*)property->data) 162 dprintf(", "); 163 dprintf("(0x%08" B_PRIx64 ", 0x%08" B_PRIx64 ")", 164 fdt64_to_cpu(*it), fdt64_to_cpu(*(it + 1))); 165 } 166 } else if ( 167 strcmp(fdt_string(fdt, fdt32_to_cpu(property->nameoff)), "phandle") == 0 || 168 strcmp(fdt_string(fdt, fdt32_to_cpu(property->nameoff)), "clock-frequency") == 0 || 169 strcmp(fdt_string(fdt, fdt32_to_cpu(property->nameoff)), "timebase-frequency") == 0 || 170 strcmp(fdt_string(fdt, fdt32_to_cpu(property->nameoff)), "#address-cells") == 0 || 171 strcmp(fdt_string(fdt, fdt32_to_cpu(property->nameoff)), "#size-cells") == 0 || 172 strcmp(fdt_string(fdt, fdt32_to_cpu(property->nameoff)), "#interrupt-cells") == 0 || 173 strcmp(fdt_string(fdt, fdt32_to_cpu(property->nameoff)), "interrupts") == 0 || 174 strcmp(fdt_string(fdt, fdt32_to_cpu(property->nameoff)), "interrupt-parent") == 0 || 175 strcmp(fdt_string(fdt, fdt32_to_cpu(property->nameoff)), "boot-hartid") == 0 || 176 strcmp(fdt_string(fdt, fdt32_to_cpu(property->nameoff)), "riscv,ndev") == 0 || 177 strcmp(fdt_string(fdt, fdt32_to_cpu(property->nameoff)), "value") == 0 || 178 strcmp(fdt_string(fdt, fdt32_to_cpu(property->nameoff)), "offset") == 0 || 179 strcmp(fdt_string(fdt, fdt32_to_cpu(property->nameoff)), "regmap") == 0 || 180 strcmp(fdt_string(fdt, fdt32_to_cpu(property->nameoff)), "bank-width") == 0 || 181 strcmp(fdt_string(fdt, fdt32_to_cpu(property->nameoff)), "width") == 0 || 182 strcmp(fdt_string(fdt, fdt32_to_cpu(property->nameoff)), "height") == 0 || 183 strcmp(fdt_string(fdt, fdt32_to_cpu(property->nameoff)), "stride") == 0 184 ) { 185 dprintf("%" B_PRId32, fdt32_to_cpu(*(uint32_t*)property->data)); 186 } else if ( 187 strcmp(fdt_string(fdt, fdt32_to_cpu(property->nameoff)), "interrupts-extended") == 0 188 ) { 189 for (uint32_t *it = (uint32_t*)property->data; (uint8_t*)it - (uint8_t*)property->data < fdt32_to_cpu(property->len); it += 2) { 190 if (it != (uint32_t*)property->data) 191 dprintf(", "); 192 dprintf("(%" B_PRId32 ", %" B_PRId32 ")", 193 fdt32_to_cpu(*it), fdt32_to_cpu(*(it + 1))); 194 } 195 } else if ( 196 strcmp(fdt_string(fdt, fdt32_to_cpu(property->nameoff)), "ranges") == 0 197 ) { 198 dprintf("\n"); 199 depth++; 200 // kind 201 // child address 202 // parent address 203 // size 204 for (uint32_t *it = (uint32_t*)property->data; (uint8_t*)it - (uint8_t*)property->data < fdt32_to_cpu(property->len); it += 7) { 205 for (int i = 0; i < depth; i++) 206 dprintf(" "); 207 uint32_t kind = fdt32_to_cpu(*(it + 0)); 208 switch (kind & 0x03000000) { 209 case 0x00000000: dprintf("CONFIG"); break; 210 case 0x01000000: dprintf("IOPORT"); break; 211 case 0x02000000: dprintf("MMIO"); break; 212 case 0x03000000: dprintf("MMIO_64BIT"); break; 213 } 214 dprintf(" (0x%08" PRIx32 "), child: 0x%08" PRIx64 ", parent: 0x%08" PRIx64 ", len: 0x%08" PRIx64 "\n", 215 kind, fdt64_to_cpu(*(uint64_t*)(it + 1)), fdt64_to_cpu(*(uint64_t*)(it + 3)), fdt64_to_cpu(*(uint64_t*)(it + 5))); 216 } 217 for (int i = 0; i < depth; i++) 218 dprintf(" "); 219 depth--; 220 } else if (strcmp(fdt_string(fdt, fdt32_to_cpu(property->nameoff)), "bus-range") == 0) { 221 uint32_t *it = (uint32_t*)property->data; 222 dprintf("%" PRId32 ", %" PRId32, fdt32_to_cpu(*it), fdt32_to_cpu(*(it + 1))); 223 } else if (strcmp(fdt_string(fdt, fdt32_to_cpu(property->nameoff)), "interrupt-map-mask") == 0) { 224 dprintf("\n"); 225 depth++; 226 for (uint32_t *it = (uint32_t*)property->data; (uint8_t*)it - (uint8_t*)property->data < fdt32_to_cpu(property->len); it++) { 227 for (int i = 0; i < depth; i++) 228 dprintf(" "); 229 dprintf("0x%08" PRIx32 "\n", fdt32_to_cpu(*(uint32_t*)it)); 230 } 231 for (int i = 0; i < depth; i++) 232 dprintf(" "); 233 depth--; 234 } else if (strcmp(fdt_string(fdt, fdt32_to_cpu(property->nameoff)), "interrupt-map") == 0) { 235 dprintf("\n"); 236 depth++; 237 238 int addressCells = 3; 239 int interruptCells = 1; 240 int phandleCells = 1; 241 242 uint32 *prop; 243 244 prop = (uint32*)fdt_getprop(fdt, node, "#address-cells", NULL); 245 if (prop != NULL) 246 addressCells = fdt32_to_cpu(*prop); 247 248 prop = (uint32*)fdt_getprop(fdt, node, "#interrupt-cells", NULL); 249 if (prop != NULL) 250 interruptCells = fdt32_to_cpu(*prop); 251 252 uint32_t *it = (uint32_t*)property->data; 253 while ((uint8_t*)it - (uint8_t*)property->data < fdt32_to_cpu(property->len)) { 254 for (int i = 0; i < depth; i++) 255 dprintf(" "); 256 257 uint32 childAddr = fdt32_to_cpu(*it); 258 dprintf("childAddr: "); 259 for (int i = 0; i < addressCells; i++) { 260 dprintf("0x%08" PRIx32 " ", fdt32_to_cpu(*it)); 261 it++; 262 } 263 264 uint8 bus = childAddr / (1 << 16) % (1 << 8); 265 uint8 dev = childAddr / (1 << 11) % (1 << 5); 266 uint8 func = childAddr % (1 << 3); 267 dprintf("(bus: %" PRId32 ", dev: %" PRId32 ", fn: %" PRId32 "), ", 268 bus, dev, func); 269 270 dprintf("childIrq: "); 271 for (int i = 0; i < interruptCells; i++) { 272 dprintf("%" PRIu32 " ", fdt32_to_cpu(*it)); 273 it++; 274 } 275 276 uint32 parentPhandle = fdt32_to_cpu(*it); 277 it += phandleCells; 278 dprintf("parentPhandle: %" PRId32 ", ", parentPhandle); 279 280 int parentAddressCells = 0; 281 int parentInterruptCells = 1; 282 283 int parentNode = fdt_node_offset_by_phandle(fdt, parentPhandle); 284 if (parentNode >= 0) { 285 prop = (uint32*)fdt_getprop(fdt, parentNode, "#address-cells", NULL); 286 if (prop != NULL) 287 parentAddressCells = fdt32_to_cpu(*prop); 288 289 prop = (uint32*)fdt_getprop(fdt, parentNode, "#interrupt-cells", NULL); 290 if (prop != NULL) 291 parentInterruptCells = fdt32_to_cpu(*prop); 292 } 293 294 dprintf("parentAddress: "); 295 for (int i = 0; i < parentAddressCells; i++) { 296 dprintf("%" PRIu32 " ", fdt32_to_cpu(*it)); 297 it++; 298 } 299 300 dprintf("parentIrq: "); 301 for (int i = 0; i < parentInterruptCells; i++) { 302 dprintf("%" PRIu32 " ", fdt32_to_cpu(*it)); 303 it++; 304 } 305 306 dprintf("\n"); 307 } 308 for (int i = 0; i < depth; i++) 309 dprintf(" "); 310 depth--; 311 } else { 312 dprintf("?"); 313 } 314 dprintf(" (len %" PRId32 ")\n", fdt32_to_cpu(property->len)); 315 /* 316 dump_hex(property->data, fdt32_to_cpu(property->len), depth); 317 */ 318 } 319 depth--; 320 } 321 } 322 #endif 323 324 325 bool 326 dtb_has_fdt_string(const char* prop, int size, const char* pattern) 327 { 328 int patternLen = strlen(pattern); 329 const char* propEnd = prop + size; 330 while (propEnd - prop > 0) { 331 int curLen = strlen(prop); 332 if (curLen == patternLen && memcmp(prop, pattern, curLen + 1) == 0) 333 return true; 334 prop += curLen + 1; 335 } 336 return false; 337 } 338 339 340 uint32 341 dtb_get_address_cells(const void* fdt, int node) 342 { 343 uint32 res = 2; 344 345 int parent = fdt_parent_offset(fdt, node); 346 if (parent < 0) 347 return res; 348 349 uint32 *prop = (uint32*)fdt_getprop(fdt, parent, "#address-cells", NULL); 350 if (prop == NULL) 351 return res; 352 353 res = fdt32_to_cpu(*prop); 354 return res; 355 } 356 357 358 uint32 359 dtb_get_size_cells(const void* fdt, int node) 360 { 361 uint32 res = 1; 362 363 int parent = fdt_parent_offset(fdt, node); 364 if (parent < 0) 365 return res; 366 367 uint32 *prop = (uint32*)fdt_getprop(fdt, parent, "#size-cells", NULL); 368 if (prop == NULL) 369 return res; 370 371 res = fdt32_to_cpu(*prop); 372 return res; 373 } 374 375 376 bool 377 dtb_get_reg(const void* fdt, int node, size_t idx, addr_range& range) 378 { 379 uint32 addressCells = dtb_get_address_cells(fdt, node); 380 uint32 sizeCells = dtb_get_size_cells(fdt, node); 381 382 int propSize; 383 const uint8* prop = (const uint8*)fdt_getprop(fdt, node, "reg", &propSize); 384 if (prop == NULL) 385 return false; 386 387 size_t entrySize = 4 * (addressCells + sizeCells); 388 if ((idx + 1) * entrySize > (size_t)propSize) 389 return false; 390 391 prop += idx * entrySize; 392 393 switch (addressCells) { 394 case 1: range.start = fdt32_to_cpu(*(uint32*)prop); prop += 4; break; 395 case 2: range.start = fdt64_to_cpu(*(uint64*)prop); prop += 8; break; 396 default: panic("unsupported addressCells"); 397 } 398 switch (sizeCells) { 399 case 1: range.size = fdt32_to_cpu(*(uint32*)prop); prop += 4; break; 400 case 2: range.size = fdt64_to_cpu(*(uint64*)prop); prop += 8; break; 401 default: panic("unsupported sizeCells"); 402 } 403 404 int parent = fdt_parent_offset(fdt, node); 405 if (parent >= 0) { 406 uint32 parentAddressCells = dtb_get_address_cells(fdt, parent); 407 408 uint32 rangesSize = 0; 409 uint32 *ranges = (uint32 *)fdt_getprop(fdt, parent, "ranges", (int *)&rangesSize); 410 if (ranges == NULL) 411 return true; 412 413 uint32 rangesPos = 0; 414 while (rangesSize >= (rangesPos + parentAddressCells + addressCells + sizeCells)) { 415 addr_t childAddress; 416 addr_t parentAddress; 417 size_t rangeSize; 418 419 if (addressCells == 1) { 420 childAddress = fdt32_to_cpu(*(uint32*)(ranges+rangesPos)); 421 } else { 422 childAddress = fdt64_to_cpu(*(uint64*)(ranges+rangesPos)); 423 } 424 rangesPos += addressCells; 425 426 if (parentAddressCells == 1) { 427 parentAddress = fdt32_to_cpu(*(uint32*)(ranges+rangesPos)); 428 } else { 429 parentAddress = fdt64_to_cpu(*(uint64*)(ranges+rangesPos)); 430 } 431 rangesPos += parentAddressCells; 432 433 if (sizeCells == 1) { 434 rangeSize = fdt32_to_cpu(*(uint32*)(ranges+rangesPos)); 435 } else { 436 rangeSize = fdt64_to_cpu(*(uint64*)(ranges+rangesPos)); 437 } 438 rangesPos += sizeCells; 439 440 if ((range.start >= childAddress) && (range.start <= childAddress + rangeSize)) { 441 range.start -= childAddress; 442 range.start += parentAddress; 443 break; 444 } 445 } 446 } 447 448 return true; 449 } 450 451 452 static int 453 dtb_get_interrupt_parent(const void* fdt, int node) 454 { 455 while (node >= 0) { 456 uint32* prop; 457 prop = (uint32*)fdt_getprop(fdt, node, "interrupt-parent", NULL); 458 if (prop != NULL) { 459 uint32_t phandle = fdt32_to_cpu(*prop); 460 return fdt_node_offset_by_phandle(fdt, phandle); 461 } 462 463 node = fdt_parent_offset(fdt, node); 464 } 465 466 return -1; 467 } 468 469 470 static uint32 471 dtb_get_interrupt_cells(const void* fdt, int node) 472 { 473 int intc_node = dtb_get_interrupt_parent(fdt, node); 474 if (intc_node >= 0) { 475 uint32* prop = (uint32*)fdt_getprop(fdt, intc_node, "#interrupt-cells", NULL); 476 if (prop != NULL) { 477 return fdt32_to_cpu(*prop); 478 } 479 } 480 481 return 1; 482 } 483 484 485 uint32 486 dtb_get_interrupt(const void* fdt, int node) 487 { 488 uint32 interruptCells = dtb_get_interrupt_cells(fdt, node); 489 490 if (uint32* prop = (uint32*)fdt_getprop(fdt, node, "interrupts-extended", NULL)) { 491 return fdt32_to_cpu(*(prop + 1)); 492 } 493 if (uint32* prop = (uint32*)fdt_getprop(fdt, node, "interrupts", NULL)) { 494 if ((interruptCells == 1) || (interruptCells == 2)) { 495 return fdt32_to_cpu(*prop); 496 } else if (interruptCells == 3) { 497 uint32 interruptType = fdt32_to_cpu(prop[GIC_INTERRUPT_CELL_TYPE]); 498 uint32 interruptNumber = fdt32_to_cpu(prop[GIC_INTERRUPT_CELL_ID]); 499 if (interruptType == GIC_INTERRUPT_TYPE_SPI) 500 interruptNumber += GIC_INTERRUPT_BASE_SPI; 501 else if (interruptType == GIC_INTERRUPT_TYPE_PPI) 502 interruptNumber += GIC_INTERRUPT_BASE_PPI; 503 504 return interruptNumber; 505 } else { 506 panic("unsupported interruptCells"); 507 } 508 } 509 dprintf("[!] no interrupt field\n"); 510 return 0; 511 } 512 513 514 static int64 515 dtb_get_clock_frequency(const void* fdt, int node) 516 { 517 uint32* prop; 518 int len = 0; 519 520 prop = (uint32*)fdt_getprop(fdt, node, "clock-frequency", NULL); 521 if (prop != NULL) { 522 return fdt32_to_cpu(*prop); 523 } 524 525 prop = (uint32*)fdt_getprop(fdt, node, "clocks", &len); 526 if (prop != NULL) { 527 uint32_t phandle = fdt32_to_cpu(*prop); 528 int offset = fdt_node_offset_by_phandle(fdt, phandle); 529 if (offset > 0) { 530 uint32* prop2 = (uint32*)fdt_getprop(fdt, offset, "clock-frequency", NULL); 531 if (prop2 != NULL) { 532 return fdt32_to_cpu(*prop2); 533 } 534 } 535 } 536 537 return 0; 538 } 539 540 541 static void 542 dtb_handle_fdt(const void* fdt, int node) 543 { 544 arch_handle_fdt(fdt, node); 545 546 int compatibleLen; 547 const char* compatible = (const char*)fdt_getprop(fdt, node, 548 "compatible", &compatibleLen); 549 550 if (compatible == NULL) 551 return; 552 553 // check for a uart if we don't have one 554 uart_info &uart = gKernelArgs.arch_args.uart; 555 if (uart.kind[0] == 0) { 556 for (uint32 i = 0; i < B_COUNT_OF(kSupportedUarts); i++) { 557 if (dtb_has_fdt_string(compatible, compatibleLen, 558 kSupportedUarts[i].dtb_compat)) { 559 560 memcpy(uart.kind, kSupportedUarts[i].kind, 561 sizeof(uart.kind)); 562 563 dtb_get_reg(fdt, node, 0, uart.regs); 564 uart.irq = dtb_get_interrupt(fdt, node); 565 uart.clock = dtb_get_clock_frequency(fdt, node); 566 567 gUART = kSupportedUarts[i].uart_driver_init(uart.regs.start, 568 uart.clock); 569 } 570 } 571 572 if (gUART != NULL) 573 gUART->InitEarly(); 574 } 575 } 576 577 578 static void 579 dtb_handle_chosen_node(const void *fdt) 580 { 581 int chosen = fdt_path_offset(fdt, "/chosen"); 582 if (chosen < 0) 583 return; 584 585 int len; 586 const char *stdoutPath = (const char *)fdt_getprop(fdt, chosen, "stdout-path", &len); 587 if (stdoutPath == NULL) 588 return; 589 590 // stdout-path can optionally contain a ":" separator character 591 // The part after the ":" character specifies the UART configuration 592 // We can ignore it here as the UART should be already initialized 593 // by the UEFI firmware (e.g. U-Boot or TianoCore) 594 595 char *separator = strchr(stdoutPath, ':'); 596 int namelen = (separator == NULL) ? len - 1 : separator - stdoutPath; 597 598 int stdoutNode = fdt_path_offset_namelen(fdt, stdoutPath, namelen); 599 if (stdoutNode < 0) 600 return; 601 602 dtb_handle_fdt(fdt, stdoutNode); 603 } 604 605 606 void 607 dtb_init() 608 { 609 efi_configuration_table *table = kSystemTable->ConfigurationTable; 610 size_t entries = kSystemTable->NumberOfTableEntries; 611 612 INFO("Probing for device trees from UEFI...\n"); 613 614 // Try to find an FDT 615 for (uint32 i = 0; i < entries; i++) { 616 if (!table[i].VendorGuid.equals(DEVICE_TREE_GUID)) 617 continue; 618 619 void* dtbPtr = (void*)(table[i].VendorTable); 620 621 int res = fdt_check_header(dtbPtr); 622 if (res != 0) { 623 ERROR("Invalid FDT from UEFI table %d: %s\n", i, fdt_strerror(res)); 624 continue; 625 } 626 627 sDtbTable = dtbPtr; 628 sDtbSize = fdt_totalsize(dtbPtr); 629 630 INFO("Valid FDT from UEFI table %d, size: %" B_PRIu32 "\n", i, sDtbSize); 631 632 #ifdef TRACE_DUMP_FDT 633 dump_fdt(sDtbTable); 634 #endif 635 636 dtb_handle_chosen_node(sDtbTable); 637 638 int node = -1; 639 int depth = -1; 640 while ((node = fdt_next_node(sDtbTable, node, &depth)) >= 0 && depth >= 0) { 641 dtb_handle_fdt(sDtbTable, node); 642 } 643 break; 644 } 645 } 646 647 648 void 649 dtb_set_kernel_args() 650 { 651 // pack into proper location if the architecture cares 652 if (sDtbTable != NULL) { 653 // libfdt requires 8-byte alignment 654 gKernelArgs.arch_args.fdt = (void*)(addr_t)kernel_args_malloc(sDtbSize, 8); 655 656 if (gKernelArgs.arch_args.fdt != NULL) 657 memcpy(gKernelArgs.arch_args.fdt, sDtbTable, sDtbSize); 658 else 659 ERROR("unable to malloc for fdt!\n"); 660 } 661 662 uart_info &uart = gKernelArgs.arch_args.uart; 663 dprintf("Chosen UART:\n"); 664 if (uart.kind[0] == 0) { 665 dprintf("kind: None!\n"); 666 } else { 667 dprintf(" kind: %s\n", uart.kind); 668 dprintf(" regs: %#" B_PRIx64 ", %#" B_PRIx64 "\n", uart.regs.start, uart.regs.size); 669 dprintf(" irq: %" B_PRIu32 "\n", uart.irq); 670 dprintf(" clock: %" B_PRIu64 "\n", uart.clock); 671 } 672 673 arch_dtb_set_kernel_args(); 674 } 675