1#![no_std]
8#![cfg_attr(docsrs, feature(doc_cfg))]
9#![warn(missing_docs)]
10
11#[cfg(feature = "loader")]
12extern crate alloc;
13
14pub mod boot_info;
15
16#[cfg(feature = "loader")]
17pub mod config;
18
19#[cfg(feature = "loader")]
20pub mod elf;
21
22#[cfg(feature = "kernel")]
23mod note;
24
25use core::error::Error;
26use core::fmt;
27use core::str::FromStr;
28
29#[doc(hidden)]
30pub use const_parse::parse_u128 as _parse_u128;
31#[cfg(feature = "kernel")]
32#[doc(hidden)]
33pub use note::{_AbiTag, _Note};
34
35#[cfg(feature = "loader")]
39const GZIPMAG: &[u8; 3] = &[0x1f, 0x8b, 0x08];
40
41#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
43#[cfg(feature = "loader")]
44pub enum Format {
45 Elf,
47 Gzip,
49}
50
51#[cfg(feature = "loader")]
53pub fn detect_format(data: &[u8]) -> Option<Format> {
54 if data.len() < 4 {
55 None
56 } else if data.starts_with(goblin::elf64::header::ELFMAG) {
57 Some(Format::Elf)
58 } else if data.starts_with(GZIPMAG) {
59 Some(Format::Gzip)
60 } else {
61 None
62 }
63}
64
65#[cfg(not(target_arch = "riscv64"))]
73pub type Entry =
74 unsafe extern "C" fn(raw_boot_info: &'static boot_info::RawBootInfo, cpu_id: u32) -> !;
75
76#[cfg(target_arch = "riscv64")]
84pub type Entry =
85 unsafe extern "C" fn(hart_id: usize, raw_boot_info: &'static boot_info::RawBootInfo) -> !;
86
87#[cfg_attr(not(any(feature = "loader", feature = "kernel")), expect(dead_code))]
93const NT_HERMIT_ENTRY_VERSION: u32 = 0x5a00;
94
95#[cfg_attr(not(any(feature = "loader", feature = "kernel")), expect(dead_code))]
97const HERMIT_ENTRY_VERSION: u8 = 4;
98
99#[cfg_attr(not(any(feature = "loader", feature = "kernel")), expect(dead_code))]
101const NT_UHYVE_INTERFACE_VERSION: u32 = 0x5b00;
102
103#[expect(missing_docs)]
107#[deprecated]
108pub mod fc {
109 pub const LINUX_KERNEL_BOOT_FLAG_MAGIC: u16 = 0xaa55;
110 pub const LINUX_KERNEL_HRD_MAGIC: u32 = 0x53726448;
111 pub const LINUX_SETUP_HEADER_OFFSET: usize = 0x1f1;
112 pub const BOOT_FLAG_OFFSET: usize = 13;
113 pub const HDR_MAGIC_OFFSET: usize = 17;
114 pub const E820_ENTRIES_OFFSET: usize = 0x1e8;
115 pub const E820_TABLE_OFFSET: usize = 0x2d0;
116 pub const RAMDISK_IMAGE_OFFSET: usize = 39;
117 pub const RAMDISK_SIZE_OFFSET: usize = 43;
118 pub const CMD_LINE_PTR_OFFSET: usize = 55;
119 pub const CMD_LINE_SIZE_OFFSET: usize = 71;
120}
121
122#[cfg_attr(not(any(feature = "loader", feature = "kernel")), expect(dead_code))]
123const NT_GNU_ABI_TAG: u32 = 1;
124#[cfg_attr(not(any(feature = "loader", feature = "kernel")), expect(dead_code))]
125const ELF_NOTE_OS_HERMIT: u32 = 6;
126
127#[derive(PartialOrd, Ord, PartialEq, Eq, Clone, Copy, Debug)]
129pub struct HermitVersion {
130 pub major: u32,
132
133 pub minor: u32,
135
136 pub patch: u32,
138}
139
140impl HermitVersion {
141 pub const fn new(major: u32, minor: u32, patch: u32) -> Self {
143 Self {
144 major,
145 minor,
146 patch,
147 }
148 }
149}
150
151impl fmt::Display for HermitVersion {
152 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
153 let Self {
154 major,
155 minor,
156 patch,
157 } = self;
158 write!(f, "{major}.{minor}.{patch}")
159 }
160}
161
162impl FromStr for HermitVersion {
163 type Err = ParseHermitVersionError;
164
165 fn from_str(s: &str) -> Result<Self, Self::Err> {
166 let (major, rest) = s.split_once('.').ok_or(ParseHermitVersionError)?;
167 let (minor, patch) = rest.split_once('.').ok_or(ParseHermitVersionError)?;
168
169 let major = major.parse().map_err(|_| ParseHermitVersionError)?;
170 let minor = minor.parse().map_err(|_| ParseHermitVersionError)?;
171 let patch = patch.parse().map_err(|_| ParseHermitVersionError)?;
172
173 Ok(Self {
174 major,
175 minor,
176 patch,
177 })
178 }
179}
180
181#[derive(Debug, Clone, PartialEq, Eq)]
183#[non_exhaustive]
184pub struct ParseHermitVersionError;
185
186impl fmt::Display for ParseHermitVersionError {
187 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
188 f.write_str("provided string could not be parsed as Hermit version")
189 }
190}
191
192impl Error for ParseHermitVersionError {}
193
194#[derive(PartialOrd, Ord, PartialEq, Eq, Clone, Copy, Debug)]
196pub struct UhyveIfVersion(pub u32);
197
198impl fmt::Display for UhyveIfVersion {
199 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
200 self.0.fmt(f)
201 }
202}
203
204#[cfg(test)]
205mod tests {
206 use super::*;
207
208 #[test]
209 fn cmp_hermit_version() {
210 let small = HermitVersion::new(0, 1, 2);
211 let big = HermitVersion::new(2, 1, 0);
212
213 assert!(small < big);
214 assert!(small == small);
215 assert!(big == big);
216 assert!(big > small);
217 }
218
219 #[test]
220 fn parse_hermit_version() {
221 let version = HermitVersion::from_str("0.1.2").unwrap();
222 assert_eq!(version, HermitVersion::new(0, 1, 2));
223
224 let version = HermitVersion::from_str("2.1.0").unwrap();
225 assert_eq!(version, HermitVersion::new(2, 1, 0));
226 }
227}