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