Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ align-address = "0.4"
allocator-api2 = { version = "0.4", default-features = false }
anstyle = { version = "1", default-features = false }
cfg-if = "1"
hermit-entry = { version = "0.10", features = ["loader"] }
compression = { version = "0.1", default-features = false, features = ["gzip"] }
hermit-entry = { version = "0.10.8", features = ["loader"] }
lazy_static = { version = "1.5.0", features = ["spin_no_std"] }
log = "0.4"
one-shot-mutex = "0.2"
take-static = "0.1"
Expand Down
6 changes: 4 additions & 2 deletions src/arch/aarch64/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use log::info;

use crate::BootInfoExt;
use crate::arch::paging::*;
use crate::os::CONSOLE;
use crate::os::{CONSOLE, ExtraBootInfo};

unsafe extern "C" {
static mut loader_end: u8;
Expand Down Expand Up @@ -106,12 +106,14 @@ pub fn find_kernel() -> &'static [u8] {
}
}

pub unsafe fn boot_kernel(kernel_info: LoadedKernel) -> ! {
pub unsafe fn boot_kernel(kernel_info: LoadedKernel, extra_info: ExtraBootInfo) -> ! {
let LoadedKernel {
load_info,
entry_point,
} = kernel_info;

assert!(extra_info.image.is_none());

let fdt = unsafe {
Fdt::from_ptr(ptr::with_exposed_provenance(DEVICE_TREE as usize))
.expect(".fdt file has invalid header")
Expand Down
2 changes: 1 addition & 1 deletion src/arch/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ cfg_if::cfg_if! {
} else if #[cfg(target_arch = "riscv64")] {
mod riscv64;
pub use self::riscv64::*;
} else if #[cfg(all(target_arch = "x86_64"))] {
} else if #[cfg(target_arch = "x86_64")] {
mod x86_64;
pub use self::x86_64::*;
}
Expand Down
5 changes: 4 additions & 1 deletion src/arch/riscv64/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use hermit_entry::elf::LoadedKernel;
use log::info;

use crate::BootInfoExt;
use crate::os::ExtraBootInfo;

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

pub unsafe fn boot_kernel(kernel_info: LoadedKernel) -> ! {
pub unsafe fn boot_kernel(kernel_info: LoadedKernel, extra_info: ExtraBootInfo) -> ! {
let LoadedKernel {
load_info,
entry_point,
Expand Down Expand Up @@ -117,6 +118,8 @@ pub unsafe fn boot_kernel(kernel_info: LoadedKernel) -> ! {
DeviceTreeAddress::new(fdt_addr.try_into().unwrap())
};

assert!(extra_info.image.is_none());

let boot_info = BootInfo {
hardware_info: HardwareInfo {
phys_addr_range,
Expand Down
10 changes: 8 additions & 2 deletions src/arch/x86_64/platform/linux/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use crate::BootInfoExt;
use crate::arch::x86_64::physicalmem::PhysAlloc;
use crate::arch::x86_64::{KERNEL_STACK_SIZE, SERIAL_IO_PORT, paging};
use crate::fdt::Fdt;
use crate::os::ExtraBootInfo;

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

pub unsafe fn boot_kernel(kernel_info: LoadedKernel) -> ! {
pub unsafe fn boot_kernel(kernel_info: LoadedKernel, extra_info: ExtraBootInfo) -> ! {
let LoadedKernel {
load_info,
entry_point,
Expand All @@ -74,7 +75,12 @@ pub unsafe fn boot_kernel(kernel_info: LoadedKernel) -> ! {
write_bytes(stack, 0, KERNEL_STACK_SIZE.try_into().unwrap());
}

let mut fdt = Fdt::new("linux").unwrap();
let maybe_image = match extra_info.image {
None => &[],
Some(tar_image) => tar_image,
};

let mut fdt = Fdt::new("linux", maybe_image).unwrap();

let e820_entries = boot_params_ref.e820_entries();
assert!(!e820_entries.is_empty());
Expand Down
14 changes: 10 additions & 4 deletions src/arch/x86_64/platform/multiboot/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use crate::BootInfoExt;
use crate::arch::x86_64::physicalmem::PhysAlloc;
use crate::arch::x86_64::{KERNEL_STACK_SIZE, SERIAL_IO_PORT, paging};
use crate::fdt::Fdt;
use crate::os::ExtraBootInfo;

unsafe extern "C" {
static mut loader_end: u8;
Expand Down Expand Up @@ -53,15 +54,20 @@ impl MemoryManagement for Mem {
pub struct DeviceTree;

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

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

let mut fdt = Fdt::new("multiboot")?.memory_regions(memory_regions)?;
let maybe_image = match extra_info.image {
None => &[],
Some(tar_image) => tar_image,
};

let mut fdt = Fdt::new("multiboot", maybe_image)?.memory_regions(memory_regions)?;

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

pub unsafe fn boot_kernel(kernel_info: LoadedKernel) -> ! {
pub unsafe fn boot_kernel(kernel_info: LoadedKernel, extra_info: ExtraBootInfo) -> ! {
let LoadedKernel {
load_info,
entry_point,
Expand Down Expand Up @@ -183,7 +189,7 @@ pub unsafe fn boot_kernel(kernel_info: LoadedKernel) -> ! {
write_bytes(stack, 0, KERNEL_STACK_SIZE.try_into().unwrap());
}

let device_tree = DeviceTree::create().expect("Unable to create devicetree!");
let device_tree = DeviceTree::create(&extra_info).expect("Unable to create devicetree!");
let device_tree =
DeviceTreeAddress::new(u64::try_from(device_tree.as_ptr().expose_provenance()).unwrap());

Expand Down
30 changes: 25 additions & 5 deletions src/fdt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,31 +9,51 @@ pub struct Fdt {
writer: FdtWriter,
root_node: FdtWriterNode,
bootargs: Option<String>,
image_range: Option<(u64, u64)>,
}

impl Fdt {
pub fn new(platform: &str) -> FdtWriterResult<Self> {
let mut writer = FdtWriter::new()?;
pub fn new(platform: &str, maybe_image: &'static [u8]) -> FdtWriterResult<Self> {
let mut mem_reserved = Vec::new();

let image_range = if maybe_image.is_empty() {
None
} else {
let image_start = (&maybe_image[0]) as *const u8 as u64;
mem_reserved.push(vm_fdt::FdtReserveEntry::new(
image_start,
maybe_image.len() as u64,
)?);
Some((image_start, maybe_image.len() as u64))
};

let mut writer = FdtWriter::new_with_mem_reserv(&mem_reserved[..])?;

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

let bootargs = None;

Ok(Self {
writer,
root_node,
bootargs,
bootargs: None,
image_range,
})
}

pub fn finish(mut self) -> FdtWriterResult<Vec<u8>> {
let chosen_node = self.writer.begin_node("chosen")?;

if let Some(bootargs) = &self.bootargs {
self.writer.property_string("bootargs", bootargs)?;
}

if let Some((image_start, image_len)) = self.image_range {
self.writer
.property_array_u64("image_reg", &[image_start, image_len])?;
}

self.writer.end_node(chosen_node)?;

self.writer.end_node(self.root_node)?;
Expand Down
41 changes: 40 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@ use hermit_entry::boot_info::{BootInfo, RawBootInfo};
mod macros;

mod arch;

mod bump_allocator;

#[cfg(any(target_os = "uefi", target_arch = "x86_64"))]
mod fdt;
mod log;
mod os;

#[cfg(any(target_os = "uefi", all(target_arch = "x86_64", target_os = "none")))]
extern crate alloc;

mod built_info {
Expand Down Expand Up @@ -75,3 +76,41 @@ fn _print(args: core::fmt::Arguments<'_>) {

self::os::CONSOLE.lock().write_fmt(args).unwrap();
}

/// Detects the input format are resolves the kernel
fn resolve_kernel<'a>(
input_blob: &'a [u8],
buf: &'a mut Option<alloc::boxed::Box<[u8]>>,
) -> (&'a [u8], Option<hermit_entry::config::Config<'a>>) {
use hermit_entry::{Format, detect_format};
match detect_format(input_blob) {
Some(Format::Elf) => (input_blob, None),

Some(Format::Gzip) => {
use compression::prelude::{DecodeExt as _, GZipDecoder};
*buf = Some(
input_blob
.iter()
.copied()
.decode(&mut GZipDecoder::new())
.collect::<Result<alloc::boxed::Box<[u8]>, _>>()
.expect("Unable to decompress Hermit gzip image"),
);
match *buf {
Some(ref mut tmp) => {
let handle = hermit_entry::config::parse_tar(tmp)
.expect("Unable to find Hermit image configuration + kernel");

// TODO: do we just let the kernel handle the config

(handle.raw_kernel, Some(handle.config))
}
None => unreachable!(),
}
}

None => {
panic!("Input BLOB has unknown magic bytes (neither Gzip nor ELF)")
}
}
}
6 changes: 6 additions & 0 deletions src/os/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,9 @@ cfg_if::cfg_if! {
pub use self::uefi::*;
}
}

#[cfg_attr(not(target_os = "none"), allow(dead_code))]
#[derive(Clone, Default)]
pub struct ExtraBootInfo {
pub(crate) image: Option<&'static [u8]>,
}
15 changes: 13 additions & 2 deletions src/os/none/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
mod allocator;
pub(crate) mod allocator;
mod console;

use core::fmt::Write;
Expand All @@ -10,6 +10,7 @@ use log::info;

pub use self::console::CONSOLE;
use crate::arch;
use crate::os::ExtraBootInfo;

unsafe extern "C" {
static loader_end: u8;
Expand All @@ -27,6 +28,10 @@ pub(crate) unsafe extern "C" fn loader_main() -> ! {
}

let kernel = arch::find_kernel();
let mut buf = None;
// TODO: handle config
let (kernel, _) = crate::resolve_kernel(kernel, &mut buf);

let kernel = KernelObject::parse(kernel).unwrap();

let mem_size = kernel.mem_size();
Expand All @@ -41,7 +46,13 @@ pub(crate) unsafe extern "C" fn loader_main() -> ! {

let kernel_info = kernel.load_kernel(memory, memory.as_ptr() as u64);

unsafe { arch::boot_kernel(kernel_info) }
let mut extra_info = ExtraBootInfo::default();
if let Some(tar_image) = buf {
let tar_image = alloc::boxed::Box::leak(tar_image);
extra_info.image = Some(&*tar_image);
}

unsafe { arch::boot_kernel(kernel_info, extra_info) }
}

#[panic_handler]
Expand Down
Loading