DragonOS/kernel/src/init/initial_kthread.rs
LoGin f9fe30be89
feat(boot): 内核启动命令行参数解析 (#969)
支持解析启动命令行参数,行为与Linux一致。具体见文档。

bbs链接:https://bbs.dragonos.org.cn/t/topic/362
issue: https://github.com/DragonOS-Community/DragonOS/issues/865

支持了三种参数:
- Arg (不带Value的参数)
- KV (正常的KV参数)
- EarlyKV (在内存管理初始化之前解析)

# TODO

- 支持在`/proc/cmdline`下面查看内核启动时的命令行参数。
- 支持回调函数,允许更加灵活的设置参数的值(目前用不到,就没写了)

Signed-off-by: longjin <longjin@DragonOS.org>
2024-10-13 23:39:55 +08:00

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