diff options
author | Himbeer <himbeer@disroot.org> | 2024-05-18 10:58:01 +0200 |
---|---|---|
committer | Himbeer <himbeer@disroot.org> | 2024-05-18 10:58:01 +0200 |
commit | 573f58487f899563e1ae08fd829eb4053a1f10ac (patch) | |
tree | e051c2169533aea52885c1cd12e0636afe468399 | |
parent | 71a8c414d0ffcb6426f440542ea97e54133034f6 (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.zig | 46 | ||||
-rw-r--r-- | src/interrupts.zig | 5 | ||||
-rw-r--r-- | src/main.zig | 51 | ||||
-rw-r--r-- | src/paging.zig | 4 | ||||
-rw-r--r-- | src/uart.zig | 58 |
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) }; +} |