1 use core::{ 2 str, 3 sync::atomic::{fence, Ordering}, 4 }; 5 6 use alloc::{ffi::CString, vec::Vec}; 7 8 use crate::libs::spinlock::SpinLock; 9 10 use super::boot_params; 11 12 #[::linkme::distributed_slice] 13 pub static KCMDLINE_PARAM_EARLY_KV: [KernelCmdlineParameter] = [..]; 14 15 #[::linkme::distributed_slice] 16 pub static KCMDLINE_PARAM_KV: [KernelCmdlineParameter] = [..]; 17 18 #[::linkme::distributed_slice] 19 pub static KCMDLINE_PARAM_ARG: [KernelCmdlineParameter] = [..]; 20 21 static KERNEL_CMDLINE_PARAM_MANAGER: KernelCmdlineManager = KernelCmdlineManager::new(); 22 23 #[inline(always)] 24 pub fn kenrel_cmdline_param_manager() -> &'static KernelCmdlineManager { 25 &KERNEL_CMDLINE_PARAM_MANAGER 26 } 27 28 #[derive(Debug, Clone, Copy, PartialEq, Eq)] 29 pub enum KCmdlineParamType { 30 /// bool类型参数 31 Arg, 32 /// key-value类型参数 33 KV, 34 /// 内存管理初始化之前的KV参数 35 EarlyKV, 36 } 37 38 pub struct KernelCmdlineParamBuilder { 39 name: &'static str, 40 ty: KCmdlineParamType, 41 default_str: &'static str, 42 default_bool: bool, 43 inv: bool, 44 } 45 46 impl KernelCmdlineParamBuilder { 47 pub const fn new(name: &'static str, ty: KCmdlineParamType) -> Self { 48 Self { 49 name, 50 ty, 51 default_str: "", 52 default_bool: false, 53 inv: false, 54 } 55 } 56 57 pub const fn default_str(mut self, default_str: &'static str) -> Self { 58 self.default_str = default_str; 59 self 60 } 61 62 pub const fn default_bool(mut self, default_bool: bool) -> Self { 63 self.default_bool = default_bool; 64 self 65 } 66 67 pub const fn inv(mut self, inv: bool) -> Self { 68 self.inv = inv; 69 self 70 } 71 72 pub const fn build_early_kv(self) -> Option<KernelCmdlineEarlyKV> { 73 if matches!(self.ty, KCmdlineParamType::EarlyKV) { 74 Some(KernelCmdlineEarlyKV { 75 name: self.name, 76 value: [0; KernelCmdlineEarlyKV::VALUE_MAX_LEN], 77 index: 0, 78 initialized: false, 79 default: self.default_str, 80 }) 81 } else { 82 None 83 } 84 } 85 86 pub const fn build(self) -> Option<KernelCmdlineParameter> { 87 match self.ty { 88 KCmdlineParamType::Arg => Some(KernelCmdlineParameter::Arg(KernelCmdlineArg { 89 name: self.name, 90 value: self.default_bool, 91 initialized: false, 92 inv: self.inv, 93 default: self.default_bool, 94 })), 95 KCmdlineParamType::KV => Some(KernelCmdlineParameter::KV(KernelCmdlineKV { 96 name: self.name, 97 value: None, 98 initialized: false, 99 default: self.default_str, 100 })), 101 _ => None, 102 } 103 } 104 } 105 106 #[allow(dead_code)] 107 pub enum KernelCmdlineParameter { 108 Arg(KernelCmdlineArg), 109 KV(KernelCmdlineKV), 110 EarlyKV(&'static KernelCmdlineEarlyKV), 111 } 112 113 impl KernelCmdlineParameter { 114 pub fn name(&self) -> &str { 115 match self { 116 KernelCmdlineParameter::Arg(v) => v.name, 117 KernelCmdlineParameter::KV(v) => v.name, 118 KernelCmdlineParameter::EarlyKV(v) => v.name, 119 } 120 } 121 122 /// 获取bool类型参数的值 123 pub fn value_bool(&self) -> Option<bool> { 124 match self { 125 KernelCmdlineParameter::Arg(v) => Some(v.value()), 126 _ => None, 127 } 128 } 129 130 /// 获取key-value类型参数的值 131 pub fn value_str(&self) -> Option<&str> { 132 match self { 133 KernelCmdlineParameter::Arg(_) => None, 134 KernelCmdlineParameter::KV(v) => v 135 .value 136 .as_ref() 137 .and_then(|v| str::from_utf8(v.as_bytes()).ok()), 138 KernelCmdlineParameter::EarlyKV(v) => v.value_str(), 139 } 140 } 141 142 pub fn is_arg(&self) -> bool { 143 matches!(self, KernelCmdlineParameter::Arg(_)) 144 } 145 146 pub fn is_kv(&self) -> bool { 147 matches!(self, KernelCmdlineParameter::KV(_)) 148 } 149 150 pub fn is_early_kv(&self) -> bool { 151 matches!(self, KernelCmdlineParameter::EarlyKV(_)) 152 } 153 154 /// 强行获取可变引用 155 /// 156 /// # Safety 157 /// 158 /// 只能在内核初始化阶段pid0使用! 159 #[allow(clippy::mut_from_ref)] 160 unsafe fn force_mut(&self) -> &mut Self { 161 let p = self as *const Self as *mut Self; 162 p.as_mut().unwrap() 163 } 164 } 165 166 #[derive(Debug)] 167 pub struct KernelCmdlineArg { 168 name: &'static str, 169 value: bool, 170 initialized: bool, 171 /// 是否反转 172 inv: bool, 173 default: bool, 174 } 175 176 impl KernelCmdlineArg { 177 pub fn value(&self) -> bool { 178 volatile_read!(self.value) 179 } 180 } 181 182 pub struct KernelCmdlineKV { 183 name: &'static str, 184 value: Option<CString>, 185 initialized: bool, 186 default: &'static str, 187 } 188 189 /// 在内存管理初始化之前的KV参数 190 pub struct KernelCmdlineEarlyKV { 191 name: &'static str, 192 value: [u8; Self::VALUE_MAX_LEN], 193 index: usize, 194 initialized: bool, 195 default: &'static str, 196 } 197 198 impl KernelCmdlineEarlyKV { 199 pub const VALUE_MAX_LEN: usize = 256; 200 201 pub fn value(&self) -> &[u8] { 202 &self.value[..self.index] 203 } 204 205 pub fn value_str(&self) -> Option<&str> { 206 core::str::from_utf8(&self.value[..self.index]).ok() 207 } 208 209 /// 强行获取可变引用 210 /// 211 /// # Safety 212 /// 213 /// 只能在内核初始化阶段pid0使用! 214 #[allow(clippy::mut_from_ref)] 215 unsafe fn force_mut(&self) -> &mut Self { 216 let p = self as *const Self as *mut Self; 217 p.as_mut().unwrap() 218 } 219 } 220 221 pub struct KernelCmdlineManager { 222 inner: SpinLock<InnerKernelCmdlineManager>, 223 } 224 225 pub(super) struct InnerKernelCmdlineManager { 226 /// init进程的路径 227 init_path: Option<CString>, 228 init_args: Vec<CString>, 229 init_envs: Vec<CString>, 230 } 231 232 impl KernelCmdlineManager { 233 const fn new() -> Self { 234 Self { 235 inner: SpinLock::new(InnerKernelCmdlineManager { 236 init_path: None, 237 init_args: Vec::new(), 238 init_envs: Vec::new(), 239 }), 240 } 241 } 242 243 pub(super) fn init_proc_path(&self) -> Option<CString> { 244 self.inner.lock().init_path.clone() 245 } 246 247 pub(super) fn init_proc_args(&self) -> Vec<CString> { 248 self.inner.lock().init_args.clone() 249 } 250 251 pub(super) fn init_proc_envs(&self) -> Vec<CString> { 252 self.inner.lock().init_envs.clone() 253 } 254 255 /// 在内存管理初始化之前设置部分参数 256 pub fn early_init(&self) { 257 let boot_params = boot_params().read(); 258 259 for argument in self.split_args(boot_params.boot_cmdline_str()) { 260 let (node, option, value) = match self.split_arg(argument) { 261 Some(v) => v, 262 None => continue, 263 }; 264 // 查找参数 265 if let Some(param) = self.find_param(node, option, KCmdlineParamType::EarlyKV) { 266 let param = unsafe { param.force_mut() }; 267 match param { 268 KernelCmdlineParameter::EarlyKV(p) => { 269 let p = unsafe { p.force_mut() }; 270 if let Some(value) = value { 271 let value = value.as_bytes(); 272 let len = value.len().min(KernelCmdlineEarlyKV::VALUE_MAX_LEN); 273 p.value[..len].copy_from_slice(&value[..len]); 274 p.index = len; 275 } 276 p.initialized = true; 277 } 278 _ => unreachable!(), 279 } 280 fence(Ordering::SeqCst); 281 } 282 } 283 284 // 初始化默认值 285 KCMDLINE_PARAM_EARLY_KV.iter().for_each(|x| { 286 let x = unsafe { x.force_mut() }; 287 if let KernelCmdlineParameter::EarlyKV(v) = x { 288 if !v.initialized { 289 let v = unsafe { v.force_mut() }; 290 let len = v.default.len().min(KernelCmdlineEarlyKV::VALUE_MAX_LEN); 291 v.value[..len].copy_from_slice(v.default.as_bytes()); 292 v.index = len; 293 v.initialized = true; 294 } 295 } 296 }); 297 } 298 299 /// 在内存管理初始化之后设置命令行参数 300 pub fn init(&self) { 301 let mut inner = self.inner.lock(); 302 let boot_params = boot_params().read(); 303 // `--`以后的参数都是init进程的参数 304 let mut kernel_cmdline_end = false; 305 for argument in self.split_args(boot_params.boot_cmdline_str()) { 306 if kernel_cmdline_end { 307 if inner.init_path.is_none() { 308 panic!("cmdline: init proc path is not set while init proc args are set"); 309 } 310 if !argument.is_empty() { 311 inner.init_args.push(CString::new(argument).unwrap()); 312 } 313 continue; 314 } 315 316 if argument == "--" { 317 kernel_cmdline_end = true; 318 continue; 319 } 320 321 let (node, option, value) = match self.split_arg(argument) { 322 Some(v) => v, 323 None => continue, 324 }; 325 if option == "init" && value.is_some() { 326 if inner.init_path.is_some() { 327 panic!("cmdline: init proc path is set twice"); 328 } 329 inner.init_path = Some(CString::new(value.unwrap()).unwrap()); 330 continue; 331 } 332 // log::debug!( 333 // "cmdline: node: {:?}, option: {:?}, value: {:?}", 334 // node, 335 // option, 336 // value 337 // ); 338 if let Some(param) = self.find_param(node, option, KCmdlineParamType::KV) { 339 let param = unsafe { param.force_mut() }; 340 match param { 341 KernelCmdlineParameter::KV(p) => { 342 if p.value.is_some() { 343 log::warn!("cmdline: parameter {} is set twice", p.name); 344 continue; 345 } 346 p.value = Some(CString::new(value.unwrap()).unwrap()); 347 p.initialized = true; 348 } 349 _ => unreachable!(), 350 } 351 fence(Ordering::SeqCst); 352 } else if let Some(param) = self.find_param(node, option, KCmdlineParamType::Arg) { 353 let param = unsafe { param.force_mut() }; 354 match param { 355 KernelCmdlineParameter::Arg(p) => { 356 if p.initialized { 357 log::warn!("cmdline: parameter {} is set twice", p.name); 358 continue; 359 } 360 p.value = !p.inv; 361 p.initialized = true; 362 } 363 _ => unreachable!(), 364 } 365 fence(Ordering::SeqCst); 366 } else if node.is_none() { 367 if let Some(val) = value { 368 inner 369 .init_envs 370 .push(CString::new(format!("{}={}", option, val)).unwrap()); 371 } else if !option.is_empty() { 372 inner.init_args.push(CString::new(option).unwrap()); 373 } 374 } 375 } 376 fence(Ordering::SeqCst); 377 // 初始化默认值 378 self.default_initialize(); 379 fence(Ordering::SeqCst); 380 } 381 382 fn default_initialize(&self) { 383 KCMDLINE_PARAM_ARG.iter().for_each(|x| { 384 let x = unsafe { x.force_mut() }; 385 if let KernelCmdlineParameter::Arg(v) = x { 386 if !v.initialized { 387 v.value = v.default; 388 v.initialized = true; 389 } 390 } 391 fence(Ordering::SeqCst); 392 }); 393 394 KCMDLINE_PARAM_KV.iter().for_each(|x| { 395 let x = unsafe { x.force_mut() }; 396 if let KernelCmdlineParameter::KV(v) = x { 397 if !v.initialized { 398 v.value = Some(CString::new(v.default).unwrap()); 399 v.initialized = true; 400 } 401 } 402 fence(Ordering::SeqCst); 403 }); 404 } 405 406 fn find_param( 407 &self, 408 node: Option<&str>, 409 option: &str, 410 param_typ: KCmdlineParamType, 411 ) -> Option<&KernelCmdlineParameter> { 412 let list = match param_typ { 413 KCmdlineParamType::Arg => &KCMDLINE_PARAM_ARG, 414 KCmdlineParamType::KV => &KCMDLINE_PARAM_KV, 415 KCmdlineParamType::EarlyKV => &KCMDLINE_PARAM_EARLY_KV, 416 }; 417 418 list.iter().find(|x| { 419 let name = x.name(); 420 if let Some(node) = node { 421 // 加1是因为有一个点号 422 name.len() == (node.len() + option.len() + 1) 423 && name.starts_with(node) 424 && name[node.len() + 1..].starts_with(option) 425 } else { 426 name == option 427 } 428 }) 429 } 430 431 fn split_arg<'a>(&self, arg: &'a str) -> Option<(Option<&'a str>, &'a str, Option<&'a str>)> { 432 let mut iter = arg.splitn(2, '='); 433 let key = iter.next().unwrap(); 434 let value = iter.next(); 435 let value = value.map(|v| v.trim()); 436 if value.is_some() && iter.next().is_some() { 437 log::warn!("cmdline: invalid argument: {}", arg); 438 return None; 439 } 440 441 let mut iter = key.splitn(2, '.'); 442 let v1 = iter.next().map(|v| v.trim()); 443 let v2 = iter.next().map(|v| v.trim()); 444 let v3 = iter.next().map(|v| v.trim()); 445 let v = [v1, v2, v3]; 446 447 let mut key_split_len = 0; 448 v.iter().for_each(|x| { 449 if x.is_some() { 450 key_split_len += 1 451 } 452 }); 453 454 let (node, option) = match key_split_len { 455 1 => (None, v[0].unwrap()), 456 2 => (Some(v[0].unwrap()), v[1].unwrap()), 457 _ => { 458 log::warn!("cmdline: invalid argument: {}", arg); 459 return None; 460 } 461 }; 462 463 Some((node, option, value)) 464 } 465 466 fn split_args<'a>(&self, cmdline: &'a str) -> impl Iterator<Item = &'a str> { 467 // 是否在引号内 468 let mut in_quote = false; 469 cmdline.split(move |c: char| { 470 if c == '"' { 471 in_quote = !in_quote; 472 } 473 !in_quote && c.is_whitespace() 474 }) 475 } 476 } 477