Skip to main content

kernel/lib/types/
boot_info.rs

1// SPDX-License-Identifier: GPL-3.0-only
2//! Boot Info Struct (and all necessary types for it), used to call kernel_main
3//!
4//! Authors: MarioS271
5
6use crate::kprint::log_entry::LogLevel;
7use crate::kprint::state::LogTargets;
8
9/// Standardized Boot Info passed to [`kernel_main`](crate::kernel_main)
10///
11/// This does not contain a mem map entry, each arch is responsible for that as mm_init
12/// is per arch anyway
13pub struct BootInfo {
14    pub hhdm_offset: u64,
15    pub rsdp_addr: Option<u64>,
16    pub kernel_sections: KernelSectionInfo,
17    pub cmdline: KernelCmdline,
18    pub framebuffer: FramebufferInfo,
19}
20
21
22///////////////// KERNEL CMD LINE /////////////////
23
24/// Kernel CMD line params
25pub struct KernelCmdline {
26    pub log_level: LogLevel,
27    pub log_targets: LogTargets,
28    pub panic_action: PanicAction
29}
30impl KernelCmdline {
31    const KEY_PARSE_BUFFER_LEN: usize = 16;
32    const VALUE_PARSE_BUFFER_LEN: usize = 32;
33
34    /// Parse a given CMD line into `self`
35    pub fn parse_in_cmd_line(&mut self, cmd_line: &str) {
36        let tokens = cmd_line.split_ascii_whitespace();
37
38        for token in tokens {
39            let mut parts = token.splitn(2, '=');
40
41            let key_ptr = parts.next().unwrap();
42            let value_ptr = parts.next().unwrap_or("");
43
44            let mut key = [0u8; Self::KEY_PARSE_BUFFER_LEN];
45            let mut value = [0u8; Self::VALUE_PARSE_BUFFER_LEN];
46
47            let key_len = key_ptr.len().min(Self::KEY_PARSE_BUFFER_LEN);
48            key[..key_len].copy_from_slice(&key_ptr.as_bytes()[..key_len]);
49
50            let value_len = value_ptr.len().min(Self::VALUE_PARSE_BUFFER_LEN);
51            value[..value_len].copy_from_slice(&value_ptr.as_bytes()[..value_len]);
52
53            key.make_ascii_lowercase();
54            value.make_ascii_lowercase();
55
56            let key_as_str_slice = || {
57                core::str::from_utf8(&key[..key_len]).unwrap_or("")
58            };
59
60            let value_as_str_slice = || {
61                core::str::from_utf8(&value[..value_len]).unwrap_or("")
62            };
63            let value_as_u8 = || {
64                value_as_str_slice().parse::<u8>().ok()
65            };
66
67            match key_as_str_slice() {
68                // Key+Value flags
69                "loglevel" => {
70                    let Some(value_u8) = value_as_u8() else {
71                        match value_as_str_slice() {
72                            "emergency" | "emerg" => {
73                                self.log_level = LogLevel::Emergency;
74                                continue;
75                            },
76                            "alert" => {
77                                self.log_level = LogLevel::Alert;
78                                continue;
79                            }
80                            "critical" | "crit" => {
81                                self.log_level = LogLevel::Critical;
82                                continue;
83                            }
84                            "error" => {
85                                self.log_level = LogLevel::Error;
86                                continue;
87                            }
88                            "warn" => {
89                                self.log_level = LogLevel::Warn;
90                                continue;
91                            }
92                            "notice" => {
93                                self.log_level = LogLevel::Notice;
94                                continue;
95                            }
96                            "info" => {
97                                self.log_level = LogLevel::Info;
98                                continue;
99                            }
100                            "debug" => {
101                                self.log_level = LogLevel::Debug;
102                                continue;
103                            }
104                            _ => { continue; }
105                        }
106                    };
107
108                    let log_level = LogLevel::from_u8(value_u8);
109                    if log_level.is_none() { return; }
110                    self.log_level = log_level.unwrap();
111                }
112                "console" => {
113                    let tokens = value_as_str_slice().split(',');
114                    for token in tokens {
115                         match token {
116                             "all" => { self.log_targets |= LogTargets::ALL; }
117                             "uart" => { self.log_targets |= LogTargets::UART; }
118                             "basic-fb" => { self.log_targets |= LogTargets::BASIC_FB; }
119                             _ => {}
120                         }
121                    }
122                }
123                "panic" => {
124                    match value_as_str_slice() {
125                        "halt" => { self.panic_action = PanicAction::Halt; }
126                        "reboot" => { self.panic_action = PanicAction::Reboot; }
127                        _ => {}
128                    }
129                }
130
131                // Key only flags
132                "quiet" => {
133                    self.log_level = LogLevel::Warn;
134                }
135                "debug" => {
136                    self.log_level = LogLevel::Debug;
137                }
138
139                _ => {}
140            }
141        }
142    }
143}
144impl Default for KernelCmdline {
145    /// Default kernel CMD line params
146    fn default() -> Self {
147        Self {
148            log_level: crate::config::MAX_LOG_LEVEL,
149            log_targets: crate::config::DEFAULT_LOG_TARGETS,
150            panic_action: crate::config::DEFAULT_PANIC_ACTION
151        }
152    }
153}
154
155
156/// What the kernel should do at the end of a panic
157///
158/// The default value should always be 0 to avoid moving structs which statically
159/// initialize this from `.bss` to `.data`
160#[derive(Copy, Clone)]
161#[repr(u8)]
162pub enum PanicAction {
163    Halt = 0,
164    Reboot = 1
165}
166impl PanicAction {
167    /// Construct a new [`PanicAction`] from a `u8`
168    pub fn from_u8(value: u8) -> Option<Self> {
169        use PanicAction::*;
170        match value {
171            0 => Some(Halt),
172            1 => Some(Reboot),
173            _ => None
174        }
175    }
176
177    /// Check if the given `u8` corresponds to a valid panic action
178    pub fn is_valid_panic_action(value: u8) -> bool {
179        use PanicAction::*;
180        if value >= Halt as u8 && value <= Reboot as u8 {
181            return true;
182        }
183        false
184    }
185}
186
187
188///////////////// FRAMEBUFFER INFO /////////////////
189
190/// Bootloader-provided info for constructing the basic framebuffer
191pub struct FramebufferInfo {
192    pub addr: *mut u32,
193    pub pixels_per_row: u64,
194    pub width: u64,
195    pub height: u64,
196    pub bpp: u16
197}
198
199/// Virtual addresses of kernel ELF section boundaries
200pub struct KernelSectionInfo {
201    pub kernel_phys_start: u64,
202    pub kernel_start: u64,
203    /// This points to the byte after the last `.text` byte
204    pub kernel_text_end: u64,
205    /// This points to the byte after the last `.rodata` byte
206    pub kernel_rodata_end: u64,
207    pub kernel_end: u64
208}