254 lines
6.0 KiB
Zig
254 lines
6.0 KiB
Zig
// MARKUS MAIWALD (ARCHITECT) | VOXIS FORGE (AI)
|
|
// RUMPK HAL // RISC-V ENTRY - SOVEREIGN TRAP ARCHITECTURE
|
|
const std = @import("std");
|
|
const uart = @import("uart.zig");
|
|
const virtio_net = @import("virtio_net.zig");
|
|
|
|
// =========================================================
|
|
// Entry Point (Naked)
|
|
// =========================================================
|
|
|
|
export fn _start() callconv(.naked) noreturn {
|
|
asm volatile (
|
|
// 1. Disable Interrupts
|
|
\\ csrw sie, zero
|
|
\\ csrw satp, zero
|
|
// 1.1 Enable FPU (sstatus.FS = Initial [01])
|
|
\\ li t0, 0x2000
|
|
\\ csrs sstatus, t0
|
|
|
|
// 1.2 Initialize Global Pointer
|
|
\\ .option push
|
|
\\ .option norelax
|
|
\\ la gp, __global_pointer$
|
|
\\ .option pop
|
|
|
|
// 2. Set up Stack
|
|
\\ la sp, stack_bytes
|
|
\\ li t0, 65536
|
|
\\ add sp, sp, t0
|
|
|
|
// 2.1 Install Trap Handler (Direct Mode)
|
|
\\ la t0, trap_entry
|
|
\\ csrw stvec, t0
|
|
|
|
// 3. Jump to Zig Entry
|
|
\\ call zig_entry
|
|
\\ 1: wfi
|
|
\\ j 1b
|
|
);
|
|
unreachable;
|
|
}
|
|
|
|
// Trap Frame Layout (Packed on stack)
|
|
const TrapFrame = extern struct {
|
|
ra: usize,
|
|
gp: usize,
|
|
tp: usize,
|
|
t0: usize,
|
|
t1: usize,
|
|
t2: usize,
|
|
s0: usize,
|
|
s1: usize,
|
|
a0: usize,
|
|
a1: usize,
|
|
a2: usize,
|
|
a3: usize,
|
|
a4: usize,
|
|
a5: usize,
|
|
a6: usize,
|
|
a7: usize,
|
|
s2: usize,
|
|
s3: usize,
|
|
s4: usize,
|
|
s5: usize,
|
|
s6: usize,
|
|
s7: usize,
|
|
s8: usize,
|
|
s9: usize,
|
|
s10: usize,
|
|
s11: usize,
|
|
t3: usize,
|
|
t4: usize,
|
|
t5: usize,
|
|
t6: usize,
|
|
sepc: usize,
|
|
sstatus: usize,
|
|
scause: usize,
|
|
stval: usize,
|
|
};
|
|
|
|
// Full Context Save Trap Entry
|
|
export fn trap_entry() callconv(.naked) void {
|
|
asm volatile (
|
|
// Allocate stack (36 words * 8 bytes = 288 bytes)
|
|
\\ addi sp, sp, -288
|
|
|
|
// Save GPRs
|
|
\\ sd ra, 0(sp)
|
|
\\ sd gp, 8(sp)
|
|
\\ sd tp, 16(sp)
|
|
\\ sd t0, 24(sp)
|
|
\\ sd t1, 32(sp)
|
|
\\ sd t2, 40(sp)
|
|
\\ sd s0, 48(sp)
|
|
\\ sd s1, 56(sp)
|
|
\\ sd a0, 64(sp)
|
|
\\ sd a1, 72(sp)
|
|
\\ sd a2, 80(sp)
|
|
\\ sd a3, 88(sp)
|
|
\\ sd a4, 96(sp)
|
|
\\ sd a5, 104(sp)
|
|
\\ sd a6, 112(sp)
|
|
\\ sd a7, 120(sp)
|
|
\\ sd s2, 128(sp)
|
|
\\ sd s3, 136(sp)
|
|
\\ sd s4, 144(sp)
|
|
\\ sd s5, 152(sp)
|
|
\\ sd s6, 160(sp)
|
|
\\ sd s7, 168(sp)
|
|
\\ sd s8, 176(sp)
|
|
\\ sd s9, 184(sp)
|
|
\\ sd s10, 192(sp)
|
|
\\ sd s11, 200(sp)
|
|
\\ sd t3, 208(sp)
|
|
\\ sd t4, 216(sp)
|
|
\\ sd t5, 224(sp)
|
|
\\ sd t6, 232(sp)
|
|
|
|
// Save CSRs
|
|
\\ csrr t0, sepc
|
|
\\ sd t0, 240(sp)
|
|
\\ csrr t1, sstatus
|
|
\\ sd t1, 248(sp)
|
|
\\ csrr t2, scause
|
|
\\ sd t2, 256(sp)
|
|
\\ csrr t3, stval
|
|
\\ sd t3, 264(sp)
|
|
|
|
// Call Handler (Arg0 = Frame Pointer)
|
|
\\ mv a0, sp
|
|
\\ call rss_trap_handler
|
|
|
|
// Restore CSRs (sepc might be modified by syscall handler to skip ecall)
|
|
\\ ld t0, 240(sp)
|
|
\\ csrw sepc, t0
|
|
// We restore sstatus to preserve interrupt state if needed, though usually fixed in kernel
|
|
\\ ld t1, 248(sp)
|
|
\\ csrw sstatus, t1
|
|
|
|
// Restore GPRs
|
|
\\ ld ra, 0(sp)
|
|
\\ ld gp, 8(sp)
|
|
\\ ld tp, 16(sp)
|
|
\\ ld t0, 24(sp)
|
|
\\ ld t1, 32(sp)
|
|
\\ ld t2, 40(sp)
|
|
\\ ld s0, 48(sp)
|
|
\\ ld s1, 56(sp)
|
|
\\ ld a0, 64(sp)
|
|
\\ ld a1, 72(sp)
|
|
\\ ld a2, 80(sp)
|
|
\\ ld a3, 88(sp)
|
|
\\ ld a4, 96(sp)
|
|
\\ ld a5, 104(sp)
|
|
\\ ld a6, 112(sp)
|
|
\\ ld a7, 120(sp)
|
|
\\ ld s2, 128(sp)
|
|
\\ ld s3, 136(sp)
|
|
\\ ld s4, 144(sp)
|
|
\\ ld s5, 152(sp)
|
|
\\ ld s6, 160(sp)
|
|
\\ ld s7, 168(sp)
|
|
\\ ld s8, 176(sp)
|
|
\\ ld s9, 184(sp)
|
|
\\ ld s10, 192(sp)
|
|
\\ ld s11, 200(sp)
|
|
\\ ld t3, 208(sp)
|
|
\\ ld t4, 216(sp)
|
|
\\ ld t5, 224(sp)
|
|
\\ ld t6, 232(sp)
|
|
|
|
// Deallocate stack
|
|
\\ addi sp, sp, 288
|
|
\\ sret
|
|
);
|
|
}
|
|
|
|
// L1 Kernel Logic
|
|
extern fn k_handle_syscall(nr: usize, a0: usize, a1: usize, a2: usize) usize;
|
|
|
|
extern fn k_handle_exception(scause: usize, sepc: usize, stval: usize) void;
|
|
|
|
export fn rss_trap_handler(frame: *TrapFrame) void {
|
|
const scause = frame.scause;
|
|
|
|
// 8: ECALL from U-mode
|
|
// 9: ECALL from S-mode
|
|
if (scause == 8 or scause == 9) {
|
|
// Advance PC to skip 'ecall' instruction (4 bytes)
|
|
frame.sepc += 4;
|
|
// Dispatch Syscall
|
|
const res = k_handle_syscall(frame.a7, frame.a0, frame.a1, frame.a2);
|
|
// Write result back to a0
|
|
frame.a0 = res;
|
|
return;
|
|
}
|
|
|
|
// Delegate all other exceptions to the Kernel Immune System
|
|
// It will decide whether to segregate (worker) or halt (system)
|
|
// Note: k_handle_exception handles flow control (yield/halt) and does not return
|
|
k_handle_exception(scause, frame.sepc, frame.stval);
|
|
|
|
// Safety halt if kernel returns (should be unreachable)
|
|
while (true) {}
|
|
}
|
|
|
|
export var stack_bytes: [64 * 1024]u8 align(16) = undefined;
|
|
|
|
const hud = @import("hud.zig");
|
|
extern fn kmain() void;
|
|
extern fn NimMain() void;
|
|
|
|
export fn zig_entry() void {
|
|
uart.init_riscv();
|
|
uart.print("[Rumpk L0] zig_entry reached\n");
|
|
uart.print("[Rumpk RISC-V] Handing off to Nim L1...\n");
|
|
_ = virtio_net;
|
|
NimMain();
|
|
kmain();
|
|
rumpk_halt();
|
|
}
|
|
|
|
export fn console_write(ptr: [*]const u8, len: usize) void {
|
|
uart.write_bytes(ptr[0..len]);
|
|
}
|
|
|
|
export fn console_read() c_int {
|
|
if (uart.read_byte()) |b| {
|
|
return @as(c_int, b);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
const virtio_block = @import("virtio_block.zig");
|
|
|
|
export fn hal_io_init() void {
|
|
uart.init();
|
|
virtio_net.init();
|
|
virtio_block.init();
|
|
}
|
|
|
|
export fn rumpk_halt() noreturn {
|
|
uart.print("[Rumpk RISC-V] Halting.\n");
|
|
while (true) {
|
|
asm volatile ("wfi");
|
|
}
|
|
}
|
|
|
|
var mock_ticks: u64 = 0;
|
|
export fn rumpk_timer_now_ns() u64 {
|
|
mock_ticks += 100000;
|
|
return mock_ticks;
|
|
}
|