Skip to content

Commit eaef245

Browse files
committed
feat: implement decompression of Hermit images
1 parent 854b756 commit eaef245

File tree

12 files changed

+169
-27
lines changed

12 files changed

+169
-27
lines changed

Cargo.lock

Lines changed: 29 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ align-address = "0.4"
1212
allocator-api2 = { version = "0.4", default-features = false }
1313
anstyle = { version = "1", default-features = false }
1414
cfg-if = "1"
15-
hermit-entry = { version = "0.10", features = ["loader"] }
15+
compression = { version = "0.1", default-features = false, features = ["gzip"] }
16+
hermit-entry = { version = "0.10.8", features = ["loader"] }
17+
lazy_static = { version = "1.5.0", features = ["spin_no_std"] }
1618
log = "0.4"
1719
one-shot-mutex = "0.2"
1820
take-static = "0.1"

src/arch/aarch64/mod.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use log::info;
1919

2020
use crate::BootInfoExt;
2121
use crate::arch::paging::*;
22-
use crate::os::CONSOLE;
22+
use crate::os::{CONSOLE, ExtraBootInfo};
2323

2424
unsafe extern "C" {
2525
static mut loader_end: u8;
@@ -106,12 +106,14 @@ pub fn find_kernel() -> &'static [u8] {
106106
}
107107
}
108108

109-
pub unsafe fn boot_kernel(kernel_info: LoadedKernel) -> ! {
109+
pub unsafe fn boot_kernel(kernel_info: LoadedKernel, extra_info: ExtraBootInfo) -> ! {
110110
let LoadedKernel {
111111
load_info,
112112
entry_point,
113113
} = kernel_info;
114114

115+
assert!(extra_info.image.is_none());
116+
115117
let fdt = unsafe {
116118
Fdt::from_ptr(ptr::with_exposed_provenance(DEVICE_TREE as usize))
117119
.expect(".fdt file has invalid header")

src/arch/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ cfg_if::cfg_if! {
55
} else if #[cfg(target_arch = "riscv64")] {
66
mod riscv64;
77
pub use self::riscv64::*;
8-
} else if #[cfg(all(target_arch = "x86_64"))] {
8+
} else if #[cfg(target_arch = "x86_64")] {
99
mod x86_64;
1010
pub use self::x86_64::*;
1111
}

src/arch/riscv64/mod.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use hermit_entry::elf::LoadedKernel;
1616
use log::info;
1717

1818
use crate::BootInfoExt;
19+
use crate::os::ExtraBootInfo;
1920

2021
fn find_kernel_linux(chosen: &FdtNode<'_, '_>) -> Option<&'static [u8]> {
2122
let initrd_start = chosen.property("linux,initrd-start")?.as_usize()?;
@@ -89,7 +90,7 @@ pub unsafe fn get_memory(memory_size: u64) -> u64 {
8990
u64::try_from(start_address).unwrap()
9091
}
9192

92-
pub unsafe fn boot_kernel(kernel_info: LoadedKernel) -> ! {
93+
pub unsafe fn boot_kernel(kernel_info: LoadedKernel, extra_info: ExtraBootInfo) -> ! {
9394
let LoadedKernel {
9495
load_info,
9596
entry_point,
@@ -117,6 +118,8 @@ pub unsafe fn boot_kernel(kernel_info: LoadedKernel) -> ! {
117118
DeviceTreeAddress::new(fdt_addr.try_into().unwrap())
118119
};
119120

121+
assert!(extra_info.image.is_none());
122+
120123
let boot_info = BootInfo {
121124
hardware_info: HardwareInfo {
122125
phys_addr_range,

src/arch/x86_64/platform/linux/mod.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use crate::BootInfoExt;
1616
use crate::arch::x86_64::physicalmem::PhysAlloc;
1717
use crate::arch::x86_64::{KERNEL_STACK_SIZE, SERIAL_IO_PORT, paging};
1818
use crate::fdt::Fdt;
19+
use crate::os::ExtraBootInfo;
1920

2021
unsafe extern "C" {
2122
static mut loader_end: u8;
@@ -51,7 +52,7 @@ pub fn find_kernel() -> &'static [u8] {
5152
boot_params_ref.map_ramdisk().unwrap()
5253
}
5354

54-
pub unsafe fn boot_kernel(kernel_info: LoadedKernel) -> ! {
55+
pub unsafe fn boot_kernel(kernel_info: LoadedKernel, extra_info: ExtraBootInfo) -> ! {
5556
let LoadedKernel {
5657
load_info,
5758
entry_point,
@@ -74,7 +75,12 @@ pub unsafe fn boot_kernel(kernel_info: LoadedKernel) -> ! {
7475
write_bytes(stack, 0, KERNEL_STACK_SIZE.try_into().unwrap());
7576
}
7677

77-
let mut fdt = Fdt::new("linux").unwrap();
78+
let maybe_image = match extra_info.image {
79+
None => &[],
80+
Some(tar_image) => tar_image,
81+
};
82+
83+
let mut fdt = Fdt::new("linux", maybe_image).unwrap();
7884

7985
let e820_entries = boot_params_ref.e820_entries();
8086
assert!(!e820_entries.is_empty());

src/arch/x86_64/platform/multiboot/mod.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use crate::BootInfoExt;
1616
use crate::arch::x86_64::physicalmem::PhysAlloc;
1717
use crate::arch::x86_64::{KERNEL_STACK_SIZE, SERIAL_IO_PORT, paging};
1818
use crate::fdt::Fdt;
19+
use crate::os::ExtraBootInfo;
1920

2021
unsafe extern "C" {
2122
static mut loader_end: u8;
@@ -53,15 +54,20 @@ impl MemoryManagement for Mem {
5354
pub struct DeviceTree;
5455

5556
impl DeviceTree {
56-
pub fn create() -> FdtWriterResult<&'static [u8]> {
57+
pub fn create(extra_info: &ExtraBootInfo) -> FdtWriterResult<&'static [u8]> {
5758
let mut mem = Mem;
5859
let multiboot = unsafe { Multiboot::from_ptr(mb_info as u64, &mut mem).unwrap() };
5960

6061
let memory_regions = multiboot
6162
.memory_regions()
6263
.expect("Could not find a memory map in the Multiboot information");
6364

64-
let mut fdt = Fdt::new("multiboot")?.memory_regions(memory_regions)?;
65+
let maybe_image = match extra_info.image {
66+
None => &[],
67+
Some(tar_image) => tar_image,
68+
};
69+
70+
let mut fdt = Fdt::new("multiboot", maybe_image)?.memory_regions(memory_regions)?;
6571

6672
if let Some(cmdline) = multiboot.command_line() {
6773
fdt = fdt.bootargs(cmdline.to_owned())?;
@@ -140,7 +146,7 @@ pub fn find_kernel() -> &'static [u8] {
140146
unsafe { slice::from_raw_parts(ptr::with_exposed_provenance(elf_start), elf_len) }
141147
}
142148

143-
pub unsafe fn boot_kernel(kernel_info: LoadedKernel) -> ! {
149+
pub unsafe fn boot_kernel(kernel_info: LoadedKernel, extra_info: ExtraBootInfo) -> ! {
144150
let LoadedKernel {
145151
load_info,
146152
entry_point,
@@ -183,7 +189,7 @@ pub unsafe fn boot_kernel(kernel_info: LoadedKernel) -> ! {
183189
write_bytes(stack, 0, KERNEL_STACK_SIZE.try_into().unwrap());
184190
}
185191

186-
let device_tree = DeviceTree::create().expect("Unable to create devicetree!");
192+
let device_tree = DeviceTree::create(&extra_info).expect("Unable to create devicetree!");
187193
let device_tree =
188194
DeviceTreeAddress::new(u64::try_from(device_tree.as_ptr().expose_provenance()).unwrap());
189195

src/fdt.rs

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,31 +9,51 @@ pub struct Fdt {
99
writer: FdtWriter,
1010
root_node: FdtWriterNode,
1111
bootargs: Option<String>,
12+
image_range: Option<(u64, u64)>,
1213
}
1314

1415
impl Fdt {
15-
pub fn new(platform: &str) -> FdtWriterResult<Self> {
16-
let mut writer = FdtWriter::new()?;
16+
pub fn new(platform: &str, maybe_image: &'static [u8]) -> FdtWriterResult<Self> {
17+
let mut mem_reserved = Vec::new();
18+
19+
let image_range = if maybe_image.is_empty() {
20+
None
21+
} else {
22+
let image_start = (&maybe_image[0]) as *const u8 as u64;
23+
mem_reserved.push(vm_fdt::FdtReserveEntry::new(
24+
image_start,
25+
maybe_image.len() as u64,
26+
)?);
27+
Some((image_start, maybe_image.len() as u64))
28+
};
29+
30+
let mut writer = FdtWriter::new_with_mem_reserv(&mem_reserved[..])?;
1731

1832
let root_node = writer.begin_node("")?;
1933
writer.property_string("compatible", &format!("hermit,{platform}"))?;
2034
writer.property_u32("#address-cells", 0x2)?;
2135
writer.property_u32("#size-cells", 0x2)?;
2236

23-
let bootargs = None;
24-
2537
Ok(Self {
2638
writer,
2739
root_node,
28-
bootargs,
40+
bootargs: None,
41+
image_range,
2942
})
3043
}
3144

3245
pub fn finish(mut self) -> FdtWriterResult<Vec<u8>> {
3346
let chosen_node = self.writer.begin_node("chosen")?;
47+
3448
if let Some(bootargs) = &self.bootargs {
3549
self.writer.property_string("bootargs", bootargs)?;
3650
}
51+
52+
if let Some((image_start, image_len)) = self.image_range {
53+
self.writer
54+
.property_array_u64("image_reg", &[image_start, image_len])?;
55+
}
56+
3757
self.writer.end_node(chosen_node)?;
3858

3959
self.writer.end_node(self.root_node)?;

src/main.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ use hermit_entry::boot_info::{BootInfo, RawBootInfo};
1212
mod macros;
1313

1414
mod arch;
15+
1516
mod bump_allocator;
17+
1618
#[cfg(any(target_os = "uefi", target_arch = "x86_64"))]
1719
mod fdt;
1820
mod log;
@@ -75,3 +77,41 @@ fn _print(args: core::fmt::Arguments<'_>) {
7577

7678
self::os::CONSOLE.lock().write_fmt(args).unwrap();
7779
}
80+
81+
/// Detects the input format are resolves the kernel
82+
fn resolve_kernel<'a>(
83+
input_blob: &'a [u8],
84+
buf: &'a mut Option<alloc::boxed::Box<[u8]>>,
85+
) -> (&'a [u8], Option<hermit_entry::config::Config<'a>>) {
86+
use hermit_entry::{Format, detect_format};
87+
match detect_format(input_blob) {
88+
Some(Format::Elf) => (input_blob, None),
89+
90+
Some(Format::Gzip) => {
91+
use compression::prelude::{DecodeExt as _, GZipDecoder};
92+
*buf = Some(
93+
input_blob
94+
.iter()
95+
.copied()
96+
.decode(&mut GZipDecoder::new())
97+
.collect::<Result<alloc::boxed::Box<[u8]>, _>>()
98+
.expect("Unable to decompress Hermit gzip image"),
99+
);
100+
match *buf {
101+
Some(ref mut tmp) => {
102+
let handle = hermit_entry::config::parse_tar(tmp)
103+
.expect("Unable to find Hermit image configuration + kernel");
104+
105+
// TODO: do we just let the kernel handle the config
106+
107+
(handle.raw_kernel, Some(handle.config))
108+
}
109+
None => unreachable!(),
110+
}
111+
}
112+
113+
None => {
114+
panic!("Input BLOB has unknown magic bytes (neither Gzip nor ELF)")
115+
}
116+
}
117+
}

src/os/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,9 @@ cfg_if::cfg_if! {
77
pub use self::uefi::*;
88
}
99
}
10+
11+
#[cfg_attr(not(target_os = "none"), allow(dead_code))]
12+
#[derive(Clone, Default)]
13+
pub struct ExtraBootInfo {
14+
pub(crate) image: Option<&'static [u8]>,
15+
}

0 commit comments

Comments
 (0)