Skip to content
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
17 changes: 10 additions & 7 deletions src/arch/aarch64/kernel/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ pub(crate) use self::processor::set_oneshot_timer;
use crate::arch::aarch64::kernel::core_local::*;
use crate::arch::aarch64::mm::paging::{BasePageSize, PageSize};
use crate::config::*;
use crate::env;

#[repr(align(8))]
pub(crate) struct AlignedAtomicU32(AtomicU32);
Expand All @@ -42,7 +41,7 @@ global_asm!(include_str!("start.s"));

#[cfg(feature = "smp")]
pub fn get_possible_cpus() -> u32 {
let fdt = env::fdt().unwrap();
let fdt = crate::env::fdt().unwrap();
let cpu_count = fdt.cpus().count();
u32::try_from(cpu_count).unwrap()
}
Expand All @@ -60,9 +59,7 @@ pub fn get_processor_count() -> u32 {
/// Real Boot Processor initialization as soon as we have put the first Welcome message on the screen.
#[cfg(target_os = "none")]
pub fn boot_processor_init() {
if !env::is_uhyve() {
processor::configure();
}
processor::configure();

crate::mm::init();
crate::mm::print_information();
Expand Down Expand Up @@ -102,8 +99,14 @@ pub fn boot_next_processor() {
#[allow(unused_variables)]
let cpu_online = CPU_ONLINE.0.fetch_add(1, Ordering::Release);

#[allow(clippy::needless_return)]
#[cfg(feature = "uhyve")]
if crate::env::is_uhyve() {
return;
}

#[cfg(all(target_os = "none", feature = "smp"))]
if !env::is_uhyve() && get_possible_cpus() > 1 {
if get_possible_cpus() > 1 {
use core::arch::asm;
use core::hint::spin_loop;

Expand All @@ -122,7 +125,7 @@ pub fn boot_next_processor() {
trace!("Virtual address of smp_start 0x{virt_start:x}");
trace!("Physical address of smp_start 0x{phys_start:x}");

let fdt = env::fdt().unwrap();
let fdt = crate::env::fdt().unwrap();
let psci_node = fdt.find_node("/psci").unwrap();

let cpu_on = psci_node.property("cpu_on").unwrap().as_usize().unwrap();
Expand Down
5 changes: 5 additions & 0 deletions src/arch/aarch64/kernel/processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,11 @@ pub fn supports_2mib_pages() -> bool {
}

pub fn configure() {
#[cfg(feature = "uhyve")]
if env::is_uhyve() {
return;
}

// TODO: PMCCNTR_EL0 is the best replacement for RDTSC on AArch64.
// However, this test code showed that it's apparently not supported under uhyve yet.
// Finish the boot loader for QEMU first and then run this code under QEMU, where it should be supported.
Expand Down
89 changes: 41 additions & 48 deletions src/arch/aarch64/kernel/systemtime.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use core::arch::asm;

use free_list::PageLayout;
use hermit_entry::boot_info::PlatformInfo;
use hermit_sync::OnceCell;
use memory_addresses::{PhysAddr, VirtAddr};
use time::OffsetDateTime;
Expand Down Expand Up @@ -45,55 +44,49 @@ fn rtc_read(off: usize) -> u32 {
u32::from_le(value)
}

pub fn init() {
match env::boot_info().platform_info {
PlatformInfo::Uhyve { boot_time, .. } => {
PL031_ADDRESS.set(VirtAddr::zero()).unwrap();
BOOT_TIME
.set(u64::try_from(boot_time.unix_timestamp_nanos() / 1000).unwrap())
.unwrap();
info!("Hermit booted on {boot_time}");

return;
}
_ => {
let fdt = env::fdt().unwrap();
if let Some(pl031_node) = fdt.find_compatible(&["arm,pl031"]) {
let reg = pl031_node.reg().unwrap().next().unwrap();
let addr = PhysAddr::from(reg.starting_address.addr());
let size = u64::try_from(reg.size.unwrap()).unwrap();

debug!("Found RTC at {addr:p} (size {size:#X})");

let layout = PageLayout::from_size(size.try_into().unwrap()).unwrap();
let page_range = PageAlloc::allocate(layout).unwrap();
let pl031_address = VirtAddr::from(page_range.start());
PL031_ADDRESS.set(pl031_address).unwrap();
debug!("Mapping RTC to virtual address {pl031_address:p}");

let mut flags = PageTableEntryFlags::empty();
flags.device().writable().execute_disable();
paging::map::<BasePageSize>(
pl031_address,
addr,
(size / BasePageSize::SIZE).try_into().unwrap(),
flags,
);

let boot_time =
OffsetDateTime::from_unix_timestamp(rtc_read(reg::RTC_DR).into()).unwrap();
info!("Hermit booted on {boot_time}");

BOOT_TIME
.set(u64::try_from(boot_time.unix_timestamp_nanos() / 1000).unwrap())
.unwrap();

return;
}
}
fn boot_time() -> OffsetDateTime {
#[cfg(feature = "uhyve")]
if let Some(boot_time) = env::uhyve_boot_time() {
return boot_time;
}

let fdt = env::fdt().unwrap();
let Some(pl031_node) = fdt.find_compatible(&["arm,pl031"]) else {
error!("Could not find PL031 Real Time Clock to determine the boot time.");
return OffsetDateTime::UNIX_EPOCH;
};

BOOT_TIME.set(0).unwrap();
let reg = pl031_node.reg().unwrap().next().unwrap();
let addr = PhysAddr::from(reg.starting_address.addr());
let size = u64::try_from(reg.size.unwrap()).unwrap();

debug!("Found RTC at {addr:p} (size {size:#X})");

let layout = PageLayout::from_size(size.try_into().unwrap()).unwrap();
let page_range = PageAlloc::allocate(layout).unwrap();
let pl031_address = VirtAddr::from(page_range.start());
PL031_ADDRESS.set(pl031_address).unwrap();
debug!("Mapping RTC to virtual address {pl031_address:p}");

let mut flags = PageTableEntryFlags::empty();
flags.device().writable().execute_disable();
paging::map::<BasePageSize>(
pl031_address,
addr,
(size / BasePageSize::SIZE).try_into().unwrap(),
flags,
);

OffsetDateTime::from_unix_timestamp(rtc_read(reg::RTC_DR).into()).unwrap()
}

pub fn init() {
let boot_time = boot_time();
info!("Hermit booted on {boot_time}");

BOOT_TIME
.set(u64::try_from(boot_time.unix_timestamp_nanos() / 1000).unwrap())
.unwrap();
}

/// Returns the current time in microseconds since UNIX epoch.
Expand Down
11 changes: 7 additions & 4 deletions src/arch/riscv64/kernel/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,11 +149,14 @@ pub fn boot_next_processor() {
// TODO: Old: Changing cpu_online will cause uhyve to start the next processor
CPU_ONLINE.fetch_add(1, Ordering::Release);

//When running bare-metal/QEMU we use the firmware to start the next hart
if !env::is_uhyve() {
let start_addr = (start::_start as *const ()).expose_provenance();
sbi_rt::hart_start(next_hart_id as usize, start_addr, 0).unwrap();
#[cfg(feature = "uhyve")]
if env::is_uhyve() {
return;
}

//When running bare-metal/QEMU we use the firmware to start the next hart
let start_addr = (start::_start as *const ()).expose_provenance();
sbi_rt::hart_start(next_hart_id as usize, start_addr, 0).unwrap();
}

pub fn print_statistics() {
Expand Down
5 changes: 5 additions & 0 deletions src/arch/x86_64/kernel/acpi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,11 @@ pub fn poweroff() {
}

pub fn init() {
#[cfg(feature = "uhyve")]
if env::is_uhyve() {
return;
}

// Detect the RSDP and get a pointer to either the XSDT (64-bit) or RSDT (32-bit), whichever is available.
// Both are called RSDT in the following.
let rsdp = detect_acpi().expect("Hermit requires an ACPI-compliant system");
Expand Down
32 changes: 20 additions & 12 deletions src/arch/x86_64/kernel/apic.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
use alloc::alloc::alloc;
use alloc::vec::Vec;
use core::alloc::Layout;
#[cfg(feature = "smp")]
use core::arch::x86_64::_mm_mfence;
#[cfg(feature = "acpi")]
use core::fmt;
use core::hint::spin_loop;
use core::sync::atomic::Ordering;
use core::{cmp, ptr};

use align_address::Align;
Expand All @@ -21,15 +18,13 @@ use x86_64::registers::control::Cr3;
use x86_64::registers::model_specific::Msr;

use super::interrupts::IDT;
use crate::arch::x86_64::kernel::CURRENT_STACK_ADDRESS;
#[cfg(feature = "acpi")]
use crate::arch::x86_64::kernel::acpi;
use crate::arch::x86_64::mm::paging;
use crate::arch::x86_64::mm::paging::{
BasePageSize, PageSize, PageTableEntryFlags, PageTableEntryFlagsExt,
};
use crate::arch::x86_64::swapgs;
use crate::config::*;
use crate::mm::{PageAlloc, PageBox, PageRangeAllocator};
use crate::scheduler::CoreId;
use crate::{arch, env, scheduler};
Expand Down Expand Up @@ -511,19 +506,24 @@ fn default_apic() -> PhysAddr {
default_local
}

fn apic_addr() -> PhysAddr {
#[cfg(feature = "uhyve")]
if env::is_uhyve() {
return default_apic();
}

detect_from_acpi()
.or_else(|()| detect_from_mp())
.unwrap_or_else(|()| default_apic())
}

pub fn eoi() {
local_apic_write(IA32_X2APIC_EOI, APIC_EOI_ACK);
}

pub fn init() {
// Detect CPUs and APICs.
let local_apic_physical_address = if env::is_uhyve() {
default_apic()
} else {
detect_from_acpi()
.or_else(|()| detect_from_mp())
.unwrap_or_else(|()| default_apic())
};
let local_apic_physical_address = apic_addr();

// Initialize x2APIC or xAPIC, depending on what's available.
if processor::supports_x2apic() {
Expand Down Expand Up @@ -729,7 +729,15 @@ pub fn init_x2apic() {
}

/// Initialize the required _start variables for the next CPU to be booted.
#[cfg(feature = "smp")]
pub fn init_next_processor_variables() {
use alloc::alloc::alloc;
use core::alloc::Layout;
use core::sync::atomic::Ordering;

use crate::arch::x86_64::kernel::CURRENT_STACK_ADDRESS;
use crate::config::KERNEL_STACK_SIZE;

// Allocate stack for the CPU and pass the addresses.
let layout = Layout::from_size_align(KERNEL_STACK_SIZE, BasePageSize::SIZE as usize).unwrap();
let stack = unsafe { alloc(layout) };
Expand Down
47 changes: 24 additions & 23 deletions src/arch/x86_64/kernel/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use x86_64::registers::control::{Cr0, Cr4};

pub(crate) use self::apic::{set_oneshot_timer, wakeup_core};
use crate::arch::x86_64::kernel::core_local::*;
use crate::env::{self, is_uhyve};
use crate::env;

#[cfg(feature = "acpi")]
pub mod acpi;
Expand Down Expand Up @@ -40,12 +40,12 @@ pub mod vga;

#[cfg(feature = "smp")]
pub fn get_possible_cpus() -> u32 {
use hermit_entry::boot_info::PlatformInfo;

match env::boot_info().platform_info {
PlatformInfo::Uhyve { num_cpus, .. } => u32::try_from(num_cpus.get()).unwrap(),
_ => apic::local_apic_id_count(),
#[cfg(feature = "uhyve")]
if let Some(num_cpus) = env::uhyve_num_cpus() {
return num_cpus.get().try_into().unwrap();
}

apic::local_apic_id_count()
}

#[cfg(feature = "smp")]
Expand All @@ -64,10 +64,8 @@ pub fn boot_processor_init() {
processor::detect_features();
processor::configure();

if cfg!(feature = "vga") && !is_uhyve() {
#[cfg(feature = "vga")]
vga::init();
}
#[cfg(feature = "vga")]
vga::init();

crate::mm::init();
crate::mm::print_information();
Expand All @@ -84,10 +82,8 @@ pub fn boot_processor_init() {
interrupts::install();
systemtime::init();

if !is_uhyve() {
#[cfg(feature = "acpi")]
acpi::init();
}
#[cfg(feature = "acpi")]
acpi::init();

#[cfg(feature = "pci")]
pci::init();
Expand All @@ -114,7 +110,8 @@ pub fn application_processor_init() {
}

fn finish_processor_init() {
if is_uhyve() {
#[cfg(feature = "uhyve")]
if env::is_uhyve() {
// uhyve does not use apic::detect_from_acpi and therefore does not know the number of processors and
// their APIC IDs in advance.
// Therefore, we have to add each booted processor into the CPU_LOCAL_APIC_IDS vector ourselves.
Expand All @@ -123,6 +120,7 @@ fn finish_processor_init() {

// uhyve also boots each processor into _start itself and does not use apic::boot_application_processors.
// Therefore, the current processor already needs to prepare the processor variables for a possible next processor.
#[cfg(feature = "smp")]
apic::init_next_processor_variables();
}
}
Expand All @@ -132,15 +130,18 @@ pub fn boot_next_processor() {
// to initialize the next processor.
let cpu_online = CPU_ONLINE.fetch_add(1, Ordering::Release);

if !is_uhyve() {
if cpu_online == 0 {
#[cfg(all(target_os = "none", feature = "smp"))]
apic::boot_application_processors();
}
#[cfg(feature = "uhyve")]
if env::is_uhyve() {
return;
}

if !cfg!(feature = "smp") {
apic::print_information();
}
if cpu_online == 0 {
#[cfg(all(target_os = "none", feature = "smp"))]
apic::boot_application_processors();
}

if !cfg!(feature = "smp") {
apic::print_information();
}
}

Expand Down
Loading
Loading