119 lines
3.6 KiB
Rust

//! 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<Options> = OneTimeInit::new();
static OPTIONS_STRING: OneTimeInit<String> = 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<Item = &'a str>>(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<String, Error> {
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(' '));
}