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