use core::{ str, sync::atomic::{fence, Ordering}, }; use alloc::{ffi::CString, vec::Vec}; use crate::libs::spinlock::SpinLock; use super::boot_params; #[::linkme::distributed_slice] pub static KCMDLINE_PARAM_EARLY_KV: [KernelCmdlineParameter] = [..]; #[::linkme::distributed_slice] pub static KCMDLINE_PARAM_KV: [KernelCmdlineParameter] = [..]; #[::linkme::distributed_slice] pub static KCMDLINE_PARAM_ARG: [KernelCmdlineParameter] = [..]; static KERNEL_CMDLINE_PARAM_MANAGER: KernelCmdlineManager = KernelCmdlineManager::new(); #[inline(always)] pub fn kenrel_cmdline_param_manager() -> &'static KernelCmdlineManager { &KERNEL_CMDLINE_PARAM_MANAGER } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum KCmdlineParamType { /// bool类型参数 Arg, /// key-value类型参数 KV, /// 内存管理初始化之前的KV参数 EarlyKV, } pub struct KernelCmdlineParamBuilder { name: &'static str, ty: KCmdlineParamType, default_str: &'static str, default_bool: bool, inv: bool, } impl KernelCmdlineParamBuilder { pub const fn new(name: &'static str, ty: KCmdlineParamType) -> Self { Self { name, ty, default_str: "", default_bool: false, inv: false, } } pub const fn default_str(mut self, default_str: &'static str) -> Self { self.default_str = default_str; self } pub const fn default_bool(mut self, default_bool: bool) -> Self { self.default_bool = default_bool; self } pub const fn inv(mut self, inv: bool) -> Self { self.inv = inv; self } pub const fn build_early_kv(self) -> Option { if matches!(self.ty, KCmdlineParamType::EarlyKV) { Some(KernelCmdlineEarlyKV { name: self.name, value: [0; KernelCmdlineEarlyKV::VALUE_MAX_LEN], index: 0, initialized: false, default: self.default_str, }) } else { None } } pub const fn build(self) -> Option { match self.ty { KCmdlineParamType::Arg => Some(KernelCmdlineParameter::Arg(KernelCmdlineArg { name: self.name, value: self.default_bool, initialized: false, inv: self.inv, default: self.default_bool, })), KCmdlineParamType::KV => Some(KernelCmdlineParameter::KV(KernelCmdlineKV { name: self.name, value: None, initialized: false, default: self.default_str, })), _ => None, } } } #[allow(dead_code)] pub enum KernelCmdlineParameter { Arg(KernelCmdlineArg), KV(KernelCmdlineKV), EarlyKV(&'static KernelCmdlineEarlyKV), } impl KernelCmdlineParameter { pub fn name(&self) -> &str { match self { KernelCmdlineParameter::Arg(v) => v.name, KernelCmdlineParameter::KV(v) => v.name, KernelCmdlineParameter::EarlyKV(v) => v.name, } } /// 获取bool类型参数的值 pub fn value_bool(&self) -> Option { match self { KernelCmdlineParameter::Arg(v) => Some(v.value()), _ => None, } } /// 获取key-value类型参数的值 pub fn value_str(&self) -> Option<&str> { match self { KernelCmdlineParameter::Arg(_) => None, KernelCmdlineParameter::KV(v) => v .value .as_ref() .and_then(|v| str::from_utf8(v.as_bytes()).ok()), KernelCmdlineParameter::EarlyKV(v) => v.value_str(), } } pub fn is_arg(&self) -> bool { matches!(self, KernelCmdlineParameter::Arg(_)) } pub fn is_kv(&self) -> bool { matches!(self, KernelCmdlineParameter::KV(_)) } pub fn is_early_kv(&self) -> bool { matches!(self, KernelCmdlineParameter::EarlyKV(_)) } /// 强行获取可变引用 /// /// # Safety /// /// 只能在内核初始化阶段pid0使用! #[allow(clippy::mut_from_ref)] unsafe fn force_mut(&self) -> &mut Self { let p = self as *const Self as *mut Self; p.as_mut().unwrap() } } #[derive(Debug)] pub struct KernelCmdlineArg { name: &'static str, value: bool, initialized: bool, /// 是否反转 inv: bool, default: bool, } impl KernelCmdlineArg { pub fn value(&self) -> bool { volatile_read!(self.value) } } pub struct KernelCmdlineKV { name: &'static str, value: Option, initialized: bool, default: &'static str, } /// 在内存管理初始化之前的KV参数 pub struct KernelCmdlineEarlyKV { name: &'static str, value: [u8; Self::VALUE_MAX_LEN], index: usize, initialized: bool, default: &'static str, } impl KernelCmdlineEarlyKV { pub const VALUE_MAX_LEN: usize = 256; pub fn value(&self) -> &[u8] { &self.value[..self.index] } pub fn value_str(&self) -> Option<&str> { core::str::from_utf8(&self.value[..self.index]).ok() } /// 强行获取可变引用 /// /// # Safety /// /// 只能在内核初始化阶段pid0使用! #[allow(clippy::mut_from_ref)] unsafe fn force_mut(&self) -> &mut Self { let p = self as *const Self as *mut Self; p.as_mut().unwrap() } } pub struct KernelCmdlineManager { inner: SpinLock, } pub(super) struct InnerKernelCmdlineManager { /// init进程的路径 init_path: Option, init_args: Vec, init_envs: Vec, } impl KernelCmdlineManager { const fn new() -> Self { Self { inner: SpinLock::new(InnerKernelCmdlineManager { init_path: None, init_args: Vec::new(), init_envs: Vec::new(), }), } } pub(super) fn init_proc_path(&self) -> Option { self.inner.lock().init_path.clone() } pub(super) fn init_proc_args(&self) -> Vec { self.inner.lock().init_args.clone() } pub(super) fn init_proc_envs(&self) -> Vec { self.inner.lock().init_envs.clone() } /// 在内存管理初始化之前设置部分参数 pub fn early_init(&self) { let boot_params = boot_params().read(); for argument in self.split_args(boot_params.boot_cmdline_str()) { let (node, option, value) = match self.split_arg(argument) { Some(v) => v, None => continue, }; // 查找参数 if let Some(param) = self.find_param(node, option, KCmdlineParamType::EarlyKV) { let param = unsafe { param.force_mut() }; match param { KernelCmdlineParameter::EarlyKV(p) => { let p = unsafe { p.force_mut() }; if let Some(value) = value { let value = value.as_bytes(); let len = value.len().min(KernelCmdlineEarlyKV::VALUE_MAX_LEN); p.value[..len].copy_from_slice(&value[..len]); p.index = len; } p.initialized = true; } _ => unreachable!(), } fence(Ordering::SeqCst); } } // 初始化默认值 KCMDLINE_PARAM_EARLY_KV.iter().for_each(|x| { let x = unsafe { x.force_mut() }; if let KernelCmdlineParameter::EarlyKV(v) = x { if !v.initialized { let v = unsafe { v.force_mut() }; let len = v.default.len().min(KernelCmdlineEarlyKV::VALUE_MAX_LEN); v.value[..len].copy_from_slice(v.default.as_bytes()); v.index = len; v.initialized = true; } } }); } /// 在内存管理初始化之后设置命令行参数 pub fn init(&self) { let mut inner = self.inner.lock(); let boot_params = boot_params().read(); // `--`以后的参数都是init进程的参数 let mut kernel_cmdline_end = false; for argument in self.split_args(boot_params.boot_cmdline_str()) { if kernel_cmdline_end { if inner.init_path.is_none() { panic!("cmdline: init proc path is not set while init proc args are set"); } if !argument.is_empty() { inner.init_args.push(CString::new(argument).unwrap()); } continue; } if argument == "--" { kernel_cmdline_end = true; continue; } let (node, option, value) = match self.split_arg(argument) { Some(v) => v, None => continue, }; if option == "init" && value.is_some() { if inner.init_path.is_some() { panic!("cmdline: init proc path is set twice"); } inner.init_path = Some(CString::new(value.unwrap()).unwrap()); continue; } // log::debug!( // "cmdline: node: {:?}, option: {:?}, value: {:?}", // node, // option, // value // ); if let Some(param) = self.find_param(node, option, KCmdlineParamType::KV) { let param = unsafe { param.force_mut() }; match param { KernelCmdlineParameter::KV(p) => { if p.value.is_some() { log::warn!("cmdline: parameter {} is set twice", p.name); continue; } p.value = Some(CString::new(value.unwrap()).unwrap()); p.initialized = true; } _ => unreachable!(), } fence(Ordering::SeqCst); } else if let Some(param) = self.find_param(node, option, KCmdlineParamType::Arg) { let param = unsafe { param.force_mut() }; match param { KernelCmdlineParameter::Arg(p) => { if p.initialized { log::warn!("cmdline: parameter {} is set twice", p.name); continue; } p.value = !p.inv; p.initialized = true; } _ => unreachable!(), } fence(Ordering::SeqCst); } else if node.is_none() { if let Some(val) = value { inner .init_envs .push(CString::new(format!("{}={}", option, val)).unwrap()); } else if !option.is_empty() { inner.init_args.push(CString::new(option).unwrap()); } } } fence(Ordering::SeqCst); // 初始化默认值 self.default_initialize(); fence(Ordering::SeqCst); } fn default_initialize(&self) { KCMDLINE_PARAM_ARG.iter().for_each(|x| { let x = unsafe { x.force_mut() }; if let KernelCmdlineParameter::Arg(v) = x { if !v.initialized { v.value = v.default; v.initialized = true; } } fence(Ordering::SeqCst); }); KCMDLINE_PARAM_KV.iter().for_each(|x| { let x = unsafe { x.force_mut() }; if let KernelCmdlineParameter::KV(v) = x { if !v.initialized { v.value = Some(CString::new(v.default).unwrap()); v.initialized = true; } } fence(Ordering::SeqCst); }); } fn find_param( &self, node: Option<&str>, option: &str, param_typ: KCmdlineParamType, ) -> Option<&KernelCmdlineParameter> { let list = match param_typ { KCmdlineParamType::Arg => &KCMDLINE_PARAM_ARG, KCmdlineParamType::KV => &KCMDLINE_PARAM_KV, KCmdlineParamType::EarlyKV => &KCMDLINE_PARAM_EARLY_KV, }; list.iter().find(|x| { let name = x.name(); if let Some(node) = node { // 加1是因为有一个点号 name.len() == (node.len() + option.len() + 1) && name.starts_with(node) && name[node.len() + 1..].starts_with(option) } else { name == option } }) } fn split_arg<'a>(&self, arg: &'a str) -> Option<(Option<&'a str>, &'a str, Option<&'a str>)> { let mut iter = arg.splitn(2, '='); let key = iter.next().unwrap(); let value = iter.next(); let value = value.map(|v| v.trim()); if value.is_some() && iter.next().is_some() { log::warn!("cmdline: invalid argument: {}", arg); return None; } let mut iter = key.splitn(2, '.'); let v1 = iter.next().map(|v| v.trim()); let v2 = iter.next().map(|v| v.trim()); let v3 = iter.next().map(|v| v.trim()); let v = [v1, v2, v3]; let mut key_split_len = 0; v.iter().for_each(|x| { if x.is_some() { key_split_len += 1 } }); let (node, option) = match key_split_len { 1 => (None, v[0].unwrap()), 2 => (Some(v[0].unwrap()), v[1].unwrap()), _ => { log::warn!("cmdline: invalid argument: {}", arg); return None; } }; Some((node, option, value)) } fn split_args<'a>(&self, cmdline: &'a str) -> impl Iterator { // 是否在引号内 let mut in_quote = false; cmdline.split(move |c: char| { if c == '"' { in_quote = !in_quote; } !in_quote && c.is_whitespace() }) } }