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