// SPDX-FileCopyrightText: 2024 Himbeer // // SPDX-License-Identifier: AGPL-3.0-or-later const std = @import("std"); const Console = @import("Console.zig"); const channel = @import("channel.zig"); const hwinfo = @import("hwinfo.zig"); const interrupts = @import("interrupts.zig"); const mem = @import("mem.zig"); const paging = @import("paging.zig"); const plic = @import("plic.zig"); const process = @import("process.zig"); const riscv = @import("riscv.zig"); const init = @embedFile("cfg/init"); const Error = error{ HartIdOutOfRange, }; const BootArgs = packed struct(usize) { hart_id: u16, reserved: u48, pub inline fn loadScratch() BootArgs { return @bitCast(riscv.sscratch.read()); } pub inline fn storeScratch(self: BootArgs) void { riscv.sscratch.write(@bitCast(self)); } }; inline fn halt() noreturn { while (true) asm volatile ("wfi"); } pub fn panic(msg: []const u8, error_return_trace: ?*std.builtin.StackTrace, ret_addr: ?usize) noreturn { _ = &error_return_trace; _ = &ret_addr; @setCold(true); var sstatus = riscv.sstatus.read(); sstatus.user_interrupt_enable = 0; sstatus.supervisor_interrupt_enable = 0; riscv.sstatus.write(sstatus); riscv.sie.write(interrupts.Enable.none); riscv.sip.write(interrupts.Enable.none); const sepc = riscv.sepc.read(); const stval = riscv.stval.read(); const console = Console.autoChoose() orelse halt(); const w = console.writer(); w.print("\r\n", .{}) catch halt(); w.print("= !! ============================= kernel panic =========================== !! =\r\n", .{}) catch halt(); w.print("{s}\r\n\r\n", .{msg}) catch halt(); w.print("------------------------------------ csr dump ----------------------------------\r\n", .{}) catch halt(); w.print("sepc = 0x{x:0>16}\r\n", .{sepc}) catch halt(); w.print("stval = 0x{x:0>16}\r\n", .{stval}) catch halt(); w.print("= !! ====================================================================== !! =\r\n", .{}) catch halt(); halt(); } export fn _start() callconv(.Naked) noreturn { // Stack grows down, use (exclusive) end instead of start. asm volatile ( \\ .option push \\ .option norelax \\ la gp, _global_pointer \\ .option pop \\ \\ la sp, _stack_end \\ j %[function] : : [function] "s" (&kmain), ); } fn kmain(hart_id: usize, _: usize) noreturn { run(hart_id) catch |err| std.debug.panic("{}", .{err}); } fn run(hart_id: usize) !noreturn { if (hart_id > ~@as(u16, 0)) return Error.HartIdOutOfRange; const hart_data = BootArgs{ .hart_id = @intCast(hart_id), .reserved = 0, }; hart_data.storeScratch(); try paging.init(); riscv.satp.write(paging.kmem.satp(0)); asm volatile ( \\ la sp, _stack_end \\ j %[function] : : [function] "s" (&pagedStart), ); unreachable; } fn pagedStart() callconv(.Naked) noreturn { asm volatile ( \\ la sp, _stack_end \\ j %[function] : : [function] "s" (&pagedMain), ); } fn pagedMain() noreturn { pagedRun() catch |err| std.debug.panic("{}", .{err}); } fn pagedRun() !noreturn { const w = Console.autoChoose().?.writer(); try w.print("\r\n", .{}); try w.print("Console init\r\n", .{}); try w.print("\r\n", .{}); const hart_data = BootArgs.loadScratch(); try w.print("Hart : {d}\r\n", .{hart_data.hart_id}); try w.print("Paging : Sv39\r\n", .{}); interrupts.init(hart_data.hart_id); riscv.sie.write(interrupts.Enable.all); try w.print("Interrupts : All\r\n", .{}); // var chunk_allocator = try mem.ChunkAllocator(.{ .auto_merge_free = true }).init(128); // const allocator = chunk_allocator.allocator(); const allocator = mem.page_allocator; try w.print("\r\n", .{}); try w.print("===================== Kernel Page Table =====================\r\n", .{}); try w.print(".text: 0x{x:0>8} - 0x{x:0>8} -> identity mapped (-r-x)\r\n", .{ @intFromPtr(paging.text_start), @intFromPtr(paging.text_end) }); try w.print(".rodata: 0x{x:0>8} - 0x{x:0>8} -> identity mapped (-r--)\r\n", .{ @intFromPtr(paging.rodata_start), @intFromPtr(paging.rodata_end) }); try w.print(".data: 0x{x:0>8} - 0x{x:0>8} -> identity mapped (-rw-)\r\n", .{ @intFromPtr(paging.data_start), @intFromPtr(paging.data_end) }); try w.print(".bss: 0x{x:0>8} - 0x{x:0>8} -> identity mapped (-rw-)\r\n", .{ @intFromPtr(paging.bss_start), @intFromPtr(paging.bss_end) }); try w.print("Stack: 0x{x:0>8} - 0x{x:0>8} -> identity mapped (-rw-)\r\n", .{ @intFromPtr(paging.stack_start), @intFromPtr(paging.stack_end) }); try w.print("Trap Stack: 0x{x:0>8} - 0x{x:0>8} -> identity mapped (-rw-)\r\n", .{ @intFromPtr(paging.stvec_stack_start), @intFromPtr(paging.stvec_stack_end) }); try w.print("\r\n", .{}); try w.print("Heap: 0x{x:0>8} - 0x{x:0>8} -> identity mapped (-rw-)\r\n", .{ @intFromPtr(paging.heap_start), @intFromPtr(paging.heap_end) }); try w.print("=============================================================\r\n", .{}); try w.print("\r\n", .{}); try w.print("Timer : {d} Hz\r\n", .{1 / (@as(f64, process.schedule_interval_millis) / 1000)}); var plics = try hwinfo.byKind(.plic); if (plics.next() != null) { try w.print("PLIC : Disabled\r\n", .{}); } else { try w.print("PLIC : Not present\r\n", .{}); } try w.print("\r\n", .{}); channel.init(allocator); try w.print("Initialize message passing\r\n", .{}); try w.print("Start init process\r\n", .{}); try process.run(allocator, @alignCast(init)); }