Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix,refactor,docs: misc. preparations for UEFI #330

Merged
merged 9 commits into from
Apr 12, 2024
44 changes: 22 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# The Hermit Loader

This project is a loader to run the [Hermit kernel](https://github.com/hermitcore/kernel) within [QEMU](https://www.qemu.org).
This project is a bootloader to run the [Hermit kernel](https://github.com/hermitcore/kernel) in different environments.

## Requirements

Expand All @@ -9,21 +9,21 @@ This project is a loader to run the [Hermit kernel](https://github.com/hermitcor
## Building

```bash
$ cargo xtask build --target <TARGET> --release
cargo xtask build --target <TARGET> --release
```

With `<TARGET>` being either `x86_64`, `x86_64-uefi`, or `aarch64`.
With `<TARGET>` being either `x86_64`, `x86_64-uefi`, `aarch64`, or `riscv64`.

Afterward, the loader is located at `target/<TARGET>/release/hermit-loader`.
Afterward, the loader is located in `target/release`.

## Running

### x86-64

On x86-64 Linux with KVM, you can boot Hermit like this:

```
$ qemu-system-x86_64 \
```bash
qemu-system-x86_64 \
-enable-kvm \
-cpu host \
-smp 1 \
Expand All @@ -46,17 +46,17 @@ If you want to benchmark Hermit, make sure to enable the _invariant TSC_ (`invts

Unikernel arguments can be provided like this:

```
$ qemu-system-x86_64 ... \
```bash
qemu-system-x86_64 ... \
-append "[KERNEL_ARGS] [--] [APP_ARGS]"
```

### AArch64

On AArch64, the base command is as follows:

```
$ qemu-system-aarch64 \
```bash
qemu-system-aarch64 \
-machine virt,gic-version=3 \
-cpu cortex-a76 \
-smp 1 \
Expand Down Expand Up @@ -126,8 +126,8 @@ Microvms have a smaller memory footprint and a faster boot time.

To use this VM type, PCI and ACPI support have to be disabled for your app (using `no-default-features`).

```
$ qemu-system-x86_64 ... \
```bash
qemu-system-x86_64 ... \
-M microvm,x-option-roms=off,pit=off,pic=off,rtc=on,auto-kernel-cmdline=off \
-nodefaults -no-user-config \
-append "-freq 2800"
Expand All @@ -140,24 +140,24 @@ Depending on the virtualized processor, the processor frequency has to be passed
To enable an Ethernet device, we have to set up a tap device on the host system.
The following commands establish the tap device `tap10` on Linux:

```
# ip tuntap add tap10 mode tap
# ip addr add 10.0.5.1/24 broadcast 10.0.5.255 dev tap10
# ip link set dev tap10 up
# echo 1 > /proc/sys/net/ipv4/conf/tap10/proxy_arp
```bash
ip tuntap add tap10 mode tap
ip addr add 10.0.5.1/24 broadcast 10.0.5.255 dev tap10
ip link set dev tap10 up
echo 1 > /proc/sys/net/ipv4/conf/tap10/proxy_arp
```

If you want Hermit to be accessible from outside the host, you have to enable IP forwarding:
```
# sysctl -w net.ipv4.ip_forward=1
```bash
sysctl -w net.ipv4.ip_forward=1
```

You need to enable the `tcp` feature of the kernel.

The network configuration can be set via environment variables during compile time.
By default, it is:

```
```bash
HERMIT_IP="10.0.5.3"
HERMIT_GATEWAY="10.0.5.1"
HERMIT_MASK="255.255.255.0"
Expand All @@ -167,8 +167,8 @@ Currently, Hermit only supports [Virtio]:

[Virtio]: https://www.redhat.com/en/blog/introduction-virtio-networking-and-vhost-net

```
$ qemu-system-x86_64 ... \
```bash
qemu-system-x86_64 ... \
-netdev tap,id=net0,ifname=tap10,script=no,downscript=no,vhost=on \
-device virtio-net-pci,netdev=net0,disable-legacy=on
```
Expand Down
54 changes: 22 additions & 32 deletions src/arch/aarch64/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use sptr::Strict;

use crate::arch::paging::*;
use crate::os::CONSOLE;
use crate::BootInfoExt;

extern "C" {
static loader_end: u8;
Expand Down Expand Up @@ -192,14 +193,6 @@ pub unsafe fn boot_kernel(kernel_info: LoadedKernel) -> ! {
);
}

let current_stack_address = load_info.kernel_image_addr_range.start - KERNEL_STACK_SIZE as u64;

take_static::take_static! {
static RAW_BOOT_INFO: Option<RawBootInfo> = None;
}

let raw_boot_info = RAW_BOOT_INFO.take().unwrap();

let dtb = unsafe {
Dtb::from_raw(sptr::from_exposed_addr(DEVICE_TREE as usize))
.expect(".dtb file has invalid header")
Expand Down Expand Up @@ -227,39 +220,36 @@ pub unsafe fn boot_kernel(kernel_info: LoadedKernel) -> ! {
platform_info: PlatformInfo::LinuxBoot,
};

info!("boot_info = {boot_info:#?}");
let boot_info_ptr = raw_boot_info.insert(RawBootInfo::from(boot_info));
info!("boot_info at {boot_info_ptr:p}");
let stack = boot_info.load_info.kernel_image_addr_range.start as usize - KERNEL_STACK_SIZE;
let stack = sptr::from_exposed_addr_mut(stack);
let entry = sptr::from_exposed_addr(entry_point.try_into().unwrap());
let raw_boot_info = boot_info.write();

unsafe { enter_kernel(stack, entry, raw_boot_info) }
}

unsafe fn enter_kernel(stack: *mut u8, entry: *const (), raw_boot_info: &'static RawBootInfo) -> ! {
// Check expected signature of entry function
let entry: Entry = {
let entry: unsafe extern "C" fn(raw_boot_info: &'static RawBootInfo, cpu_id: u32) -> ! =
unsafe { core::mem::transmute(entry) };
entry
};

// Jump to the kernel entry point and provide the Multiboot information to it.
info!(
"Jumping to HermitCore Application Entry Point at {:#x}",
entry_point
);
info!("Entering kernel at {entry:p}, stack at {stack:p}, raw_boot_info at {raw_boot_info:p}");

/* Memory barrier */
// Memory barrier
unsafe {
asm!("dsb sy", options(nostack));
}

#[allow(dead_code)]
const ENTRY_TYPE_CHECK: Entry = {
unsafe extern "C" fn entry_signature(
_raw_boot_info: &'static RawBootInfo,
_cpu_id: u32,
) -> ! {
unimplemented!()
}
entry_signature
};

unsafe {
asm!(
"mov sp, {stack_address}",
"mov sp, {stack}",
"br {entry}",
stack_address = in(reg) current_stack_address,
entry = in(reg) entry_point,
in("x0") boot_info_ptr,
stack = in(reg) stack,
entry = in(reg) entry,
in("x0") raw_boot_info,
in("x1") 0,
options(noreturn)
)
Expand Down
36 changes: 20 additions & 16 deletions src/arch/riscv64/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ use hermit_entry::Entry;
use log::info;
use sptr::Strict;

use crate::BootInfoExt;

fn find_kernel_linux(chosen: &FdtNode<'_, '_>) -> Option<&'static [u8]> {
let initrd_start = chosen.property("linux,initrd-start")?.as_usize()?;
let initrd_start = sptr::from_exposed_addr_mut::<u8>(initrd_start);
Expand Down Expand Up @@ -96,14 +98,6 @@ pub unsafe fn boot_kernel(kernel_info: LoadedKernel) -> ! {

let fdt = start::get_fdt();

info!("hart_id = {}", start::get_hart_id());

take_static::take_static! {
static RAW_BOOT_INFO: Option<RawBootInfo> = None;
}

let raw_boot_info = RAW_BOOT_INFO.take().unwrap();

let phys_addr_range = {
let memory = fdt.memory();
let mut regions = memory.regions();
Expand Down Expand Up @@ -134,27 +128,37 @@ pub unsafe fn boot_kernel(kernel_info: LoadedKernel) -> ! {
platform_info: PlatformInfo::LinuxBoot,
};

info!("boot_info = {boot_info:#?}");
let boot_info_ptr = raw_boot_info.insert(RawBootInfo::from(boot_info));
info!("boot_info at {boot_info_ptr:p}");
let stack = start::get_stack_ptr();
let entry = sptr::from_exposed_addr(entry_point.try_into().unwrap());
let hart_id = start::get_hart_id();
let raw_boot_info = boot_info.write();

unsafe { enter_kernel(stack, entry, hart_id, raw_boot_info) }
}

unsafe fn enter_kernel(
stack: *mut u8,
entry: *const (),
hart_id: usize,
raw_boot_info: &'static RawBootInfo,
) -> ! {
// Check expected signature of entry function
let entry: Entry = {
let entry: unsafe extern "C" fn(hart_id: usize, boot_info: &'static RawBootInfo) -> ! =
unsafe { core::mem::transmute(entry_point) };
unsafe { core::mem::transmute(entry) };
entry
};

info!("Jumping into kernel at {entry:p}");
info!("Entering kernel at {entry:p}, stack at {stack:p}, raw_boot_info at {raw_boot_info:p}");

unsafe {
asm!(
"mv sp, {stack}",
"jr {entry}",
entry = in(reg) entry,
stack = in(reg) start::get_stack_ptr(),
in("a0") start::get_hart_id(),
in("a1") boot_info_ptr,
stack = in(reg) stack,
in("a0") hart_id,
in("a1") raw_boot_info,
options(noreturn)
)
}
Expand Down
53 changes: 6 additions & 47 deletions src/arch/x86_64/firecracker.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
use core::arch::asm;
use core::ptr::write_bytes;
use core::{ptr, slice};

use align_address::Align;
use hermit_entry::boot_info::{BootInfo, HardwareInfo, PlatformInfo, RawBootInfo, SerialPortBase};
use hermit_entry::boot_info::{BootInfo, HardwareInfo, PlatformInfo, SerialPortBase};
use hermit_entry::elf::LoadedKernel;
use hermit_entry::fc::{
BOOT_FLAG_OFFSET, CMD_LINE_PTR_OFFSET, CMD_LINE_SIZE_OFFSET, E820_ENTRIES_OFFSET,
E820_TABLE_OFFSET, HDR_MAGIC_OFFSET, LINUX_KERNEL_BOOT_FLAG_MAGIC, LINUX_KERNEL_HRD_MAGIC,
LINUX_SETUP_HEADER_OFFSET, RAMDISK_IMAGE_OFFSET, RAMDISK_SIZE_OFFSET,
};
use hermit_entry::Entry;
use log::info;
use sptr::Strict;
use x86_64::structures::paging::{PageSize, PageTableFlags, Size2MiB, Size4KiB};

use super::physicalmem::PhysAlloc;
use super::{paging, KERNEL_STACK_SIZE, SERIAL_IO_PORT};
use crate::BootInfoExt;

extern "C" {
static loader_end: u8;
Expand Down Expand Up @@ -151,13 +150,6 @@ pub unsafe fn boot_kernel(kernel_info: LoadedKernel) -> ! {
None
};

let current_stack_address = new_stack as u64;
info!(
"Use kernel stack: [{:#x} - {:#x}]",
current_stack_address,
current_stack_address + KERNEL_STACK_SIZE
);

// map stack in the address space
paging::map::<Size4KiB>(
new_stack,
Expand Down Expand Up @@ -220,12 +212,6 @@ pub unsafe fn boot_kernel(kernel_info: LoadedKernel) -> ! {
start_address, end_address
);

take_static::take_static! {
static RAW_BOOT_INFO: Option<RawBootInfo> = None;
}

let raw_boot_info = RAW_BOOT_INFO.take().unwrap();

let boot_info = BootInfo {
hardware_info: HardwareInfo {
phys_addr_range: start_address as u64..end_address as u64,
Expand All @@ -239,36 +225,9 @@ pub unsafe fn boot_kernel(kernel_info: LoadedKernel) -> ! {
},
};

info!("boot_info = {boot_info:#?}");
let boot_info_ptr = raw_boot_info.insert(RawBootInfo::from(boot_info));
info!("boot_info at {boot_info_ptr:p}");

// Jump to the kernel entry point and provide the Multiboot information to it.
info!(
"Jumping to HermitCore Application Entry Point at {:#x}",
entry_point
);
let stack = sptr::from_exposed_addr_mut(new_stack);
let entry = sptr::from_exposed_addr(entry_point.try_into().unwrap());
let raw_boot_info = boot_info.write();

#[allow(dead_code)]
const ENTRY_TYPE_CHECK: Entry = {
unsafe extern "C" fn entry_signature(
_raw_boot_info: &'static RawBootInfo,
_cpu_id: u32,
) -> ! {
unimplemented!()
}
entry_signature
};

unsafe {
asm!(
"mov rsp, {stack_address}",
"jmp {entry}",
stack_address = in(reg) current_stack_address,
entry = in(reg) entry_point,
in("rdi") boot_info_ptr,
in("rsi") 0,
options(noreturn)
)
}
unsafe { super::enter_kernel(stack, entry, raw_boot_info) }
}
34 changes: 34 additions & 0 deletions src/arch/x86_64/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,37 @@ pub unsafe fn get_memory(memory_size: u64) -> u64 {
let address = PhysAlloc::allocate((memory_size as usize).align_up(Size2MiB::SIZE as usize));
unsafe { map_memory(address, memory_size as usize) as u64 }
}

#[cfg(target_os = "none")]
unsafe fn enter_kernel(
stack: *mut u8,
entry: *const (),
raw_boot_info: &'static hermit_entry::boot_info::RawBootInfo,
) -> ! {
use core::arch::asm;

use hermit_entry::boot_info::RawBootInfo;
use hermit_entry::Entry;
use log::info;

// Check expected signature of entry function
let entry: Entry = {
let entry: unsafe extern "C" fn(raw_boot_info: &'static RawBootInfo, cpu_id: u32) -> ! =
unsafe { core::mem::transmute(entry) };
entry
};

info!("Entering kernel at {entry:p}, stack at {stack:p}, raw_boot_info at {raw_boot_info:p}");

unsafe {
asm!(
"mov rsp, {stack_address}",
"jmp {entry}",
stack_address = in(reg) stack,
entry = in(reg) entry,
in("rdi") raw_boot_info,
in("rsi") 0,
options(noreturn)
)
}
}
Loading