123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476 |
- 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<KernelCmdlineEarlyKV> {
- 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<KernelCmdlineParameter> {
- 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<bool> {
- 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<CString>,
- 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<InnerKernelCmdlineManager>,
- }
- pub(super) struct InnerKernelCmdlineManager {
- /// init进程的路径
- init_path: Option<CString>,
- init_args: Vec<CString>,
- init_envs: Vec<CString>,
- }
- 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<CString> {
- self.inner.lock().init_path.clone()
- }
- pub(super) fn init_proc_args(&self) -> Vec<CString> {
- self.inner.lock().init_args.clone()
- }
- pub(super) fn init_proc_envs(&self) -> Vec<CString> {
- 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<Item = &'a str> {
- // 是否在引号内
- let mut in_quote = false;
- cmdline.split(move |c: char| {
- if c == '"' {
- in_quote = !in_quote;
- }
- !in_quote && c.is_whitespace()
- })
- }
- }
|