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}