Explorar o código

feat(arch): build up trap framework

Heinz hai 8 meses
pai
achega
477364e5d8

+ 6 - 16
arch/src/riscv64/init.rs

@@ -1,11 +1,8 @@
 use core::pin::Pin;
-use riscv::{
-    asm::sfence_vma_all, register::{
-        mhartid,
-        sscratch,
-        sstatus,
-        stvec::{self, Stvec}
-    }
+use riscv::register::{
+    mhartid,
+    sscratch,
+    sstatus
 };
 use sbi::PhysicalAddress;
 
@@ -13,7 +10,7 @@ use sbi::PhysicalAddress;
 /// 中断handler
 /// 
 
-use super::{config::smp::get_num_harts, enable_sse, setup_kernel_satp, InterruptControl};
+use super::{config::smp::get_num_harts, enable_sse, setup_kernel_satp, setup_kernel_trap, InterruptControl};
 
 /// RISC-V Hart
 pub struct CPU {
@@ -41,8 +38,7 @@ impl CPU {
 
         sscratch::write(self_mut.hart_id as usize);
 
-        // TODO: in somewhere
-        setup_trap_vector(__trap_handler_entry as usize);
+        setup_kernel_trap();
 
         // CLINT, 10_000 ms
         self_mut.interrupt.setup_timer(10_000);
@@ -147,9 +143,3 @@ macro_rules! define_smp_bootstrap {
     };
 }
 
-fn setup_trap_vector(trap_entry_addr: usize) {
-    unsafe {
-        stvec::write(Stvec::from_bits(trap_entry_addr));
-    }
-    sfence_vma_all();
-}

+ 63 - 0
arch/src/riscv64/interrupt/context.rs

@@ -0,0 +1,63 @@
+use riscv::register::sstatus::{Sstatus, SPP};
+
+
+/// Floating-point registers context.
+#[repr(C)]
+#[derive(Debug, Clone, Copy, Default)]
+pub struct FpuRegisters {
+    pub f: [u64; 32],
+    pub fcsr: u32,
+}
+
+/// Saved CPU context when a trap (interrupt or exception) occurs on RISC-V 64.
+#[repr(C)]
+#[derive(Debug, Clone, Copy)]
+pub struct TrapContext {
+    pub x: [usize; 32],
+
+    // CSRs
+    pub sstatus: Sstatus, // sstatus CSR value. Contains privilege mode, interrupt enable, FPU state.
+    pub sepc: usize,    // sepc (Supervisor Exception Program Counter). Program counter at trap.
+    
+    pub kernel_sp: usize,
+    pub kernel_ra: usize,
+    pub kernel_s: [usize; 12],
+    pub kernel_fp: usize,
+    pub kernel_tp: usize,
+
+    // may need to save
+    // FPU
+    // pub fpu_regs: FpuRegisters,
+}
+
+impl TrapContext {
+    pub fn set_return_value(&mut self, value: usize) {
+        // a0, x10
+        self.x[10] = value;
+    }
+
+    pub fn set_return_address(&mut self, addr: usize, user: bool) {
+        self.sepc = addr; // set Supervisor Exception Program Counter
+
+        // if user==true,set SPP to U-mode (0)
+        // if user==false, set SPP to S-mode (1)
+        if user {
+            self.sstatus.set_spp(SPP::User);
+        } else {
+            self.sstatus.set_spp(SPP::Supervisor);
+        }
+    }
+
+    pub fn set_stack_pointer(&mut self, sp: usize, _user: bool) {
+        self.x[2] = sp;
+    }
+
+    pub fn set_interrupt_enabled(&mut self, enabled: bool) {
+        // S mode Previous Interrupt Enable (SPIE)
+        if enabled {
+            self.sstatus.set_spie(true);
+        } else {
+            self.sstatus.set_spie(false);
+        }
+    }
+}

+ 36 - 63
arch/src/riscv64/interrupt/mod.rs

@@ -1,76 +1,29 @@
 mod plic;
 mod clint;
+mod context;
+mod trap;
 
-pub use plic::*;
-pub use clint::*;
+use plic::*;
+use clint::*;
+use context::*;
+use trap::*;
 
 /// TODO:
-/// 一开始的中断汇编
+/// 切换回到user的入口函数
 
-use riscv::register::sstatus::{self, Sstatus};
+use riscv::{
+    asm::sfence_vma_all,
+    register::{
+        sstatus::{self, Sstatus},
+        stvec::{self, Stvec}
+    }
+};
 use sbi::SbiError;
+use core::arch::global_asm;
 
 use super::platform::virt::*;
 
-/// Floating-point registers context.
-#[repr(C)]
-#[derive(Debug, Clone, Copy, Default)]
-pub struct FpuRegisters {
-    pub f: [u64; 32],
-    pub fcsr: u32,
-}
-
-/// Saved CPU context when a trap (interrupt or exception) occurs on RISC-V 64.
-#[repr(C)]
-#[derive(Debug, Clone, Copy, Default)]
-pub struct TrapContext {
-    pub x: [usize; 32],
-
-    // CSRs
-    pub sstatus: usize, // sstatus CSR value. Contains privilege mode, interrupt enable, FPU state.
-    pub sepc: usize,    // sepc (Supervisor Exception Program Counter). Program counter at trap.
-    pub scause: usize,  // scause (Supervisor Cause). Describes the cause of the trap.
-    pub stval: usize,   // stval (Supervisor Trap Value). Contains faulting address for exceptions.
-    pub satp: usize,    // satp (Supervisor Address Translation and Protection). Page table base.
-
-    // may need to save
-    // pub sscratch: usize, // sscratch (Supervisor Scratch).
-
-    // FPU
-    // pub fpu_regs: FpuRegisters,
-}
-
-impl TrapContext {
-    pub fn set_return_value(&mut self, value: usize) {
-        // a0, x10
-        self.x[10] = value;
-    }
-
-    pub fn set_return_address(&mut self, addr: usize, user: bool) {
-        self.sepc = addr; // 设置 Supervisor Exception Program Counter
-
-        // if user==true,set SPP to U-mode (0)
-        // if user==false, set SPP to S-mode (1)
-        if user {
-            self.sstatus &= !(1 << 8); // clear SPP bit
-        } else {
-            self.sstatus |= 1 << 8;  // set SPP bit
-        }
-    }
-
-    pub fn set_stack_pointer(&mut self, sp: usize, _user: bool) {
-        self.x[2] = sp;
-    }
-
-    pub fn set_interrupt_enabled(&mut self, enabled: bool) {
-        // S mode Previous Interrupt Enable (SPIE)
-        if enabled {
-            self.sstatus |= 1 << 5;
-        } else {
-            self.sstatus &= !(1 << 5);
-        }
-    }
-}
+global_asm!(include_str!("trap.S"));
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
 pub struct IrqState(usize);
@@ -184,3 +137,23 @@ impl InterruptControl {
         self.plic.claim_interrupt()
     }
 }
+
+extern "C" {
+    fn trap_from_kernel();
+    fn trap_from_user();
+}
+
+fn setup_trap_handler(trap_entry_addr: usize) {
+    unsafe {
+        stvec::write(Stvec::from_bits(trap_entry_addr));
+    }
+    sfence_vma_all();
+}
+
+pub fn setup_kernel_trap() {
+    setup_trap_handler(trap_from_kernel as usize);
+}
+
+pub fn setup_user_trap() {
+    setup_trap_handler(trap_from_user as usize);
+}

+ 139 - 0
arch/src/riscv64/interrupt/trap.S

@@ -0,0 +1,139 @@
+.altmacro
+.macro SAVE_GP n
+    sd x\n, \n*8(sp)
+.endm
+.macro LOAD_GP n
+    ld x\n, \n*8(sp)
+.endm
+
+.section .text
+    .globl trap_from_kernel
+    .globl trap_from_user
+    .globl return_to_user
+    .align 2
+
+# just like a function call
+trap_from_kernel:
+    # save s*
+    addi sp, sp, -17*8
+    sd  ra,  1*8(sp)
+    sd  t0,  2*8(sp)
+    sd  t1,  3*8(sp)
+    sd  t2,  4*8(sp)
+    sd  t3,  5*8(sp)
+    sd  t4,  6*8(sp)
+    sd  t5,  7*8(sp)
+    sd  t6,  8*8(sp)
+    sd  a0,  9*8(sp)
+    sd  a1, 10*8(sp)
+    sd  a2, 11*8(sp)
+    sd  a3, 12*8(sp)
+    sd  a4, 13*8(sp)
+    sd  a5, 14*8(sp)
+    sd  a6, 15*8(sp)
+    sd  a7, 16*8(sp)
+
+    call kernel_trap_entry
+
+    # restore s*
+    ld  ra,  1*8(sp)
+    ld  t0,  2*8(sp)
+    ld  t1,  3*8(sp)
+    ld  t2,  4*8(sp)
+    ld  t3,  5*8(sp)
+    ld  t4,  6*8(sp)
+    ld  t5,  7*8(sp)
+    ld  t6,  8*8(sp)
+    ld  a0,  9*8(sp)
+    ld  a1, 10*8(sp)
+    ld  a2, 11*8(sp)
+    ld  a3, 12*8(sp)
+    ld  a4, 13*8(sp)
+    ld  a5, 14*8(sp)
+    ld  a6, 15*8(sp)
+    ld  a7, 16*8(sp)
+    addi sp, sp, 17*8
+
+    sret
+
+trap_from_user:
+    # swap sp and sscratch(previously stored user TrapContext's address in return_to_user)
+    csrrw sp, sscratch, sp
+
+    sd x1, 1*8(sp)
+    .set n, 3
+    .rept 29
+        SAVE_GP %n
+        .set n, n+1
+    .endr
+
+    csrr t0, sstatus
+    csrr t1, sepc
+    sd t0, 32*8(sp)     # save sstatus into the TrapContext
+    sd t1, 33*8(sp)     # save sepc into the TrapContext
+
+    csrr t2, sscratch
+    sd t2, 2*8(sp)      # save user stack pointer into the TrapContext
+
+    ld ra, 35*8(sp)
+    ld s0, 36*8(sp)
+    ld s1, 37*8(sp)
+    ld s2, 38*8(sp)
+    ld s3, 39*8(sp)
+    ld s4, 40*8(sp)
+    ld s5, 41*8(sp)
+    ld s6, 42*8(sp)
+    ld s7, 43*8(sp)
+    ld s8, 44*8(sp)
+    ld s9, 45*8(sp)
+    ld s10, 46*8(sp)
+    ld s11, 47*8(sp)
+
+    ld fp, 48*8(sp)
+    ld tp, 49*8(sp)
+
+    ld sp, 34*8(sp)
+    ret
+
+# a0: pointer to TrapContext in user space (constant)
+return_to_user:
+    # sscratch store the TrapContext's address
+    csrw sscratch, a0
+
+    # offset in TrapContext's order
+    sd sp, 34*8(a0)
+    sd ra, 35*8(a0)
+    sd s0, 36*8(a0)
+    sd s1, 37*8(a0) 
+    sd s2, 38*8(a0)
+    sd s3, 39*8(a0)
+    sd s4, 40*8(a0)
+    sd s5, 41*8(a0)
+    sd s6, 42*8(a0)
+    sd s7, 43*8(a0)
+    sd s8, 44*8(a0)
+    sd s9, 45*8(a0)
+    sd s10, 46*8(a0)
+    sd s11, 47*8(a0)
+    sd fp, 48*8(a0)
+    sd tp, 49*8(a0)
+
+    mv sp, a0
+    # now sp points to TrapContext in kernel space
+
+    # restore sstatus and sepc
+    ld t0, 32*8(sp)
+    ld t1, 33*8(sp)
+    csrw sstatus, t0
+    csrw sepc, t1
+
+    # save x* expect x0 and sp
+    ld x1, 1*8(sp)
+    .set n, 3
+    .rept 29
+        LOAD_GP %n
+        .set n, n+1
+    .endr
+    ld sp, 2*8(sp)
+
+    sret

+ 32 - 0
arch/src/riscv64/interrupt/trap.rs

@@ -0,0 +1,32 @@
+use super::setup_kernel_trap;
+
+use riscv::register::{scause, sepc, stval};
+
+/// TODO:
+/// kernel_trap_entry, 暂时不知道要干什么,大概是处理一下原因,然后跳到default handler
+/// user_trap_entry, 大概是一样的
+/// trap_return, 估计不是在这里写,还不太清楚
+
+#[no_mangle]
+pub fn kernel_trap_entry() {
+    let stval = stval::read();
+    let scause = scause::read();
+    let sepc = sepc::read();
+    let cause = scause.cause();
+
+    match scause.cause() {
+        scause::Trap::Interrupt(_) => todo!(),
+        scause::Trap::Exception(_) => todo!(),
+    }
+}
+
+#[no_mangle]
+pub fn user_trap_entry() {
+    setup_kernel_trap();
+
+}
+
+#[no_mangle]
+pub fn trap_return() {
+
+}