hermit_entry/boot_info/
mod.rs

1//! Creating and reading [`RawBootInfo`] from [`Entry`](crate::Entry).
2//!
3//! Loaders assemble [`BootInfo`] and convert it into a [`RawBootInfo`] to pass it to the kernel.
4//!
5//! The kernel copies [`BootInfo`] from [`RawBootInfo`] to work with the values.
6
7#[cfg(feature = "loader")]
8mod loader;
9
10#[cfg(feature = "kernel")]
11mod kernel;
12
13use core::fmt;
14use core::num::{NonZeroU32, NonZeroU64};
15use core::ops::Range;
16
17use time::OffsetDateTime;
18
19/// Serial I/O port.
20#[cfg(target_arch = "x86_64")]
21pub type SerialPortBase = core::num::NonZeroU16;
22
23/// Serial port base address
24#[cfg(target_arch = "aarch64")]
25pub type SerialPortBase = core::num::NonZeroU64;
26
27/// Serial port base address
28#[cfg(target_arch = "riscv64")]
29pub type SerialPortBase = core::num::NonZeroU64;
30
31/// Device tree address
32pub type DeviceTreeAddress = core::num::NonZeroU64;
33
34/// Boot information.
35///
36/// This struct is built by the loader and consumed by the kernel.
37/// It contains information on how the kernel image was loaded as well as
38/// additional hardware and loader specific information.
39#[derive(Debug)]
40pub struct BootInfo {
41    /// Hardware information.
42    pub hardware_info: HardwareInfo,
43
44    /// Load information.
45    pub load_info: LoadInfo,
46
47    /// Platform information.
48    pub platform_info: PlatformInfo,
49}
50
51/// Hardware information.
52#[derive(Debug)]
53pub struct HardwareInfo {
54    /// The range of all possible physical memory addresses.
55    pub phys_addr_range: Range<u64>,
56
57    /// Serial port base address.
58    pub serial_port_base: Option<SerialPortBase>,
59
60    /// Address of the device tree
61    pub device_tree: Option<DeviceTreeAddress>,
62}
63
64/// Load information.
65#[derive(Debug)]
66pub struct LoadInfo {
67    /// The virtual address range of the loaded kernel image.
68    pub kernel_image_addr_range: Range<u64>,
69
70    /// Kernel image TLS information.
71    pub tls_info: Option<TlsInfo>,
72}
73
74/// Platform information.
75///
76/// This struct holds platform and loader specific information.
77#[derive(Debug)]
78pub enum PlatformInfo {
79    /// Multiboot.
80    #[cfg(target_arch = "x86_64")]
81    Multiboot {
82        /// Command line passed to the kernel.
83        command_line: Option<&'static str>,
84
85        /// Multiboot boot information address.
86        multiboot_info_addr: core::num::NonZeroU64,
87    },
88    /// Direct Linux Boot.
89    #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
90    LinuxBoot,
91    /// Uhyve.
92    Uhyve {
93        /// PCI support.
94        has_pci: bool,
95
96        /// Total number of CPUs available.
97        num_cpus: NonZeroU64,
98
99        /// CPU frequency in kHz.
100        cpu_freq: Option<NonZeroU32>,
101
102        /// Boot time.
103        boot_time: OffsetDateTime,
104    },
105    /// Linux Boot Parameters.
106    LinuxBootParams {
107        /// Command line passed to the kernel.
108        command_line: Option<&'static str>,
109
110        /// Address to Linux boot parameters.
111        boot_params_addr: core::num::NonZeroU64,
112    },
113    /// FDT.
114    ///
115    /// This is a transitional platform for migrating to FDTs.
116    /// The real platform information is stored in [`HardwareInfo::device_tree`].
117    Fdt,
118}
119
120/// Thread local storage (TLS) image information.
121#[repr(C)]
122#[derive(Clone, Copy)]
123pub struct TlsInfo {
124    /// The start address of the TLS image.
125    pub start: u64,
126
127    /// `filesz` of the TLS program header.
128    pub filesz: u64,
129
130    /// `memsz` of the TLS program header.
131    pub memsz: u64,
132
133    /// `align` of the TLS program header.
134    pub align: u64,
135}
136
137impl fmt::Debug for TlsInfo {
138    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
139        f.debug_struct("TlsInfo")
140            .field("start", &format_args!("{:#x}", self.start))
141            .field("filesz", &format_args!("{:#x}", self.filesz))
142            .field("memsz", &format_args!("{:#x}", self.memsz))
143            .field("align", &format_args!("{:#x}", self.align))
144            .finish()
145    }
146}
147
148/// The raw boot information struct.
149///
150/// This is kept separate from [`BootInfo`] to make non-breaking API evolution possible.
151#[derive(Clone, Copy, Debug)]
152#[repr(C)]
153pub struct RawBootInfo {
154    hardware_info: RawHardwareInfo,
155    load_info: RawLoadInfo,
156    platform_info: RawPlatformInfo,
157}
158
159#[derive(Clone, Copy, Debug)]
160#[repr(C)]
161struct RawHardwareInfo {
162    phys_addr_start: u64,
163    phys_addr_end: u64,
164    serial_port_base: Option<SerialPortBase>,
165    device_tree: Option<DeviceTreeAddress>,
166}
167
168#[derive(Clone, Copy, Debug)]
169#[repr(C)]
170struct RawLoadInfo {
171    kernel_image_addr_start: u64,
172    kernel_image_addr_end: u64,
173    tls_info: TlsInfo,
174}
175
176#[derive(Clone, Copy, Debug)]
177#[cfg_attr(target_arch = "x86_64", repr(C, align(8)))]
178#[cfg_attr(not(target_arch = "x86_64"), repr(transparent))]
179struct Align8<T>(pub T);
180
181impl<T> From<T> for Align8<T> {
182    fn from(value: T) -> Self {
183        Self(value)
184    }
185}
186
187#[cfg_attr(not(all(feature = "loader", feature = "kernel")), expect(dead_code))]
188#[derive(Clone, Copy, Debug)]
189#[repr(C)]
190enum RawPlatformInfo {
191    #[cfg(target_arch = "x86_64")]
192    Multiboot {
193        command_line_data: *const u8,
194        command_line_len: u64,
195        multiboot_info_addr: core::num::NonZeroU64,
196    },
197    #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
198    LinuxBoot,
199    Uhyve {
200        has_pci: bool,
201        num_cpus: NonZeroU64,
202        cpu_freq: Option<NonZeroU32>,
203        boot_time: Align8<[u8; 16]>,
204    },
205    LinuxBootParams {
206        command_line_data: *const u8,
207        command_line_len: u64,
208        boot_params_addr: core::num::NonZeroU64,
209    },
210    Fdt,
211}