DragonOS/kernel/src/init/initial_kthread.rs

153 lines
4.4 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! 这个文件内放置初始内核线程的代码。
use core::sync::atomic::{compiler_fence, Ordering};
use alloc::{ffi::CString, string::ToString};
use log::{debug, error};
use system_error::SystemError;
use crate::{
arch::{interrupt::TrapFrame, process::arch_switch_to_user},
driver::{net::e1000e::e1000e::e1000e_init, virtio::virtio::virtio_probe},
filesystem::vfs::core::mount_root_fs,
net::net_core::net_init,
process::{
exec::ProcInitInfo, kthread::KernelThreadMechanism, stdio::stdio_init, ProcessFlags,
ProcessManager,
},
smp::smp_init,
syscall::Syscall,
};
use super::{cmdline::kenrel_cmdline_param_manager, initcall::do_initcalls};
const INIT_PROC_TRYLIST: [&str; 3] = ["/bin/dragonreach", "/bin/init", "/bin/sh"];
pub fn initial_kernel_thread() -> i32 {
kernel_init().unwrap_or_else(|err| {
log::error!("Failed to initialize kernel: {:?}", err);
panic!()
});
switch_to_user();
}
fn kernel_init() -> Result<(), SystemError> {
KernelThreadMechanism::init_stage2();
kenrel_init_freeable()?;
#[cfg(target_arch = "x86_64")]
crate::driver::disk::ahci::ahci_init()
.inspect_err(|e| log::error!("ahci_init failed: {:?}", e))
.ok();
virtio_probe();
mount_root_fs().expect("Failed to mount root fs");
e1000e_init();
net_init().unwrap_or_else(|err| {
error!("Failed to initialize network: {:?}", err);
});
debug!("initial kernel thread done.");
return Ok(());
}
#[inline(never)]
fn kenrel_init_freeable() -> Result<(), SystemError> {
do_initcalls().unwrap_or_else(|err| {
panic!("Failed to initialize subsystems: {:?}", err);
});
stdio_init().expect("Failed to initialize stdio");
smp_init();
return Ok(());
}
/// 切换到用户态
#[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 proc_init_info = ProcInitInfo::new("");
proc_init_info.envs.push(CString::new("PATH=/").unwrap());
proc_init_info.args = kenrel_cmdline_param_manager().init_proc_args();
proc_init_info.envs = kenrel_cmdline_param_manager().init_proc_envs();
let mut trap_frame = TrapFrame::new();
if let Some(path) = kenrel_cmdline_param_manager().init_proc_path() {
log::info!("Boot with specified init process: {:?}", path);
try_to_run_init_process(
path.as_c_str().to_str().unwrap(),
&mut proc_init_info,
&mut trap_frame,
)
.unwrap_or_else(|e| {
panic!(
"Failed to run specified init process: {:?}, err: {:?}",
path, e
)
});
} else {
let mut ok = false;
for path in INIT_PROC_TRYLIST.iter() {
if try_to_run_init_process(path, &mut proc_init_info, &mut trap_frame).is_ok() {
ok = true;
break;
}
}
if !ok {
panic!("Failed to run init process: No working init found.");
}
}
drop(proc_init_info);
// 需要确保执行到这里之后上面所有的资源都已经释放比如arc之类的
compiler_fence(Ordering::SeqCst);
unsafe { arch_switch_to_user(trap_frame) };
}
fn try_to_run_init_process(
path: &str,
proc_init_info: &mut ProcInitInfo,
trap_frame: &mut TrapFrame,
) -> Result<(), SystemError> {
proc_init_info.proc_name = CString::new(path).unwrap();
proc_init_info.args.insert(0, CString::new(path).unwrap());
if let Err(e) = run_init_process(proc_init_info, trap_frame) {
if e != SystemError::ENOENT {
error!(
"Failed to run init process: {path} exists but couldn't execute it (error {:?})",
e
);
}
proc_init_info.args.remove(0);
return Err(e);
}
Ok(())
}
fn run_init_process(
proc_init_info: &ProcInitInfo,
trap_frame: &mut TrapFrame,
) -> Result<(), SystemError> {
compiler_fence(Ordering::SeqCst);
let path = proc_init_info.proc_name.to_str().unwrap();
Syscall::do_execve(
path.to_string(),
proc_init_info.args.clone(),
proc_init_info.envs.clone(),
trap_frame,
)?;
Ok(())
}