refactor(process): 调整arch_switch_to_user函数,把riscv和x86_64的共用逻辑抽取出来。 (#773)

* refactor(process): Extract common logic for riscv and x86_64 in arch_switch_to_user to run_init_process

调整arch_switch_to_user函数,把riscv和x86_64的共用逻辑抽取出来。写成run_init_process函数,并且能够尝试运行多个不同的init程序,直到某个运行成功
This commit is contained in:
LoGin 2024-04-27 15:35:24 +08:00 committed by GitHub
parent 173c4567cf
commit f75cb0f8ed
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 65 additions and 79 deletions

View File

@ -19,7 +19,7 @@ use crate::{
smp::cpu::ProcessorId,
};
use self::init::riscv_mm_init;
use self::init::{riscv_mm_init, INITIAL_PGTABLE_VALUE};
pub mod bump;
pub(super) mod init;
@ -185,7 +185,7 @@ impl MemoryManagementArch for RiscV64MMArch {
}
fn initial_page_table() -> PhysAddr {
todo!()
unsafe { INITIAL_PGTABLE_VALUE }
}
fn setup_new_usermapper() -> Result<UserMapper, SystemError> {

View File

@ -1,8 +1,6 @@
use core::hint::spin_loop;
use crate::{
arch::CurrentIrqArch, exception::InterruptArch, kBUG, kdebug, process::ProcessManager,
};
use crate::{arch::CurrentIrqArch, exception::InterruptArch, kBUG, process::ProcessManager};
impl ProcessManager {
/// 每个核的idle进程

View File

@ -19,7 +19,7 @@ use crate::{
CurrentIrqArch,
},
exception::InterruptArch,
kdebug, kerror,
kerror,
libs::spinlock::SpinLockGuard,
mm::VirtAddr,
process::{
@ -53,7 +53,7 @@ static BSP_IDLE_STACK_SPACE: InitProcUnion = InitProcUnion {
idle_stack: [0; 32768],
};
pub unsafe fn arch_switch_to_user(path: String, argv: Vec<String>, envp: Vec<String>) -> ! {
pub unsafe fn arch_switch_to_user(trap_frame: TrapFrame) -> ! {
// 以下代码不能发生中断
CurrentIrqArch::interrupt_disable();
@ -69,28 +69,12 @@ pub unsafe fn arch_switch_to_user(path: String, argv: Vec<String>, envp: Vec<Str
arch_guard.ra = new_pc.data();
drop(arch_guard);
// 删除kthread的标志
current_pcb.flags().remove(ProcessFlags::KTHREAD);
current_pcb.worker_private().take();
drop(current_pcb);
*current_pcb.sched_info().sched_policy.write_irqsave() = crate::sched::SchedPolicy::CFS;
let mut trap_frame = TrapFrame::new();
compiler_fence(Ordering::SeqCst);
Syscall::do_execve(path, argv, envp, &mut trap_frame).unwrap_or_else(|e| {
panic!(
"arch_switch_to_user(): pid: {pid:?}, Failed to execve: , error: {e:?}",
pid = current_pcb.pid(),
e = e
);
});
compiler_fence(Ordering::SeqCst);
// 重要在这里之后一定要保证上面的引用计数变量、动态申请的变量、锁的守卫都被drop了否则可能导致内存安全问题
drop(current_pcb);
*(trap_frame_vaddr.data() as *mut TrapFrame) = trap_frame;
compiler_fence(Ordering::SeqCst);

View File

@ -1,11 +1,10 @@
use alloc::{string::String, vec::Vec};
use riscv::register::sstatus::{Sstatus, FS, SPP};
use riscv::register::sstatus::{FS, SPP};
use system_error::SystemError;
use crate::{
arch::{interrupt::TrapFrame, CurrentIrqArch},
exception::InterruptArch,
kdebug,
mm::ucontext::AddressSpace,
process::{
exec::{load_binary_file, ExecParam, ExecParamFlags},
@ -64,8 +63,7 @@ impl Syscall {
let mut param = ExecParam::new(path.as_str(), address_space.clone(), ExecParamFlags::EXEC)?;
// 加载可执行文件
let load_result = load_binary_file(&mut param)
.unwrap_or_else(|e| panic!("Failed to load binary file: {:?}, path: {:?}", e, path));
let load_result = load_binary_file(&mut param)?;
// kdebug!("load binary file done");
// kdebug!("argv: {:?}, envp: {:?}", argv, envp);
param.init_info_mut().args = argv;

View File

@ -2,7 +2,7 @@
pub mod nr;
use system_error::SystemError;
use crate::{exception::InterruptArch, kdebug, process::ProcessManager, syscall::Syscall};
use crate::{exception::InterruptArch, process::ProcessManager, syscall::Syscall};
use super::{interrupt::TrapFrame, CurrentIrqArch};

View File

@ -5,11 +5,7 @@ use core::{
sync::atomic::{compiler_fence, Ordering},
};
use alloc::{
string::String,
sync::{Arc, Weak},
vec::Vec,
};
use alloc::sync::{Arc, Weak};
use kdepends::memoffset::offset_of;
use system_error::SystemError;
@ -511,7 +507,7 @@ unsafe extern "sysv64" fn switch_back() -> ! {
asm!("ret", options(noreturn));
}
pub unsafe fn arch_switch_to_user(path: String, argv: Vec<String>, envp: Vec<String>) -> ! {
pub unsafe fn arch_switch_to_user(trap_frame: TrapFrame) -> ! {
// 以下代码不能发生中断
CurrentIrqArch::interrupt_disable();
@ -520,7 +516,6 @@ pub unsafe fn arch_switch_to_user(path: String, argv: Vec<String>, envp: Vec<Str
current_pcb.kernel_stack().stack_max_address().data() - core::mem::size_of::<TrapFrame>(),
);
// kdebug!("trap_frame_vaddr: {:?}", trap_frame_vaddr);
let new_rip = VirtAddr::new(ret_from_intr as usize);
assert!(
(x86::current::registers::rsp() as usize) < trap_frame_vaddr.data(),
@ -531,6 +526,7 @@ pub unsafe fn arch_switch_to_user(path: String, argv: Vec<String>, envp: Vec<Str
trap_frame_vaddr.data()
);
let new_rip = VirtAddr::new(ret_from_intr as usize);
let mut arch_guard = current_pcb.arch_info_irqsave();
arch_guard.rsp = trap_frame_vaddr.data();
@ -548,28 +544,11 @@ pub unsafe fn arch_switch_to_user(path: String, argv: Vec<String>, envp: Vec<Str
drop(arch_guard);
// 删除kthread的标志
current_pcb.flags().remove(ProcessFlags::KTHREAD);
current_pcb.worker_private().take();
*current_pcb.sched_info().sched_policy.write_irqsave() = crate::sched::SchedPolicy::CFS;
let mut trap_frame = TrapFrame::new();
compiler_fence(Ordering::SeqCst);
Syscall::do_execve(path, argv, envp, &mut trap_frame).unwrap_or_else(|e| {
panic!(
"arch_switch_to_user(): pid: {pid:?}, Failed to execve: , error: {e:?}",
pid = current_pcb.pid(),
e = e
);
});
drop(current_pcb);
compiler_fence(Ordering::SeqCst);
// 重要在这里之后一定要保证上面的引用计数变量、动态申请的变量、锁的守卫都被drop了否则可能导致内存安全问题
drop(current_pcb);
compiler_fence(Ordering::SeqCst);
ready_to_switch_to_user(trap_frame, trap_frame_vaddr.data(), new_rip.data());
}

View File

@ -66,8 +66,7 @@ impl Syscall {
let mut param = ExecParam::new(path.as_str(), address_space.clone(), ExecParamFlags::EXEC)?;
// 加载可执行文件
let load_result = load_binary_file(&mut param)
.unwrap_or_else(|e| panic!("Failed to load binary file: {:?}, path: {:?}", e, path));
let load_result = load_binary_file(&mut param)?;
// kdebug!("load binary file done");
// kdebug!("argv: {:?}, envp: {:?}", argv, envp);
param.init_info_mut().args = argv;

View File

@ -11,7 +11,6 @@ use crate::{
process::ProcessManager,
syscall::{Syscall, SYS_SCHED},
};
use alloc::string::String;
use system_error::SystemError;
use super::{
@ -133,19 +132,6 @@ pub fn arch_syscall_init() -> Result<(), SystemError> {
return Ok(());
}
/// 执行第一个用户进程的函数(只应该被调用一次)
///
/// 当进程管理重构完成后,这个函数应该被删除。调整为别的函数。
#[no_mangle]
pub extern "C" fn rs_exec_init_process(frame: &mut TrapFrame) -> usize {
let path = String::from("/bin/shell.elf");
let argv = vec![String::from("/bin/shell.elf")];
let envp = vec![String::from("PATH=/bin")];
let r = Syscall::do_execve(path, argv, envp, frame);
// kdebug!("rs_exec_init_process: r: {:?}\n", r);
return r.map(|_| 0).unwrap_or_else(|e| e.to_posix_errno() as usize);
}
/// syscall指令初始化函数
pub(super) unsafe fn init_syscall_64() {
let mut efer = x86::msr::rdmsr(x86::msr::IA32_EFER);

View File

@ -1,16 +1,19 @@
//! 这个文件内放置初始内核线程的代码。
use alloc::string::String;
use core::sync::atomic::{compiler_fence, Ordering};
use alloc::string::{String, ToString};
use system_error::SystemError;
use crate::{
arch::process::arch_switch_to_user,
arch::{interrupt::TrapFrame, process::arch_switch_to_user},
driver::{net::e1000e::e1000e::e1000e_init, virtio::virtio::virtio_probe},
filesystem::vfs::core::mount_root_fs,
kdebug, kerror,
net::net_core::net_init,
process::{kthread::KernelThreadMechanism, stdio::stdio_init},
process::{kthread::KernelThreadMechanism, stdio::stdio_init, ProcessFlags, ProcessManager},
smp::smp_init,
syscall::Syscall,
};
use super::initcall::do_initcalls;
@ -21,8 +24,6 @@ pub fn initial_kernel_thread() -> i32 {
});
switch_to_user();
unreachable!();
}
fn kernel_init() -> Result<(), SystemError> {
@ -60,11 +61,52 @@ fn kenrel_init_freeable() -> Result<(), SystemError> {
}
/// 切换到用户态
fn switch_to_user() {
const INIT_PROGRAM: &str = "/bin/dragonreach";
let path = String::from(INIT_PROGRAM);
#[inline(never)]
fn switch_to_user() -> ! {
let current_pcb = ProcessManager::current_pcb();
// 删除kthread的标志
current_pcb.flags().remove(ProcessFlags::KTHREAD);
current_pcb.worker_private().take();
*current_pcb.sched_info().sched_policy.write_irqsave() = crate::sched::SchedPolicy::CFS;
drop(current_pcb);
let mut trap_frame = TrapFrame::new();
// 逐个尝试运行init进程
if try_to_run_init_process("/bin/dragonreach", &mut trap_frame).is_err()
&& try_to_run_init_process("/bin/init", &mut trap_frame).is_err()
&& try_to_run_init_process("/bin/sh", &mut trap_frame).is_err()
{
panic!("Failed to run init process: No working init found.");
}
// 需要确保执行到这里之后上面所有的资源都已经释放比如arc之类的
unsafe { arch_switch_to_user(trap_frame) };
}
fn try_to_run_init_process(path: &str, trap_frame: &mut TrapFrame) -> Result<(), SystemError> {
if let Err(e) = run_init_process(path.to_string(), trap_frame) {
if e != SystemError::ENOENT {
kerror!(
"Failed to run init process: {path} exists but couldn't execute it (error {:?})",
e
);
}
return Err(e);
}
Ok(())
}
fn run_init_process(path: String, trap_frame: &mut TrapFrame) -> Result<(), SystemError> {
let argv = vec![path.clone()];
let envp = vec![String::from("PATH=/")];
unsafe { arch_switch_to_user(path, argv, envp) };
compiler_fence(Ordering::SeqCst);
Syscall::do_execve(path, argv, envp, trap_frame)?;
Ok(())
}