cmdline.rs 14 KB

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