mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 14:16:47 +00:00
支持解析启动命令行参数,行为与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>
153 lines
4.4 KiB
Rust
153 lines
4.4 KiB
Rust
//! 这个文件内放置初始内核线程的代码。
|
||
|
||
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(())
|
||
}
|