system/kernel: Rework uart management

Change-Id: I6cb31760519c8ba4542d217d6e68439602eda558
Reviewed-on: https://review.haiku-os.org/c/haiku/+/4356
Reviewed-by: Jessica Hamilton <[email protected]>
Reviewed-by: Alex von Gluck IV <[email protected]>
This commit is contained in:
Alexander von Gluck IV
2021-08-20 03:03:25 +00:00
committed by Alex von Gluck IV
parent fbd2589b8c
commit d637e0bec1
9 changed files with 141 additions and 92 deletions
@@ -11,17 +11,19 @@
#include <util/FixedWidthPointer.h>
#include <boot/uart.h>
#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<void> acpi_root;
FixedWidthPointer<void> fdt;
uart_info uart;
} _PACKED arch_kernel_args;
#endif /* KERNEL_ARCH_ARM_KERNEL_ARGS_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 <arch/generic/debug_uart.h>
#define UART_KIND_PL011 "pl011"
class ArchUARTPL011 : public DebugUART {
public:
ArchUARTPL011(addr_t base, int64 clock);
@@ -17,6 +17,9 @@
#include "debug_uart.h"
#define UART_KIND_8250 "8250"
class DebugUART8250 : public DebugUART {
public:
DebugUART8250(addr_t base, int64 clock);
@@ -11,6 +11,7 @@
#include <util/FixedWidthPointer.h>
#include <boot/uart.h>
#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 */
@@ -9,6 +9,9 @@
#include <arch/generic/debug_uart.h>
#define UART_KIND_SIFIVE "sifive"
// UARTSifiveRegs.ie, ip
enum {
kUartSifiveTxwm = 1 << 0,
+21
View File
@@ -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 <boot/addr_range.h>
#include <SupportDefs.h>
typedef struct {
char kind[32];
addr_range regs;
uint32 irq;
int64 clock;
} __attribute__((packed)) uart_info;
#endif /* KERNEL_BOOT_UART_H */
@@ -10,9 +10,9 @@
#include <arch_kernel.h>
#include <boot/platform.h>
#include <boot/stage2.h>
#include <efi/types.h>
#include <efi/boot-services.h>
#include <string.h>
#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));
}
+84 -55
View File
@@ -7,13 +7,19 @@
*/
#include <arch_smp.h>
#include <arch/generic/debug_uart_8250.h>
#if defined(__riscv)
# include <arch/riscv64/arch_uart_sifive.h>
#elif defined(__ARM__) || defined(__ARM64__)
# include <arch/arm/arch_uart_pl011.h>
#endif
#include <boot/addr_range.h>
#include <boot/platform.h>
#include <boot/stage2.h>
#include <boot/uart.h>
#include <string.h>
#include <kernel/kernel.h>
#include <arch_smp.h>
#include <arch/generic/debug_uart_8250.h>
#include <arch/riscv64/arch_uart_sifive.h>
#include <ByteOrder.h>
@@ -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 <typename T> 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<DebugUART8250> },
{ "ns16550", UART_KIND_8250, &get_uart<DebugUART8250> },
#if defined(__riscv)
{ "sifive,uart0", UART_KIND_SIFIVE, &get_uart<ArchUARTSifive> },
#elif defined(__ARM__) || defined(__ARM64__)
{ "arm,pl011", UART_KIND_PL011, &get_uart<ArchUARTPL011> },
{ "arm,primecell", UART_KIND_PL011, &get_uart<ArchUARTPL011> },
#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
}
@@ -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)