Pārlūkot izejas kodu

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程序,直到某个运行成功
LoGin 10 mēneši atpakaļ
vecāks
revīzija
f75cb0f8ed

+ 2 - 2
kernel/src/arch/riscv64/mm/mod.rs

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

+ 1 - 3
kernel/src/arch/riscv64/process/idle.rs

@@ -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进程

+ 3 - 19
kernel/src/arch/riscv64/process/mod.rs

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

+ 2 - 4
kernel/src/arch/riscv64/process/syscall.rs

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

+ 1 - 1
kernel/src/arch/riscv64/syscall/mod.rs

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

+ 4 - 25
kernel/src/arch/x86_64/process/mod.rs

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

+ 1 - 2
kernel/src/arch/x86_64/process/syscall.rs

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

+ 0 - 14
kernel/src/arch/x86_64/syscall/mod.rs

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

+ 51 - 9
kernel/src/init/initial_kthread.rs

@@ -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(())
 }