Skip to content

Commit

Permalink
Merge pull request #330 from hermit-os/uefi-prep
Browse files Browse the repository at this point in the history
fix,refactor,docs: misc. preparations for UEFI
  • Loading branch information
mkroening authored Apr 12, 2024
2 parents 188c96c + b0a9473 commit 774aa41
Show file tree
Hide file tree
Showing 11 changed files with 150 additions and 183 deletions.
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

0 comments on commit 774aa41

Please sign in to comment.