riscv64: switch process (#678)

* riscv64: switch process

* fixname
This commit is contained in:
LoGin 2024-03-31 22:53:01 +08:00 committed by GitHub
parent 7d580ef99d
commit 9b96c5b547
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 415 additions and 47 deletions

View File

@ -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"] }

View File

@ -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;
}
}
/// 初始化本地上下文

View File

@ -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 {

View File

@ -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<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 {
@ -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);
}
}

View File

@ -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;