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