summaryrefslogtreecommitdiff
path: root/na/arch/riscv/include
diff options
context:
space:
mode:
authorRichard Qin <richard.qin.x@gmail.com>2026-04-17 01:05:31 +0800
committerRichard Qin <richard.qin.x@gmail.com>2026-04-17 01:05:31 +0800
commite2564d112ba03b432f9f44f445cbc4a3ed85751a (patch)
tree1541ee010bfd9c0e614fc91c2de5c9aa741418ae /na/arch/riscv/include
parent81563cb415d8214f1d1e34f73d49a404424f8f2c (diff)
downloadlume-e2564d112ba03b432f9f44f445cbc4a3ed85751a.tar.gz
lume-e2564d112ba03b432f9f44f445cbc4a3ed85751a.tar.xz
feat: add initial RISC-V architecture support and core kernel functionality
- Implement MMU hardware primitives for RISC-V SV39 in mmu.h - Create trap vector control primitives in trap.h - Define trap frame structure for RISC-V in trapframe.h - Add assembly routines for context switching in swtch.S - Implement trap vector entry/exit in trap_vector.S - Introduce basic error number definitions in errno.h - Provide placement new/delete operators in new.h - Define kernel panic handler in panic.h and implement in panic.cc - Establish basic type definitions in types.h - Create the kernel main entry point in main.cc with global initialization - Add synchronization primitives using spinlocks in spinlock.h and spinlock.cc - Define per-CPU state tracking for interrupts in cpu_state.h - Create a linker script for the kernel in linker.ld - Update module makefiles for kernel and library components
Diffstat (limited to 'na/arch/riscv/include')
-rw-r--r--na/arch/riscv/include/arch/context.h33
-rw-r--r--na/arch/riscv/include/arch/cpu.h64
-rw-r--r--na/arch/riscv/include/arch/mmu.h63
-rw-r--r--na/arch/riscv/include/arch/trap.h82
-rw-r--r--na/arch/riscv/include/arch/trapframe.h92
5 files changed, 334 insertions, 0 deletions
diff --git a/na/arch/riscv/include/arch/context.h b/na/arch/riscv/include/arch/context.h
new file mode 100644
index 0000000..3d935fa
--- /dev/null
+++ b/na/arch/riscv/include/arch/context.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* Copyright (C) 2026 Richard Qin */
+
+#pragma once
+
+/*
+ * Context Switch Structure (RISC-V 64)
+ *
+ * Holds only callee-saved registers for voluntary (non-preemptive)
+ * context switches between kernel threads / tasks.
+ *
+ * Used by: arch::context_switch() in swtch.S
+ * Reference: docs/specs/arch_abstraction.md §3.1
+ */
+
+#include <lume/types.h>
+
+namespace arch {
+
+struct Context {
+ uint64 ra; // 0: Return address
+ uint64 sp; // 8: Stack pointer
+ uint64 s[12]; // 16: s0-s11 (callee-saved registers)
+};
+
+static_assert(sizeof(Context) == 112);
+
+// Assembly-implemented context switch.
+// Saves current CPU registers to old_ctx, loads next_ctx into CPU.
+// Defined in arch/riscv/trap/swtch.S
+extern "C" void context_switch(Context* old_ctx, Context* next_ctx);
+
+} // namespace arch
diff --git a/na/arch/riscv/include/arch/cpu.h b/na/arch/riscv/include/arch/cpu.h
new file mode 100644
index 0000000..644ae37
--- /dev/null
+++ b/na/arch/riscv/include/arch/cpu.h
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* Copyright (C) 2026 Richard Qin */
+
+#pragma once
+
+/*
+ * CPU Control & Status Primitives (RISC-V 64)
+ *
+ * Provides interrupt enable/disable, CPU ID, timer, and halt.
+ * All functions are static inline — zero call overhead.
+ *
+ * Precondition: tp register must be initialized with CPU ID
+ * by entry.S before any of these functions are called.
+ *
+ * Reference: docs/specs/arch_abstraction.md §4.1
+ */
+
+#include <lume/types.h>
+
+/* RISC-V sstatus register bit definitions */
+#define SSTATUS_SIE (1UL << 1) /* Supervisor Interrupt Enable */
+#define SSTATUS_SPIE (1UL << 5) /* Supervisor Previous Interrupt Enable */
+#define SSTATUS_SPP (1UL << 8) /* Supervisor Previous Privilege (0=U, 1=S) */
+
+namespace arch::cpu {
+
+// Get current CPU ID (from tp register, set by entry.S)
+static inline uint64 id() {
+ uint64 val;
+ __asm__ volatile("mv %0, tp" : "=r"(val));
+ return val;
+}
+
+// Enable interrupts (set sstatus.SIE = 1)
+static inline void intr_on() {
+ __asm__ volatile("csrs sstatus, %0" :: "r"(SSTATUS_SIE));
+}
+
+// Disable interrupts (clear sstatus.SIE = 0)
+static inline void intr_off() {
+ __asm__ volatile("csrc sstatus, %0" :: "r"(SSTATUS_SIE));
+}
+
+// Check if interrupts are currently enabled
+static inline bool intr_enabled() {
+ uint64 sstatus;
+ __asm__ volatile("csrr %0, sstatus" : "=r"(sstatus));
+ return (sstatus & SSTATUS_SIE) != 0;
+}
+
+// Halt CPU until next interrupt (wfi instruction)
+static inline void halt_until_interrupt() {
+ __asm__ volatile("wfi");
+}
+
+// Read hardware monotonic timer (rdtime instruction)
+// Returns ticks since boot; frequency from FDT timebase-frequency.
+static inline uint64 read_time() {
+ uint64 val;
+ __asm__ volatile("rdtime %0" : "=r"(val));
+ return val;
+}
+
+} // namespace arch::cpu
diff --git a/na/arch/riscv/include/arch/mmu.h b/na/arch/riscv/include/arch/mmu.h
new file mode 100644
index 0000000..a0ee1ed
--- /dev/null
+++ b/na/arch/riscv/include/arch/mmu.h
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* Copyright (C) 2026 Richard Qin */
+
+#pragma once
+
+/*
+ * MMU Hardware Primitives (RISC-V SV39)
+ *
+ * Page table switching, TLB flushing, and fault address reading.
+ * All functions are static inline — zero call overhead.
+ *
+ * Note on SMP: flush_tlb_page() only flushes the LOCAL CPU's TLB.
+ * Cross-CPU TLB shootdown via IPI is not yet implemented.
+ *
+ * Reference: docs/specs/arch_abstraction.md §4.2
+ */
+
+#include <lume/types.h>
+
+/* SATP register: mode field for SV39 */
+#define SATP_SV39 (8UL << 60)
+
+/* SATP PPN mask (bits 43:0) */
+#define SATP_PPN_MASK ((1UL << 44) - 1)
+
+namespace arch::mmu {
+
+// Read the faulting virtual address from stval (set by HW on page fault)
+static inline uint64 get_fault_address() {
+ uint64 val;
+ __asm__ volatile("csrr %0, stval" : "=r"(val));
+ return val;
+}
+
+// Switch the top-level page table.
+// Takes a PHYSICAL ADDRESS (not PPN); internally shifts right by 12
+// and combines with SV39 mode bits before writing to satp.
+static inline void set_page_table(uint64 physical_pgdir_addr) {
+ uint64 ppn = physical_pgdir_addr >> 12;
+ uint64 satp_val = SATP_SV39 | ppn;
+ __asm__ volatile("csrw satp, %0" :: "r"(satp_val));
+ // Note: caller should call flush_tlb_all() after this
+}
+
+// Read the current page table physical address.
+// Extracts PPN from satp and converts back to physical address.
+static inline uint64 get_page_table() {
+ uint64 satp_val;
+ __asm__ volatile("csrr %0, satp" : "=r"(satp_val));
+ return (satp_val & SATP_PPN_MASK) << 12;
+}
+
+// Flush the entire TLB (all ASIDs, all addresses)
+static inline void flush_tlb_all() {
+ __asm__ volatile("sfence.vma zero, zero" ::: "memory");
+}
+
+// Flush a single TLB entry for the given virtual address
+static inline void flush_tlb_page(uint64 vaddr) {
+ __asm__ volatile("sfence.vma %0, zero" :: "r"(vaddr) : "memory");
+}
+
+} // namespace arch::mmu
diff --git a/na/arch/riscv/include/arch/trap.h b/na/arch/riscv/include/arch/trap.h
new file mode 100644
index 0000000..c99d8cb
--- /dev/null
+++ b/na/arch/riscv/include/arch/trap.h
@@ -0,0 +1,82 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* Copyright (C) 2026 Richard Qin */
+
+#pragma once
+
+/*
+ * Trap Vector Control Primitives (RISC-V 64)
+ *
+ * Set/read the S-mode trap vector (stvec), trap cause (scause),
+ * and trap value (stval) registers.
+ *
+ * Reference: docs/specs/arch_abstraction.md §4.3
+ */
+
+#include <lume/types.h>
+
+/* scause interrupt bit (bit 63): 1 = interrupt, 0 = exception */
+#define SCAUSE_INTERRUPT (1UL << 63)
+
+/* Exception cause codes (scause with bit 63 = 0) */
+#define EXC_INST_MISALIGNED 0
+#define EXC_INST_ACCESS_FAULT 1
+#define EXC_ILLEGAL_INST 2
+#define EXC_BREAKPOINT 3
+#define EXC_LOAD_MISALIGNED 4
+#define EXC_LOAD_ACCESS_FAULT 5
+#define EXC_STORE_MISALIGNED 6
+#define EXC_STORE_ACCESS_FAULT 7
+#define EXC_ECALL_FROM_U 8
+#define EXC_ECALL_FROM_S 9
+#define EXC_INST_PAGE_FAULT 12
+#define EXC_LOAD_PAGE_FAULT 13
+#define EXC_STORE_PAGE_FAULT 15
+
+/* Interrupt cause codes (scause with bit 63 = 1, lower bits) */
+#define IRQ_S_SOFTWARE 1
+#define IRQ_S_TIMER 5
+#define IRQ_S_EXTERNAL 9
+
+namespace arch::trap {
+
+// Set S-mode trap vector base address (writes stvec).
+// Mode: Direct (all traps go to handler_addr).
+static inline void set_vector(uint64 handler_addr) {
+ // Lowest 2 bits of stvec = mode. 0 = Direct.
+ __asm__ volatile("csrw stvec, %0" :: "r"(handler_addr));
+}
+
+// Read current trap vector base address
+static inline uint64 get_vector() {
+ uint64 val;
+ __asm__ volatile("csrr %0, stvec" : "=r"(val));
+ return val;
+}
+
+// Read trap cause register (scause)
+// Bit 63: 1=interrupt, 0=exception. Lower bits: cause code.
+static inline uint64 get_cause() {
+ uint64 val;
+ __asm__ volatile("csrr %0, scause" : "=r"(val));
+ return val;
+}
+
+// Read trap value register (stval)
+// Contains faulting address (page faults) or faulting instruction.
+static inline uint64 get_value() {
+ uint64 val;
+ __asm__ volatile("csrr %0, stval" : "=r"(val));
+ return val;
+}
+
+// Check if a scause value represents an interrupt (vs exception)
+static inline bool is_interrupt(uint64 cause) {
+ return (cause & SCAUSE_INTERRUPT) != 0;
+}
+
+// Extract the cause code (strip the interrupt bit)
+static inline uint64 cause_code(uint64 cause) {
+ return cause & ~SCAUSE_INTERRUPT;
+}
+
+} // namespace arch::trap
diff --git a/na/arch/riscv/include/arch/trapframe.h b/na/arch/riscv/include/arch/trapframe.h
new file mode 100644
index 0000000..de49e9c
--- /dev/null
+++ b/na/arch/riscv/include/arch/trapframe.h
@@ -0,0 +1,92 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* Copyright (C) 2026 Richard Qin */
+
+#pragma once
+
+/*
+ * Trap Frame Structure (RISC-V 64)
+ *
+ * Saved/restored by the assembly trap_vector on every interrupt,
+ * exception, or system call. Contains the full CPU snapshot needed
+ * to resume execution after trap handling.
+ *
+ * Layout must match the assembly offsets in trap_vector.S exactly.
+ * Reference: docs/specs/arch_abstraction.md §3.2
+ */
+
+/*
+ * TrapFrame field offsets for use in assembly.
+ * These must be kept in sync with the struct layout below.
+ * Placed before any C++ code so assembly can #include this file.
+ */
+#define TF_KERNEL_SATP 0
+#define TF_KERNEL_SP 8
+#define TF_KERNEL_TRAP 16
+#define TF_KERNEL_CPUID 24
+#define TF_EPC 32
+#define TF_SSTATUS 40
+#define TF_RA 48
+#define TF_SP 56
+#define TF_GP 64
+#define TF_TP 72
+#define TF_T0 80
+#define TF_T1 88
+#define TF_T2 96
+#define TF_T3 104
+#define TF_T4 112
+#define TF_T5 120
+#define TF_T6 128
+#define TF_S0 136
+#define TF_S1 144
+#define TF_S2 152
+#define TF_S3 160
+#define TF_S4 168
+#define TF_S5 176
+#define TF_S6 184
+#define TF_S7 192
+#define TF_S8 200
+#define TF_S9 208
+#define TF_S10 216
+#define TF_S11 224
+#define TF_A0 232
+#define TF_A1 240
+#define TF_A2 248
+#define TF_A3 256
+#define TF_A4 264
+#define TF_A5 272
+#define TF_A6 280
+#define TF_A7 288
+#define TF_SIZE 296
+
+#ifndef __ASSEMBLER__
+
+#include <lume/types.h>
+
+namespace arch {
+
+struct TrapFrame {
+ /* ---- Kernel metadata (offset 0-39) ---- */
+ uint64 kernel_satp; // 0: Kernel page table (written to satp on trap entry)
+ uint64 kernel_sp; // 8: Top of kernel stack for this task
+ uint64 kernel_trap; // 16: Address of C++ trap_handler function
+ uint64 kernel_cpu_id; // 24: CPU ID (loaded into tp on trap entry)
+ uint64 epc; // 32: Interrupted instruction address (sepc)
+
+ /* ---- CSR backup (offset 40-47) ---- */
+ uint64 sstatus; // 40: Privilege status (SPP, SPIE bits)
+
+ /* ---- General-purpose registers (offset 48-295) ---- */
+ uint64 ra; // 48: x1 - Return address
+ uint64 sp; // 56: x2 - User stack pointer
+ uint64 gp; // 64: x3 - Global pointer
+ uint64 tp; // 72: x4 - Thread pointer
+ uint64 t[7]; // 80: x5-x7, x28-x31 (t0-t6, caller-saved temporaries)
+ uint64 s[12]; // 136: x8-x9, x18-x27 (s0-s11, callee-saved)
+ uint64 a[8]; // 232: x10-x17 (a0-a7, arguments / syscall params)
+};
+
+static_assert(sizeof(TrapFrame) == 296, "TrapFrame size mismatch with assembly offsets");
+
+} // namespace arch
+
+#endif /* __ASSEMBLER__ */