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