1#![allow(deprecated)]
2
3#[derive(Debug, PartialEq, Eq, Clone, Copy)]
8#[non_exhaustive]
9pub struct BootloaderConfig {
10 pub version: ApiVersion,
16
17 pub mappings: Mappings,
19
20 pub kernel_stack_size: u64,
28
29 #[deprecated(
32 since = "0.11.1",
33 note = "The frame buffer is now configured through the `BootConfig` struct when creating the bootable disk image"
34 )]
35 pub frame_buffer: FrameBuffer,
36}
37
38impl BootloaderConfig {
39 pub(crate) const UUID: [u8; 16] = [
40 0x74, 0x3C, 0xA9, 0x61, 0x09, 0x36, 0x46, 0xA0, 0xBB, 0x55, 0x5C, 0x15, 0x89, 0x15, 0x25,
41 0x3D,
42 ];
43 #[doc(hidden)]
44 pub const SERIALIZED_LEN: usize = 124;
45
46 pub const fn new_default() -> Self {
51 Self {
52 kernel_stack_size: 80 * 1024,
53 version: ApiVersion::new_default(),
54 mappings: Mappings::new_default(),
55 frame_buffer: FrameBuffer::new_default(),
56 }
57 }
58
59 pub const fn serialize(&self) -> [u8; Self::SERIALIZED_LEN] {
64 let Self {
65 version,
66 mappings,
67 kernel_stack_size,
68 frame_buffer
69 } = self;
70 let ApiVersion {
71 version_major,
72 version_minor,
73 version_patch,
74 pre_release,
75 } = version;
76 let Mappings {
77 kernel_stack,
78 boot_info,
79 framebuffer,
80 physical_memory,
81 page_table_recursive,
82 aslr,
83 dynamic_range_start,
84 dynamic_range_end,
85 ramdisk_memory,
86 } = mappings;
87 let FrameBuffer {
88 minimum_framebuffer_height,
89 minimum_framebuffer_width,
90 } = frame_buffer;
91
92 let version = {
93 let one = concat_2_2(version_major.to_le_bytes(), version_minor.to_le_bytes());
94 let two = concat_2_1(version_patch.to_le_bytes(), [*pre_release as u8]);
95 concat_4_3(one, two)
96 };
97 let buf = concat_16_7(Self::UUID, version);
98 let buf = concat_23_8(buf, kernel_stack_size.to_le_bytes());
99
100 let buf = concat_31_9(buf, kernel_stack.serialize());
101 let buf = concat_40_9(buf, boot_info.serialize());
102 let buf = concat_49_9(buf, framebuffer.serialize());
103
104 let buf = concat_58_10(
105 buf,
106 match physical_memory {
107 Option::None => [0; 10],
108 Option::Some(m) => concat_1_9([1], m.serialize()),
109 },
110 );
111 let buf = concat_68_10(
112 buf,
113 match page_table_recursive {
114 Option::None => [0; 10],
115 Option::Some(m) => concat_1_9([1], m.serialize()),
116 },
117 );
118 let buf = concat_78_1(buf, [(*aslr) as u8]);
119 let buf = concat_79_9(
120 buf,
121 match dynamic_range_start {
122 Option::None => [0; 9],
123 Option::Some(addr) => concat_1_8([1], addr.to_le_bytes()),
124 },
125 );
126 let buf = concat_88_9(
127 buf,
128 match dynamic_range_end {
129 Option::None => [0; 9],
130 Option::Some(addr) => concat_1_8([1], addr.to_le_bytes()),
131 },
132 );
133
134 let buf = concat_97_9(buf, ramdisk_memory.serialize());
135
136 let buf = concat_106_9(
137 buf,
138 match minimum_framebuffer_height {
139 Option::None => [0; 9],
140 Option::Some(addr) => concat_1_8([1], addr.to_le_bytes()),
141 },
142 );
143
144 concat_115_9(
145 buf,
146 match minimum_framebuffer_width {
147 Option::None => [0; 9],
148 Option::Some(addr) => concat_1_8([1], addr.to_le_bytes()),
149 },
150 )
151 }
152
153 pub fn deserialize(serialized: &[u8]) -> Result<Self, &'static str> {
160 if serialized.len() != Self::SERIALIZED_LEN {
161 return Err("invalid len");
162 }
163
164 let s = serialized;
165
166 let (uuid, s) = split_array_ref(s);
167 if uuid != &Self::UUID {
168 return Err("invalid UUID");
169 }
170
171 let (version, s) = {
172 let (&major, s) = split_array_ref(s);
173 let (&minor, s) = split_array_ref(s);
174 let (&patch, s) = split_array_ref(s);
175 let (&pre, s) = split_array_ref(s);
176 let pre = match pre {
177 [0] => false,
178 [1] => true,
179 _ => return Err("invalid pre version"),
180 };
181
182 let version = ApiVersion {
183 version_major: u16::from_le_bytes(major),
184 version_minor: u16::from_le_bytes(minor),
185 version_patch: u16::from_le_bytes(patch),
186 pre_release: pre,
187 };
188 (version, s)
189 };
190
191 let (&kernel_stack_size, s) = split_array_ref(s);
194
195 let (mappings, s) = {
196 let (&kernel_stack, s) = split_array_ref(s);
197 let (&boot_info, s) = split_array_ref(s);
198 let (&framebuffer, s) = split_array_ref(s);
199 let (&physical_memory_some, s) = split_array_ref(s);
200 let (&physical_memory, s) = split_array_ref(s);
201 let (&page_table_recursive_some, s) = split_array_ref(s);
202 let (&page_table_recursive, s) = split_array_ref(s);
203 let (&[alsr], s) = split_array_ref(s);
204 let (&dynamic_range_start_some, s) = split_array_ref(s);
205 let (&dynamic_range_start, s) = split_array_ref(s);
206 let (&dynamic_range_end_some, s) = split_array_ref(s);
207 let (&dynamic_range_end, s) = split_array_ref(s);
208 let (&ramdisk_memory, s) = split_array_ref(s);
209
210 let mappings = Mappings {
211 kernel_stack: Mapping::deserialize(&kernel_stack)?,
212 boot_info: Mapping::deserialize(&boot_info)?,
213 framebuffer: Mapping::deserialize(&framebuffer)?,
214 physical_memory: match physical_memory_some {
215 [0] if physical_memory == [0; 9] => Option::None,
216 [1] => Option::Some(Mapping::deserialize(&physical_memory)?),
217 _ => return Err("invalid phys memory value"),
218 },
219 page_table_recursive: match page_table_recursive_some {
220 [0] if page_table_recursive == [0; 9] => Option::None,
221 [1] => Option::Some(Mapping::deserialize(&page_table_recursive)?),
222 _ => return Err("invalid page table recursive value"),
223 },
224 aslr: match alsr {
225 1 => true,
226 0 => false,
227 _ => return Err("invalid aslr value"),
228 },
229 dynamic_range_start: match dynamic_range_start_some {
230 [0] if dynamic_range_start == [0; 8] => Option::None,
231 [1] => Option::Some(u64::from_le_bytes(dynamic_range_start)),
232 _ => return Err("invalid dynamic range start value"),
233 },
234 dynamic_range_end: match dynamic_range_end_some {
235 [0] if dynamic_range_end == [0; 8] => Option::None,
236 [1] => Option::Some(u64::from_le_bytes(dynamic_range_end)),
237 _ => return Err("invalid dynamic range end value"),
238 },
239 ramdisk_memory: Mapping::deserialize(&ramdisk_memory)?,
240 };
241 (mappings, s)
242 };
243
244 let (frame_buffer, s) = {
245 let (&min_framebuffer_height_some, s) = split_array_ref(s);
246 let (&min_framebuffer_height, s) = split_array_ref(s);
247 let (&min_framebuffer_width_some, s) = split_array_ref(s);
248 let (&min_framebuffer_width, s) = split_array_ref(s);
249
250 let frame_buffer = FrameBuffer {
251 minimum_framebuffer_height: match min_framebuffer_height_some {
252 [0] if min_framebuffer_height == [0; 8] => Option::None,
253 [1] => Option::Some(u64::from_le_bytes(min_framebuffer_height)),
254 _ => return Err("minimum_framebuffer_height invalid"),
255 },
256 minimum_framebuffer_width: match min_framebuffer_width_some {
257 [0] if min_framebuffer_width == [0; 8] => Option::None,
258 [1] => Option::Some(u64::from_le_bytes(min_framebuffer_width)),
259 _ => return Err("minimum_framebuffer_width invalid"),
260 },
261 };
262 (frame_buffer, s)
263 };
264
265 if !s.is_empty() {
266 return Err("unexpected rest");
267 }
268
269 Ok(Self {
270 version,
271 kernel_stack_size: u64::from_le_bytes(kernel_stack_size),
272 mappings,
273 frame_buffer,
274 })
275 }
276
277 #[cfg(test)]
278 fn random() -> Self {
279 Self {
280 version: ApiVersion::random(),
281 mappings: Mappings::random(),
282 kernel_stack_size: rand::random(),
283 frame_buffer: FrameBuffer::random(),
284 }
285 }
286}
287
288impl Default for BootloaderConfig {
289 fn default() -> Self {
290 Self::new_default()
291 }
292}
293
294#[derive(Debug, PartialEq, Eq, Clone, Copy)]
296#[repr(C)]
297pub struct ApiVersion {
298 version_major: u16,
300 version_minor: u16,
302 version_patch: u16,
304 pre_release: bool,
309}
310
311impl ApiVersion {
312 pub(crate) const fn new_default() -> Self {
313 Self {
314 version_major: version_info::VERSION_MAJOR,
315 version_minor: version_info::VERSION_MINOR,
316 version_patch: version_info::VERSION_PATCH,
317 pre_release: version_info::VERSION_PRE,
318 }
319 }
320
321 #[cfg(test)]
322 fn random() -> ApiVersion {
323 Self {
324 version_major: rand::random(),
325 version_minor: rand::random(),
326 version_patch: rand::random(),
327 pre_release: rand::random(),
328 }
329 }
330
331 pub fn version_major(&self) -> u16 {
333 self.version_major
334 }
335
336 pub fn version_minor(&self) -> u16 {
338 self.version_minor
339 }
340
341 pub fn version_patch(&self) -> u16 {
343 self.version_patch
344 }
345
346 pub fn pre_release(&self) -> bool {
348 self.pre_release
349 }
350}
351
352impl Default for ApiVersion {
353 fn default() -> Self {
354 Self::new_default()
355 }
356}
357
358#[derive(Debug, Default, PartialEq, Eq, Clone, Copy)]
360#[non_exhaustive]
361pub struct Mappings {
362 pub kernel_stack: Mapping,
372 pub boot_info: Mapping,
374 pub framebuffer: Mapping,
376 pub physical_memory: Option<Mapping>,
382 pub page_table_recursive: Option<Mapping>,
388 pub aslr: bool,
394 pub dynamic_range_start: Option<u64>,
398 pub dynamic_range_end: Option<u64>,
402 pub ramdisk_memory: Mapping,
405}
406
407impl Mappings {
408 pub const fn new_default() -> Self {
412 Self {
413 kernel_stack: Mapping::new_default(),
414 boot_info: Mapping::new_default(),
415 framebuffer: Mapping::new_default(),
416 physical_memory: Option::None,
417 page_table_recursive: Option::None,
418 aslr: false,
419 dynamic_range_start: None,
420 dynamic_range_end: None,
421 ramdisk_memory: Mapping::new_default(),
422 }
423 }
424
425 #[cfg(test)]
426 fn random() -> Mappings {
427 let phys = rand::random();
428 let recursive = rand::random();
429 Self {
430 kernel_stack: Mapping::random(),
431 boot_info: Mapping::random(),
432 framebuffer: Mapping::random(),
433 physical_memory: if phys {
434 Option::Some(Mapping::random())
435 } else {
436 Option::None
437 },
438 page_table_recursive: if recursive {
439 Option::Some(Mapping::random())
440 } else {
441 Option::None
442 },
443 aslr: rand::random(),
444 dynamic_range_start: if rand::random() {
445 Option::Some(rand::random())
446 } else {
447 Option::None
448 },
449 dynamic_range_end: if rand::random() {
450 Option::Some(rand::random())
451 } else {
452 Option::None
453 },
454 ramdisk_memory: Mapping::random(),
455 }
456 }
457}
458
459#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
461pub enum Mapping {
462 Dynamic,
464 FixedAddress(u64),
471}
472
473impl Mapping {
474 pub const fn new_default() -> Self {
479 Self::Dynamic
480 }
481
482 #[cfg(test)]
483 fn random() -> Mapping {
484 let fixed = rand::random();
485 if fixed {
486 Self::Dynamic
487 } else {
488 Self::FixedAddress(rand::random())
489 }
490 }
491
492 const fn serialize(&self) -> [u8; 9] {
493 match self {
494 Mapping::Dynamic => [0; 9],
495 Mapping::FixedAddress(addr) => concat_1_8([1], addr.to_le_bytes()),
496 }
497 }
498
499 fn deserialize(serialized: &[u8; 9]) -> Result<Self, &'static str> {
500 let (&variant, s) = split_array_ref(serialized);
501 let (&addr, s) = split_array_ref(s);
502 if !s.is_empty() {
503 return Err("invalid mapping format");
504 }
505
506 match variant {
507 [0] if addr == [0; 8] => Ok(Mapping::Dynamic),
508 [1] => Ok(Mapping::FixedAddress(u64::from_le_bytes(addr))),
509 _ => Err("invalid mapping value"),
510 }
511 }
512}
513
514impl Default for Mapping {
515 fn default() -> Self {
516 Self::new_default()
517 }
518}
519
520#[derive(Debug, Default, PartialEq, Eq, Clone, Copy)]
522#[non_exhaustive]
523pub struct FrameBuffer {
524 pub minimum_framebuffer_height: Option<u64>,
528 pub minimum_framebuffer_width: Option<u64>,
532}
533
534impl FrameBuffer {
535 pub const fn new_default() -> Self {
537 Self {
538 minimum_framebuffer_height: Option::None,
539 minimum_framebuffer_width: Option::None,
540 }
541 }
542
543 #[cfg(test)]
544 fn random() -> FrameBuffer {
545 Self {
546 minimum_framebuffer_height: if rand::random() {
547 Option::Some(rand::random())
548 } else {
549 Option::None
550 },
551 minimum_framebuffer_width: if rand::random() {
552 Option::Some(rand::random())
553 } else {
554 Option::None
555 },
556 }
557 }
558}
559
560fn split_array_ref<const N: usize, T>(slice: &[T]) -> (&[T; N], &[T]) {
565 let (a, b) = slice.split_at(N);
566 unsafe { (&*(a.as_ptr() as *const [T; N]), b) }
568}
569
570#[cfg(test)]
571mod tests {
572 use super::*;
573
574 #[test]
575 fn mapping_serde() {
576 for _ in 0..10000 {
577 let config = Mapping::random();
578 assert_eq!(Mapping::deserialize(&config.serialize()), Ok(config));
579 }
580 }
581
582 #[test]
583 fn config_serde() {
584 for _ in 0..10000 {
585 let config = BootloaderConfig::random();
586 assert_eq!(
587 BootloaderConfig::deserialize(&config.serialize()),
588 Ok(config)
589 );
590 }
591 }
592}
593
594use {
597 crate::{concat::*, version_info}
598};