hermit_entry/
lib.rs
1#![no_std]
8#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
9#![warn(missing_docs)]
10
11pub mod boot_info;
12
13#[cfg(feature = "loader")]
14pub mod elf;
15
16#[cfg(feature = "kernel")]
17mod note;
18
19use core::error::Error;
20use core::fmt;
21use core::str::FromStr;
22
23#[doc(hidden)]
24pub use const_parse::parse_u128 as _parse_u128;
25#[cfg(feature = "kernel")]
26#[doc(hidden)]
27pub use note::{_AbiTag, _Note};
28
29#[cfg(not(target_arch = "riscv64"))]
37pub type Entry =
38 unsafe extern "C" fn(raw_boot_info: &'static boot_info::RawBootInfo, cpu_id: u32) -> !;
39
40#[cfg(target_arch = "riscv64")]
48pub type Entry =
49 unsafe extern "C" fn(hart_id: usize, raw_boot_info: &'static boot_info::RawBootInfo) -> !;
50
51#[cfg_attr(not(any(feature = "loader", feature = "kernel")), expect(dead_code))]
57const NT_HERMIT_ENTRY_VERSION: u32 = 0x5a00;
58
59#[cfg_attr(not(any(feature = "loader", feature = "kernel")), expect(dead_code))]
61const HERMIT_ENTRY_VERSION: u8 = 4;
62
63#[expect(missing_docs)]
67pub mod fc {
68 pub const LINUX_KERNEL_BOOT_FLAG_MAGIC: u16 = 0xaa55;
69 pub const LINUX_KERNEL_HRD_MAGIC: u32 = 0x53726448;
70 pub const LINUX_SETUP_HEADER_OFFSET: usize = 0x1f1;
71 pub const BOOT_FLAG_OFFSET: usize = 13;
72 pub const HDR_MAGIC_OFFSET: usize = 17;
73 pub const E820_ENTRIES_OFFSET: usize = 0x1e8;
74 pub const E820_TABLE_OFFSET: usize = 0x2d0;
75 pub const RAMDISK_IMAGE_OFFSET: usize = 39;
76 pub const RAMDISK_SIZE_OFFSET: usize = 43;
77 pub const CMD_LINE_PTR_OFFSET: usize = 55;
78 pub const CMD_LINE_SIZE_OFFSET: usize = 71;
79}
80
81#[cfg_attr(not(any(feature = "loader", feature = "kernel")), expect(dead_code))]
82const NT_GNU_ABI_TAG: u32 = 1;
83#[cfg_attr(not(any(feature = "loader", feature = "kernel")), expect(dead_code))]
84const ELF_NOTE_OS_HERMIT: u32 = 6;
85
86#[derive(PartialOrd, Ord, PartialEq, Eq, Clone, Copy, Debug)]
88pub struct HermitVersion {
89 pub major: u32,
91
92 pub minor: u32,
94
95 pub patch: u32,
97}
98
99impl fmt::Display for HermitVersion {
100 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101 let Self {
102 major,
103 minor,
104 patch,
105 } = self;
106 write!(f, "{major}.{minor}.{patch}")
107 }
108}
109
110impl FromStr for HermitVersion {
111 type Err = ParseHermitVersionError;
112
113 fn from_str(s: &str) -> Result<Self, Self::Err> {
114 let (major, rest) = s.split_once('.').ok_or(ParseHermitVersionError)?;
115 let (minor, patch) = rest.split_once('.').ok_or(ParseHermitVersionError)?;
116
117 let major = major.parse().map_err(|_| ParseHermitVersionError)?;
118 let minor = minor.parse().map_err(|_| ParseHermitVersionError)?;
119 let patch = patch.parse().map_err(|_| ParseHermitVersionError)?;
120
121 Ok(Self {
122 major,
123 minor,
124 patch,
125 })
126 }
127}
128
129#[derive(Debug, Clone, PartialEq, Eq)]
131#[non_exhaustive]
132pub struct ParseHermitVersionError;
133
134impl fmt::Display for ParseHermitVersionError {
135 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
136 f.write_str("provided string could not be parsed as Hermit version")
137 }
138}
139
140impl Error for ParseHermitVersionError {}
141
142#[cfg(test)]
143mod tests {
144 use super::*;
145
146 #[test]
147 fn cmp_hermit_version() {
148 let small = HermitVersion {
149 major: 0,
150 minor: 1,
151 patch: 2,
152 };
153 let big = HermitVersion {
154 major: 2,
155 minor: 1,
156 patch: 0,
157 };
158
159 assert!(small < big);
160 assert!(small == small);
161 assert!(big == big);
162 assert!(big > small);
163 }
164
165 #[test]
166 fn parse_hermit_version() {
167 let version = HermitVersion::from_str("0.1.2").unwrap();
168 assert_eq!(
169 version,
170 HermitVersion {
171 major: 0,
172 minor: 1,
173 patch: 2,
174 }
175 );
176
177 let version = HermitVersion::from_str("2.1.0").unwrap();
178 assert_eq!(
179 version,
180 HermitVersion {
181 major: 2,
182 minor: 1,
183 patch: 0,
184 }
185 );
186 }
187}