stivale_boot/v1/mod.rs
1//! This module contains the definitions for stivale boot protocol. The stivale boot protocol aims
2//! to be a simple to implement protocol which provides the kernel with most of the features one may
3//! need in a modern x86_64 context (although 32-bit x86 is also supported).
4
5mod utils;
6
7use core::marker::PhantomData;
8
9union StivaleHeaderEntryPoint {
10 func: extern "C" fn(&'static StivaleStruct) -> !,
11 zero: u16,
12}
13
14bitflags::bitflags! {
15 pub struct StivaleHeaderFlags: u16 {
16 /// If set, the bootloader will be instructed to use graphics
17 /// framebuffer mode. Else text mode will be selected.
18 const FRAMEBUFFER_MODE = 1 << 0;
19 /// If set, level 5 paging will be requested to the bootloader
20 /// (only if avaliable). Else standard level 4 paging will be used.
21 ///
22 /// ## 32-bit
23 /// This bit is ignored for 32-bit kernels.
24 const LEVEL_5_PAGING = 1 << 1;
25 /// Formerly used to indicate whether to enable KASLR,
26 /// this flag is now reserved as KASLR is enabled in the
27 /// bootloader configuration instead. Presently
28 /// reserved and unused.
29 const KASLR = 1 << 2;
30 /// If set, all pointers, except otherwise noted,
31 /// are to be offset to the higher half. That is,
32 /// their value will be their physical address plus
33 /// `0xffff800000000000` with 4-level paging or
34 /// `0xff00000000000000` with 5-level paging on x86_64.
35 /// Success for this feature can be tested by checking
36 /// whether the stivale struct pointer argument passed
37 /// to the entry point function is in the higher
38 /// half or not.
39 const HIGHER_HALF = 1 << 3;
40 const NULL = 0x00;
41 }
42}
43
44#[repr(C)]
45pub struct StivaleHeader {
46 stack: *const u8,
47 flags: StivaleHeaderFlags,
48 framebuffer_width: u16,
49 framebuffer_height: u16,
50 framebuffer_bpp: u16,
51 entry_point: StivaleHeaderEntryPoint,
52}
53
54impl StivaleHeader {
55 pub fn new() -> Self {
56 Self {
57 stack: core::ptr::null(),
58 flags: StivaleHeaderFlags::empty(),
59 framebuffer_width: 0x00,
60 framebuffer_height: 0x00,
61 framebuffer_bpp: 0x00,
62 entry_point: StivaleHeaderEntryPoint { zero: 0x00 },
63 }
64 }
65
66 /// Sets the requested framebuffer width. Only parsed if a graphics mode is requested. If
67 /// set to zero, the bootloader would pick the best possible video mode automatically (recommended).
68 pub fn framebuffer_width(mut self, framebuffer_width: u16) -> Self {
69 self.framebuffer_width = framebuffer_width;
70 self
71 }
72
73 /// Sets the requested framebuffer height. Only parsed if a graphics mode is requested. If
74 /// set to zero, the bootloader would pick the best possible video mode automatically (recommended).
75 pub fn framebuffer_height(mut self, framebuffer_height: u16) -> Self {
76 self.framebuffer_height = framebuffer_height;
77 self
78 }
79
80 /// Sets the requested framebuffer bpp. Only parsed if a graphics mode is requested. If
81 /// set to zero, the bootloader would pick the best possible video mode automatically (recommended).
82 pub fn framebuffer_bpp(mut self, framebuffer_bpp: u16) -> Self {
83 self.framebuffer_bpp = framebuffer_bpp;
84 self
85 }
86
87 /// Sets the provided stivale header flags. See the documentation of [StivaleHeaderFlags]
88 /// for more information.
89 pub fn flags(mut self, flags: StivaleHeaderFlags) -> Self {
90 self.flags = flags;
91 self
92 }
93
94 /// Sets the stack pointer which will be in ESP/RSP when the kernel is loaded.
95 /// It can only be set to NULL for 64-bit kernels. 32-bit kernels are mandated to
96 /// provide a vaild stack. 64-bit and 32-bit valid stacks must be at least 256 bytes
97 /// in usable space and must be 16 byte aligned addresses.
98 pub fn stack(mut self, stack: *const u8) -> Self {
99 self.stack = stack;
100 self
101 }
102
103 /// Sets the entry point address. If not zero, the bootloader would jump to the specified
104 /// entry point instead of jumping to the entry point specified the kernel ELF.
105 pub fn entry_point(mut self, func: extern "C" fn(&'static StivaleStruct) -> !) -> Self {
106 self.entry_point = StivaleHeaderEntryPoint { func };
107 self
108 }
109}
110
111/// Structure representing a module, containing the information of a module that
112/// the bootloader loaded alongside the kernel.
113#[repr(C)]
114pub struct StivaleModule {
115 /// Address where this module has been loaded.
116 pub start: u64,
117 /// End address of this module.
118 pub end: u64,
119 /// ASCII 0-terminated string passed to the module as specified in
120 /// the config file.
121 pub string: [u8; 128],
122}
123
124impl StivaleModule {
125 /// Returns the size of this module.
126 #[inline]
127 pub fn size(&self) -> u64 {
128 self.end - self.start
129 }
130
131 /// Returns the ASCII 0-terminated string passed to the module as specified in the config file
132 /// as a rust string.
133 #[inline]
134 pub fn as_str(&self) -> &str {
135 self::utils::string_from_slice(&self.string)
136 }
137}
138
139/// Iterator over all the modules that were loaded.
140#[derive(Clone)]
141pub struct StivaleModuleIter<'a> {
142 /// A reference to the stivale structure.
143 sref: &'a StivaleStruct,
144 /// The index of the module entry that we are about to index.
145 current: u64,
146 phantom: PhantomData<&'a StivaleModule>,
147}
148
149impl<'a> Iterator for StivaleModuleIter<'a> {
150 type Item = &'a StivaleModule;
151
152 fn next(&mut self) -> Option<Self::Item> {
153 if self.current < self.sref.module_len {
154 let entry = &self.sref.modules_as_slice()[self.current as usize];
155 self.current += 1;
156
157 Some(entry)
158 } else {
159 None
160 }
161 }
162}
163
164/// The type of a memory map entry. The entries are guaranteed to be sorted by base address,
165/// lowest to highest.
166///
167/// ## Alignment
168/// Usable and bootloader reclaimable entries are guaranteed to be 4096 byte aligned for both
169/// base and length. Usable and bootloader reclaimable entries are **guaranteed** not to overlap with
170/// any other entry.
171#[repr(u32)]
172#[derive(Clone, Copy, Debug, PartialEq)]
173pub enum StivaleMemoryMapEntryType {
174 /// Usable memory.
175 Usable = 1,
176 /// Memory reserved by the system.
177 Reserved = 2,
178 /// ACPI memory that can be reclaimed.
179 AcpiReclaimable = 3,
180 /// ACPI memory that cannot be reclaimed.
181 AcpiNvs = 4,
182 /// Memory marked as defective (bad RAM).
183 BadMemory = 5,
184 /// Memory used by the bootloader that can be reclaimed after it's not being used anymore.
185 BootloaderReclaimable = 0x1000,
186 /// Memory containing the kernel and any modules.
187 Kernel = 0x1001,
188 /// Memory containing the framebuffer.
189 Framebuffer = 0x1002,
190}
191
192#[repr(C)]
193#[derive(Debug, Copy, Clone)]
194pub struct StivaleMemoryMapEntry {
195 /// Physical address of base of the memory section.
196 pub base: u64,
197 /// Length of this memory section.
198 pub length: u64,
199 /// The type of this memory map entry.
200 pub entry_type: StivaleMemoryMapEntryType,
201
202 padding: u32,
203}
204
205impl StivaleMemoryMapEntry {
206 /// Returns the end address of this memory region.
207 #[inline]
208 pub fn end_address(&self) -> u64 {
209 self.base + self.length
210 }
211
212 /// Returns the entry type of this memory region. External function is required
213 /// as reference the entry_type packed field is not aligned.
214 #[inline]
215 pub fn entry_type(&self) -> StivaleMemoryMapEntryType {
216 self.entry_type
217 }
218}
219
220/// Iterator over all the memory regions provided by the stivale bootloader.
221#[derive(Clone)]
222pub struct StivaleMemoryMapIter<'a> {
223 /// A reference to the stivale structure.
224 sref: &'a StivaleStruct,
225 /// The index of the memory map entry that we are about to index.
226 current: u64,
227 phantom: PhantomData<&'a StivaleMemoryMapEntry>,
228}
229
230impl<'a> Iterator for StivaleMemoryMapIter<'a> {
231 type Item = &'a StivaleMemoryMapEntry;
232
233 fn next(&mut self) -> Option<Self::Item> {
234 if self.current < self.sref.memory_map_len {
235 let entry = &self.sref.memory_map_as_slice()[self.current as usize];
236 self.current += 1;
237
238 Some(entry)
239 } else {
240 None
241 }
242 }
243}
244
245#[repr(C)]
246pub struct StivaleStruct {
247 /// Address of the null-terminated command line.
248 pub command_line: u64,
249 /// Pointer to the memory map array.
250 pub memory_map_array: [StivaleMemoryMapEntry; 0],
251 /// Length of the memory map entries.
252 pub memory_map_len: u64,
253
254 /// Address of the framebuffer if avaliable else its set to zero.
255 pub framebuffer_addr: u64,
256 /// The framebuffer pitch in bytes.
257 pub framebuffer_pitch: u16,
258 /// Width of the framebuffer in pixels.
259 pub framebuffer_width: u16,
260 /// Height of the framebuffer in pixels.
261 pub framebuffer_height: u16,
262 /// The framebuffer bits per pixels.
263 pub framebuffer_bpp: u16,
264
265 /// Address of the RSDP ACPI structure.
266 pub rsdp_adddres: u64,
267
268 /// The length of modules that the stivale bootloader loaded according to the
269 /// config.
270 pub module_len: u64,
271 /// Pointer to the modules array.
272 pub modules: [StivaleModule; 0],
273
274 /// UNIX epoch at boot, which is read from system RTC.
275 pub unix_epoch: u64,
276 pub flags: u64,
277
278 /// Size of the red mask in RGB.
279 pub red_mask_size: u8,
280 /// Shift of the red mask in RGB.
281 pub red_mask_shift: u8,
282 /// Size of the green mask in RGB.
283 pub green_mask_size: u8,
284 /// Shift of the green mask in RGB.
285 pub green_mask_shift: u8,
286 /// Size of the blue mask in RGB.
287 pub blue_mask_size: u8,
288 /// Shift of the blue mask in RGB.
289 pub blue_mask_shift: u8,
290 _padding: u8,
291
292 /// 32-bit SMBIOS entry point address. Set to 0 if unavailable.
293 pub smbios_entry_32: u64,
294 /// 64-bit SMBIOS entry point address. Set to 0 if unavailable.
295 pub smbios_entry_64: u64,
296}
297
298impl StivaleStruct {
299 /// Return's the modules array pointer as a rust slice.
300 pub fn modules_as_slice(&self) -> &[StivaleModule] {
301 unsafe { core::slice::from_raw_parts(self.modules.as_ptr(), self.module_len as usize) }
302 }
303
304 /// Returns an iterator over all the modules that were loaded.
305 pub fn modules_iter(&self) -> StivaleModuleIter {
306 StivaleModuleIter {
307 sref: self,
308 current: 0,
309 phantom: PhantomData::default(),
310 }
311 }
312
313 /// Return's memory map entries pointer as a rust slice.
314 pub fn memory_map_as_slice(&self) -> &[StivaleMemoryMapEntry] {
315 unsafe {
316 core::slice::from_raw_parts(
317 self.memory_map_array.as_ptr(),
318 self.memory_map_len as usize,
319 )
320 }
321 }
322
323 /// Returns an iterator over all the memory regions.
324 pub fn memory_map_iter(&self) -> StivaleMemoryMapIter {
325 StivaleMemoryMapIter {
326 sref: self,
327 current: 0x00,
328 phantom: PhantomData::default(),
329 }
330 }
331}