aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHimbeer <himbeer@disroot.org>2024-05-18 10:58:01 +0200
committerHimbeer <himbeer@disroot.org>2024-05-18 10:58:01 +0200
commit573f58487f899563e1ae08fd829eb4053a1f10ac (patch)
treee051c2169533aea52885c1cd12e0636afe468399
parent71a8c414d0ffcb6426f440542ea97e54133034f6 (diff)
logging: Use UART directly if available
Some SBIs don't implement the Debug Console extension. Using the UART is one solution, supporting the SBI Legacy extension might work too if it exists.
-rw-r--r--src/Console.zig46
-rw-r--r--src/interrupts.zig5
-rw-r--r--src/main.zig51
-rw-r--r--src/paging.zig4
-rw-r--r--src/uart.zig58
5 files changed, 137 insertions, 27 deletions
diff --git a/src/Console.zig b/src/Console.zig
new file mode 100644
index 0000000..a54bb41
--- /dev/null
+++ b/src/Console.zig
@@ -0,0 +1,46 @@
+// SPDX-FileCopyrightText: 2024 Himbeer <himbeer@disroot.org>
+//
+// SPDX-License-Identifier: AGPL-3.0-or-later
+
+const std = @import("std");
+
+const debug_console = @import("sbi/debug_console.zig");
+const fdt = @import("fdt.zig");
+const paging = @import("paging.zig");
+const uart = @import("uart.zig");
+
+provider: Provider,
+
+const Self = @This();
+
+pub const Provider = union(enum) {
+ uart_port: uart.Port.Writer,
+ sbi_debug: debug_console.Writer,
+};
+
+pub fn init(kmem: *paging.Table, dt: *const fdt.Tree, allocator: std.mem.Allocator) !void {
+ if (uart.default == null) {
+ try uart.init(kmem, dt, allocator);
+ }
+}
+
+pub fn autoChoose() ?Self {
+ if (uart.default) |uart_con| {
+ return .{
+ .provider = .{ .uart_port = uart_con.writer() },
+ };
+ } else if (debug_console.writer()) |sbi_con| {
+ return .{
+ .provider = .{ .sbi_debug = sbi_con },
+ };
+ } else |_| {}
+
+ return null;
+}
+
+pub fn writer(console: *const Self) std.io.AnyWriter {
+ switch (console.provider) {
+ .uart_port => return console.provider.uart_port.any(),
+ .sbi_debug => return console.provider.sbi_debug.any(),
+ }
+}
diff --git a/src/interrupts.zig b/src/interrupts.zig
index eb42ff1..de762d3 100644
--- a/src/interrupts.zig
+++ b/src/interrupts.zig
@@ -4,7 +4,7 @@
const std = @import("std");
-const debug_console = @import("sbi/debug_console.zig");
+const Console = @import("Console.zig");
const instructions = @import("instructions.zig");
const paging = @import("paging.zig");
const plic = @import("plic.zig");
@@ -114,7 +114,8 @@ export fn handleTrap(epc: usize, tval: usize, cause_bits: usize, hart_id: usize,
_ = &status;
_ = &frame;
- const w = debug_console.writer() catch while (true) {};
+ const console = Console.autoChoose() orelse while (true) asm volatile ("wfi");
+ const w = console.writer();
const cause: Cause = @bitCast(cause_bits);
diff --git a/src/main.zig b/src/main.zig
index d727d6f..540e8f8 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -4,7 +4,7 @@
const std = @import("std");
-const debug_console = @import("sbi/debug_console.zig");
+const Console = @import("Console.zig");
const fdt = @import("fdt.zig");
const instructions = @import("instructions.zig");
const interrupts = @import("interrupts.zig");
@@ -25,7 +25,8 @@ pub fn panic(msg: []const u8, error_return_trace: ?*std.builtin.StackTrace, ret_
@setCold(true);
- const w = debug_console.writer() catch while (true) asm volatile ("wfi");
+ const console = Console.autoChoose() orelse while (true) asm volatile ("wfi");
+ const w = console.writer();
w.print("\r\n", .{}) catch while (true) asm volatile ("wfi");
w.print("= !! ========== !! =\r\n", .{}) catch while (true) asm volatile ("wfi");
@@ -49,20 +50,11 @@ export fn _start() callconv(.Naked) noreturn {
}
fn kmain(hart_id: usize, fdt_blob: *fdt.RawHeader) noreturn {
- const w = debug_console.writer() catch while (true) {};
- w.print("Kernel init\r\n", .{}) catch while (true) {};
-
- run(hart_id, fdt_blob, w) catch |err| std.debug.panic("Hart {d}: {any}", .{ hart_id, err });
+ run(hart_id, fdt_blob) catch |err| std.debug.panic("Hart {d}: {any}", .{ hart_id, err });
}
-fn run(hart_id: usize, fdt_blob: *fdt.RawHeader, w: debug_console.Writer) !noreturn {
- try w.print("\r\n", .{});
-
- try w.print("Hart : {d}\r\n", .{hart_id});
- try w.print("FDT address : 0x{x:0>8}\r\n", .{@intFromPtr(fdt_blob)});
-
+fn run(hart_id: usize, fdt_blob: *fdt.RawHeader) !noreturn {
if (hart_id > ~@as(u16, 0)) return Error.HartIdOutOfRange;
- if (@intFromPtr(fdt_blob) < 0xf000000) return Error.SuspiciousFdtAddr;
const dt_header = try fdt.Header.parse(fdt_blob);
@@ -70,6 +62,26 @@ fn run(hart_id: usize, fdt_blob: *fdt.RawHeader, w: debug_console.Writer) !noret
const kmem: *paging.Table = @alignCast(@ptrCast(try paging.zeroedAlloc(1)));
+ try kmem.mapKernel();
+ try kmem.mapFdt(&dt_header);
+
+ var chunk_allocator = try mem.ChunkAllocator(.{ .auto_merge_free = true }).init(128);
+ const allocator = chunk_allocator.allocator();
+
+ fdt.default = try dt_header.parseTree(allocator);
+
+ try Console.init(kmem, &fdt.default, allocator);
+
+ const console = Console.autoChoose() orelse while (true) asm volatile ("wfi");
+ const w = console.writer();
+
+ try w.print("\r\n", .{});
+ try w.print("Console init\r\n", .{});
+ try w.print("\r\n", .{});
+
+ try w.print("Hart : {d}\r\n", .{hart_id});
+ try w.print("FDT address : 0x{x:0>8}\r\n", .{@intFromPtr(fdt_blob)});
+
try w.print("\r\n", .{});
try w.print("===================== Kernel Page Table =====================\r\n", .{});
try w.print("MMIO: 0x{x:0>8} - 0x{x:0>8} -> identity mapped (rw-)\r\n", .{ paging.mmio_start, paging.mmio_end });
@@ -87,10 +99,8 @@ fn run(hart_id: usize, fdt_blob: *fdt.RawHeader, w: debug_console.Writer) !noret
try w.print("=============================================================\r\n", .{});
try w.print("\r\n", .{});
- try kmem.mapKernel();
- try kmem.mapFdt(&dt_header);
-
instructions.setSatp(kmem.satp(0));
+
try w.print("Paging : Sv39\r\n", .{});
interrupts.init();
@@ -99,15 +109,6 @@ fn run(hart_id: usize, fdt_blob: *fdt.RawHeader, w: debug_console.Writer) !noret
try w.print("\r\n", .{});
- var chunk_allocator = try mem.ChunkAllocator(.{ .auto_merge_free = true }).init(64);
- const allocator = chunk_allocator.allocator();
-
- try w.print("Parse FDT\r\n", .{});
-
- fdt.default = try dt_header.parseTree(allocator);
-
- try w.print("\r\n", .{});
-
try w.print("Timer : {d} Hz\r\n", .{1 / (@as(f64, process.schedule_interval_millis) / 1000)});
try plic.init(&fdt.default, allocator);
diff --git a/src/paging.zig b/src/paging.zig
index 1c7b49f..e2860cc 100644
--- a/src/paging.zig
+++ b/src/paging.zig
@@ -440,6 +440,10 @@ pub const Table = struct {
const fdt_blob = @intFromPtr(dt_header.raw_hdr);
try root.identityMapRange(fdt_blob, fdt_blob + dt_header.total_size, EntryFlags.readOnly);
}
+
+ pub fn mapDevice(root: *Table, reg: fdt.Reg) !void {
+ try root.identityMapRange(reg.start, reg.start + reg.len, EntryFlags.readWrite);
+ }
};
pub fn init() void {
diff --git a/src/uart.zig b/src/uart.zig
new file mode 100644
index 0000000..3a15a6c
--- /dev/null
+++ b/src/uart.zig
@@ -0,0 +1,58 @@
+// SPDX-FileCopyrightText: 2024 Himbeer <himbeer@disroot.org>
+//
+// SPDX-License-Identifier: AGPL-3.0-or-later
+
+const std = @import("std");
+
+const fdt = @import("fdt.zig");
+const paging = @import("paging.zig");
+
+pub var default: ?Port = null;
+
+pub const Error = error{
+ NoSocNode,
+};
+
+pub const Port = struct {
+ reg: []volatile u8,
+ reg_shift: u6,
+
+ const lsr_temt = 1 << 5;
+
+ pub const Writer = std.io.Writer(Port, error{}, write);
+
+ fn isWriteReady(self: Port) bool {
+ return self.reg[@as(usize, 5) << self.reg_shift] & lsr_temt != 0;
+ }
+
+ pub fn write(self: Port, bytes: []const u8) !usize {
+ for (bytes) |byte| {
+ while (!self.isWriteReady()) {}
+ self.reg[0] = byte;
+ }
+
+ return bytes.len;
+ }
+
+ pub fn writer(port: Port) Writer {
+ return .{ .context = port };
+ }
+};
+
+pub fn init(kmem: *paging.Table, dt: *const fdt.Tree, allocator: std.mem.Allocator) !void {
+ var soc = fdt.findPathExact(dt, "/soc") orelse return Error.NoSocNode;
+
+ const compatible = fdt.findCompatible(&soc, &[_][]const u8{ "ns16550", "snps,dw-apb-uart" }, 1);
+
+ const node = if (compatible.len > 0) compatible[0] else return;
+
+ const regs = try node.reg(allocator);
+ defer regs.deinit();
+
+ try kmem.mapDevice(regs.items[0]);
+
+ const reg_shift_bytes = node.props.get("reg-shift");
+ const reg_shift = if (reg_shift_bytes) |bytes| std.mem.readInt(u32, bytes[0..4], .big) else 0;
+
+ default = .{ .reg = regs.items[0].slice(u8), .reg_shift = @intCast(reg_shift) };
+}