Browse Source

riscv64: switch process (#678)

* riscv64: switch process

* fixname
LoGin 11 months ago
parent
commit
9b96c5b547

+ 1 - 1
kernel/Cargo.toml

@@ -62,7 +62,7 @@ x86_64 = "=0.14.10"
 
 # target为riscv64时,使用下面的依赖
 [target.'cfg(target_arch = "riscv64")'.dependencies]
-riscv = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/riscv.git", revision = "79d27d0f3a", features = [ "s-mode" ] }
+riscv = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/riscv.git", revision = "01fc40d", features = [ "s-mode" ] }
 sbi-rt = { version = "=0.0.3", features = ["legacy"] }
 
 

+ 9 - 2
kernel/src/arch/riscv64/cpu.rs

@@ -53,7 +53,7 @@ pub(super) fn local_context() -> &'static PerCpuVar<LocalContext> {
 ///
 /// - 从用户态进入内核态时,会从sscratch寄存器加载这个结构体的地址到tp寄存器,并把sscratch寄存器清零
 /// - 从内核态进入用户态时,会将tp寄存器的值保存到sscratch寄存器
-#[derive(Debug)]
+#[derive(Debug, Clone, Copy)]
 pub(super) struct LocalContext {
     /// 当前cpu的id
     pub current_cpu: ProcessorId,
@@ -64,7 +64,7 @@ pub(super) struct LocalContext {
 }
 
 impl LocalContext {
-    fn new(cpu: ProcessorId) -> Self {
+    pub fn new(cpu: ProcessorId) -> Self {
         Self {
             current_cpu: cpu,
             kernel_sp: 0,
@@ -102,6 +102,13 @@ impl LocalContext {
         // 写入tp寄存器
         riscv::register::tp::write(ptr);
     }
+
+    pub fn restore(&mut self, from: &LocalContext) {
+        // 不恢复cpu id
+
+        self.kernel_sp = from.kernel_sp;
+        self.user_sp = from.user_sp;
+    }
 }
 
 /// 初始化本地上下文

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

@@ -61,44 +61,44 @@ impl InterruptArch for RiscV64InterruptArch {
 #[repr(C)]
 #[derive(Debug, Copy, Clone)]
 pub struct TrapFrame {
-    epc: usize,
-    ra: usize,
-    sp: 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,
+    pub epc: usize,
+    pub ra: usize,
+    pub sp: usize,
+    pub gp: usize,
+    pub tp: usize,
+    pub t0: usize,
+    pub t1: usize,
+    pub t2: usize,
+    pub s0: usize,
+    pub s1: usize,
+    pub a0: usize,
+    pub a1: usize,
+    pub a2: usize,
+    pub a3: usize,
+    pub a4: usize,
+    pub a5: usize,
+    pub a6: usize,
+    pub a7: usize,
+    pub s2: usize,
+    pub s3: usize,
+    pub s4: usize,
+    pub s5: usize,
+    pub s6: usize,
+    pub s7: usize,
+    pub s8: usize,
+    pub s9: usize,
+    pub s10: usize,
+    pub s11: usize,
+    pub t3: usize,
+    pub t4: usize,
+    pub t5: usize,
+    pub t6: usize,
     // 以下是中断发生时自动保存的寄存器
-    status: Sstatus,
-    badaddr: usize,
-    cause: Scause,
+    pub status: Sstatus,
+    pub badaddr: usize,
+    pub cause: Scause,
     /// a0 value before the syscall
-    origin_a0: usize,
+    pub origin_a0: usize,
 }
 
 impl TrapFrame {

+ 368 - 8
kernel/src/arch/riscv64/process/mod.rs

@@ -1,19 +1,34 @@
-use core::{arch::asm, mem::ManuallyDrop};
-
 use alloc::{
     string::String,
     sync::{Arc, Weak},
     vec::Vec,
 };
+use core::{
+    arch::asm,
+    intrinsics::unlikely,
+    mem::ManuallyDrop,
+    sync::atomic::{compiler_fence, Ordering},
+};
+use kdepends::memoffset::offset_of;
 use system_error::SystemError;
 
 use crate::{
+    arch::CurrentIrqArch,
+    exception::InterruptArch,
     kerror,
+    libs::spinlock::SpinLockGuard,
     mm::VirtAddr,
-    process::{fork::KernelCloneArgs, KernelStack, ProcessControlBlock, ProcessManager},
+    process::{
+        fork::KernelCloneArgs, KernelStack, ProcessControlBlock, ProcessManager,
+        PROCESS_SWITCH_RESULT,
+    },
+    smp::cpu::ProcessorId,
 };
 
-use super::interrupt::TrapFrame;
+use super::{
+    cpu::{local_context, LocalContext},
+    interrupt::TrapFrame,
+};
 
 pub mod idle;
 pub mod kthread;
@@ -59,12 +74,125 @@ impl ProcessManager {
     ///
     /// - `prev`:上一个进程的pcb
     /// - `next`:下一个进程的pcb
+    ///
+    /// 参考: https://code.dragonos.org.cn/xref/linux-6.6.21/arch/riscv/include/asm/switch_to.h#76
     pub unsafe fn switch_process(prev: Arc<ProcessControlBlock>, next: Arc<ProcessControlBlock>) {
-        // todo: https://code.dragonos.org.cn/xref/linux-6.6.21/arch/riscv/include/asm/switch_to.h#76
-        unimplemented!("ProcessManager::switch_process")
+        assert!(!CurrentIrqArch::is_irq_enabled());
+        Self::switch_process_fpu(&prev, &next);
+        Self::switch_local_context(&prev, &next);
+
+        // 切换地址空间
+        let next_addr_space = next.basic().user_vm().as_ref().unwrap().clone();
+        compiler_fence(Ordering::SeqCst);
+
+        next_addr_space.read().user_mapper.utable.make_current();
+        drop(next_addr_space);
+        compiler_fence(Ordering::SeqCst);
+
+        // 获取arch info的锁,并强制泄露其守卫(切换上下文后,在switch_finish_hook中会释放锁)
+        let next_arch = SpinLockGuard::leak(next.arch_info_irqsave()) as *mut ArchPCBInfo;
+        let prev_arch = SpinLockGuard::leak(prev.arch_info_irqsave()) as *mut ArchPCBInfo;
+
+        // 恢复当前的 preempt count*2
+        ProcessManager::current_pcb().preempt_enable();
+        ProcessManager::current_pcb().preempt_enable();
+        PROCESS_SWITCH_RESULT.as_mut().unwrap().get_mut().prev_pcb = Some(prev);
+        PROCESS_SWITCH_RESULT.as_mut().unwrap().get_mut().next_pcb = Some(next);
+        // kdebug!("switch tss ok");
+        compiler_fence(Ordering::SeqCst);
+        // 正式切换上下文
+        switch_to_inner(prev_arch, next_arch);
+    }
+
+    fn switch_process_fpu(prev: &Arc<ProcessControlBlock>, next: &Arc<ProcessControlBlock>) {
+        let prev_regs = unsafe { Self::task_trapframe(prev) };
+        let next_regs = unsafe { Self::task_trapframe(next) };
+        if unlikely(prev_regs.status.sd()) {
+            prev.arch_info_irqsave().fp_state.save(prev_regs);
+        }
+        next.arch_info_irqsave().fp_state.restore(next_regs);
+    }
+
+    fn switch_local_context(prev: &Arc<ProcessControlBlock>, next: &Arc<ProcessControlBlock>) {
+        prev.arch_info_irqsave().local_context = *local_context().get();
+        local_context()
+            .get_mut()
+            .restore(&next.arch_info_irqsave().local_context);
+    }
+
+    unsafe fn task_trapframe(task: &Arc<ProcessControlBlock>) -> &mut TrapFrame {
+        let mut sp = task.kernel_stack().stack_max_address().data();
+        sp -= core::mem::size_of::<TrapFrame>();
+        return (sp as *mut TrapFrame).as_mut().unwrap();
     }
 }
 
+/// 切换上下文
+///
+/// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/arch/riscv/kernel/entry.S#233
+#[naked]
+unsafe extern "C" fn switch_to_inner(prev: *mut ArchPCBInfo, next: *mut ArchPCBInfo) {
+    core::arch::asm!(concat!(
+        "
+            sd ra, {off_ra}(a0)
+            sd sp, {off_sp}(a0)
+            sd s0, {off_s0}(a0)
+            sd s1, {off_s1}(a0)
+            sd s2, {off_s2}(a0)
+            sd s3, {off_s3}(a0)
+            sd s4, {off_s4}(a0)
+            sd s5, {off_s5}(a0)
+            sd s6, {off_s6}(a0)
+            sd s7, {off_s7}(a0)
+            sd s8, {off_s8}(a0)
+            sd s9, {off_s9}(a0)
+            sd s10, {off_s10}(a0)
+            sd s11, {off_s11}(a0)
+
+
+            ld sp, {off_sp}(a1)
+            ld s0, {off_s0}(a1)
+            ld s1, {off_s1}(a1)
+            ld s2, {off_s2}(a1)
+            ld s3, {off_s3}(a1)
+            ld s4, {off_s4}(a1)
+            ld s5, {off_s5}(a1)
+            ld s6, {off_s6}(a1)
+            ld s7, {off_s7}(a1)
+            ld s8, {off_s8}(a1)
+            ld s9, {off_s9}(a1)
+            ld s10, {off_s10}(a1)
+            ld s11, {off_s11}(a1)
+            
+            // 将ra设置为标签1,并跳转到{switch_finish_hook}
+            la ra, 1f
+            j {switch_finish_hook}
+            
+            1:
+            ld sp, {off_sp}(a1)
+            ld ra, {off_ra}(a1)
+            ret
+
+        "
+    ), 
+    off_ra = const(offset_of!(ArchPCBInfo, ra)),
+    off_sp = const(offset_of!(ArchPCBInfo, ksp)),
+    off_s0 = const(offset_of!(ArchPCBInfo, s0)),
+    off_s1 = const(offset_of!(ArchPCBInfo, s1)),
+    off_s2 = const(offset_of!(ArchPCBInfo, s2)),
+    off_s3 = const(offset_of!(ArchPCBInfo, s3)),
+    off_s4 = const(offset_of!(ArchPCBInfo, s4)),
+    off_s5 = const(offset_of!(ArchPCBInfo, s5)),
+    off_s6 = const(offset_of!(ArchPCBInfo, s6)),
+    off_s7 = const(offset_of!(ArchPCBInfo, s7)),
+    off_s8 = const(offset_of!(ArchPCBInfo, s8)),
+    off_s9 = const(offset_of!(ArchPCBInfo, s9)),
+    off_s10 = const(offset_of!(ArchPCBInfo, s10)),
+    off_s11 = const(offset_of!(ArchPCBInfo, s11)),
+    switch_finish_hook = sym crate::process::switch_finish_hook,
+    options(noreturn));
+}
+
 impl ProcessControlBlock {
     /// 获取当前进程的pcb
     pub fn arch_current_pcb() -> Arc<Self> {
@@ -95,8 +223,25 @@ impl ProcessControlBlock {
 /// PCB中与架构相关的信息
 #[derive(Debug)]
 #[allow(dead_code)]
+#[repr(C)]
 pub struct ArchPCBInfo {
-    // todo: add arch related fields
+    ra: usize,
+    ksp: usize,
+    s0: usize,
+    s1: usize,
+    s2: usize,
+    s3: usize,
+    s4: usize,
+    s5: usize,
+    s6: usize,
+    s7: usize,
+    s8: usize,
+    s9: usize,
+    s10: usize,
+    s11: usize,
+
+    fp_state: FpDExtState,
+    local_context: LocalContext,
 }
 
 #[allow(dead_code)]
@@ -111,10 +256,225 @@ impl ArchPCBInfo {
     ///
     /// 返回一个新的ArchPCBInfo
     pub fn new(kstack: &KernelStack) -> Self {
-        Self {}
+        Self {
+            ra: 0,
+            ksp: kstack.stack_max_address().data(),
+            s0: 0,
+            s1: 0,
+            s2: 0,
+            s3: 0,
+            s4: 0,
+            s5: 0,
+            s6: 0,
+            s7: 0,
+            s8: 0,
+            s9: 0,
+            s10: 0,
+            s11: 0,
+            fp_state: FpDExtState::new(),
+            local_context: LocalContext::new(ProcessorId::new(0)),
+        }
     }
     // ### 从另一个ArchPCBInfo处clone,但是保留部分字段不变
     pub fn clone_from(&mut self, from: &Self) {
         unimplemented!("ArchPCBInfo::clone_from")
     }
 }
+
+#[repr(C)]
+#[derive(Debug)]
+struct FpDExtState {
+    f: [u64; 32],
+    fcsr: u32,
+}
+
+impl FpDExtState {
+    /// 创建一个新的FpState
+    const fn new() -> Self {
+        Self {
+            f: [0; 32],
+            fcsr: 0,
+        }
+    }
+
+    fn save(&mut self, regs: &mut TrapFrame) {
+        if regs.status.fs() == riscv::register::sstatus::FS::Dirty {
+            self.do_save();
+            self.do_clean(regs);
+        }
+    }
+
+    fn restore(&mut self, regs: &mut TrapFrame) {
+        if regs.status.fs() != riscv::register::sstatus::FS::Off {
+            self.do_restore();
+            self.do_clean(regs);
+        }
+    }
+
+    fn do_clean(&mut self, regs: &mut TrapFrame) {
+        regs.status.update_fs(riscv::register::sstatus::FS::Clean);
+    }
+
+    fn do_save(&mut self) {
+        compiler_fence(Ordering::SeqCst);
+        unsafe {
+            riscv::register::sstatus::set_fs(riscv::register::sstatus::FS::Initial);
+            asm!("frcsr {0}", lateout(reg) self.fcsr);
+            asm!(concat!(
+                    "
+                fsd f0, {0}
+                fsd f1, {1}
+                fsd f2, {2}
+                fsd f3, {3}
+                fsd f4, {4}
+                fsd f5, {5}
+                fsd f6, {6}
+                fsd f7, {7}
+                fsd f8, {8}
+                fsd f9, {9}
+                fsd f10, {10}
+                fsd f11, {11}
+                fsd f12, {12}
+                fsd f13, {13}
+                fsd f14, {14}
+                fsd f15, {15}
+                fsd f16, {16}
+                fsd f17, {17}
+                fsd f18, {18}
+                fsd f19, {19}
+                fsd f20, {20}
+                fsd f21, {21}
+                fsd f22, {22}
+                fsd f23, {23}
+                fsd f24, {24}
+                fsd f25, {25}
+                fsd f26, {26}
+                fsd f27, {27}
+                fsd f28, {28}
+                fsd f29, {29}
+                fsd f30, {30}
+                fsd f31, {31}
+                "
+                ),
+                lateout(reg) self.f[0],
+                lateout(reg) self.f[1],
+                lateout(reg) self.f[2],
+                lateout(reg) self.f[3],
+                lateout(reg) self.f[4],
+                lateout(reg) self.f[5],
+                lateout(reg) self.f[6],
+                lateout(reg) self.f[7],
+                lateout(reg) self.f[8],
+                lateout(reg) self.f[9],
+                lateout(reg) self.f[10],
+                lateout(reg) self.f[11],
+                lateout(reg) self.f[12],
+                lateout(reg) self.f[13],
+                lateout(reg) self.f[14],
+                lateout(reg) self.f[15],
+                lateout(reg) self.f[16],
+                lateout(reg) self.f[17],
+                lateout(reg) self.f[18],
+                lateout(reg) self.f[19],
+                lateout(reg) self.f[20],
+                lateout(reg) self.f[21],
+                lateout(reg) self.f[22],
+                lateout(reg) self.f[23],
+                lateout(reg) self.f[24],
+                lateout(reg) self.f[25],
+                lateout(reg) self.f[26],
+                lateout(reg) self.f[27],
+                lateout(reg) self.f[28],
+                lateout(reg) self.f[29],
+                lateout(reg) self.f[30],
+                lateout(reg) self.f[31],
+
+            );
+            riscv::register::sstatus::set_fs(riscv::register::sstatus::FS::Off);
+        }
+
+        compiler_fence(Ordering::SeqCst);
+    }
+
+    fn do_restore(&mut self) {
+        compiler_fence(Ordering::SeqCst);
+        let fcsr = self.fcsr;
+        unsafe {
+            riscv::register::sstatus::set_fs(riscv::register::sstatus::FS::Initial);
+            compiler_fence(Ordering::SeqCst);
+            asm!(concat!(
+                    "
+                fld f0, {0}
+                fld f1, {1}
+                fld f2, {2}
+                fld f3, {3}
+                fld f4, {4}
+                fld f5, {5}
+                fld f6, {6}
+                fld f7, {7}
+                fld f8, {8}
+                fld f9, {9}
+                fld f10, {10}
+                fld f11, {11}
+                fld f12, {12}
+                fld f13, {13}
+                fld f14, {14}
+                fld f15, {15}
+                fld f16, {16}
+                fld f17, {17}
+                fld f18, {18}
+                fld f19, {19}
+                fld f20, {20}
+                fld f21, {21}
+                fld f22, {22}
+                fld f23, {23}
+                fld f24, {24}
+                fld f25, {25}
+                fld f26, {26}
+                fld f27, {27}
+                fld f28, {28}
+                fld f29, {29}
+                fld f30, {30}
+                fld f31, {31}
+                "
+                ),
+                in(reg) self.f[0],
+                in(reg) self.f[1],
+                in(reg) self.f[2],
+                in(reg) self.f[3],
+                in(reg) self.f[4],
+                in(reg) self.f[5],
+                in(reg) self.f[6],
+                in(reg) self.f[7],
+                in(reg) self.f[8],
+                in(reg) self.f[9],
+                in(reg) self.f[10],
+                in(reg) self.f[11],
+                in(reg) self.f[12],
+                in(reg) self.f[13],
+                in(reg) self.f[14],
+                in(reg) self.f[15],
+                in(reg) self.f[16],
+                in(reg) self.f[17],
+                in(reg) self.f[18],
+                in(reg) self.f[19],
+                in(reg) self.f[20],
+                in(reg) self.f[21],
+                in(reg) self.f[22],
+                in(reg) self.f[23],
+                in(reg) self.f[24],
+                in(reg) self.f[25],
+                in(reg) self.f[26],
+                in(reg) self.f[27],
+                in(reg) self.f[28],
+                in(reg) self.f[29],
+                in(reg) self.f[30],
+                in(reg) self.f[31],
+            );
+            compiler_fence(Ordering::SeqCst);
+            asm!("fscsr {0}", in(reg) fcsr);
+            riscv::register::sstatus::set_fs(riscv::register::sstatus::FS::Off);
+        }
+        compiler_fence(Ordering::SeqCst);
+    }
+}

+ 1 - 0
kernel/src/syscall/mod.rs

@@ -344,6 +344,7 @@ impl Syscall {
                 Self::rmdir(path)
             }
 
+            #[cfg(target_arch = "x86_64")]
             SYS_LINK => {
                 let old = args[0] as *const u8;
                 let new = args[1] as *const u8;