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 impl KernelCmdlineParamBuilder {
new(name: &'static str, ty: KCmdlineParamType) -> Self47 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
default_str(mut self, default_str: &'static str) -> Self57 pub const fn default_str(mut self, default_str: &'static str) -> Self {
58 self.default_str = default_str;
59 self
60 }
61
default_bool(mut self, default_bool: bool) -> Self62 pub const fn default_bool(mut self, default_bool: bool) -> Self {
63 self.default_bool = default_bool;
64 self
65 }
66
inv(mut self, inv: bool) -> Self67 pub const fn inv(mut self, inv: bool) -> Self {
68 self.inv = inv;
69 self
70 }
71
build_early_kv(self) -> Option<KernelCmdlineEarlyKV>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
build(self) -> Option<KernelCmdlineParameter>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 {
name(&self) -> &str114 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类型参数的值
value_bool(&self) -> Option<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类型参数的值
value_str(&self) -> Option<&str>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
is_arg(&self) -> bool142 pub fn is_arg(&self) -> bool {
143 matches!(self, KernelCmdlineParameter::Arg(_))
144 }
145
is_kv(&self) -> bool146 pub fn is_kv(&self) -> bool {
147 matches!(self, KernelCmdlineParameter::KV(_))
148 }
149
is_early_kv(&self) -> bool150 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)]
force_mut(&self) -> &mut Self160 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 {
value(&self) -> bool177 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
value(&self) -> &[u8]201 pub fn value(&self) -> &[u8] {
202 &self.value[..self.index]
203 }
204
value_str(&self) -> Option<&str>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)]
force_mut(&self) -> &mut Self215 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 {
new() -> Self233 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
init_proc_path(&self) -> Option<CString>243 pub(super) fn init_proc_path(&self) -> Option<CString> {
244 self.inner.lock().init_path.clone()
245 }
246
init_proc_args(&self) -> Vec<CString>247 pub(super) fn init_proc_args(&self) -> Vec<CString> {
248 self.inner.lock().init_args.clone()
249 }
250
init_proc_envs(&self) -> Vec<CString>251 pub(super) fn init_proc_envs(&self) -> Vec<CString> {
252 self.inner.lock().init_envs.clone()
253 }
254
255 /// 在内存管理初始化之前设置部分参数
early_init(&self)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 /// 在内存管理初始化之后设置命令行参数
init(&self)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
default_initialize(&self)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
find_param( &self, node: Option<&str>, option: &str, param_typ: KCmdlineParamType, ) -> Option<&KernelCmdlineParameter>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
split_arg<'a>(&self, arg: &'a str) -> Option<(Option<&'a str>, &'a str, Option<&'a str>)>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
split_args<'a>(&self, cmdline: &'a str) -> impl Iterator<Item = &'a str>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