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) {}