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
use core::{ops, slice};
/// 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::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 {
/// Bootloader version (major).
pub version_major: u16,
/// Bootloader version (minor).
pub version_minor: u16,
/// Bootloader version (patch).
pub version_patch: u16,
/// Whether the bootloader version is a pre-release.
///
/// We can't store the full prerelease string of the version number since it could be
/// arbitrarily long.
pub pre_release: bool,
/// 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>,
}
/// 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 kernel and boot info mappings.
///
/// This memory should _not_ be used by the kernel.
Bootloader,
/// An unknown memory region reported by the UEFI firmware.
///
/// This should only be used if the UEFI memory type is known as usable.
UnknownUefi(u32),
/// An unknown memory region reported by the BIOS firmware.
///
/// This should only be used if the BIOS memory type is known as usable.
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) buffer_byte_len: usize,
pub(crate) info: FrameBufferInfo,
}
impl FrameBuffer {
/// 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() }
}
unsafe fn create_buffer<'a>(&self) -> &'a mut [u8] {
unsafe { slice::from_raw_parts_mut(self.buffer_start as *mut u8, self.buffer_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 horizontal_resolution: usize,
/// The height in pixels.
pub vertical_resolution: 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,
}
/// 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) {}