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