From 375760064b27596d89e3f047eaeb1530b33e9511 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kr=C3=B6ning?= Date: Tue, 23 Jun 2026 14:02:36 +0200 Subject: [PATCH 01/15] refactor(x86_64): don't import is_uhyve directly --- src/arch/x86_64/kernel/mod.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/arch/x86_64/kernel/mod.rs b/src/arch/x86_64/kernel/mod.rs index fc5bcc2484..ec2ae1b8b2 100644 --- a/src/arch/x86_64/kernel/mod.rs +++ b/src/arch/x86_64/kernel/mod.rs @@ -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; @@ -64,7 +64,7 @@ pub fn boot_processor_init() { processor::detect_features(); processor::configure(); - if cfg!(feature = "vga") && !is_uhyve() { + if cfg!(feature = "vga") && !env::is_uhyve() { #[cfg(feature = "vga")] vga::init(); } @@ -84,7 +84,7 @@ pub fn boot_processor_init() { interrupts::install(); systemtime::init(); - if !is_uhyve() { + if !env::is_uhyve() { #[cfg(feature = "acpi")] acpi::init(); } @@ -114,7 +114,7 @@ pub fn application_processor_init() { } fn finish_processor_init() { - if is_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. @@ -132,7 +132,7 @@ pub fn boot_next_processor() { // to initialize the next processor. let cpu_online = CPU_ONLINE.fetch_add(1, Ordering::Release); - if !is_uhyve() { + if !env::is_uhyve() { if cpu_online == 0 { #[cfg(all(target_os = "none", feature = "smp"))] apic::boot_application_processors(); From 381553f8124b861475be5e8fe4555d9d8807633c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kr=C3=B6ning?= Date: Mon, 6 Jul 2026 21:48:11 +0200 Subject: [PATCH 02/15] refactor(x86_64/acpi): move `is_uhyve()` check inside --- src/arch/x86_64/kernel/acpi.rs | 4 ++++ src/arch/x86_64/kernel/mod.rs | 6 ++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/arch/x86_64/kernel/acpi.rs b/src/arch/x86_64/kernel/acpi.rs index cfa47caa3e..5e0b4dc225 100644 --- a/src/arch/x86_64/kernel/acpi.rs +++ b/src/arch/x86_64/kernel/acpi.rs @@ -517,6 +517,10 @@ pub fn poweroff() { } pub fn init() { + 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"); diff --git a/src/arch/x86_64/kernel/mod.rs b/src/arch/x86_64/kernel/mod.rs index ec2ae1b8b2..84329b34af 100644 --- a/src/arch/x86_64/kernel/mod.rs +++ b/src/arch/x86_64/kernel/mod.rs @@ -84,10 +84,8 @@ pub fn boot_processor_init() { interrupts::install(); systemtime::init(); - if !env::is_uhyve() { - #[cfg(feature = "acpi")] - acpi::init(); - } + #[cfg(feature = "acpi")] + acpi::init(); #[cfg(feature = "pci")] pci::init(); From 5d9c623ccf7babc648625ce306fb3854d3f89179 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kr=C3=B6ning?= Date: Mon, 6 Jul 2026 21:51:41 +0200 Subject: [PATCH 03/15] refactor(x86_64/vga): move `is_uhyve()` check inside --- src/arch/x86_64/kernel/mod.rs | 6 ++---- src/arch/x86_64/kernel/vga.rs | 4 ++++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/arch/x86_64/kernel/mod.rs b/src/arch/x86_64/kernel/mod.rs index 84329b34af..d9aa39612c 100644 --- a/src/arch/x86_64/kernel/mod.rs +++ b/src/arch/x86_64/kernel/mod.rs @@ -64,10 +64,8 @@ pub fn boot_processor_init() { processor::detect_features(); processor::configure(); - if cfg!(feature = "vga") && !env::is_uhyve() { - #[cfg(feature = "vga")] - vga::init(); - } + #[cfg(feature = "vga")] + vga::init(); crate::mm::init(); crate::mm::print_information(); diff --git a/src/arch/x86_64/kernel/vga.rs b/src/arch/x86_64/kernel/vga.rs index ea5c0f7a89..2d0706bd64 100644 --- a/src/arch/x86_64/kernel/vga.rs +++ b/src/arch/x86_64/kernel/vga.rs @@ -133,6 +133,10 @@ impl VgaScreen { } pub fn init() { + if crate::env::is_uhyve() { + return; + } + VGA_SCREEN.lock().init(); } From dcc097d46fc53283e3d9024434c469fd757d1358 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kr=C3=B6ning?= Date: Mon, 6 Jul 2026 22:11:27 +0200 Subject: [PATCH 04/15] refactor(aarch64/processor): move `is_uhyve()` check inside --- src/arch/aarch64/kernel/mod.rs | 11 ++++------- src/arch/aarch64/kernel/processor.rs | 4 ++++ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/arch/aarch64/kernel/mod.rs b/src/arch/aarch64/kernel/mod.rs index a61f1bbc4c..f2277c3325 100644 --- a/src/arch/aarch64/kernel/mod.rs +++ b/src/arch/aarch64/kernel/mod.rs @@ -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); @@ -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() } @@ -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(); @@ -103,7 +100,7 @@ pub fn boot_next_processor() { let cpu_online = CPU_ONLINE.0.fetch_add(1, Ordering::Release); #[cfg(all(target_os = "none", feature = "smp"))] - if !env::is_uhyve() && get_possible_cpus() > 1 { + if !crate::env::is_uhyve() && get_possible_cpus() > 1 { use core::arch::asm; use core::hint::spin_loop; @@ -122,7 +119,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(); diff --git a/src/arch/aarch64/kernel/processor.rs b/src/arch/aarch64/kernel/processor.rs index 3a62f128a7..c970802d6a 100644 --- a/src/arch/aarch64/kernel/processor.rs +++ b/src/arch/aarch64/kernel/processor.rs @@ -262,6 +262,10 @@ pub fn supports_2mib_pages() -> bool { } pub fn configure() { + 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. From e40773a15b705c10d9c5473bedc5d0bcc50c711a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kr=C3=B6ning?= Date: Wed, 1 Jul 2026 17:59:15 +0200 Subject: [PATCH 05/15] refactor(env): extract `uhyve_boot_time()` --- src/arch/aarch64/kernel/systemtime.rs | 88 ++++++++++++--------------- src/arch/x86_64/kernel/systemtime.rs | 25 ++++---- src/env.rs | 9 +++ 3 files changed, 63 insertions(+), 59 deletions(-) diff --git a/src/arch/aarch64/kernel/systemtime.rs b/src/arch/aarch64/kernel/systemtime.rs index 8202bff934..62f5589a81 100644 --- a/src/arch/aarch64/kernel/systemtime.rs +++ b/src/arch/aarch64/kernel/systemtime.rs @@ -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; @@ -45,55 +44,48 @@ 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::( - 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 { + 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::( + 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. diff --git a/src/arch/x86_64/kernel/systemtime.rs b/src/arch/x86_64/kernel/systemtime.rs index cea2329330..1a0770f030 100644 --- a/src/arch/x86_64/kernel/systemtime.rs +++ b/src/arch/x86_64/kernel/systemtime.rs @@ -1,6 +1,5 @@ use core::hint::spin_loop; -use hermit_entry::boot_info::PlatformInfo; use hermit_sync::{OnceCell, without_interrupts}; use time::OffsetDateTime; use x86_64::instructions::port::Port; @@ -175,17 +174,21 @@ impl Rtc { static BOOT_TIME: OnceCell = OnceCell::new(); +fn boot_time() -> OffsetDateTime { + if let Some(boot_time) = env::uhyve_boot_time() { + return boot_time; + } + + // Get the current time in microseconds since the epoch (1970-01-01) from the x86 RTC. + // Subtract the timer ticks to get the actual time when Hermit was booted. + let current_time = without_interrupts(|| Rtc::new().get_microseconds_since_epoch()); + let boot_micros = current_time - processor::get_timer_ticks(); + let boot_nanos = i128::from(boot_micros) * 1000; + OffsetDateTime::from_unix_timestamp_nanos(boot_nanos).unwrap() +} + pub fn init() { - let boot_time = match env::boot_info().platform_info { - PlatformInfo::Uhyve { boot_time, .. } => boot_time, - _ => { - // Get the current time in microseconds since the epoch (1970-01-01) from the x86 RTC. - // Subtract the timer ticks to get the actual time when Hermit was booted. - let current_time = without_interrupts(|| Rtc::new().get_microseconds_since_epoch()); - let boot_time = current_time - processor::get_timer_ticks(); - OffsetDateTime::from_unix_timestamp_nanos(i128::from(boot_time) * 1000).unwrap() - } - }; + let boot_time = boot_time(); info!("Hermit booted on {boot_time}"); let micros = u64::try_from(boot_time.unix_timestamp_nanos() / 1000).unwrap(); diff --git a/src/env.rs b/src/env.rs index f016f27edb..d984328bef 100644 --- a/src/env.rs +++ b/src/env.rs @@ -13,6 +13,7 @@ use hashbrown::hash_map::Iter; use hermit_entry::boot_info::{BootInfo, PlatformInfo, RawBootInfo}; use hermit_sync::OnceCell; use memory_addresses::PhysAddr; +use time::OffsetDateTime; static BOOT_INFO: OnceCell = OnceCell::new(); @@ -48,6 +49,14 @@ pub fn is_uhyve() -> bool { matches!(boot_info().platform_info, PlatformInfo::Uhyve { .. }) } +#[cfg_attr(target_arch = "riscv64", expect(dead_code))] +pub fn uhyve_boot_time() -> Option { + match boot_info().platform_info { + PlatformInfo::Uhyve { boot_time, .. } => Some(boot_time), + _ => None, + } +} + pub fn is_uefi() -> bool { fdt().is_some_and(|fdt| fdt.root().compatible().first() == "hermit,uefi") } From 4f36d049cab4720f1e40b8114c284597a5d9d9cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kr=C3=B6ning?= Date: Wed, 1 Jul 2026 18:13:37 +0200 Subject: [PATCH 06/15] refactor(env): extract `uhyve_num_cpus()` --- src/arch/x86_64/kernel/mod.rs | 9 ++++----- src/env.rs | 13 +++++++++++++ 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/arch/x86_64/kernel/mod.rs b/src/arch/x86_64/kernel/mod.rs index d9aa39612c..5e11728b4b 100644 --- a/src/arch/x86_64/kernel/mod.rs +++ b/src/arch/x86_64/kernel/mod.rs @@ -40,12 +40,11 @@ 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(), + if let Some(num_cpus) = env::uhyve_num_cpus() { + return num_cpus.get().try_into().unwrap(); } + + apic::local_apic_id_count() } #[cfg(feature = "smp")] diff --git a/src/env.rs b/src/env.rs index d984328bef..f707829e53 100644 --- a/src/env.rs +++ b/src/env.rs @@ -57,6 +57,19 @@ pub fn uhyve_boot_time() -> Option { } } +#[cfg_attr( + any(not(target_arch = "x86_64"), not(feature = "smp")), + expect(dead_code) +)] +pub fn uhyve_num_cpus() -> Option> { + match boot_info().platform_info { + PlatformInfo::Uhyve { num_cpus, .. } => { + Some(NonZero::new(num_cpus.get() as usize).unwrap()) + } + _ => None, + } +} + pub fn is_uefi() -> bool { fdt().is_some_and(|fdt| fdt.root().compatible().first() == "hermit,uefi") } From f774b5f534faf70f5f202f3e74cd4461b28686da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kr=C3=B6ning?= Date: Wed, 1 Jul 2026 18:28:55 +0200 Subject: [PATCH 07/15] refactor(env): extract `uhyve_cpu_freq()` --- src/arch/x86_64/kernel/processor.rs | 19 +++++-------------- src/env.rs | 8 ++++++++ 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/arch/x86_64/kernel/processor.rs b/src/arch/x86_64/kernel/processor.rs index 0915d6365c..fc5d06def9 100644 --- a/src/arch/x86_64/kernel/processor.rs +++ b/src/arch/x86_64/kernel/processor.rs @@ -8,10 +8,9 @@ use core::arch::x86_64::{ }; use core::fmt; use core::hint::spin_loop; -use core::num::{NonZero, NonZeroU32}; +use core::num::NonZero; use core::sync::atomic::{AtomicU64, Ordering}; -use hermit_entry::boot_info::PlatformInfo; use hermit_sync::Lazy; use raw_cpuid::*; use x86_64::instructions::interrupts::int3; @@ -369,18 +368,10 @@ impl CpuFrequency { } fn detect_from_hypervisor(&mut self) -> Result<(), ()> { - fn detect_from_uhyve() -> Result { - match env::boot_info().platform_info { - PlatformInfo::Uhyve { cpu_freq, .. } => Ok(u16::try_from( - cpu_freq.map(NonZeroU32::get).unwrap_or_default() / 1000, - ) - .unwrap()), - _ => Err(()), - } - } - // future implementations could add support for different hypervisors - // by adding or_else here - self.set_detected_cpu_frequency(detect_from_uhyve()?, CpuFrequencySources::Hypervisor) + let cpu_freq = env::uhyve_cpu_freq().ok_or(())?.get(); + let mhz = cpu_freq / 1000; + + self.set_detected_cpu_frequency(mhz.try_into().unwrap(), CpuFrequencySources::Hypervisor) } extern "x86-interrupt" fn measure_frequency_timer_handler( diff --git a/src/env.rs b/src/env.rs index f707829e53..ba2e1a4b2d 100644 --- a/src/env.rs +++ b/src/env.rs @@ -70,6 +70,14 @@ pub fn uhyve_num_cpus() -> Option> { } } +#[cfg_attr(not(target_arch = "x86_64"), expect(dead_code))] +pub fn uhyve_cpu_freq() -> Option> { + match boot_info().platform_info { + PlatformInfo::Uhyve { cpu_freq, .. } => Some(NonZero::new(cpu_freq?.get()).unwrap()), + _ => None, + } +} + pub fn is_uefi() -> bool { fdt().is_some_and(|fdt| fdt.root().compatible().first() == "hermit,uefi") } From d6b57755d5cd85d2f8113382d866f554deca0e3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kr=C3=B6ning?= Date: Mon, 6 Jul 2026 17:34:46 +0200 Subject: [PATCH 08/15] fix: don't print Uhyve and common system --- src/lib.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 965d925019..25745c5744 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -175,12 +175,6 @@ extern "C" fn initd(_arg: usize) { fn main(argc: i32, argv: *const *const u8, env: *const *const u8); } - if env::is_uhyve() { - info!("Hermit is running on uhyve!"); - } else { - info!("Hermit is running on common system!"); - } - // Initialize Drivers drivers::init(); // The filesystem needs to be initialized before network to allow writing packet captures to a file. From 36931c3e7715dabe206b6cf9169ef92408eeb36d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kr=C3=B6ning?= Date: Mon, 6 Jul 2026 17:36:10 +0200 Subject: [PATCH 09/15] fix(x86_64/processor): dead_code --- src/arch/x86_64/kernel/processor.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/arch/x86_64/kernel/processor.rs b/src/arch/x86_64/kernel/processor.rs index fc5d06def9..e18fd39494 100644 --- a/src/arch/x86_64/kernel/processor.rs +++ b/src/arch/x86_64/kernel/processor.rs @@ -659,10 +659,6 @@ impl fmt::Display for CpuFeaturePrinter { } } -pub(crate) fn run_on_hypervisor() -> bool { - env::is_uhyve() || FEATURES.run_on_hypervisor -} - #[derive(Debug)] struct CpuSpeedStep { eist_available: bool, From 50fa0ac0fc9c7307f3ee60199a8d8b4740b0646a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kr=C3=B6ning?= Date: Mon, 6 Jul 2026 21:45:39 +0200 Subject: [PATCH 10/15] fix(x86_64/processor): dead_code When we are on Uhyve, we are trying `detect_from_hypervisor()` earlier anyway. --- src/arch/x86_64/kernel/processor.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/arch/x86_64/kernel/processor.rs b/src/arch/x86_64/kernel/processor.rs index e18fd39494..08a09cd47b 100644 --- a/src/arch/x86_64/kernel/processor.rs +++ b/src/arch/x86_64/kernel/processor.rs @@ -392,11 +392,6 @@ impl CpuFrequency { fn measure_frequency(&mut self) -> Result<(), ()> { use crate::arch::x86_64::kernel::interrupts::IDT; - // The PIC is not initialized for uhyve, so we cannot measure anything. - if env::is_uhyve() { - return Err(()); - } - // Measure the CPU frequency by counting 3 ticks of a 100Hz timer. let tick_count = 3; let measurement_frequency = 100; From 86ffb7f353620ff5159386daae3066d889c38012 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kr=C3=B6ning?= Date: Mon, 6 Jul 2026 22:26:20 +0200 Subject: [PATCH 11/15] fix(x86_64/apic): feature-gate `init_next_processor_variables()` --- src/arch/x86_64/kernel/apic.rs | 13 ++++++++----- src/arch/x86_64/kernel/mod.rs | 1 + 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/arch/x86_64/kernel/apic.rs b/src/arch/x86_64/kernel/apic.rs index b0b07fa9f2..ff7aa51efa 100644 --- a/src/arch/x86_64/kernel/apic.rs +++ b/src/arch/x86_64/kernel/apic.rs @@ -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; @@ -21,7 +18,6 @@ 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; @@ -29,7 +25,6 @@ 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}; @@ -729,7 +724,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) }; diff --git a/src/arch/x86_64/kernel/mod.rs b/src/arch/x86_64/kernel/mod.rs index 5e11728b4b..a4845ac319 100644 --- a/src/arch/x86_64/kernel/mod.rs +++ b/src/arch/x86_64/kernel/mod.rs @@ -118,6 +118,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(); } } From 33f456ffe8c148e48c2df29f7c938f22a4535817 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kr=C3=B6ning?= Date: Thu, 2 Jul 2026 10:02:26 +0200 Subject: [PATCH 12/15] fix(env): feature-gate `uhyve_cpu_freq()` --- src/arch/x86_64/kernel/processor.rs | 15 ++++++++++++--- src/env.rs | 1 + 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/arch/x86_64/kernel/processor.rs b/src/arch/x86_64/kernel/processor.rs index 08a09cd47b..460c6713d8 100644 --- a/src/arch/x86_64/kernel/processor.rs +++ b/src/arch/x86_64/kernel/processor.rs @@ -368,10 +368,19 @@ impl CpuFrequency { } fn detect_from_hypervisor(&mut self) -> Result<(), ()> { - let cpu_freq = env::uhyve_cpu_freq().ok_or(())?.get(); - let mhz = cpu_freq / 1000; + #[cfg(feature = "uhyve")] + { + let cpu_freq = env::uhyve_cpu_freq().ok_or(())?.get(); + let mhz = cpu_freq / 1000; - self.set_detected_cpu_frequency(mhz.try_into().unwrap(), CpuFrequencySources::Hypervisor) + self.set_detected_cpu_frequency( + mhz.try_into().unwrap(), + CpuFrequencySources::Hypervisor, + ) + } + + #[cfg(not(feature = "uhyve"))] + Err(()) } extern "x86-interrupt" fn measure_frequency_timer_handler( diff --git a/src/env.rs b/src/env.rs index ba2e1a4b2d..cd571f942d 100644 --- a/src/env.rs +++ b/src/env.rs @@ -71,6 +71,7 @@ pub fn uhyve_num_cpus() -> Option> { } #[cfg_attr(not(target_arch = "x86_64"), expect(dead_code))] +#[cfg(feature = "uhyve")] pub fn uhyve_cpu_freq() -> Option> { match boot_info().platform_info { PlatformInfo::Uhyve { cpu_freq, .. } => Some(NonZero::new(cpu_freq?.get()).unwrap()), From 4ee0d3d96684b13cf0634244069648b620ce9e59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kr=C3=B6ning?= Date: Thu, 2 Jul 2026 10:06:13 +0200 Subject: [PATCH 13/15] fix(env): feature-gate `uhyve_num_cpus()` --- src/arch/x86_64/kernel/mod.rs | 1 + src/env.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/arch/x86_64/kernel/mod.rs b/src/arch/x86_64/kernel/mod.rs index a4845ac319..bd45d17359 100644 --- a/src/arch/x86_64/kernel/mod.rs +++ b/src/arch/x86_64/kernel/mod.rs @@ -40,6 +40,7 @@ pub mod vga; #[cfg(feature = "smp")] pub fn get_possible_cpus() -> u32 { + #[cfg(feature = "uhyve")] if let Some(num_cpus) = env::uhyve_num_cpus() { return num_cpus.get().try_into().unwrap(); } diff --git a/src/env.rs b/src/env.rs index cd571f942d..6a8cfc439e 100644 --- a/src/env.rs +++ b/src/env.rs @@ -61,6 +61,7 @@ pub fn uhyve_boot_time() -> Option { any(not(target_arch = "x86_64"), not(feature = "smp")), expect(dead_code) )] +#[cfg(feature = "uhyve")] pub fn uhyve_num_cpus() -> Option> { match boot_info().platform_info { PlatformInfo::Uhyve { num_cpus, .. } => { From 6573f518313b5a0a5639d9afb902633230355fcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kr=C3=B6ning?= Date: Thu, 2 Jul 2026 10:07:41 +0200 Subject: [PATCH 14/15] fix(env): feature-gate `uhyve_boot_time()` --- src/arch/aarch64/kernel/systemtime.rs | 1 + src/arch/x86_64/kernel/systemtime.rs | 4 ++-- src/env.rs | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/arch/aarch64/kernel/systemtime.rs b/src/arch/aarch64/kernel/systemtime.rs index 62f5589a81..4385b468ac 100644 --- a/src/arch/aarch64/kernel/systemtime.rs +++ b/src/arch/aarch64/kernel/systemtime.rs @@ -45,6 +45,7 @@ fn rtc_read(off: usize) -> u32 { } fn boot_time() -> OffsetDateTime { + #[cfg(feature = "uhyve")] if let Some(boot_time) = env::uhyve_boot_time() { return boot_time; } diff --git a/src/arch/x86_64/kernel/systemtime.rs b/src/arch/x86_64/kernel/systemtime.rs index 1a0770f030..43531e0f4d 100644 --- a/src/arch/x86_64/kernel/systemtime.rs +++ b/src/arch/x86_64/kernel/systemtime.rs @@ -5,7 +5,6 @@ use time::OffsetDateTime; use x86_64::instructions::port::Port; use crate::arch::x86_64::kernel::processor; -use crate::env; const CMOS_COMMAND: Port = Port::new(0x70); const CMOS_DATA: Port = Port::new(0x71); @@ -175,7 +174,8 @@ impl Rtc { static BOOT_TIME: OnceCell = OnceCell::new(); fn boot_time() -> OffsetDateTime { - if let Some(boot_time) = env::uhyve_boot_time() { + #[cfg(feature = "uhyve")] + if let Some(boot_time) = crate::env::uhyve_boot_time() { return boot_time; } diff --git a/src/env.rs b/src/env.rs index 6a8cfc439e..a55f26de7b 100644 --- a/src/env.rs +++ b/src/env.rs @@ -13,7 +13,6 @@ use hashbrown::hash_map::Iter; use hermit_entry::boot_info::{BootInfo, PlatformInfo, RawBootInfo}; use hermit_sync::OnceCell; use memory_addresses::PhysAddr; -use time::OffsetDateTime; static BOOT_INFO: OnceCell = OnceCell::new(); @@ -50,7 +49,8 @@ pub fn is_uhyve() -> bool { } #[cfg_attr(target_arch = "riscv64", expect(dead_code))] -pub fn uhyve_boot_time() -> Option { +#[cfg(feature = "uhyve")] +pub fn uhyve_boot_time() -> Option { match boot_info().platform_info { PlatformInfo::Uhyve { boot_time, .. } => Some(boot_time), _ => None, From cda4266edf4d5d86a976682b7c5fdd0878dfbd96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kr=C3=B6ning?= Date: Mon, 6 Jul 2026 17:47:16 +0200 Subject: [PATCH 15/15] fix(env): feature-gate `is_uhyve()` --- src/arch/aarch64/kernel/mod.rs | 8 +++++++- src/arch/aarch64/kernel/processor.rs | 1 + src/arch/riscv64/kernel/mod.rs | 11 +++++++---- src/arch/x86_64/kernel/acpi.rs | 1 + src/arch/x86_64/kernel/apic.rs | 19 ++++++++++++------- src/arch/x86_64/kernel/mod.rs | 20 ++++++++++++-------- src/arch/x86_64/kernel/vga.rs | 1 + src/env.rs | 11 ++++++++++- 8 files changed, 51 insertions(+), 21 deletions(-) diff --git a/src/arch/aarch64/kernel/mod.rs b/src/arch/aarch64/kernel/mod.rs index f2277c3325..cb9587b0c8 100644 --- a/src/arch/aarch64/kernel/mod.rs +++ b/src/arch/aarch64/kernel/mod.rs @@ -99,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 !crate::env::is_uhyve() && get_possible_cpus() > 1 { + if get_possible_cpus() > 1 { use core::arch::asm; use core::hint::spin_loop; diff --git a/src/arch/aarch64/kernel/processor.rs b/src/arch/aarch64/kernel/processor.rs index c970802d6a..c27034b922 100644 --- a/src/arch/aarch64/kernel/processor.rs +++ b/src/arch/aarch64/kernel/processor.rs @@ -262,6 +262,7 @@ pub fn supports_2mib_pages() -> bool { } pub fn configure() { + #[cfg(feature = "uhyve")] if env::is_uhyve() { return; } diff --git a/src/arch/riscv64/kernel/mod.rs b/src/arch/riscv64/kernel/mod.rs index a24a0606b4..de549e7aeb 100644 --- a/src/arch/riscv64/kernel/mod.rs +++ b/src/arch/riscv64/kernel/mod.rs @@ -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() { diff --git a/src/arch/x86_64/kernel/acpi.rs b/src/arch/x86_64/kernel/acpi.rs index 5e0b4dc225..e4aa03cf83 100644 --- a/src/arch/x86_64/kernel/acpi.rs +++ b/src/arch/x86_64/kernel/acpi.rs @@ -517,6 +517,7 @@ pub fn poweroff() { } pub fn init() { + #[cfg(feature = "uhyve")] if env::is_uhyve() { return; } diff --git a/src/arch/x86_64/kernel/apic.rs b/src/arch/x86_64/kernel/apic.rs index ff7aa51efa..6695a69b30 100644 --- a/src/arch/x86_64/kernel/apic.rs +++ b/src/arch/x86_64/kernel/apic.rs @@ -506,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() { diff --git a/src/arch/x86_64/kernel/mod.rs b/src/arch/x86_64/kernel/mod.rs index bd45d17359..e0696d93a6 100644 --- a/src/arch/x86_64/kernel/mod.rs +++ b/src/arch/x86_64/kernel/mod.rs @@ -110,6 +110,7 @@ pub fn application_processor_init() { } fn finish_processor_init() { + #[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. @@ -129,15 +130,18 @@ pub fn boot_next_processor() { // to initialize the next processor. let cpu_online = CPU_ONLINE.fetch_add(1, Ordering::Release); - if !env::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(); } } diff --git a/src/arch/x86_64/kernel/vga.rs b/src/arch/x86_64/kernel/vga.rs index 2d0706bd64..7f763ccc8c 100644 --- a/src/arch/x86_64/kernel/vga.rs +++ b/src/arch/x86_64/kernel/vga.rs @@ -133,6 +133,7 @@ impl VgaScreen { } pub fn init() { + #[cfg(feature = "uhyve")] if crate::env::is_uhyve() { return; } diff --git a/src/env.rs b/src/env.rs index a55f26de7b..17cd879576 100644 --- a/src/env.rs +++ b/src/env.rs @@ -10,7 +10,7 @@ use ahash::RandomState; use fdt::Fdt; use hashbrown::HashMap; use hashbrown::hash_map::Iter; -use hermit_entry::boot_info::{BootInfo, PlatformInfo, RawBootInfo}; +use hermit_entry::boot_info::{BootInfo, RawBootInfo}; use hermit_sync::OnceCell; use memory_addresses::PhysAddr; @@ -44,13 +44,18 @@ struct Cli { } /// Whether Hermit is running under the "uhyve" hypervisor. +#[cfg(feature = "uhyve")] pub fn is_uhyve() -> bool { + use hermit_entry::boot_info::PlatformInfo; + matches!(boot_info().platform_info, PlatformInfo::Uhyve { .. }) } #[cfg_attr(target_arch = "riscv64", expect(dead_code))] #[cfg(feature = "uhyve")] pub fn uhyve_boot_time() -> Option { + use hermit_entry::boot_info::PlatformInfo; + match boot_info().platform_info { PlatformInfo::Uhyve { boot_time, .. } => Some(boot_time), _ => None, @@ -63,6 +68,8 @@ pub fn uhyve_boot_time() -> Option { )] #[cfg(feature = "uhyve")] pub fn uhyve_num_cpus() -> Option> { + use hermit_entry::boot_info::PlatformInfo; + match boot_info().platform_info { PlatformInfo::Uhyve { num_cpus, .. } => { Some(NonZero::new(num_cpus.get() as usize).unwrap()) @@ -74,6 +81,8 @@ pub fn uhyve_num_cpus() -> Option> { #[cfg_attr(not(target_arch = "x86_64"), expect(dead_code))] #[cfg(feature = "uhyve")] pub fn uhyve_cpu_freq() -> Option> { + use hermit_entry::boot_info::PlatformInfo; + match boot_info().platform_info { PlatformInfo::Uhyve { cpu_freq, .. } => Some(NonZero::new(cpu_freq?.get()).unwrap()), _ => None,