diff --git a/headers/private/kernel/arch/arm/arch_kernel_args.h b/headers/private/kernel/arch/arm/arch_kernel_args.h index 9758ea7035..78b34058d7 100644 --- a/headers/private/kernel/arch/arm/arch_kernel_args.h +++ b/headers/private/kernel/arch/arm/arch_kernel_args.h @@ -11,17 +11,19 @@ #include +#include #define _PACKED __attribute__((packed)) + // kernel args typedef struct { - int cpu_type; - int fpu_type; - int mmu_type; - int platform; - int machine; // platform specific machine type + int cpu_type; + int fpu_type; + int mmu_type; + int platform; + int machine; // platform specific machine type // architecture specific uint32 phys_pgdir; @@ -31,6 +33,8 @@ typedef struct { // needed for UEFI, otherwise kernel acpi support can't find ACPI root FixedWidthPointer acpi_root; FixedWidthPointer fdt; + + uart_info uart; } _PACKED arch_kernel_args; #endif /* KERNEL_ARCH_ARM_KERNEL_ARGS_H */ diff --git a/headers/private/kernel/arch/arm/arch_uart_pl011.h b/headers/private/kernel/arch/arm/arch_uart_pl011.h index de335baccd..04f513d220 100644 --- a/headers/private/kernel/arch/arm/arch_uart_pl011.h +++ b/headers/private/kernel/arch/arm/arch_uart_pl011.h @@ -1,5 +1,5 @@ /* - * Copyright 2011-2012 Haiku, Inc. All rights reserved. + * Copyright 2011-2021 Haiku, Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -16,6 +16,9 @@ #include +#define UART_KIND_PL011 "pl011" + + class ArchUARTPL011 : public DebugUART { public: ArchUARTPL011(addr_t base, int64 clock); diff --git a/headers/private/kernel/arch/generic/debug_uart_8250.h b/headers/private/kernel/arch/generic/debug_uart_8250.h index e8edf8552d..45a06fd8f9 100644 --- a/headers/private/kernel/arch/generic/debug_uart_8250.h +++ b/headers/private/kernel/arch/generic/debug_uart_8250.h @@ -17,6 +17,9 @@ #include "debug_uart.h" +#define UART_KIND_8250 "8250" + + class DebugUART8250 : public DebugUART { public: DebugUART8250(addr_t base, int64 clock); diff --git a/headers/private/kernel/arch/riscv64/arch_kernel_args.h b/headers/private/kernel/arch/riscv64/arch_kernel_args.h index 02706489e0..99459ef8dc 100644 --- a/headers/private/kernel/arch/riscv64/arch_kernel_args.h +++ b/headers/private/kernel/arch/riscv64/arch_kernel_args.h @@ -11,6 +11,7 @@ #include +#include #define _PACKED __attribute__((packed)) @@ -24,21 +25,6 @@ enum { kPlatformSbi, }; -enum { - kUartKindNone, - kUartKind8250, - kUartKindSifive, - kUartKindPl011, -}; - - -typedef struct { - uint32 kind; - addr_range regs; - uint32 irq; - int64 clock; -} _PACKED ArchUart; - // kernel args typedef struct { @@ -62,7 +48,8 @@ typedef struct { addr_range htif; addr_range plic; addr_range clint; - ArchUart uart; + + uart_info uart; } _PACKED arch_kernel_args; #endif /* KERNEL_ARCH_RISCV64_KERNEL_ARGS_H */ diff --git a/headers/private/kernel/arch/riscv64/arch_uart_sifive.h b/headers/private/kernel/arch/riscv64/arch_uart_sifive.h index 96f78866b5..79f83dff24 100644 --- a/headers/private/kernel/arch/riscv64/arch_uart_sifive.h +++ b/headers/private/kernel/arch/riscv64/arch_uart_sifive.h @@ -9,6 +9,9 @@ #include +#define UART_KIND_SIFIVE "sifive" + + // UARTSifiveRegs.ie, ip enum { kUartSifiveTxwm = 1 << 0, diff --git a/headers/private/kernel/boot/uart.h b/headers/private/kernel/boot/uart.h new file mode 100644 index 0000000000..25d207a53e --- /dev/null +++ b/headers/private/kernel/boot/uart.h @@ -0,0 +1,21 @@ +/* + * Copyright 2021 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef KERNEL_BOOT_UART_H +#define KERNEL_BOOT_UART_H + + +#include +#include + + +typedef struct { + char kind[32]; + addr_range regs; + uint32 irq; + int64 clock; +} __attribute__((packed)) uart_info; + + +#endif /* KERNEL_BOOT_UART_H */ diff --git a/src/system/boot/platform/efi/arch/riscv64/arch_mmu.cpp b/src/system/boot/platform/efi/arch/riscv64/arch_mmu.cpp index 5fc1fed7fd..b48811b667 100644 --- a/src/system/boot/platform/efi/arch/riscv64/arch_mmu.cpp +++ b/src/system/boot/platform/efi/arch/riscv64/arch_mmu.cpp @@ -10,9 +10,9 @@ #include #include #include - #include #include +#include #include "mmu.h" #include "efi_platform.h" @@ -419,10 +419,12 @@ arch_mmu_generate_post_efi_page_tables(size_t memory_map_size, MapAddrRange(gKernelArgs.arch_args.clint, (1 << pteRead) | (1 << pteWrite)); MapAddrRange(gKernelArgs.arch_args.htif, (1 << pteRead) | (1 << pteWrite)); MapAddrRange(gKernelArgs.arch_args.plic, (1 << pteRead) | (1 << pteWrite)); - if (gKernelArgs.arch_args.uart.kind != kUartKindNone) { - // !!! - MapRange(gKernelArgs.arch_args.uart.regs.start, gKernelArgs.arch_args.uart.regs.start, gKernelArgs.arch_args.uart.regs.size, (1 << pteRead) | (1 << pteWrite)); + if (strcmp(gKernelArgs.arch_args.uart.kind, "") != 0) { + MapRange(gKernelArgs.arch_args.uart.regs.start, + gKernelArgs.arch_args.uart.regs.start, + gKernelArgs.arch_args.uart.regs.size, + (1 << pteRead) | (1 << pteWrite)); MapAddrRange(gKernelArgs.arch_args.uart.regs, (1 << pteRead) | (1 << pteWrite)); } diff --git a/src/system/boot/platform/efi/dtb.cpp b/src/system/boot/platform/efi/dtb.cpp index 12004585b9..3b54c980d7 100644 --- a/src/system/boot/platform/efi/dtb.cpp +++ b/src/system/boot/platform/efi/dtb.cpp @@ -7,13 +7,19 @@ */ +#include +#include +#if defined(__riscv) +# include +#elif defined(__ARM__) || defined(__ARM64__) +# include +#endif #include #include #include +#include +#include #include -#include -#include -#include #include @@ -37,7 +43,6 @@ static uint64 sTimerFrequency = 10000000; static addr_range sPlic = {0}; static addr_range sClint = {0}; -static ArchUart sUart = {.kind = kUartKindNone}; static void WriteString(const char *str) {dprintf("%s", str);} @@ -46,6 +51,29 @@ static void WriteHex(uint64_t val, int n) {dprintf("%08" B_PRIx64, val);} static void WriteInt(int64_t val) {dprintf("%" B_PRId64, val);} +template DebugUART* +get_uart(addr_t base, int64 clock) { + static char buffer[sizeof(T)]; + return new(buffer) T(base, clock); +} + + +const struct supported_uarts { + const char* dtb_compat; + const char* kind; + DebugUART* (*uart_driver_init)(addr_t base, int64 clock); +} kSupportedUarts[] = { + { "ns16550a", UART_KIND_8250, &get_uart }, + { "ns16550", UART_KIND_8250, &get_uart }, +#if defined(__riscv) + { "sifive,uart0", UART_KIND_SIFIVE, &get_uart }, +#elif defined(__ARM__) || defined(__ARM64__) + { "arm,pl011", UART_KIND_PL011, &get_uart }, + { "arm,primecell", UART_KIND_PL011, &get_uart }, +#endif +}; + + static void WriteStringList(const char* prop, size_t size) { bool first = true; @@ -341,47 +369,48 @@ HandleFdt(const void* fdt, int node, uint32 addressCells, uint32 sizeCells, int compatibleLen; const char* compatible = (const char*)fdt_getprop(fdt, node, "compatible", &compatibleLen); - if (compatible == NULL) return; + + if (compatible == NULL) + return; + if (HasFdtString(compatible, compatibleLen, "riscv,clint0")) { GetReg(fdt, node, addressCells, sizeCells, 0, sClint); - } else if ( - HasFdtString(compatible, compatibleLen, "riscv,plic0") || - HasFdtString(compatible, compatibleLen, "sifive,plic-1.0.0") - ) { - GetReg(fdt, node, addressCells, sizeCells, 0, sPlic); - } else if ( - sUart.kind == kUartKindNone && ( - HasFdtString(compatible, compatibleLen, "ns16550a") || - HasFdtString(compatible, compatibleLen, "sifive,uart0") || - HasFdtString(compatible, compatibleLen, "arm,pl011") - ) - ) { - if (HasFdtString(compatible, compatibleLen, "ns16550a")) - sUart.kind = kUartKind8250; - else if (HasFdtString(compatible, compatibleLen, "sifive,uart0")) - sUart.kind = kUartKindSifive; - else if (HasFdtString(compatible, compatibleLen, "arm,pl011")) - sUart.kind = kUartKindPl011; - - GetReg(fdt, node, addressCells, sizeCells, 0, sUart.regs); - sUart.irq = GetInterrupt(fdt, node, interruptCells); - const void* prop = fdt_getprop(fdt, node, "clock-frequency", NULL); - sUart.clock = (prop == NULL) ? 0 : fdt32_to_cpu(*(uint32*)prop); - - switch (sUart.kind) { - case kUartKind8250: - gUART = arch_get_uart_8250(sUart.regs.start, sUart.clock); - break; - case kUartKindSifive: - gUART = arch_get_uart_sifive(sUart.regs.start, sUart.clock); - break; - default: - ; - } - - if (gUART != NULL) - gUART->InitEarly(); + return; } + + if (HasFdtString(compatible, compatibleLen, "riscv,plic0") + || HasFdtString(compatible, compatibleLen, "sifive,plic-1.0.0")) { + GetReg(fdt, node, addressCells, sizeCells, 0, sPlic); + return; + } + + // TODO: We should check for the "chosen" uart and prioritize that one + + uart_info &uart = gKernelArgs.arch_args.uart; + if (uart.kind[0] != 0) + return; + + // check for a uart if we don't have one + for (uint32 i = 0; i < B_COUNT_OF(kSupportedUarts); i++) { + if (HasFdtString(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, interruptCells); + const void* prop = fdt_getprop(fdt, node, "clock-frequency", NULL); + + uart.clock = (prop == NULL) ? 0 : fdt32_to_cpu(*(uint32*)prop); + + gUART = kSupportedUarts[i].uart_driver_init(uart.regs.start, + uart.clock); + } + } + + if (gUART != NULL) + gUART->InitEarly(); } @@ -391,6 +420,9 @@ dtb_init() efi_configuration_table *table = kSystemTable->ConfigurationTable; size_t entries = kSystemTable->NumberOfTableEntries; + // Ensure uart is empty before we scan for one + memset(&gKernelArgs.arch_args.uart, 0, sizeof(uart_info)); + INFO("Probing for device trees from UEFI...\n"); // Try to find an FDT @@ -450,19 +482,16 @@ dtb_set_kernel_args() gKernelArgs.arch_args.clint = sClint; #endif #if defined(__ARM__) || defined(__riscv) - gKernelArgs.arch_args.uart = sUart; - dprintf("UART:\n"); - dprintf(" kind: "); - switch (sUart.kind) { - case kUartKindNone: dprintf("none"); break; - case kUartKind8250: dprintf("8250"); break; - case kUartKindSifive: dprintf("sifive"); break; - case kUartKindPl011: dprintf("pl011"); break; - default: ; + uart_info &uart = gKernelArgs.arch_args.uart; + dprintf("Chosen UART:\n"); + if (uart.kind[0] == 0) { + dprintf("kind: None!\n"); + } else { + dprintf(" kind: %s", uart.kind); + dprintf("\n"); + dprintf(" regs: %#" B_PRIx64 ", %#" B_PRIx64 "\n", uart.regs.start, uart.regs.size); + dprintf(" irq: %" B_PRIu32 "\n", uart.irq); + dprintf(" clock: %" B_PRIu64 "\n", uart.clock); } - dprintf("\n"); - dprintf(" regs: %#" B_PRIx64 ", %#" B_PRIx64 "\n", sUart.regs.start, sUart.regs.size); - dprintf(" irq: %" B_PRIu32 "\n", sUart.irq); - dprintf(" clock: %" B_PRIu64 "\n", sUart.clock); #endif } diff --git a/src/system/kernel/arch/riscv64/arch_debug_console.cpp b/src/system/kernel/arch/riscv64/arch_debug_console.cpp index 656e348cf4..ba0ecd1aa6 100644 --- a/src/system/kernel/arch/riscv64/arch_debug_console.cpp +++ b/src/system/kernel/arch/riscv64/arch_debug_console.cpp @@ -103,17 +103,14 @@ arch_debug_serial_early_boot_message(const char *string) status_t arch_debug_console_init(kernel_args *args) { - switch (args->arch_args.uart.kind) { - case kUartKind8250: - sArchDebugUART = arch_get_uart_8250(args->arch_args.uart.regs.start, - args->arch_args.uart.clock); - break; - case kUartKindSifive: - sArchDebugUART = arch_get_uart_sifive(args->arch_args.uart.regs.start, - args->arch_args.uart.clock); - break; - default: - ; + if (strncmp(args->arch_args.uart.kind, UART_KIND_8250, + sizeof(args->arch_args.uart.kind)) == 0) { + sArchDebugUART = arch_get_uart_8250(args->arch_args.uart.regs.start, + args->arch_args.uart.clock); + } else if (strncmp(args->arch_args.uart.kind, UART_KIND_SIFIVE, + sizeof(args->arch_args.uart.kind)) == 0) { + sArchDebugUART = arch_get_uart_sifive(args->arch_args.uart.regs.start, + args->arch_args.uart.clock); } if (sArchDebugUART != NULL)