Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

switch_to_user来看,init程序的启动是有优先级的,所以我觉得这里的日志应该更完善一点,提示当前是运行哪个init程序,前面的为什么出错。

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

会有报错的,在那个exec那里就会报出错误的

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