springboard_api/
info.rs

1use core::{ops, slice};
2
3use crate::config::ApiVersion;
4
5/// This structure represents the information that the bootloader passes to the kernel.
6///
7/// The information is passed as an argument to the entry point. The entry point function must
8/// have the following signature:
9///
10/// ```
11/// # use springboard_api::BootInfo;
12/// # type _SIGNATURE =
13/// extern "C" fn(boot_info: &'static mut BootInfo) -> !;
14/// ```
15///
16/// Note that no type checking occurs for the entry point function, so be careful to
17/// use the correct argument types. To ensure that the entry point function has the correct
18/// signature, use the [`entry_point`] macro.
19#[derive(Debug)]
20#[repr(C)]
21#[non_exhaustive]
22pub struct BootInfo {
23   /// The version of the `bootloader_api` crate. Must match the `bootloader` version.
24   pub api_version: ApiVersion,
25   /// A map of the physical memory regions of the underlying machine.
26   ///
27   /// The bootloader queries this information from the BIOS/UEFI firmware and translates this
28   /// information to Rust types. It also marks any memory regions that the bootloader uses in
29   /// the memory map before passing it to the kernel. Regions marked as usable can be freely
30   /// used by the kernel.
31   pub memory_regions: MemoryRegions,
32   /// Information about the framebuffer for screen output if available.
33   pub framebuffer: Optional<FrameBuffer>,
34   /// The virtual address at which the mapping of the physical memory starts.
35   ///
36   /// Physical addresses can be converted to virtual addresses by adding this offset to them.
37   ///
38   /// The mapping of the physical memory allows to access arbitrary physical frames. Accessing
39   /// frames that are also mapped at other virtual addresses can easily break memory safety and
40   /// cause undefined behavior. Only frames reported as `USABLE` by the memory map in the `BootInfo`
41   /// can be safely accessed.
42   ///
43   /// Only available if the `map-physical-memory` config option is enabled.
44   pub physical_memory_offset: Optional<u64>,
45   /// The virtual address of the recursively mapped level 4 page table.
46   ///
47   /// Only available if the `map-page-table-recursively` config option is enabled.
48   pub recursive_index: Optional<u16>,
49   /// The address of the `RSDP` data structure, which can be use to find the ACPI tables.
50   ///
51   /// This field is `None` if no `RSDP` was found (for BIOS) or reported (for UEFI).
52   pub rsdp_addr: Optional<u64>,
53   /// The thread local storage (TLS) template of the kernel executable, if present.
54   pub tls_template: Optional<TlsTemplate>,
55   /// Ramdisk address, if loaded
56   pub ramdisk_addr: Optional<u64>,
57   /// Ramdisk image size, set to 0 if addr is None
58   pub ramdisk_len: u64,
59   /// Physical address of the kernel ELF in memory.
60   pub kernel_addr: u64,
61   /// Size of the kernel ELF in memory.
62   pub kernel_len: u64,
63   /// Virtual address of the loaded kernel image.
64   pub kernel_image_offset: u64,
65
66   #[doc(hidden)]
67   pub _test_sentinel: u64,
68}
69
70impl BootInfo {
71   /// Create a new boot info structure with the given memory map.
72   ///
73   /// The other fields are initialized with default values.
74   pub fn new(memory_regions: MemoryRegions) -> Self {
75      Self {
76         api_version: ApiVersion::new_default(),
77         memory_regions,
78         framebuffer: Optional::None,
79         physical_memory_offset: Optional::None,
80         recursive_index: Optional::None,
81         rsdp_addr: Optional::None,
82         tls_template: Optional::None,
83         ramdisk_addr: Optional::None,
84         ramdisk_len: 0,
85         kernel_addr: 0,
86         kernel_len: 0,
87         kernel_image_offset: 0,
88         _test_sentinel: 0,
89      }
90   }
91}
92
93/// FFI-safe slice of [`MemoryRegion`] structs, semantically equivalent to
94/// `&'static mut [MemoryRegion]`.
95///
96/// This type implements the [`Deref`][core::ops::Deref] and [`DerefMut`][core::ops::DerefMut]
97/// traits, so it can be used like a `&mut [MemoryRegion]` slice. It also implements [`From`]
98/// and [`Into`] for easy conversions from and to `&'static mut [MemoryRegion]`.
99#[derive(Debug)]
100#[repr(C)]
101pub struct MemoryRegions {
102   pub(crate) ptr: *mut MemoryRegion,
103   pub(crate) len: usize,
104}
105
106impl ops::Deref for MemoryRegions {
107   type Target = [MemoryRegion];
108
109   fn deref(&self) -> &Self::Target {
110      unsafe { slice::from_raw_parts(self.ptr, self.len) }
111   }
112}
113
114impl ops::DerefMut for MemoryRegions {
115   fn deref_mut(&mut self) -> &mut Self::Target {
116      unsafe { slice::from_raw_parts_mut(self.ptr, self.len) }
117   }
118}
119
120impl From<&'static mut [MemoryRegion]> for MemoryRegions {
121   fn from(regions: &'static mut [MemoryRegion]) -> Self {
122      MemoryRegions {
123         ptr: regions.as_mut_ptr(),
124         len: regions.len(),
125      }
126   }
127}
128
129impl From<MemoryRegions> for &'static mut [MemoryRegion] {
130   fn from(regions: MemoryRegions) -> &'static mut [MemoryRegion] {
131      unsafe { slice::from_raw_parts_mut(regions.ptr, regions.len) }
132   }
133}
134
135/// Represent a physical memory region.
136#[derive(Debug, Copy, Clone, Eq, PartialEq)]
137#[repr(C)]
138pub struct MemoryRegion {
139   /// The physical start address of the region.
140   pub start: u64,
141   /// The physical end address (exclusive) of the region.
142   pub end: u64,
143   /// The memory type of the memory region.
144   ///
145   /// Only [`Usable`][MemoryRegionKind::Usable] regions can be freely used.
146   pub kind: MemoryRegionKind,
147}
148
149impl MemoryRegion {
150   /// Creates a new empty memory region (with length 0).
151   pub const fn empty() -> Self {
152      MemoryRegion {
153         start: 0,
154         end: 0,
155         kind: MemoryRegionKind::Bootloader,
156      }
157   }
158}
159
160/// Represents the different types of memory.
161#[derive(Debug, Copy, Clone, Eq, PartialEq)]
162#[non_exhaustive]
163#[repr(C)]
164pub enum MemoryRegionKind {
165   /// Unused conventional memory, can be used by the kernel.
166   Usable,
167   /// Memory mappings created by the bootloader, including the page table and boot info mappings.
168   ///
169   /// This memory should _not_ be used by the kernel.
170   Bootloader,
171   /// An unknown memory region reported by the UEFI firmware.
172   ///
173   /// Contains the UEFI memory type tag.
174   UnknownUefi(u32),
175   /// An unknown memory region reported by the BIOS firmware.
176   UnknownBios(u32),
177}
178
179/// A pixel-based framebuffer that controls the screen output.
180#[derive(Clone, Copy, Debug)]
181#[repr(C)]
182pub struct FrameBuffer {
183   pub(crate) buffer_start: u64,
184   pub(crate) info: FrameBufferInfo,
185}
186
187impl FrameBuffer {
188   /// Creates a new framebuffer instance.
189   ///
190   /// ## Safety
191   ///
192   /// The given start address and info must describe a valid, accessible, and unaliased
193   /// framebuffer.
194   pub unsafe fn new(buffer_start: u64, info: FrameBufferInfo) -> Self {
195      Self { buffer_start, info }
196   }
197
198   /// Returns the raw bytes of the framebuffer as slice.
199   pub fn buffer(&self) -> &[u8] {
200      unsafe { self.create_buffer() }
201   }
202
203   /// Returns the raw bytes of the framebuffer as mutable slice.
204   pub fn buffer_mut(&mut self) -> &mut [u8] {
205      unsafe { self.create_buffer_mut() }
206   }
207
208   /// Converts the frame buffer to a raw byte slice.
209   ///
210   /// The same as `buffer_mut()` but takes the ownership and returns the
211   /// mutable buffer with a `'static` lifetime.
212   pub fn into_buffer(self) -> &'static mut [u8] {
213      unsafe { self.create_buffer_mut() }
214   }
215
216   unsafe fn create_buffer<'a>(&self) -> &'a [u8] {
217      unsafe { slice::from_raw_parts(self.buffer_start as *const u8, self.info.byte_len) }
218   }
219
220   unsafe fn create_buffer_mut<'a>(&self) -> &'a mut [u8] {
221      unsafe { slice::from_raw_parts_mut(self.buffer_start as *mut u8, self.info.byte_len) }
222   }
223
224   /// Returns layout and pixel format information of the framebuffer.
225   pub fn info(&self) -> FrameBufferInfo {
226      self.info
227   }
228}
229
230/// Describes the layout and pixel format of a framebuffer.
231#[derive(Debug, Clone, Copy)]
232#[repr(C)]
233pub struct FrameBufferInfo {
234   /// The total size in bytes.
235   pub byte_len: usize,
236   /// The width in pixels.
237   pub width: usize,
238   /// The height in pixels.
239   pub height: usize,
240   /// The color format of each pixel.
241   pub pixel_format: PixelFormat,
242   /// The number of bytes per pixel.
243   pub bytes_per_pixel: usize,
244   /// Number of pixels between the start of a line and the start of the next.
245   ///
246   /// Some framebuffers use additional padding at the end of a line, so this
247   /// value might be larger than `horizontal_resolution`. It is
248   /// therefore recommended to use this field for calculating the start address of a line.
249   pub stride: usize,
250}
251
252/// Color format of pixels in the framebuffer.
253#[derive(Debug, Clone, Copy, PartialEq, Eq)]
254#[non_exhaustive]
255#[repr(C)]
256pub enum PixelFormat {
257   /// One byte red, then one byte green, then one byte blue.
258   ///
259   /// Length might be larger than 3, check [`bytes_per_pixel`][FrameBufferInfo::bytes_per_pixel]
260   /// for this.
261   Rgb,
262   /// One byte blue, then one byte green, then one byte red.
263   ///
264   /// Length might be larger than 3, check [`bytes_per_pixel`][FrameBufferInfo::bytes_per_pixel]
265   /// for this.
266   Bgr,
267   /// A single byte, representing the grayscale value.
268   ///
269   /// Length might be larger than 1, check [`bytes_per_pixel`][FrameBufferInfo::bytes_per_pixel]
270   /// for this.
271   U8,
272   /// Unknown pixel format.
273   Unknown {
274      /// Bit offset of the red value.
275      red_position: u8,
276      /// Bit offset of the green value.
277      green_position: u8,
278      /// Bit offset of the blue value.
279      blue_position: u8,
280   },
281}
282
283/// Information about the thread local storage (TLS) template.
284///
285/// This template can be used to set up thread local storage for threads. For
286/// each thread, a new memory location of size `mem_size` must be initialized.
287/// Then the first `file_size` bytes of this template needs to be copied to the
288/// location. The additional `mem_size - file_size` bytes must be initialized with
289/// zero.
290#[derive(Debug, Clone, Copy, PartialEq, Eq)]
291#[repr(C)]
292pub struct TlsTemplate {
293   /// The virtual start address of the thread local storage template.
294   pub start_addr: u64,
295   /// The number of data bytes in the template.
296   ///
297   /// Corresponds to the length of the `.tdata` section.
298   pub file_size: u64,
299   /// The total number of bytes that the TLS segment should have in memory.
300   ///
301   /// Corresponds to the combined length of the `.tdata` and `.tbss` sections.
302   pub mem_size: u64,
303}
304
305/// FFI-safe variant of [`Option`].
306///
307/// Implements the [`From`] and [`Into`] traits for easy conversion to and from [`Option`].
308#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
309#[repr(C)]
310pub enum Optional<T> {
311   /// Some value `T`
312   Some(T),
313   /// No value
314   None,
315}
316
317impl<T> Optional<T> {
318   /// Converts the `Optional` to an [`Option`].
319   pub fn into_option(self) -> Option<T> {
320      self.into()
321   }
322
323   /// Converts from `&Optional<T>` to `Option<&T>`.
324   ///
325   /// For convenience, this method directly performs the conversion to the standard
326   /// [`Option`] type.
327   pub const fn as_ref(&self) -> Option<&T> {
328      match self {
329         Self::Some(x) => Some(x),
330         Self::None => None,
331      }
332   }
333
334   /// Converts from `&mut Optional<T>` to `Option<&mut T>`.
335   ///
336   /// For convenience, this method directly performs the conversion to the standard
337   /// [`Option`] type.
338   pub fn as_mut(&mut self) -> Option<&mut T> {
339      match self {
340         Self::Some(x) => Some(x),
341         Self::None => None,
342      }
343   }
344}
345
346impl<T> From<Option<T>> for Optional<T> {
347   fn from(v: Option<T>) -> Self {
348      match v {
349         Some(v) => Optional::Some(v),
350         None => Optional::None,
351      }
352   }
353}
354
355impl<T> From<Optional<T>> for Option<T> {
356   fn from(optional: Optional<T>) -> Option<T> {
357      match optional {
358         Optional::Some(v) => Some(v),
359         Optional::None => None,
360      }
361   }
362}
363
364/// Check that bootinfo is FFI-safe
365extern "C" fn _assert_ffi(_boot_info: BootInfo) {}