//! Kernel commandline parameters handling use alloc::string::String; use libk_util::OneTimeInit; use yggdrasil_abi::error::Error; use crate::fs::sysfs::{ self, attribute::{StringAttribute, StringAttributeOps}, }; #[cfg(any(target_arch = "x86_64", target_arch = "x86", rust_analyzer))] mod x86; #[cfg(any(target_arch = "x86_64", target_arch = "x86", rust_analyzer))] pub use x86::X86Options; #[cfg(any(target_arch = "x86_64", rust_analyzer))] mod x86_64; #[cfg(any(target_arch = "x86_64", rust_analyzer))] pub use x86_64::X86_64Options; mod general; pub use general::DebugOptions; trait SetOption { fn set_key_value(&mut self, key: &str, value: &str) -> bool; fn set_flag(&mut self, value: &str) -> bool; } /// Kernel commandline options #[derive(Debug, Default)] pub struct Options { pub debug: DebugOptions, #[cfg(any(target_arch = "x86_64", target_arch = "x86", rust_analyzer))] pub x86: X86Options, #[cfg(any(target_arch = "x86_64", rust_analyzer))] pub x86_64: X86_64Options, } impl SetOption for Options { fn set_flag(&mut self, value: &str) -> bool { match value { _ if let Some(value) = value.strip_prefix("debug.") => self.debug.set_flag(value), #[cfg(any(target_arch = "x86_64", target_arch = "x86", rust_analyzer))] _ if let Some(value) = value.strip_prefix("x86.") => self.x86.set_flag(value), #[cfg(any(target_arch = "x86_64", rust_analyzer))] _ if let Some(value) = value.strip_prefix("x86_64.") => self.x86_64.set_flag(value), _ => false, } } fn set_key_value(&mut self, key: &str, value: &str) -> bool { match key { _ if let Some(key) = key.strip_prefix("debug.") => self.debug.set_key_value(key, value), #[cfg(any(target_arch = "x86_64", target_arch = "x86", rust_analyzer))] _ if let Some(key) = key.strip_prefix("x86.") => self.x86.set_key_value(key, value), #[cfg(any(target_arch = "x86_64", rust_analyzer))] _ if let Some(key) = key.strip_prefix("x86_64.") => { self.x86_64.set_key_value(key, value) } _ => false, } } } static OPTIONS: OneTimeInit = OneTimeInit::new(); static OPTIONS_STRING: OneTimeInit = OneTimeInit::new(); pub fn get() -> &'static Options { OPTIONS.get() } fn parse_argument(options: &mut Options, arg: &str) -> bool { let arg = arg.trim(); if let Some((key, value)) = arg.split_once('=') { options.set_key_value(key.trim_end(), value.trim_start()) } else { options.set_flag(arg) } } /// Sets up kernel options from an argument list pub fn parse_boot_argument_list<'a, I: Iterator>(args: I) { let mut options = Default::default(); let mut string = String::new(); args.for_each(|arg| { if parse_argument(&mut options, arg) { string.push_str(arg); string.push('\n'); } }); OPTIONS.init(options); OPTIONS_STRING.init(string); // Add to sysfs if let Some(kernel) = sysfs::kernel() { struct Cmdline; impl StringAttributeOps for Cmdline { const NAME: &'static str = "cmdline"; const NEWLINE: bool = false; fn read(_state: &Self::Data) -> Result { Ok(OPTIONS_STRING.get().into()) } } kernel.add_attribute(StringAttribute::from(Cmdline)).ok(); } } /// Sets up kernel options from an argument string, where options are separated by whitespace pub fn parse_boot_arguments(args: &str) { parse_boot_argument_list(args.trim().split(' ')); }