Skip to content

Commit

Permalink
refactor(process): 调整arch_switch_to_user函数,把riscv和x86_64的共用逻辑抽取出来。 (#773
Browse files Browse the repository at this point in the history
)

* 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程序,直到某个运行成功
  • Loading branch information
fslongjin authored Apr 27, 2024
1 parent 173c456 commit f75cb0f
Show file tree
Hide file tree
Showing 9 changed files with 65 additions and 79 deletions.
4 changes: 2 additions & 2 deletions kernel/src/arch/riscv64/mm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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> {
Expand Down
4 changes: 1 addition & 3 deletions kernel/src/arch/riscv64/process/idle.rs
Original file line number Diff line number Diff line change
@@ -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进程
Expand Down
22 changes: 3 additions & 19 deletions kernel/src/arch/riscv64/process/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use crate::{
CurrentIrqArch,
},
exception::InterruptArch,
kdebug, kerror,
kerror,
libs::spinlock::SpinLockGuard,
mm::VirtAddr,
process::{
Expand Down Expand Up @@ -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();

Expand All @@ -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();

*current_pcb.sched_info().sched_policy.write_irqsave() = crate::sched::SchedPolicy::CFS;

let mut trap_frame = TrapFrame::new();
drop(current_pcb);

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);
Expand Down
6 changes: 2 additions & 4 deletions kernel/src/arch/riscv64/process/syscall.rs
Original file line number Diff line number Diff line change
@@ -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},
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion kernel/src/arch/riscv64/syscall/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down
29 changes: 4 additions & 25 deletions kernel/src/arch/x86_64/process/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();

Expand All @@ -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(),
Expand All @@ -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();

Expand All @@ -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());
}
Expand Down
3 changes: 1 addition & 2 deletions kernel/src/arch/x86_64/process/syscall.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
14 changes: 0 additions & 14 deletions kernel/src/arch/x86_64/syscall/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ use crate::{
process::ProcessManager,
syscall::{Syscall, SYS_SCHED},
};
use alloc::string::String;
use system_error::SystemError;

use super::{
Expand Down Expand Up @@ -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);
Expand Down
60 changes: 51 additions & 9 deletions kernel/src/init/initial_kthread.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -21,8 +24,6 @@ pub fn initial_kernel_thread() -> i32 {
});

switch_to_user();

unreachable!();
}

fn kernel_init() -> Result<(), SystemError> {
Expand Down Expand Up @@ -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(())
}

0 comments on commit f75cb0f

Please sign in to comment.