summaryrefslogtreecommitdiff
path: root/arch/riscv/trap/swtch.S
diff options
context:
space:
mode:
Diffstat (limited to 'arch/riscv/trap/swtch.S')
-rw-r--r--arch/riscv/trap/swtch.S96
1 files changed, 96 insertions, 0 deletions
diff --git a/arch/riscv/trap/swtch.S b/arch/riscv/trap/swtch.S
new file mode 100644
index 0000000..dbae43d
--- /dev/null
+++ b/arch/riscv/trap/swtch.S
@@ -0,0 +1,96 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* Copyright (C) 2026 Richard Qin */
+
+/*
+ * Context Switch & Kernel Thread Trampoline (RISC-V 64)
+ *
+ * context_switch: saves/restores callee-saved registers.
+ * kthread_entry_trampoline: entry point for newly created kernel threads.
+ * After context_switch loads the new Context, execution lands here via
+ * Context.ra = kthread_entry_trampoline. The entry function and argument
+ * are in s0 and s1 respectively, set by sched_init/create_tcb.
+ *
+ * The trampoline calls the MI-layer kthread_entry(entry, arg).
+ *
+ * Reference: docs/specs/scheduler.md ยง6
+ */
+
+ .section .text
+
+/* ========================================================================
+ * void context_switch(Context* old_ctx, Context* next_ctx);
+ * a0 = old_ctx_ptr, a1 = next_ctx_ptr
+ * ======================================================================== */
+ .globl context_switch
+ .align 2
+context_switch:
+ sd ra, 0(a0)
+ sd sp, 8(a0)
+ sd s0, 16(a0)
+ sd s1, 24(a0)
+ sd s2, 32(a0)
+ sd s3, 40(a0)
+ sd s4, 48(a0)
+ sd s5, 56(a0)
+ sd s6, 64(a0)
+ sd s7, 72(a0)
+ sd s8, 80(a0)
+ sd s9, 88(a0)
+ sd s10, 96(a0)
+ sd s11, 104(a0)
+
+ ld ra, 0(a1)
+ ld sp, 8(a1)
+ ld s0, 16(a1)
+ ld s1, 24(a1)
+ ld s2, 32(a1)
+ ld s3, 40(a1)
+ ld s4, 48(a1)
+ ld s5, 56(a1)
+ ld s6, 64(a1)
+ ld s7, 72(a1)
+ ld s8, 80(a1)
+ ld s9, 88(a1)
+ ld s10, 96(a1)
+ ld s11, 104(a1)
+
+ ret
+
+/* ========================================================================
+ * kthread_entry_trampoline
+ *
+ * Reached via context_switch when a new kthread is first scheduled.
+ * Context was set up by create_tcb():
+ * s0 = entry function pointer
+ * s1 = argument pointer
+ *
+ * Calls the MI-layer C++ function:
+ * void kthread_entry(void (*entry)(void*), void* arg);
+ * ======================================================================== */
+ .globl kthread_entry_trampoline
+ .align 2
+kthread_entry_trampoline:
+ mv a0, s0 /* a0 = entry function */
+ mv a1, s1 /* a1 = argument */
+ call kthread_entry /* MI-layer C++ function */
+
+ /* kthread_entry should never return, but if it does: */
+ wfi
+ j kthread_entry_trampoline + 12 /* loop on wfi */
+
+/* ========================================================================
+ * ret_from_fork
+ *
+ * Trampoline for newly forked processes.
+ * Context is set up by fork() so that s0 contains the TrapFrame pointer.
+ *
+ * Calls the MI-layer C++ function:
+ * void fork_child_entry(TrapFrame* tf);
+ * ======================================================================== */
+ .globl ret_from_fork
+ .align 2
+ret_from_fork:
+ mv a0, s0 /* a0 = TrapFrame pointer */
+ call fork_child_entry /* does not return, eventually calls userret */
+ wfi
+ j ret_from_fork + 8 \ No newline at end of file