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