diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 8967dd99..3a00ba65 100644 --- a/kernel/Cargo.toml +++ b/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"] } diff --git a/kernel/src/arch/riscv64/cpu.rs b/kernel/src/arch/riscv64/cpu.rs index 1e07b0ec..ae3cb1d1 100644 --- a/kernel/src/arch/riscv64/cpu.rs +++ b/kernel/src/arch/riscv64/cpu.rs @@ -53,7 +53,7 @@ pub(super) fn local_context() -> &'static PerCpuVar { /// /// - 从用户态进入内核态时,会从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; + } } /// 初始化本地上下文 diff --git a/kernel/src/arch/riscv64/interrupt/mod.rs b/kernel/src/arch/riscv64/interrupt/mod.rs index bcbc23cd..e9a18572 100644 --- a/kernel/src/arch/riscv64/interrupt/mod.rs +++ b/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 { diff --git a/kernel/src/arch/riscv64/process/mod.rs b/kernel/src/arch/riscv64/process/mod.rs index 9988dc03..a62a17ef 100644 --- a/kernel/src/arch/riscv64/process/mod.rs +++ b/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,10 +74,123 @@ 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, next: Arc) { - // 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, next: &Arc) { + 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, next: &Arc) { + 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) -> &mut TrapFrame { + let mut sp = task.kernel_stack().stack_max_address().data(); + sp -= core::mem::size_of::(); + 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 { @@ -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); + } +} diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index dcdc232f..5062ef46 100644 --- a/kernel/src/syscall/mod.rs +++ b/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;