diff --git a/headers/private/kernel/boot/platform/efi/arch_dtb.h b/headers/private/kernel/boot/platform/efi/arch_dtb.h new file mode 100644 index 0000000000..2644919772 --- /dev/null +++ b/headers/private/kernel/boot/platform/efi/arch_dtb.h @@ -0,0 +1,16 @@ +/* + * Copyright 2021 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef KERNEL_BOOT_PLATFORM_EFI_ARCH_DTB_H +#define KERNEL_BOOT_PLATFORM_EFI_ARCH_DTB_H + + +#include + + +void arch_handle_fdt(const void* fdt, int node, uint32 addressCells, uint32 sizeCells); +void arch_dtb_set_kernel_args(void); + + +#endif /* KERNEL_BOOT_PLATFORM_EFI_ARCH_DTB_H */ diff --git a/src/system/boot/platform/efi/arch/arm/Jamfile b/src/system/boot/platform/efi/arch/arm/Jamfile index 8cf1e95df8..588fdff51d 100644 --- a/src/system/boot/platform/efi/arch/arm/Jamfile +++ b/src/system/boot/platform/efi/arch/arm/Jamfile @@ -2,6 +2,8 @@ SubDir HAIKU_TOP src system boot platform efi arch arm ; SubDirHdrs $(HAIKU_TOP) src system boot platform efi ; +UseLibraryHeaders [ FDirName libfdt ] ; + UsePrivateHeaders [ FDirName kernel platform ] ; UsePrivateHeaders [ FDirName kernel boot platform efi ] ; @@ -19,6 +21,7 @@ for platform in [ MultiBootSubDirSetup efi ] { crt0-efi-$(TARGET_ARCH).S entry.S relocation_func.cpp + arch_dtb.cpp arch_mmu.cpp arch_smp.cpp arch_start.cpp diff --git a/src/system/boot/platform/efi/arch/arm/arch_dtb.cpp b/src/system/boot/platform/efi/arch/arm/arch_dtb.cpp new file mode 100644 index 0000000000..e4f45c2dc4 --- /dev/null +++ b/src/system/boot/platform/efi/arch/arm/arch_dtb.cpp @@ -0,0 +1,95 @@ +/* + * Copyright 2019-2021 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Alexander von Gluck IV + */ + +#include +#include +#include +#include +#include + +extern "C" { +#include +} + +#include "dtb.h" + + +const struct supported_interrupt_controllers { + const char* dtb_compat; + const char* kind; +} kSupportedInterruptControllers[] = { + { "arm,cortex-a9-gic", INTC_KIND_GICV1 }, + { "arm,cortex-a15-gic", INTC_KIND_GICV2 }, + { "ti,omap3-intc", INTC_KIND_OMAP3 }, + { "marvell,pxa-intc", INTC_KIND_PXA }, +}; + + +void +arch_handle_fdt(const void* fdt, int node, uint32 addressCells, uint32 sizeCells) +{ + const char* deviceType = (const char*)fdt_getprop(fdt, node, + "device_type", NULL); + + if (deviceType != NULL) { + if (strcmp(deviceType, "cpu") == 0) { + platform_cpu_info* info; + arch_smp_register_cpu(&info); + if (info == NULL) + return; + info->id = fdt32_to_cpu(*(uint32*)fdt_getprop(fdt, node, + "reg", NULL)); + dprintf("cpu\n"); + dprintf(" id: %" B_PRIu32 "\n", info->id); + + } + } + + int compatibleLen; + const char* compatible = (const char*)fdt_getprop(fdt, node, + "compatible", &compatibleLen); + + if (compatible == NULL) + return; + + intc_info &interrupt_controller = gKernelArgs.arch_args.interrupt_controller; + if (interrupt_controller.kind[0] == 0) { + for (uint32 i = 0; i < B_COUNT_OF(kSupportedInterruptControllers); i++) { + if (dtb_has_fdt_string(compatible, compatibleLen, + kSupportedInterruptControllers[i].dtb_compat)) { + + memcpy(interrupt_controller.kind, kSupportedInterruptControllers[i].kind, + sizeof(interrupt_controller.kind)); + + dtb_get_reg(fdt, node, addressCells, sizeCells, 0, + interrupt_controller.regs1); + dtb_get_reg(fdt, node, addressCells, sizeCells, 1, + interrupt_controller.regs2); + } + } + } +} + + +void +arch_dtb_set_kernel_args(void) +{ + intc_info &interrupt_controller = gKernelArgs.arch_args.interrupt_controller; + dprintf("Chosen interrupt controller:\n"); + if (interrupt_controller.kind[0] == 0) { + dprintf("kind: None!\n"); + } else { + dprintf(" kind: %s\n", interrupt_controller.kind); + dprintf(" regs: %#" B_PRIx64 ", %#" B_PRIx64 "\n", + interrupt_controller.regs1.start, + interrupt_controller.regs1.size); + dprintf(" %#" B_PRIx64 ", %#" B_PRIx64 "\n", + interrupt_controller.regs2.start, + interrupt_controller.regs2.size); + } +} diff --git a/src/system/boot/platform/efi/arch/riscv64/Jamfile b/src/system/boot/platform/efi/arch/riscv64/Jamfile index f98215fb58..12d6ae2b53 100644 --- a/src/system/boot/platform/efi/arch/riscv64/Jamfile +++ b/src/system/boot/platform/efi/arch/riscv64/Jamfile @@ -2,6 +2,8 @@ SubDir HAIKU_TOP src system boot platform efi arch riscv64 ; SubDirHdrs $(HAIKU_TOP) src system boot platform efi ; +UseLibraryHeaders [ FDirName libfdt ] ; + UsePrivateHeaders [ FDirName kernel platform ] ; UsePrivateHeaders [ FDirName kernel boot platform efi ] ; @@ -13,9 +15,10 @@ for platform in [ MultiBootSubDirSetup efi ] { crt0-efi-$(TARGET_ARCH).S entry.S relocation_func.cpp - arch_start.cpp - arch_smp.cpp + arch_dtb.cpp arch_mmu.cpp + arch_smp.cpp + arch_start.cpp arch_timer.cpp arch_traps.cpp arch_traps_asm.S diff --git a/src/system/boot/platform/efi/arch/riscv64/arch_dtb.cpp b/src/system/boot/platform/efi/arch/riscv64/arch_dtb.cpp new file mode 100644 index 0000000000..a609625b4a --- /dev/null +++ b/src/system/boot/platform/efi/arch/riscv64/arch_dtb.cpp @@ -0,0 +1,117 @@ +/* + * Copyright 2019-2021 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Alexander von Gluck IV + */ + +#include +#include +#include +#include +#include + +extern "C" { +#include +} + +#include "dtb.h" + + +uint32 gBootHart = 0; +static uint64 sTimerFrequency = 10000000; + +static addr_range sPlic = {0}; +static addr_range sClint = {0}; + + +void +arch_handle_fdt(const void* fdt, int node, uint32 addressCells, uint32 sizeCells) +{ + const char* deviceType = (const char*)fdt_getprop(fdt, node, + "device_type", NULL); + + const char* name = fdt_get_name(fdt, node, NULL); + if (strcmp(name, "chosen") == 0) { + if (uint32* prop = (uint32*)fdt_getprop(fdt, node, "boot-hartid", NULL)) + gBootHart = fdt32_to_cpu(*prop); + } else if (strcmp(name, "cpus") == 0) { + if (uint32* prop = (uint32*)fdt_getprop(fdt, node, "timebase-frequency", NULL)) + sTimerFrequency = fdt32_to_cpu(*prop); + } + + if (deviceType != NULL) { + if (strcmp(deviceType, "cpu") == 0) { + // TODO: improve incompatible CPU detection + if (!(fdt_getprop(fdt, node, "mmu-type", NULL) != NULL)) + return; + + platform_cpu_info* info; + arch_smp_register_cpu(&info); + if (info == NULL) + return; + info->id = fdt32_to_cpu(*(uint32*)fdt_getprop(fdt, node, + "reg", NULL)); + dprintf("cpu\n"); + dprintf(" id: %" B_PRIu32 "\n", info->id); + + int subNode = fdt_subnode_offset(fdt, node, "interrupt-controller"); + if (subNode < 0) { + dprintf(" [!] no interrupt controller\n"); + } else { + info->phandle = fdt_get_phandle(fdt, subNode); + dprintf(" phandle: %" B_PRIu32 "\n", info->phandle); + } + } + } + int compatibleLen; + const char* compatible = (const char*)fdt_getprop(fdt, node, + "compatible", &compatibleLen); + + if (compatible == NULL) + return; + + if (dtb_has_fdt_string(compatible, compatibleLen, "riscv,clint0")) { + dtb_get_reg(fdt, node, addressCells, sizeCells, 0, sClint); + return; + } + + if (dtb_has_fdt_string(compatible, compatibleLen, "riscv,plic0") + || dtb_has_fdt_string(compatible, compatibleLen, "sifive,plic-1.0.0")) { + dtb_get_reg(fdt, node, addressCells, sizeCells, 0, sPlic); + int propSize; + if (uint32* prop = (uint32*)fdt_getprop(fdt, node, "interrupts-extended", &propSize)) { + dprintf("PLIC contexts\n"); + uint32 contextId = 0; + for (uint32 *it = prop; (uint8_t*)it - (uint8_t*)prop < propSize; it += 2) { + uint32 phandle = fdt32_to_cpu(*it); + uint32 interrupt = fdt32_to_cpu(*(it + 1)); + if (interrupt == sExternInt) { + platform_cpu_info* cpuInfo = arch_smp_find_cpu(phandle); + dprintf(" context %" B_PRIu32 ": %" B_PRIu32 "\n", contextId, phandle); + if (cpuInfo != NULL) { + cpuInfo->plicContext = contextId; + dprintf(" cpu id: %" B_PRIu32 "\n", cpuInfo->id); + } + } + contextId++; + } + } + return; + } +} + + +void +arch_dtb_set_kernel_args(void) +{ + dprintf("bootHart: %" B_PRIu32 "\n", gBootHart); + dprintf("timerFrequency: %" B_PRIu64 "\n", sTimerFrequency); + gKernelArgs.arch_args.timerFrequency = sTimerFrequency; + +// gKernelArgs.arch_args.htif = {.start = 0x40008000, .size = 0x10}; + gKernelArgs.arch_args.htif = {.start = 0, .size = 0}; + gKernelArgs.arch_args.plic = sPlic; + gKernelArgs.arch_args.clint = sClint; +} diff --git a/src/system/boot/platform/efi/dtb.cpp b/src/system/boot/platform/efi/dtb.cpp index 4685a11e7b..4f23021b11 100644 --- a/src/system/boot/platform/efi/dtb.cpp +++ b/src/system/boot/platform/efi/dtb.cpp @@ -10,6 +10,7 @@ // TODO: split arch-depending code to per-arch source #include +#include #include #include #if defined(__riscv) @@ -41,14 +42,6 @@ extern "C" { static void* sDtbTable = NULL; static uint32 sDtbSize = 0; -// TODO: gBootHart is riscy, move -uint32 gBootHart = 0; -static uint64 sTimerFrequency = 10000000; - -static addr_range sPlic = {0}; -static addr_range sClint = {0}; - - static void WriteString(const char *str) {dprintf("%s", str);} static void WriteLn() {dprintf("\n");} static void WriteHex(uint64_t val, int n) {dprintf("%08" B_PRIx64, val);} @@ -77,19 +70,6 @@ const struct supported_uarts { }; -#ifdef __ARM__ -const struct supported_interrupt_controllers { - const char* dtb_compat; - const char* kind; -} kSupportedInterruptControllers[] = { - { "arm,cortex-a9-gic", INTC_KIND_GICV1 }, - { "arm,cortex-a15-gic", INTC_KIND_GICV2 }, - { "ti,omap3-intc", INTC_KIND_OMAP3 }, - { "marvell,pxa-intc", INTC_KIND_PXA }, -}; -#endif - - static void WriteStringList(const char* prop, size_t size) { bool first = true; @@ -295,8 +275,8 @@ static void DumpFdt(const void *fdt) -static bool -HasFdtString(const char* prop, int size, const char* pattern) +bool +dtb_has_fdt_string(const char* prop, int size, const char* pattern) { int patternLen = strlen(pattern); const char* propEnd = prop + size; @@ -310,8 +290,8 @@ HasFdtString(const char* prop, int size, const char* pattern) } -static bool -GetReg(const void* fdt, int node, uint32 addressCells, uint32 sizeCells, size_t idx, addr_range& range) +bool +dtb_get_reg(const void* fdt, int node, uint32 addressCells, uint32 sizeCells, size_t idx, addr_range& range) { int propSize; const uint8* prop = (const uint8*)fdt_getprop(fdt, node, "reg", &propSize); @@ -339,7 +319,7 @@ GetReg(const void* fdt, int node, uint32 addressCells, uint32 sizeCells, size_t static uint32 -GetInterruptParent(const void* fdt, int node) +dtb_get_interrupt_parent(const void* fdt, int node) { while (node >= 0) { uint32* prop; @@ -357,9 +337,9 @@ GetInterruptParent(const void* fdt, int node) static uint32 -GetInterruptCells(const void* fdt, int node) +dtb_get_interrupt_cells(const void* fdt, int node) { - uint32 intc_node = GetInterruptParent(fdt, node); + uint32 intc_node = dtb_get_interrupt_parent(fdt, node); if (intc_node > 0) { uint32* prop = (uint32*)fdt_getprop(fdt, intc_node, "#interrupt-cells", NULL); if (prop != NULL) { @@ -372,9 +352,9 @@ GetInterruptCells(const void* fdt, int node) static uint32 -GetInterrupt(const void* fdt, int node) +dtb_get_interrupt(const void* fdt, int node) { - uint32 interruptCells = GetInterruptCells(fdt, node); + uint32 interruptCells = dtb_get_interrupt_cells(fdt, node); if (uint32* prop = (uint32*)fdt_getprop(fdt, node, "interrupts-extended", NULL)) { return fdt32_to_cpu(*(prop + 1)); @@ -392,7 +372,7 @@ GetInterrupt(const void* fdt, int node) static int64 -GetClockFrequency(const void* fdt, int node) +dtb_get_clock_frequency(const void* fdt, int node) { uint32* prop; int len = 0; @@ -419,43 +399,9 @@ GetClockFrequency(const void* fdt, int node) static void -HandleFdt(const void* fdt, int node, uint32 addressCells, uint32 sizeCells) +dtb_handle_fdt(const void* fdt, int node, uint32 addressCells, uint32 sizeCells) { - const char* name = fdt_get_name(fdt, node, NULL); - if (strcmp(name, "chosen") == 0) { - if (uint32* prop = (uint32*)fdt_getprop(fdt, node, "boot-hartid", NULL)) - gBootHart = fdt32_to_cpu(*prop); - } else if (strcmp(name, "cpus") == 0) { - if (uint32* prop = (uint32*)fdt_getprop(fdt, node, "timebase-frequency", NULL)) - sTimerFrequency = fdt32_to_cpu(*prop); - } - - const char* deviceType = (const char*)fdt_getprop(fdt, node, - "device_type", NULL); - - if (deviceType != NULL) { - if (strcmp(deviceType, "cpu") == 0) { - // TODO: improve incompatible CPU detection - if (!(fdt_getprop(fdt, node, "mmu-type", NULL) != NULL)) - return; - platform_cpu_info* info; - arch_smp_register_cpu(&info); - if (info == NULL) - return; - info->id = fdt32_to_cpu(*(uint32*)fdt_getprop(fdt, node, - "reg", NULL)); - dprintf("cpu\n"); - dprintf(" id: %" B_PRIu32 "\n", info->id); - - int subNode = fdt_subnode_offset(fdt, node, "interrupt-controller"); - if (subNode < 0) { - dprintf(" [!] no interrupt controller\n"); - } else { - info->phandle = fdt_get_phandle(fdt, subNode); - dprintf(" phandle: %" B_PRIu32 "\n", info->phandle); - } - } - } + arch_handle_fdt(fdt, node, addressCells, sizeCells); int compatibleLen; const char* compatible = (const char*)fdt_getprop(fdt, node, @@ -464,50 +410,21 @@ HandleFdt(const void* fdt, int node, uint32 addressCells, uint32 sizeCells) if (compatible == NULL) return; - if (HasFdtString(compatible, compatibleLen, "riscv,clint0")) { - GetReg(fdt, node, addressCells, sizeCells, 0, sClint); - return; - } - - if (HasFdtString(compatible, compatibleLen, "riscv,plic0") - || HasFdtString(compatible, compatibleLen, "sifive,plic-1.0.0")) { - GetReg(fdt, node, addressCells, sizeCells, 0, sPlic); - int propSize; - if (uint32* prop = (uint32*)fdt_getprop(fdt, node, "interrupts-extended", &propSize)) { - dprintf("PLIC contexts\n"); - uint32 contextId = 0; - for (uint32 *it = prop; (uint8_t*)it - (uint8_t*)prop < propSize; it += 2) { - uint32 phandle = fdt32_to_cpu(*it); - uint32 interrupt = fdt32_to_cpu(*(it + 1)); - if (interrupt == sExternInt) { - platform_cpu_info* cpuInfo = arch_smp_find_cpu(phandle); - dprintf(" context %" B_PRIu32 ": %" B_PRIu32 "\n", contextId, phandle); - if (cpuInfo != NULL) { - cpuInfo->plicContext = contextId; - dprintf(" cpu id: %" B_PRIu32 "\n", cpuInfo->id); - } - } - contextId++; - } - } - return; - } - // TODO: We should check for the "chosen" uart and prioritize that one // check for a uart if we don't have one uart_info &uart = gKernelArgs.arch_args.uart; if (uart.kind[0] == 0) { for (uint32 i = 0; i < B_COUNT_OF(kSupportedUarts); i++) { - if (HasFdtString(compatible, compatibleLen, + if (dtb_has_fdt_string(compatible, compatibleLen, kSupportedUarts[i].dtb_compat)) { memcpy(uart.kind, kSupportedUarts[i].kind, sizeof(uart.kind)); - GetReg(fdt, node, addressCells, sizeCells, 0, uart.regs); - uart.irq = GetInterrupt(fdt, node); - uart.clock = GetClockFrequency(fdt, node); + dtb_get_reg(fdt, node, addressCells, sizeCells, 0, uart.regs); + uart.irq = dtb_get_interrupt(fdt, node); + uart.clock = dtb_get_clock_frequency(fdt, node); gUART = kSupportedUarts[i].uart_driver_init(uart.regs.start, uart.clock); @@ -517,25 +434,6 @@ HandleFdt(const void* fdt, int node, uint32 addressCells, uint32 sizeCells) if (gUART != NULL) gUART->InitEarly(); } - -#if defined(__ARM__) - intc_info &interrupt_controller = gKernelArgs.arch_args.interrupt_controller; - if (interrupt_controller.kind[0] == 0) { - for (uint32 i = 0; i < B_COUNT_OF(kSupportedInterruptControllers); i++) { - if (HasFdtString(compatible, compatibleLen, - kSupportedInterruptControllers[i].dtb_compat)) { - - memcpy(interrupt_controller.kind, kSupportedInterruptControllers[i].kind, - sizeof(interrupt_controller.kind)); - - GetReg(fdt, node, addressCells, sizeCells, 0, - interrupt_controller.regs1); - GetReg(fdt, node, addressCells, sizeCells, 1, - interrupt_controller.regs2); - } - } - } -#endif } @@ -574,7 +472,7 @@ dtb_init() int node = -1; int depth = -1; while ((node = fdt_next_node(sDtbTable, node, &depth)) >= 0 && depth >= 0) { - HandleFdt(sDtbTable, node, 2, 2); + dtb_handle_fdt(sDtbTable, node, 2, 2); } break; } @@ -586,7 +484,6 @@ dtb_set_kernel_args() { // pack into proper location if the architecture cares if (sDtbTable != NULL) { - #if defined(__ARM__) || defined(__riscv) // libfdt requires 8-byte alignment gKernelArgs.arch_args.fdt = (void*)(addr_t)kernel_args_malloc(sDtbSize, 8); @@ -594,20 +491,8 @@ dtb_set_kernel_args() memcpy(gKernelArgs.arch_args.fdt, sDtbTable, sDtbSize); else ERROR("unable to malloc for fdt!\n"); - #endif } -#ifdef __riscv - dprintf("bootHart: %" B_PRIu32 "\n", gBootHart); - dprintf("timerFrequency: %" B_PRIu64 "\n", sTimerFrequency); - gKernelArgs.arch_args.timerFrequency = sTimerFrequency; - -// gKernelArgs.arch_args.htif = {.start = 0x40008000, .size = 0x10}; - gKernelArgs.arch_args.htif = {.start = 0, .size = 0}; - gKernelArgs.arch_args.plic = sPlic; - gKernelArgs.arch_args.clint = sClint; -#endif -#if defined(__ARM__) || defined(__riscv) uart_info &uart = gKernelArgs.arch_args.uart; dprintf("Chosen UART:\n"); if (uart.kind[0] == 0) { @@ -619,20 +504,6 @@ dtb_set_kernel_args() dprintf(" irq: %" B_PRIu32 "\n", uart.irq); dprintf(" clock: %" B_PRIu64 "\n", uart.clock); } -#endif -#if defined(__ARM__) - intc_info &interrupt_controller = gKernelArgs.arch_args.interrupt_controller; - dprintf("Chosen interrupt controller:\n"); - if (interrupt_controller.kind[0] == 0) { - dprintf("kind: None!\n"); - } else { - dprintf(" kind: %s\n", interrupt_controller.kind); - dprintf(" regs: %#" B_PRIx64 ", %#" B_PRIx64 "\n", - interrupt_controller.regs1.start, - interrupt_controller.regs1.size); - dprintf(" %#" B_PRIx64 ", %#" B_PRIx64 "\n", - interrupt_controller.regs2.start, - interrupt_controller.regs2.size); - } -#endif + + arch_dtb_set_kernel_args(); } diff --git a/src/system/boot/platform/efi/dtb.h b/src/system/boot/platform/efi/dtb.h index 4595e90b3c..8257bbc742 100644 --- a/src/system/boot/platform/efi/dtb.h +++ b/src/system/boot/platform/efi/dtb.h @@ -15,6 +15,9 @@ extern void dtb_init(); extern void dtb_set_kernel_args(); +bool dtb_get_reg(const void* fdt, int node, uint32 addressCells, uint32 sizeCells, size_t idx, addr_range& range); +bool dtb_has_fdt_string(const char* prop, int size, const char* pattern); + #endif /* !_ASSEMBLER */