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