Skip to content

Commit

Permalink
Merge pull request #1140 from hermit-os/uefi
Browse files Browse the repository at this point in the history
feat: UEFI MVP
  • Loading branch information
mkroening authored Oct 30, 2024
2 parents 0c67959 + ceff58e commit 45676ab
Show file tree
Hide file tree
Showing 11 changed files with 342 additions and 105 deletions.
11 changes: 11 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,13 @@ jobs:
run: |
gh release download v1.4 --repo riscv-software-src/opensbi --pattern 'opensbi-*-rv-bin.tar.xz'
tar -xvf opensbi-*-rv-bin.tar.xz opensbi-1.4-rv-bin/share/opensbi/lp64/generic/firmware/fw_jump.bin
- name: Download OVMF
run: |
sudo apt-get update
sudo apt-get install ovmf
mkdir -p edk2-stable202408-r1-bin/x64
cp /usr/share/OVMF/OVMF_CODE.fd edk2-stable202408-r1-bin/x64/code.fd
cp /usr/share/OVMF/OVMF_VARS.fd edk2-stable202408-r1-bin/x64/vars.fd
- name: Install Firecracker
run: |
# https://github.com/firecracker-microvm/firecracker/blob/v1.5.1/docs/getting-started.md#getting-a-firecracker-binary
Expand All @@ -204,6 +211,8 @@ jobs:
- run: cargo +stable install cargo-careful
if: matrix.profile == 'dev'
- run: cargo xtask ci qemu --arch ${{ matrix.arch }} --profile ${{ matrix.profile }} ${{ matrix.flags }} --package hello_world
- run: cargo xtask ci qemu --arch ${{ matrix.arch }} --profile ${{ matrix.profile }} ${{ matrix.flags }} --package hello_world --uefi
if: matrix.arch == 'x86_64'
- run: cargo xtask ci qemu --arch ${{ matrix.arch }} --profile ${{ matrix.profile }} ${{ matrix.flags }} --package wasmtime-demo --features ci
if: matrix.arch == 'x86_64'
- run: cargo xtask ci qemu --arch ${{ matrix.arch }} --profile ${{ matrix.profile }} ${{ matrix.flags }} --package hello_world --no-default-features --microvm
Expand All @@ -222,6 +231,8 @@ jobs:
if: matrix.arch != 'aarch64'
# https://github.com/hermit-os/kernel/issues/1286
continue-on-error: ${{ matrix.arch == 'riscv64' }}
- run: cargo xtask ci qemu --arch ${{ matrix.arch }} --profile ${{ matrix.profile }} ${{ matrix.flags }} --package rusty_demo --smp 4 --uefi
if: matrix.arch == 'x86_64'
- run: cargo xtask ci qemu --arch ${{ matrix.arch }} --profile ${{ matrix.profile }} ${{ matrix.flags }} --package rftrace-example --virtiofsd
if: matrix.arch == 'x86_64'
- run: cargo xtask ci qemu --arch ${{ matrix.arch }} --profile ${{ matrix.profile }} ${{ matrix.flags }} --package httpd --features ci,hermit/dhcpv4 --netdev virtio-net-pci
Expand Down
36 changes: 35 additions & 1 deletion src/arch/x86_64/kernel/acpi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use crate::arch::x86_64::mm::paging::{
BasePageSize, PageSize, PageTableEntryFlags, PageTableEntryFlagsExt,
};
use crate::arch::x86_64::mm::{paging, virtualmem, PhysAddr, VirtAddr};
use crate::env;

/// Memory at this physical address is supposed to contain a pointer to the Extended BIOS Data Area (EBDA).
const EBDA_PTR_LOCATION: PhysAddr = PhysAddr(0x0000_040E);
Expand Down Expand Up @@ -98,6 +99,24 @@ pub struct AcpiTable<'a> {

impl AcpiTable<'_> {
fn map(physical_address: PhysAddr) -> Self {
if env::is_uefi() {
// For UEFI Systems, the tables are already mapped so we only need to return a proper reference to the table
let allocated_virtual_address = VirtAddr(physical_address.0);
let header = unsafe {
allocated_virtual_address
.as_ptr::<AcpiSdtHeader>()
.as_ref()
.unwrap()
};
let allocated_length = usize::try_from(header.length).unwrap();

return Self {
header,
allocated_virtual_address,
allocated_length,
};
}

let mut flags = PageTableEntryFlags::empty();
flags.normal().read_only().execute_disable();

Expand Down Expand Up @@ -152,7 +171,9 @@ impl AcpiTable<'_> {

impl Drop for AcpiTable<'_> {
fn drop(&mut self) {
virtualmem::deallocate(self.allocated_virtual_address, self.allocated_length);
if !env::is_uefi() {
virtualmem::deallocate(self.allocated_virtual_address, self.allocated_length);
}
}
}

Expand Down Expand Up @@ -308,6 +329,19 @@ fn detect_rsdp(start_address: PhysAddr, end_address: PhysAddr) -> Result<&'stati
/// Detects ACPI support of the computer system.
/// Returns a reference to the ACPI RSDP within the Ok() if successful or an empty Err() on failure.
fn detect_acpi() -> Result<&'static AcpiRsdp, ()> {
if let Some(rsdp) = env::rsdp() {
trace!("RSDP detected successfully at {rsdp:#x?}");
let rsdp = unsafe {
ptr::with_exposed_provenance::<AcpiRsdp>(rsdp.get())
.as_ref()
.unwrap()
};
if &rsdp.signature != b"RSD PTR " {
panic!("RSDP Address not valid!");
}
return Ok(rsdp);
}

// Get the address of the EBDA.
let frame =
PhysFrame::<BasePageSize>::containing_address(x86_64::PhysAddr::new(EBDA_PTR_LOCATION.0));
Expand Down
81 changes: 53 additions & 28 deletions src/arch/x86_64/kernel/apic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -259,13 +259,18 @@ pub fn local_apic_id_count() -> u32 {
}

fn init_ioapic_address(phys_addr: PhysAddr) {
let ioapic_address = virtualmem::allocate(BasePageSize::SIZE as usize).unwrap();
IOAPIC_ADDRESS.set(ioapic_address).unwrap();
debug!("Mapping IOAPIC at {phys_addr:p} to virtual address {ioapic_address:p}",);
if env::is_uefi() {
// UEFI systems have already id mapped everything, so we can just set the physical address as the virtual one
IOAPIC_ADDRESS.set(VirtAddr(phys_addr.as_u64())).unwrap();
} else {
let ioapic_address = virtualmem::allocate(BasePageSize::SIZE as usize).unwrap();
IOAPIC_ADDRESS.set(ioapic_address).unwrap();
debug!("Mapping IOAPIC at {phys_addr:p} to virtual address {ioapic_address:p}",);

let mut flags = PageTableEntryFlags::empty();
flags.device().writable().execute_disable();
paging::map::<BasePageSize>(ioapic_address, phys_addr, 1, flags);
let mut flags = PageTableEntryFlags::empty();
flags.device().writable().execute_disable();
paging::map::<BasePageSize>(ioapic_address, phys_addr, 1, flags);
}
}

#[cfg(not(feature = "acpi"))]
Expand Down Expand Up @@ -468,16 +473,23 @@ pub fn init() {
if !processor::supports_x2apic() {
// We use the traditional xAPIC mode available on all x86-64 CPUs.
// It uses a mapped page for communication.
let local_apic_address = virtualmem::allocate(BasePageSize::SIZE as usize).unwrap();
LOCAL_APIC_ADDRESS.set(local_apic_address).unwrap();
debug!(
"Mapping Local APIC at {:p} to virtual address {:p}",
local_apic_physical_address, local_apic_address
);
if env::is_uefi() {
//already id mapped in UEFI systems, just use the physical address as virtual one
LOCAL_APIC_ADDRESS
.set(VirtAddr(local_apic_physical_address.as_u64()))
.unwrap();
} else {
let local_apic_address = virtualmem::allocate(BasePageSize::SIZE as usize).unwrap();
LOCAL_APIC_ADDRESS.set(local_apic_address).unwrap();
debug!(
"Mapping Local APIC at {:p} to virtual address {:p}",
local_apic_physical_address, local_apic_address
);

let mut flags = PageTableEntryFlags::empty();
flags.device().writable().execute_disable();
paging::map::<BasePageSize>(local_apic_address, local_apic_physical_address, 1, flags);
let mut flags = PageTableEntryFlags::empty();
flags.device().writable().execute_disable();
paging::map::<BasePageSize>(local_apic_address, local_apic_physical_address, 1, flags);
}
}

// Set gates to ISRs for the APIC interrupts we are going to enable.
Expand Down Expand Up @@ -697,6 +709,8 @@ pub fn init_next_processor_variables() {
pub fn boot_application_processors() {
use core::hint;

use x86_64::structures::paging::Translate;

use super::start;

let smp_boot_code = include_bytes!(concat!(core::env!("OUT_DIR"), "/boot.bin"));
Expand All @@ -708,19 +722,30 @@ pub fn boot_application_processors() {
);
debug!("SMP boot code is {} bytes long", smp_boot_code.len());

// Identity-map the boot code page and copy over the code.
debug!(
"Mapping SMP boot code to physical and virtual address {:p}",
SMP_BOOT_CODE_ADDRESS
);
let mut flags = PageTableEntryFlags::empty();
flags.normal().writable();
paging::map::<BasePageSize>(
SMP_BOOT_CODE_ADDRESS,
PhysAddr(SMP_BOOT_CODE_ADDRESS.as_u64()),
1,
flags,
);
if env::is_uefi() {
// Since UEFI already provides identity-mapped pagetables, we only have to sanity-check the identity mapping
let pt = unsafe { crate::arch::mm::paging::identity_mapped_page_table() };
let virt_addr = SMP_BOOT_CODE_ADDRESS.0;
let phys_addr = pt
.translate_addr(x86_64::VirtAddr::new(virt_addr))
.unwrap()
.as_u64();
assert_eq!(phys_addr, virt_addr)
} else {
// Identity-map the boot code page and copy over the code.
debug!(
"Mapping SMP boot code to physical and virtual address {:p}",
SMP_BOOT_CODE_ADDRESS
);
let mut flags = PageTableEntryFlags::empty();
flags.normal().writable();
paging::map::<BasePageSize>(
SMP_BOOT_CODE_ADDRESS,
PhysAddr(SMP_BOOT_CODE_ADDRESS.as_u64()),
1,
flags,
);
}
unsafe {
ptr::copy_nonoverlapping(
smp_boot_code.as_ptr(),
Expand Down
55 changes: 30 additions & 25 deletions src/arch/x86_64/kernel/scheduler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,29 +115,32 @@ impl TaskStacks {
let mut flags = PageTableEntryFlags::empty();
flags.normal().writable().execute_disable();

// map IST1 into the address space
crate::arch::mm::paging::map::<BasePageSize>(
virt_addr + BasePageSize::SIZE,
phys_addr,
IST_SIZE / BasePageSize::SIZE as usize,
flags,
);
// For UEFI systems, the entire memory is already mapped, just clear the stack for safety
if !env::is_uefi() {
// map IST1 into the address space
crate::arch::mm::paging::map::<BasePageSize>(
virt_addr + BasePageSize::SIZE,
phys_addr,
IST_SIZE / BasePageSize::SIZE as usize,
flags,
);

// map kernel stack into the address space
crate::arch::mm::paging::map::<BasePageSize>(
virt_addr + IST_SIZE + 2 * BasePageSize::SIZE,
phys_addr + IST_SIZE,
DEFAULT_STACK_SIZE / BasePageSize::SIZE as usize,
flags,
);
// map kernel stack into the address space
crate::arch::mm::paging::map::<BasePageSize>(
virt_addr + IST_SIZE + 2 * BasePageSize::SIZE,
phys_addr + IST_SIZE,
DEFAULT_STACK_SIZE / BasePageSize::SIZE as usize,
flags,
);

// map user stack into the address space
crate::arch::mm::paging::map::<BasePageSize>(
virt_addr + IST_SIZE + DEFAULT_STACK_SIZE + 3 * BasePageSize::SIZE,
phys_addr + IST_SIZE + DEFAULT_STACK_SIZE,
user_stack_size / BasePageSize::SIZE as usize,
flags,
);
// map user stack into the address space
crate::arch::mm::paging::map::<BasePageSize>(
virt_addr + IST_SIZE + DEFAULT_STACK_SIZE + 3 * BasePageSize::SIZE,
phys_addr + IST_SIZE + DEFAULT_STACK_SIZE,
user_stack_size / BasePageSize::SIZE as usize,
flags,
);
}

// clear user stack
unsafe {
Expand Down Expand Up @@ -224,10 +227,12 @@ impl Drop for TaskStacks {
stacks.total_size >> 10,
);

crate::arch::mm::paging::unmap::<BasePageSize>(
stacks.virt_addr,
stacks.total_size / BasePageSize::SIZE as usize + 4,
);
if !env::is_uefi() {
crate::arch::mm::paging::unmap::<BasePageSize>(
stacks.virt_addr,
stacks.total_size / BasePageSize::SIZE as usize + 4,
);
}
crate::arch::mm::virtualmem::deallocate(
stacks.virt_addr,
stacks.total_size + 4 * BasePageSize::SIZE as usize,
Expand Down
Loading

0 comments on commit 45676ab

Please sign in to comment.