From 231ba8018c207598af67a8fa3b082067d9a8fac1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kr=C3=B6ning?= Date: Mon, 3 Aug 2026 18:00:40 +0200 Subject: [PATCH 1/4] fix(riscv64): only start next HART when built with SMP support This code needs further rework, but that is left for further PRs. --- src/arch/riscv64/kernel/mod.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/arch/riscv64/kernel/mod.rs b/src/arch/riscv64/kernel/mod.rs index e6356de222..52cbcf31ba 100644 --- a/src/arch/riscv64/kernel/mod.rs +++ b/src/arch/riscv64/kernel/mod.rs @@ -148,14 +148,19 @@ 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); + #[allow(clippy::needless_return)] #[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 = (crate::arch::start::hermit_entry::_start as *const ()).expose_provenance(); - sbi_rt::hart_start(next_hart_id as usize, start_addr, 0).unwrap(); + #[cfg(feature = "smp")] + { + //When running bare-metal/QEMU we use the firmware to start the next hart + let start_addr = + (crate::arch::start::hermit_entry::_start as *const ()).expose_provenance(); + sbi_rt::hart_start(next_hart_id as usize, start_addr, 0).unwrap(); + } } pub fn print_statistics() { From 2bb08515b426202002aa58e91eaed7d699cebbc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kr=C3=B6ning?= Date: Mon, 3 Aug 2026 16:38:19 +0200 Subject: [PATCH 2/4] fix(aarch64): don't use boot info in SMP start --- src/arch/aarch64/start/smp.rs | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/arch/aarch64/start/smp.rs b/src/arch/aarch64/start/smp.rs index 8ff69e03e8..c8582f4bd6 100644 --- a/src/arch/aarch64/start/smp.rs +++ b/src/arch/aarch64/start/smp.rs @@ -1,6 +1,8 @@ use core::ptr; use core::sync::atomic::AtomicPtr; +use aarch64_cpu::asm::barrier::{SY, dsb}; + use crate::kernel::CURRENT_STACK_ADDRESS; /* @@ -154,13 +156,13 @@ pub(crate) unsafe extern "C" fn smp_start() -> ! { "ldr x0, ={sctlr_el1}", "msr sctlr_el1, x0", - // initialize argument for pre_init + // initialize argument for `smp_start_rust()` "mov x0, xzr", "mrs x1, mpidr_el1", "and x1, x1, #0xff", // Jump to Rust code - "b {pre_init}", + "b {smp_start_rust}", mair_el1 = const mair(0x00, MT_DEVICE_nGnRnE) | mair(0x04, MT_DEVICE_nGnRE) | mair(0x0c, MT_DEVICE_GRE) | mair(0x44, MT_NORMAL_NC) | mair(0xff, MT_NORMAL), tcr_bits = const tcr_size(VA_BITS) | TCR_TG1_4K | TCR_FLAGS, @@ -168,6 +170,24 @@ pub(crate) unsafe extern "C" fn smp_start() -> ! { current_stack_address = sym CURRENT_STACK_ADDRESS, sctlr_el1 = const SCTLR_EL1, ttbr0 = sym TTBR0, - pre_init = sym crate::arch::start::hermit_entry::pre_init, + smp_start_rust = sym smp_start_rust, ) } + +unsafe extern "C" fn smp_start_rust() -> ! { + // set exception table + unsafe { + core::arch::asm!( + "adrp x4, vector_table", + "add x4, x4, #:lo12:vector_table", + "msr vbar_el1, x4", + out("x4") _, + options(nostack), + ); + } + + // Memory barrier + dsb(SY); + + crate::application_processor_main() +} From 5dea4e15b3b9a89b89ed944fd5802a4697421c91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kr=C3=B6ning?= Date: Mon, 3 Aug 2026 16:45:44 +0200 Subject: [PATCH 3/4] fix(riscv64): don't use boot info in SMP start --- src/arch/riscv64/kernel/mod.rs | 3 +-- src/arch/riscv64/start/mod.rs | 2 ++ src/arch/riscv64/start/smp.rs | 30 ++++++++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 src/arch/riscv64/start/smp.rs diff --git a/src/arch/riscv64/kernel/mod.rs b/src/arch/riscv64/kernel/mod.rs index 52cbcf31ba..bd2d8f1534 100644 --- a/src/arch/riscv64/kernel/mod.rs +++ b/src/arch/riscv64/kernel/mod.rs @@ -157,8 +157,7 @@ pub fn boot_next_processor() { #[cfg(feature = "smp")] { //When running bare-metal/QEMU we use the firmware to start the next hart - let start_addr = - (crate::arch::start::hermit_entry::_start as *const ()).expose_provenance(); + let start_addr = (crate::arch::start::smp::smp_start as *const ()).expose_provenance(); sbi_rt::hart_start(next_hart_id as usize, start_addr, 0).unwrap(); } } diff --git a/src/arch/riscv64/start/mod.rs b/src/arch/riscv64/start/mod.rs index c4658b83c1..9343da2b38 100644 --- a/src/arch/riscv64/start/mod.rs +++ b/src/arch/riscv64/start/mod.rs @@ -1 +1,3 @@ pub mod hermit_entry; +#[cfg(feature = "smp")] +pub mod smp; diff --git a/src/arch/riscv64/start/smp.rs b/src/arch/riscv64/start/smp.rs new file mode 100644 index 0000000000..c9be43b102 --- /dev/null +++ b/src/arch/riscv64/start/smp.rs @@ -0,0 +1,30 @@ +use core::arch::naked_asm; +use core::sync::atomic::Ordering; + +use crate::arch::riscv64::kernel::CURRENT_STACK_ADDRESS; +use crate::config::KERNEL_STACK_SIZE; +use crate::kernel::CURRENT_BOOT_ID; + +#[unsafe(naked)] +pub unsafe extern "C" fn smp_start(hart_id: usize) -> ! { + naked_asm!( + // Use stack pointer from `CURRENT_STACK_ADDRESS` if set + "ld t0, {current_stack_pointer}", + "beqz t0, 2f", + "li t1, {top_offset}", + "add t0, t0, t1", + "mv sp, t0", + "2:", + + "j {smp_start_rust}", + current_stack_pointer = sym CURRENT_STACK_ADDRESS, + top_offset = const KERNEL_STACK_SIZE, + smp_start_rust = sym smp_start_rust, + ) +} + +unsafe extern "C" fn smp_start_rust(hart_id: usize) -> ! { + CURRENT_BOOT_ID.store(hart_id as u32, Ordering::Relaxed); + + crate::application_processor_main(); +} From a90dc05ed399af41494536ea993d1662be6bc44d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kr=C3=B6ning?= Date: Sun, 2 Aug 2026 16:11:11 +0200 Subject: [PATCH 4/4] fix(x86_64): don't use boot info in SMP start --- src/arch/x86_64/kernel/apic.rs | 11 ++++++----- src/arch/x86_64/start/mod.rs | 2 ++ src/arch/x86_64/start/smp.rs | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 5 deletions(-) create mode 100644 src/arch/x86_64/start/smp.rs diff --git a/src/arch/x86_64/kernel/apic.rs b/src/arch/x86_64/kernel/apic.rs index 4234cce552..716e5e6121 100644 --- a/src/arch/x86_64/kernel/apic.rs +++ b/src/arch/x86_64/kernel/apic.rs @@ -728,7 +728,7 @@ pub fn init_x2apic() { } } -/// Initialize the required _start variables for the next CPU to be booted. +/// Initialize the required `smp::start` variables for the next CPU to be booted. #[cfg(feature = "smp")] pub fn init_next_processor_variables() { use alloc::alloc::alloc; @@ -751,9 +751,10 @@ pub fn init_next_processor_variables() { /// This is partly confirmed by #[cfg(all(target_os = "none", feature = "smp"))] pub fn boot_application_processors() { - use hermit_entry::boot_info::RawBootInfo; use x86_64::structures::paging::Translate; + use crate::arch::start::smp; + let smp_boot_code = include_bytes!(concat!(core::env!("OUT_DIR"), "/boot.bin")); // We shouldn't have any problems fitting the boot code into a single page, but let's better be sure. @@ -797,11 +798,11 @@ pub fn boot_application_processors() { // Set entry point debug!( "Set entry point for application processor to {:p}", - arch::start::hermit_entry::_start as *const () + smp::smp_start as *const () ); (SMP_BOOT_CODE_ADDRESS + SMP_BOOT_CODE_OFFSET_ENTRY) - .as_mut_ptr::, cpu_id: u32) -> !>() - .write_unaligned(arch::start::hermit_entry::_start); + .as_mut_ptr:: !>() + .write_unaligned(smp::smp_start); } // Now wake up each application processor. diff --git a/src/arch/x86_64/start/mod.rs b/src/arch/x86_64/start/mod.rs index c4658b83c1..9343da2b38 100644 --- a/src/arch/x86_64/start/mod.rs +++ b/src/arch/x86_64/start/mod.rs @@ -1 +1,3 @@ pub mod hermit_entry; +#[cfg(feature = "smp")] +pub mod smp; diff --git a/src/arch/x86_64/start/smp.rs b/src/arch/x86_64/start/smp.rs new file mode 100644 index 0000000000..6eef2ab189 --- /dev/null +++ b/src/arch/x86_64/start/smp.rs @@ -0,0 +1,33 @@ +use x86_64::registers::control::{Cr0, Cr0Flags}; + +use crate::arch::kernel::scheduler::TaskStacks; +use crate::config::KERNEL_STACK_SIZE; +use crate::kernel::CURRENT_STACK_ADDRESS; + +#[unsafe(naked)] +pub unsafe extern "C" fn smp_start() -> ! { + core::arch::naked_asm!( + // Overwrite RSP with `CURRENT_STACK_ADDRESS` + "mov rax, qword ptr [rip + {current_stack_address}@GOTPCREL]", + "mov rsp, qword ptr [rax]", + + // Add top stack offset + "add rsp, {stack_top_offset}", + + // Jump into Rust code + "jmp {smp_start_rust}", + + current_stack_address = sym CURRENT_STACK_ADDRESS, + stack_top_offset = const KERNEL_STACK_SIZE - TaskStacks::MARKER_SIZE, + smp_start_rust = sym smp_start_rust, + ) +} + +unsafe extern "C" fn smp_start_rust() -> ! { + // Enable caching + unsafe { + Cr0::update(|flags| flags.remove(Cr0Flags::CACHE_DISABLE | Cr0Flags::NOT_WRITE_THROUGH)); + } + + crate::application_processor_main(); +}