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

feat: UEFI MVP #1140

Merged
merged 1 commit into from
Oct 30, 2024
Merged
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
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