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