Next Generation WASM Microkernel Operating System
1// Copyright 2025 Jonas Kruckenberg
2//
3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5// http://opensource.org/licenses/MIT>, at your option. This file may not be
6// copied, modified, or distributed except according to those terms.
7
8use core::ops::{Deref, DerefMut};
9use core::range::Range;
10use core::{fmt, slice};
11
12#[derive(Debug)]
13#[non_exhaustive]
14pub struct BootInfo {
15 pub cpu_mask: usize,
16 /// A map of the physical memory regions of the underlying machine.
17 ///
18 /// The loader parses this information from the firmware and also reports regions used
19 /// during initial mapping. Regions marked as usable can be freely
20 /// used by the kernel.
21 ///
22 /// Note: Memory regions are *guaranteed* to not overlap and be sorted by their start address.
23 /// But they might not be optimally packed, i.e. adjacent regions that could be merged are not.
24 pub memory_regions: MemoryRegions,
25 /// Physical addresses can be converted to virtual addresses by adding this offset to them.
26 ///
27 /// The mapping of the physical memory allows to access arbitrary physical frames. Accessing
28 /// frames that are also mapped at other virtual addresses can easily break memory safety and
29 /// cause undefined behavior. Only frames reported as `USABLE` by the memory map in the `BootInfo`
30 /// can be safely accessed.
31 pub physical_address_offset: usize, // VirtualAddress
32 pub physical_memory_map: Range<usize>, // VirtualAddress
33 /// The thread local storage (TLS) template of the kernel executable, if present.
34 pub tls_template: Option<TlsTemplate>,
35 /// Virtual address of the loaded kernel image.
36 pub kernel_virt: Range<usize>, // VirtualAddress
37 /// Physical memory region where the kernel ELF file resides.
38 ///
39 /// This field can be used by the kernel to perform introspection of its own ELF file.
40 pub kernel_phys: Range<usize>, // PhysicalAddress
41
42 pub rng_seed: [u8; 32],
43}
44unsafe impl Send for BootInfo {}
45unsafe impl Sync for BootInfo {}
46
47impl BootInfo {
48 /// Create a new boot info structure with the given memory map.
49 ///
50 /// The other fields are initialized with default values.
51 pub fn new(memory_regions: MemoryRegions) -> Self {
52 Self {
53 memory_regions,
54 cpu_mask: 0,
55 physical_address_offset: Default::default(),
56 physical_memory_map: Default::default(),
57 tls_template: None,
58 kernel_virt: Default::default(),
59 kernel_phys: Default::default(),
60 rng_seed: [0; 32],
61 }
62 }
63}
64
65/// FFI-safe slice of [`MemoryRegion`] structs, semantically equivalent to
66/// `&'static mut [MemoryRegion]`.
67///
68/// This type implements the [`Deref`][core::ops::Deref] and [`DerefMut`][core::ops::DerefMut]
69/// traits, so it can be used like a `&mut [MemoryRegion]` slice. It also implements [`From`]
70/// and [`Into`] for easy conversions from and to `&'static mut [MemoryRegion]`.
71#[derive(Debug)]
72#[repr(C)]
73pub struct MemoryRegions {
74 pub(crate) ptr: *mut MemoryRegion,
75 pub(crate) len: usize,
76}
77
78impl Deref for MemoryRegions {
79 type Target = [MemoryRegion];
80
81 fn deref(&self) -> &Self::Target {
82 unsafe { slice::from_raw_parts(self.ptr, self.len) }
83 }
84}
85
86impl DerefMut for MemoryRegions {
87 fn deref_mut(&mut self) -> &mut Self::Target {
88 unsafe { slice::from_raw_parts_mut(self.ptr, self.len) }
89 }
90}
91
92impl From<&'static mut [MemoryRegion]> for MemoryRegions {
93 fn from(regions: &'static mut [MemoryRegion]) -> Self {
94 MemoryRegions {
95 ptr: regions.as_mut_ptr(),
96 len: regions.len(),
97 }
98 }
99}
100
101impl From<MemoryRegions> for &'static mut [MemoryRegion] {
102 fn from(regions: MemoryRegions) -> &'static mut [MemoryRegion] {
103 unsafe { slice::from_raw_parts_mut(regions.ptr, regions.len) }
104 }
105}
106
107/// Represent a physical memory region.
108#[derive(Debug, Copy, Clone, Eq, PartialEq)]
109#[repr(C)]
110pub struct MemoryRegion {
111 /// The physical start address region.
112 pub range: Range<usize>, // PhysicalAddress
113 /// The memory type of the memory region.
114 ///
115 /// Only [`Usable`][MemoryRegionKind::Usable] regions can be freely used.
116 pub kind: MemoryRegionKind,
117}
118
119/// Represents the different types of memory.
120#[derive(Debug, Copy, Clone, Eq, PartialEq)]
121#[non_exhaustive]
122#[repr(C)]
123pub enum MemoryRegionKind {
124 /// Unused conventional memory, can be used by the kernel.
125 Usable,
126 /// Memory mappings created by the loader, including the page table and boot info mappings.
127 ///
128 /// This memory should _not_ be used by the kernel.
129 Loader,
130 /// The memory region containing the flattened device tree (FDT).
131 FDT,
132}
133
134impl MemoryRegionKind {
135 pub fn is_usable(&self) -> bool {
136 matches!(self, MemoryRegionKind::Usable)
137 }
138}
139
140impl fmt::Display for BootInfo {
141 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
142 writeln!(
143 f,
144 "{:<23} : {:#x}",
145 "PHYSICAL ADDRESS OFFSET", self.physical_address_offset
146 )?;
147 writeln!(
148 f,
149 "{:<23} : {:#x}..{:#x}",
150 "PHYSICAL MEMORY MAP", self.physical_memory_map.start, self.physical_memory_map.end
151 )?;
152 writeln!(
153 f,
154 "{:<23} : {:#x}..{:#x}",
155 "KERNEL VIRT", self.kernel_virt.start, self.kernel_virt.end
156 )?;
157 writeln!(
158 f,
159 "{:<23} : {:#x}..{:#x}",
160 "KERNEL PHYS", self.kernel_phys.start, self.kernel_phys.end
161 )?;
162 if let Some(tls) = self.tls_template.as_ref() {
163 writeln!(
164 f,
165 "{:<23} : .tdata: {:#x}..{:#x}, .tbss: {:#x}..{:#x}",
166 "TLS TEMPLATE",
167 tls.start_addr,
168 tls.start_addr.checked_add(tls.file_size).unwrap(),
169 tls.start_addr.checked_add(tls.file_size).unwrap(),
170 tls.start_addr
171 .checked_add(tls.file_size + tls.mem_size)
172 .unwrap()
173 )?;
174 } else {
175 writeln!(f, "{:<23} : None", "TLS TEMPLATE")?;
176 for (idx, region) in self.memory_regions.iter().enumerate() {
177 writeln!(
178 f,
179 "MEMORY REGION {:<10}: {:#x}..{:#x} {:?}",
180 idx, region.range.start, region.range.end, region.kind,
181 )?;
182 }
183 }
184
185 Ok(())
186 }
187}
188
189#[repr(C)]
190#[derive(Debug, Clone)]
191pub struct TlsTemplate {
192 /// The address of TLS template
193 pub start_addr: usize, // VirtualAddress
194 /// The size of the TLS segment in memory
195 pub mem_size: usize,
196 /// The size of the TLS segment in the elf file.
197 /// If the TLS segment contains zero-initialized data (tbss) then this size will be smaller than
198 /// `mem_size`
199 pub file_size: usize,
200 pub align: usize,
201}