From 4ca882768a94a6b124543ca16a79c09652985d5e Mon Sep 17 00:00:00 2001 From: Anlai Lu Date: Wed, 2 Sep 2026 22:02:29 +0800 Subject: [PATCH 1/8] feat(aarch64): cache per-CPU slot pointer in TPIDR_EL2 --- src/arch/aarch64/cpu.rs | 30 ++++++++++++++++++++++-------- src/cpu_data.rs | 28 +++++++++++++--------------- 2 files changed, 35 insertions(+), 23 deletions(-) diff --git a/src/arch/aarch64/cpu.rs b/src/arch/aarch64/cpu.rs index 8c3a1c81f..ce5141b11 100644 --- a/src/arch/aarch64/cpu.rs +++ b/src/arch/aarch64/cpu.rs @@ -14,7 +14,10 @@ // Authors: // use crate::{ - arch::{mm::new_s2_memory_set, sysreg::write_sysreg}, + arch::{ + mm::new_s2_memory_set, + sysreg::{read_sysreg, write_sysreg}, + }, consts::{MAX_CPU_NUM, PAGE_SIZE, PER_CPU_ARRAY_PTR, PER_CPU_SIZE}, cpu_data::{this_cpu_data, VcpuState}, memory::{ @@ -24,9 +27,7 @@ use crate::{ platform::BOARD_MPIDR_MAPPINGS, zone::find_zone, }; -use aarch64_cpu::registers::{ - Readable, Writeable, ELR_EL2, HCR_EL2, MPIDR_EL1, SCTLR_EL1, SPSR_EL2, VTCR_EL2, -}; +use aarch64_cpu::registers::{Writeable, ELR_EL2, HCR_EL2, SCTLR_EL1, SPSR_EL2, VTCR_EL2}; use core::ptr::addr_of; use super::{ @@ -263,12 +264,25 @@ pub fn cpuid_to_mpidr_affinity(cpuid: u64) -> (u64, u64, u64, u64) { } pub fn this_cpu_id() -> usize { - mpidr_to_cpuid(MPIDR_EL1.get()) as _ + // TPIDR_EL2 caches the PerCpu slot base (written once per CPU in + // PerCpu::new); the id sits at slot offset 0, so this is a register read + // plus one load - no MPIDR_EL1 read and no BOARD_MPIDR_MAPPINGS scan. + this_cpu_data().id +} + +/// Cache the PerCpu slot base of the current CPU in TPIDR_EL2. +/// +/// TPIDR_EL2 is EL2-private and hvisor never lets a guest touch EL2 state, so +/// the value survives VM exits without any save/restore. (EL0/EL1 TPIDR_* are +/// only ever zeroed for a fresh guest in `reset_vm_regs`.) +pub fn set_this_cpu_pointer(slot_base: usize) { + write_sysreg!(TPIDR_EL2, slot_base as u64); } -pub fn store_cpu_pointer_to_reg(_pointer: usize) { - // println!("aarch64 doesn't support store cpu pointer to reg, pointer: {:#x}", pointer); - return; +/// PerCpu slot base of the current CPU, cached in TPIDR_EL2 by +/// `set_this_cpu_pointer` at `PerCpu::new` time. +pub fn this_cpu_pointer() -> usize { + read_sysreg!(TPIDR_EL2) as usize } pub fn get_target_cpu(_irq: usize, zone_id: usize) -> usize { diff --git a/src/cpu_data.rs b/src/cpu_data.rs index fc1519191..89c6417a6 100644 --- a/src/cpu_data.rs +++ b/src/cpu_data.rs @@ -16,7 +16,7 @@ use alloc::sync::Arc; use spin::Mutex; -use crate::arch::cpu::{store_cpu_pointer_to_reg, this_cpu_id, ArchCpu}; +use crate::arch::cpu::{set_this_cpu_pointer, this_cpu_id, this_cpu_pointer, ArchCpu}; use crate::consts::{INVALID_ADDRESS, PER_CPU_ARRAY_PTR, PER_CPU_SIZE}; use crate::memory::addr::VirtAddr; use crate::zone::Zone; @@ -110,6 +110,10 @@ pub struct PerCpu { pub zone: Option>, pub ctrl_lock: Mutex<()>, pub boot_cpu: bool, + /// Slot base address of this PerCpu. Written once by `PerCpu::new`; x86_64 + /// materializes it here because gs-segment accesses need the pointer in + /// memory, other architectures ignore it and read the register cache. + pub self_ptr: usize, // percpu stack } @@ -128,20 +132,13 @@ impl PerCpu { zone: None, ctrl_lock: Mutex::new(()), boot_cpu: false, + self_ptr: ret as usize, }) }; - unsafe { - let pointer = &ret.as_mut().unwrap().arch_cpu as *const _ as usize; - store_cpu_pointer_to_reg(pointer); - } - // #[cfg(target_arch = "riscv64")] - // { - // use crate::arch::csr::{write_csr, CSR_SSCRATCH}; - // write_csr!( - // CSR_SSCRATCH, - // &ret.as_mut().unwrap().arch_cpu as *const _ as usize - // ); //arch cpu pointer - // } + // Each CPU caches its own PerCpu slot base in the architecture register + // backing this_cpu_pointer()/this_cpu_id(). All later per-CPU accesses + // on this core read that cache instead of re-deriving the slot address. + set_this_cpu_pointer(ret as usize); unsafe { ret.as_mut().unwrap() } } @@ -171,8 +168,9 @@ pub fn get_cpu_data<'a>(cpu_id: usize) -> &'a mut PerCpu { } pub fn this_cpu_data<'a>() -> &'a mut PerCpu { - // Note: this_cpu_id() should return logical cpu_id 0..BOARD_NCPUS - get_cpu_data(this_cpu_id()) + // Slot base is cached per CPU in an architecture register at PerCpu::new + // time, so this is a 1-2 instruction read with no CPU-id lookup involved. + unsafe { &mut *(this_cpu_pointer() as *mut PerCpu) } } #[allow(unused)] From bdc3e735bb8996e60fd75a7d94f24ffca90b9a03 Mon Sep 17 00:00:00 2001 From: Anlai Lu Date: Wed, 2 Sep 2026 22:04:49 +0800 Subject: [PATCH 2/8] feat(x86_64): cache per-CPU slot pointer in IA32_GS_BASE --- src/arch/x86_64/cpu.rs | 55 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 49 insertions(+), 6 deletions(-) diff --git a/src/arch/x86_64/cpu.rs b/src/arch/x86_64/cpu.rs index 5741dce7e..77aa22572 100644 --- a/src/arch/x86_64/cpu.rs +++ b/src/arch/x86_64/cpu.rs @@ -30,7 +30,7 @@ use crate::{ vmx::*, }, consts::{self, core_end, PER_CPU_SIZE}, - cpu_data::{this_cpu_data, this_zone, VcpuState}, + cpu_data::{this_cpu_data, this_zone, PerCpu, VcpuState}, device::iommu, device::irqchip::pic::{check_pending_vectors, clear_vectors, ioapic, lapic::VirtLocalApic}, error::{HvError, HvResult}, @@ -188,7 +188,11 @@ pub struct ArchCpu { impl ArchCpu { pub fn new(cpuid: usize) -> Self { - let cpuid = this_cpu_id(); + // The boot entry hands the raw APIC id in; translate it to the logical + // id here. This keeps ArchCpu::new free of this_cpu_id(), whose gs:[0] + // read requires GS_BASE to be cached first (set_this_cpu_pointer runs + // later in PerCpu::new) - this is the last pre-cache call site. + let cpuid = crate::arch::acpi::get_cpu_id(cpuid); Self { guest_regs: GeneralRegisters::default(), host_stack_top: 0, @@ -565,6 +569,11 @@ impl ArchCpu { VmcsHost16::FS_SELECTOR.write(x86::segmentation::fs().bits())?; VmcsHost16::GS_SELECTOR.write(x86::segmentation::gs().bits())?; VmcsHostNW::FS_BASE.write(Msr::IA32_FS_BASE.read() as _)?; + // Timing note: set_this_cpu_pointer() (PerCpu::new) has already cached + // this CPU's slot base in IA32_GS_BASE by the time setup_vmcs_host() + // runs (run/idle happen after PerCpu::new). The hardware reloads this + // snapshot on every VM exit, which keeps gs-relative accesses in host + // mode pointing at the right PerCpu slot at all times. VmcsHostNW::GS_BASE.write(Msr::IA32_GS_BASE.read() as _)?; let tr = unsafe { x86::task::tr() }; @@ -633,7 +642,19 @@ impl ArchCpu { } pub fn this_cpu_id() -> usize { - crate::arch::acpi::get_cpu_id(this_apic_id()) + // IA32_GS_BASE caches the PerCpu slot base (set once per CPU by + // set_this_cpu_pointer in PerCpu::new); the id sits at slot offset 0, so + // this is a single gs-relative load - no serializing CPUID leaf-1 and no + // ACPI lookup. Deliberately no `nomem` option: the asm does read gs:[0]. + let id: usize; + unsafe { + asm!( + "mov {}, qword ptr gs:[0]", + out(reg) id, + options(nostack, preserves_flags) + ); + } + id } pub fn this_apic_id() -> usize { @@ -684,9 +705,31 @@ impl Debug for ArchCpu { } } -pub fn store_cpu_pointer_to_reg(pointer: usize) { - // println!("x86_64 doesn't support store cpu pointer to reg, pointer: {:#x}", pointer); - return; +/// Cache the PerCpu slot base of the current CPU in the IA32_GS_BASE MSR. +/// +/// setup_vmcs_host snapshots the MSR into the VMCS host-state field (0x6C08) +/// before every VM launch, so the hardware reloads GS_BASE on each VM exit; +/// the guest GS_BASE is a separate VMCS guest-state field (0x6810) whose +/// semantics and MSR interception policy are unchanged. +pub fn set_this_cpu_pointer(slot_base: usize) { + unsafe { Msr::IA32_GS_BASE.write(slot_base as u64) } +} + +/// PerCpu slot base of the current CPU. GS_BASE itself holds the base; the +/// slot's `self_ptr` (written by PerCpu::new) is materialized in memory so a +/// gs-relative load can recover it without a slow MSR read. +#[inline(always)] +pub fn this_cpu_pointer() -> usize { + let ptr: usize; + unsafe { + asm!( + "mov {}, qword ptr gs:[{}]", + out(reg) ptr, + const core::mem::offset_of!(PerCpu, self_ptr), + options(nostack, preserves_flags) + ); + } + ptr } pub fn get_target_cpu(irq: usize, zone_id: usize) -> usize { From ba468dcd3d1787c1cb8e64097b93b33ad2a961c3 Mon Sep 17 00:00:00 2001 From: Anlai Lu Date: Wed, 2 Sep 2026 22:05:46 +0800 Subject: [PATCH 3/8] feat(loongarch64): cache per-CPU slot pointer in root CSR SAVE0 --- src/arch/loongarch64/cpu.rs | 43 +++++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/src/arch/loongarch64/cpu.rs b/src/arch/loongarch64/cpu.rs index 7281572ac..90e72e909 100644 --- a/src/arch/loongarch64/cpu.rs +++ b/src/arch/loongarch64/cpu.rs @@ -17,13 +17,13 @@ use super::ipi::*; use super::zone::ZoneContext; use crate::arch::zone::disable_hwi_through; -use crate::cpu_data::{this_cpu_data, VcpuState}; +use crate::cpu_data::{this_cpu_data, PerCpu, VcpuState}; use crate::zone::find_zone; use core::arch::asm; use core::fmt::{self, Debug, Formatter}; +use loongArch64::register::crmd; use loongArch64::register::crmd::Crmd; use loongArch64::register::pgdl; -use loongArch64::register::{cpuid, crmd}; use crate::{ consts::{MAX_CPU_NUM, PER_CPU_ARRAY_PTR, PER_CPU_SIZE}, @@ -142,7 +142,10 @@ impl ArchCpu { } pub fn this_cpu_id() -> usize { - cpuid::read().core_id() + // SAVE0 caches the PerCpu slot base (written once per core in + // PerCpu::new); the id sits at slot offset 0. cpuid::read() (CSR 0x20) + // stays available for code that wants the raw core id. + unsafe { (*(this_cpu_pointer() as *const PerCpu)).id } } pub fn cpu_start(cpuid: usize, start_addr: usize, opaque: usize) { @@ -157,9 +160,37 @@ pub fn cpu_start(cpuid: usize, start_addr: usize, opaque: usize) { ipi_write_action_percore(cpuid, SMP_BOOT_CPU); } -pub fn store_cpu_pointer_to_reg(pointer: usize) { - // println!("loongarch64 doesn't support store cpu pointer to reg, pointer: {:#x}", pointer); - return; +/// Free root CSR used to cache the PerCpu slot base of the current core. +/// +/// CSR 0x21 (PRCFG1) is read-only and SAVE3/SAVE4 are the active trap +/// handoff (run/idle write the ctx/stack pointers), so the root SAVE0 is +/// the pragmatic free slot. Guest-state SAVE0 lives in the separate GCSR +/// file (trap.rs gcsrrd/gcsrwr) and is unaffected. +const CSR_SAVE0: usize = 0x30; + +/// Cache the PerCpu slot base of the current core in root CSR SAVE0. +pub fn set_this_cpu_pointer(slot_base: usize) { + unsafe { + asm!( + "csrwr {}, {LOONGARCH_CSR_SAVE0}", + in(reg) slot_base, + LOONGARCH_CSR_SAVE0 = const CSR_SAVE0, + ); + } +} + +/// PerCpu slot base of the current core, cached in SAVE0 by +/// `set_this_cpu_pointer` at `PerCpu::new` time. +pub fn this_cpu_pointer() -> usize { + let ptr: usize; + unsafe { + asm!( + "csrrd {}, {LOONGARCH_CSR_SAVE0}", + out(reg) ptr, + LOONGARCH_CSR_SAVE0 = const CSR_SAVE0, + ); + } + ptr } pub fn get_target_cpu(irq: usize, zone_id: usize) -> usize { From 72364b9807f92d38a0c4acc331a87a1e1bab3188 Mon Sep 17 00:00:00 2001 From: Anlai Lu Date: Wed, 2 Sep 2026 22:06:17 +0800 Subject: [PATCH 4/8] feat(riscv64): container_of PerCpu slot base from sscratch --- src/arch/riscv64/cpu.rs | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/src/arch/riscv64/cpu.rs b/src/arch/riscv64/cpu.rs index 9e595e5f2..55679b1a6 100644 --- a/src/arch/riscv64/cpu.rs +++ b/src/arch/riscv64/cpu.rs @@ -14,7 +14,7 @@ // Authors: // use super::csr::*; -use crate::cpu_data::{this_cpu_data, VcpuState}; +use crate::cpu_data::{this_cpu_data, PerCpu, VcpuState}; use crate::platform::{BOARD_HARTID_MAP, BOARD_NCPUS}; use crate::{ arch::mm::new_s2_memory_set, @@ -275,6 +275,12 @@ impl ArchCpu { } } +// CSR_SSCRATCH caches the per-pCPU scheduling-context pointer of this hart: +// the `ArchCpu` of this pCPU's PerCpu slot (guest registers live in +// `ArchCpu.x` at offset 0, which trap.S reaches by swapping via x31/sscratch, +// so the cached value must keep being `&slot.arch_cpu`). In a future N:M +// vCPU schedule this pointer is updated at vCPU switch points instead of +// staying fixed per boot. fn this_cpu_arch() -> &'static mut ArchCpu { let sscratch = read_csr!(CSR_SSCRATCH); if sscratch == 0 { @@ -288,6 +294,14 @@ pub fn this_cpu_id() -> usize { this_cpu_arch().get_cpuid() } +/// PerCpu slot base of the current hart: the sscratch-cached `&ArchCpu` minus +/// the `arch_cpu` field offset (container_of). Kept as the sum of a csrr and +/// a constant subtraction so this_cpu_data() costs no id lookup or table scan. +pub fn this_cpu_pointer() -> usize { + let arch_offset = core::mem::offset_of!(PerCpu, arch_cpu); + this_cpu_arch() as *const _ as usize - arch_offset +} + pub fn hartid_to_cpuid(hartid: usize) -> usize { (0..BOARD_NCPUS) .find(|&i| BOARD_HARTID_MAP[i] == hartid) @@ -301,11 +315,16 @@ pub fn cpu_start(cpuid: usize, start_addr: usize, opaque: usize) { } } -pub fn store_cpu_pointer_to_reg(pointer: usize) { - // Store the pointer to the current CPU's ArchCpu structure in CSR_SSCRATCH - write_csr!(CSR_SSCRATCH, pointer); - // println!("Stored CPU pointer to CSR_SSCRATCH: {:#x}", pointer); - return; +/// Cache the PerCpu slot base of the current hart in CSR_SSCRATCH. +/// +/// SSCRATCH must keep pointing at this CPU's `ArchCpu` (trap.S constraint), +/// so the slot base handed in by PerCpu::new is translated to `&arch_cpu` +/// here; reset_regs() re-writes the same value before every VM entry. +pub fn set_this_cpu_pointer(slot_base: usize) { + write_csr!( + CSR_SSCRATCH, + slot_base + core::mem::offset_of!(PerCpu, arch_cpu) + ); } pub fn get_target_cpu(_irq: usize, zone_id: usize) -> usize { From c0966a7313cee47cebfe301ace7c910f106ab1d0 Mon Sep 17 00:00:00 2001 From: Anlai Lu Date: Wed, 2 Sep 2026 22:09:45 +0800 Subject: [PATCH 5/8] refactor: replace percpu def_percpu queues with plain arrays --- src/device/irqchip/ls7a2000/mod.rs | 12 +++++++++--- src/event.rs | 14 +++++++++++--- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/device/irqchip/ls7a2000/mod.rs b/src/device/irqchip/ls7a2000/mod.rs index dea50912d..672bd91e7 100644 --- a/src/device/irqchip/ls7a2000/mod.rs +++ b/src/device/irqchip/ls7a2000/mod.rs @@ -108,13 +108,19 @@ const INT_TIMER: usize = 11; const INT_IPI: usize = 12; /// Per-pCPU software HWI bitmap, serialized with GINTC VIP updates. -#[percpu::def_percpu] -static GUEST_HWI_ASSERTED: Mutex = Mutex::new(0); +/// Indexed by logical CPU id; repr-aligned so adjacent states do not share +/// cache lines (same 64-byte stride the percpu crate's `.percpu` section +/// used). Only ever accessed remotely (by target CPU id). +#[repr(align(64))] +struct GuestHwiState(Mutex); + +static GUEST_HWI_ASSERTED: [GuestHwiState; MAX_CPU_NUM] = + [const { GuestHwiState(Mutex::new(0)) }; MAX_CPU_NUM]; // The caller ensures the cpu_id is valid. #[inline(always)] fn get_guest_hwi_state(cpu: usize) -> &'static Mutex { - unsafe { GUEST_HWI_ASSERTED.remote_ref_raw(cpu) } + &GUEST_HWI_ASSERTED[cpu].0 } fn sync_guest_irqs_for_cpu(cpu: usize, update: impl FnOnce(&mut u32) -> bool) -> bool { diff --git a/src/event.rs b/src/event.rs index 6c3947e37..593fedf11 100644 --- a/src/event.rs +++ b/src/event.rs @@ -41,13 +41,21 @@ pub const IPI_EVENT_VIRTIO_PCI_CONFIG: usize = 7; pub const IPI_EVENT_VIRTIO_PCI_DATA: usize = 8; pub const IPI_EVENT_VIRTIO_PCI_DONE: usize = 9; -#[percpu::def_percpu] -static PERCPU_EVENTS: Mutex> = Mutex::new(VecDeque::new()); +/// Per-CPU event queue indexed by logical CPU id. Repr-aligned so adjacent +/// queues do not share cache lines (same 64-byte stride the percpu crate's +/// `.percpu` section used). This is a plain array now: the queues are only +/// ever accessed remotely (by target CPU id), so no per-CPU register or +/// link-time section machinery is needed. +#[repr(align(64))] +struct EventQueue(Mutex>); + +static PERCPU_EVENTS: [EventQueue; MAX_CPU_NUM] = + [const { EventQueue(Mutex::new(VecDeque::new())) }; MAX_CPU_NUM]; // The caller ensures the cpu_id is valid #[inline(always)] fn get_percpu_events(cpu: usize) -> &'static Mutex> { - unsafe { PERCPU_EVENTS.remote_ref_raw(cpu) } + &PERCPU_EVENTS[cpu].0 } /// Enqueue an event and report whether the target queue was previously empty. From 4af2844f351a1eee5107e7095f162930f93036b0 Mon Sep 17 00:00:00 2001 From: Anlai Lu Date: Wed, 2 Sep 2026 22:12:18 +0800 Subject: [PATCH 6/8] remove: drop percpu crate and its .percpu link-time sections --- Cargo.lock | 27 ------------------- Cargo.toml | 1 - platform/aarch64/dayu200/linker.ld | 13 --------- platform/aarch64/imx8mp/linker.ld | 13 --------- platform/aarch64/jeston-orin/linker.ld | 13 --------- platform/aarch64/ok6254-c/linker.ld | 13 --------- platform/aarch64/phytium-pi/linker.ld | 13 --------- platform/aarch64/qemu-gicv2/linker.ld | 13 --------- platform/aarch64/qemu-gicv3/linker.ld | 13 --------- platform/aarch64/rk3568/linker.ld | 13 --------- platform/aarch64/rk3588/linker.ld | 13 --------- platform/aarch64/sysoul_x3300-scmi/linker.ld | 13 --------- platform/aarch64/sysoul_x3300/linker.ld | 13 --------- platform/aarch64/zcu102/linker.ld | 13 --------- platform/loongarch64/ls3a5000/linker.ld | 13 --------- platform/loongarch64/ls3a6000/linker.ld | 13 --------- .../riscv64/hifive-premier-p550/linker.ld | 13 --------- platform/riscv64/k3-com260/linker.ld | 13 --------- platform/riscv64/megrez/linker.ld | 13 --------- platform/riscv64/qemu-aia/linker.ld | 13 --------- platform/riscv64/qemu-plic/linker.ld | 13 --------- platform/riscv64/ur-dp1000/linker.ld | 13 --------- platform/x86_64/ecx-2300f-peg/linker.ld | 13 --------- platform/x86_64/nuc14mnk/linker.ld | 13 --------- platform/x86_64/qemu/linker.ld | 13 --------- src/main.rs | 5 ++-- 26 files changed, 3 insertions(+), 329 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9644e03a3..4ef6a296d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -175,7 +175,6 @@ dependencies = [ "log", "loongArch64", "numeric-enum-macro", - "percpu", "psci", "qemu-exit", "raw-cpuid", @@ -247,29 +246,6 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" -[[package]] -name = "percpu" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01e56c0c558952222967b592899f98765b48590e7bd7403bfd7075f73afc6ed6" -dependencies = [ - "cfg-if", - "percpu_macros", - "spin 0.9.8", - "x86", -] - -[[package]] -name = "percpu_macros" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9f4cc54a2e471ff72f1499461ba381ad4eae9cbd60d29c258545b995e406e0" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.111", -] - [[package]] name = "proc-macro2" version = "1.0.103" @@ -501,9 +477,6 @@ name = "spin" version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" -dependencies = [ - "lock_api", -] [[package]] name = "spin" diff --git a/Cargo.toml b/Cargo.toml index 381e11771..ed28d3caa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,6 @@ cortex-a = "8.1.1" cfg-if = "1.0" bitvec = { version="1.0.1", default-features = false, features = ["atomic", "alloc"] } heapless = { version = "0.8.0 "} -percpu = { package = "percpu", version="0.2", features=["arm-el2"]} [target.'cfg(target_arch = "aarch64")'.dependencies] aarch64-cpu = "9.4.0" diff --git a/platform/aarch64/dayu200/linker.ld b/platform/aarch64/dayu200/linker.ld index 5add6faa1..f3a64980a 100644 --- a/platform/aarch64/dayu200/linker.ld +++ b/platform/aarch64/dayu200/linker.ld @@ -1,7 +1,5 @@ ENTRY(arch_entry) BASE_ADDRESS = 0x40400000; -CPU_NUM = 4; - SECTIONS { . = BASE_ADDRESS; @@ -43,17 +41,6 @@ SECTIONS *(.sbss .sbss.*) } - . = ALIGN(4K); - _percpu_start = .; - _percpu_end = _percpu_start + SIZEOF(.percpu); - .percpu 0x0 (NOLOAD) : AT(_percpu_start) { - _percpu_load_start = .; - *(.percpu .percpu.*) - _percpu_load_end = .; - . = _percpu_load_start + ALIGN(64) * CPU_NUM; - } - . = _percpu_end; - . = ALIGN(4K); ebss = .; ekernel = .; diff --git a/platform/aarch64/imx8mp/linker.ld b/platform/aarch64/imx8mp/linker.ld index f8c4a9eb7..dcd9d9d04 100644 --- a/platform/aarch64/imx8mp/linker.ld +++ b/platform/aarch64/imx8mp/linker.ld @@ -1,7 +1,5 @@ ENTRY(arch_entry) BASE_ADDRESS = 0x40400000; -CPU_NUM = 4; - SECTIONS { . = BASE_ADDRESS; @@ -38,17 +36,6 @@ SECTIONS *(.sbss .sbss.*) } - . = ALIGN(4K); - _percpu_start = .; - _percpu_end = _percpu_start + SIZEOF(.percpu); - .percpu 0x0 (NOLOAD) : AT(_percpu_start) { - _percpu_load_start = .; - *(.percpu .percpu.*) - _percpu_load_end = .; - . = _percpu_load_start + ALIGN(64) * CPU_NUM; - } - . = _percpu_end; - . = ALIGN(4K); ebss = .; ekernel = .; diff --git a/platform/aarch64/jeston-orin/linker.ld b/platform/aarch64/jeston-orin/linker.ld index 5f97efffe..d1bd52635 100644 --- a/platform/aarch64/jeston-orin/linker.ld +++ b/platform/aarch64/jeston-orin/linker.ld @@ -1,7 +1,5 @@ ENTRY(arch_entry) BASE_ADDRESS = 0x81000000; -CPU_NUM = 6; - SECTIONS { . = BASE_ADDRESS; @@ -38,17 +36,6 @@ SECTIONS *(.sbss .sbss.*) } - . = ALIGN(4K); - _percpu_start = .; - _percpu_end = _percpu_start + SIZEOF(.percpu); - .percpu 0x0 (NOLOAD) : AT(_percpu_start) { - _percpu_load_start = .; - *(.percpu .percpu.*) - _percpu_load_end = .; - . = _percpu_load_start + ALIGN(64) * CPU_NUM; - } - . = _percpu_end; - . = ALIGN(4K); ebss = .; ekernel = .; diff --git a/platform/aarch64/ok6254-c/linker.ld b/platform/aarch64/ok6254-c/linker.ld index 4da975bb2..d62129549 100644 --- a/platform/aarch64/ok6254-c/linker.ld +++ b/platform/aarch64/ok6254-c/linker.ld @@ -1,7 +1,5 @@ ENTRY(arch_entry) BASE_ADDRESS = 0x80400000; -CPU_NUM = 4; - SECTIONS { . = BASE_ADDRESS; @@ -38,17 +36,6 @@ SECTIONS *(.sbss .sbss.*) } - . = ALIGN(4K); - _percpu_start = .; - _percpu_end = _percpu_start + SIZEOF(.percpu); - .percpu 0x0 (NOLOAD) : AT(_percpu_start) { - _percpu_load_start = .; - *(.percpu .percpu.*) - _percpu_load_end = .; - . = _percpu_load_start + ALIGN(64) * CPU_NUM; - } - . = _percpu_end; - . = ALIGN(4K); ebss = .; ekernel = .; diff --git a/platform/aarch64/phytium-pi/linker.ld b/platform/aarch64/phytium-pi/linker.ld index 1438cfec4..57042b07f 100644 --- a/platform/aarch64/phytium-pi/linker.ld +++ b/platform/aarch64/phytium-pi/linker.ld @@ -1,7 +1,5 @@ ENTRY(arch_entry) BASE_ADDRESS = 0x90100000; -CPU_NUM = 4; - SECTIONS { . = BASE_ADDRESS; @@ -38,17 +36,6 @@ SECTIONS *(.sbss .sbss.*) } - . = ALIGN(4K); - _percpu_start = .; - _percpu_end = _percpu_start + SIZEOF(.percpu); - .percpu 0x0 (NOLOAD) : AT(_percpu_start) { - _percpu_load_start = .; - *(.percpu .percpu.*) - _percpu_load_end = .; - . = _percpu_load_start + ALIGN(64) * CPU_NUM; - } - . = _percpu_end; - . = ALIGN(4K); ebss = .; ekernel = .; diff --git a/platform/aarch64/qemu-gicv2/linker.ld b/platform/aarch64/qemu-gicv2/linker.ld index f8c4a9eb7..dcd9d9d04 100644 --- a/platform/aarch64/qemu-gicv2/linker.ld +++ b/platform/aarch64/qemu-gicv2/linker.ld @@ -1,7 +1,5 @@ ENTRY(arch_entry) BASE_ADDRESS = 0x40400000; -CPU_NUM = 4; - SECTIONS { . = BASE_ADDRESS; @@ -38,17 +36,6 @@ SECTIONS *(.sbss .sbss.*) } - . = ALIGN(4K); - _percpu_start = .; - _percpu_end = _percpu_start + SIZEOF(.percpu); - .percpu 0x0 (NOLOAD) : AT(_percpu_start) { - _percpu_load_start = .; - *(.percpu .percpu.*) - _percpu_load_end = .; - . = _percpu_load_start + ALIGN(64) * CPU_NUM; - } - . = _percpu_end; - . = ALIGN(4K); ebss = .; ekernel = .; diff --git a/platform/aarch64/qemu-gicv3/linker.ld b/platform/aarch64/qemu-gicv3/linker.ld index f8c4a9eb7..dcd9d9d04 100644 --- a/platform/aarch64/qemu-gicv3/linker.ld +++ b/platform/aarch64/qemu-gicv3/linker.ld @@ -1,7 +1,5 @@ ENTRY(arch_entry) BASE_ADDRESS = 0x40400000; -CPU_NUM = 4; - SECTIONS { . = BASE_ADDRESS; @@ -38,17 +36,6 @@ SECTIONS *(.sbss .sbss.*) } - . = ALIGN(4K); - _percpu_start = .; - _percpu_end = _percpu_start + SIZEOF(.percpu); - .percpu 0x0 (NOLOAD) : AT(_percpu_start) { - _percpu_load_start = .; - *(.percpu .percpu.*) - _percpu_load_end = .; - . = _percpu_load_start + ALIGN(64) * CPU_NUM; - } - . = _percpu_end; - . = ALIGN(4K); ebss = .; ekernel = .; diff --git a/platform/aarch64/rk3568/linker.ld b/platform/aarch64/rk3568/linker.ld index 0fe74fbe7..e8ccdd948 100644 --- a/platform/aarch64/rk3568/linker.ld +++ b/platform/aarch64/rk3568/linker.ld @@ -1,7 +1,5 @@ ENTRY(arch_entry) BASE_ADDRESS = 0x60080000; -CPU_NUM = 4; - SECTIONS { . = BASE_ADDRESS; @@ -43,17 +41,6 @@ SECTIONS *(.sbss .sbss.*) } - . = ALIGN(4K); - _percpu_start = .; - _percpu_end = _percpu_start + SIZEOF(.percpu); - .percpu 0x0 (NOLOAD) : AT(_percpu_start) { - _percpu_load_start = .; - *(.percpu .percpu.*) - _percpu_load_end = .; - . = _percpu_load_start + ALIGN(64) * CPU_NUM; - } - . = _percpu_end; - . = ALIGN(4K); ebss = .; ekernel = .; diff --git a/platform/aarch64/rk3588/linker.ld b/platform/aarch64/rk3588/linker.ld index b287362b6..ca96801d8 100644 --- a/platform/aarch64/rk3588/linker.ld +++ b/platform/aarch64/rk3588/linker.ld @@ -1,7 +1,5 @@ ENTRY(arch_entry) BASE_ADDRESS = 0x500000; -CPU_NUM = 8; - SECTIONS { . = BASE_ADDRESS; @@ -43,17 +41,6 @@ SECTIONS *(.sbss .sbss.*) } - . = ALIGN(4K); - _percpu_start = .; - _percpu_end = _percpu_start + SIZEOF(.percpu); - .percpu 0x0 (NOLOAD) : AT(_percpu_start) { - _percpu_load_start = .; - *(.percpu .percpu.*) - _percpu_load_end = .; - . = _percpu_load_start + ALIGN(64) * CPU_NUM; - } - . = _percpu_end; - . = ALIGN(4K); ebss = .; ekernel = .; diff --git a/platform/aarch64/sysoul_x3300-scmi/linker.ld b/platform/aarch64/sysoul_x3300-scmi/linker.ld index b287362b6..ca96801d8 100644 --- a/platform/aarch64/sysoul_x3300-scmi/linker.ld +++ b/platform/aarch64/sysoul_x3300-scmi/linker.ld @@ -1,7 +1,5 @@ ENTRY(arch_entry) BASE_ADDRESS = 0x500000; -CPU_NUM = 8; - SECTIONS { . = BASE_ADDRESS; @@ -43,17 +41,6 @@ SECTIONS *(.sbss .sbss.*) } - . = ALIGN(4K); - _percpu_start = .; - _percpu_end = _percpu_start + SIZEOF(.percpu); - .percpu 0x0 (NOLOAD) : AT(_percpu_start) { - _percpu_load_start = .; - *(.percpu .percpu.*) - _percpu_load_end = .; - . = _percpu_load_start + ALIGN(64) * CPU_NUM; - } - . = _percpu_end; - . = ALIGN(4K); ebss = .; ekernel = .; diff --git a/platform/aarch64/sysoul_x3300/linker.ld b/platform/aarch64/sysoul_x3300/linker.ld index b287362b6..ca96801d8 100644 --- a/platform/aarch64/sysoul_x3300/linker.ld +++ b/platform/aarch64/sysoul_x3300/linker.ld @@ -1,7 +1,5 @@ ENTRY(arch_entry) BASE_ADDRESS = 0x500000; -CPU_NUM = 8; - SECTIONS { . = BASE_ADDRESS; @@ -43,17 +41,6 @@ SECTIONS *(.sbss .sbss.*) } - . = ALIGN(4K); - _percpu_start = .; - _percpu_end = _percpu_start + SIZEOF(.percpu); - .percpu 0x0 (NOLOAD) : AT(_percpu_start) { - _percpu_load_start = .; - *(.percpu .percpu.*) - _percpu_load_end = .; - . = _percpu_load_start + ALIGN(64) * CPU_NUM; - } - . = _percpu_end; - . = ALIGN(4K); ebss = .; ekernel = .; diff --git a/platform/aarch64/zcu102/linker.ld b/platform/aarch64/zcu102/linker.ld index f8c4a9eb7..dcd9d9d04 100644 --- a/platform/aarch64/zcu102/linker.ld +++ b/platform/aarch64/zcu102/linker.ld @@ -1,7 +1,5 @@ ENTRY(arch_entry) BASE_ADDRESS = 0x40400000; -CPU_NUM = 4; - SECTIONS { . = BASE_ADDRESS; @@ -38,17 +36,6 @@ SECTIONS *(.sbss .sbss.*) } - . = ALIGN(4K); - _percpu_start = .; - _percpu_end = _percpu_start + SIZEOF(.percpu); - .percpu 0x0 (NOLOAD) : AT(_percpu_start) { - _percpu_load_start = .; - *(.percpu .percpu.*) - _percpu_load_end = .; - . = _percpu_load_start + ALIGN(64) * CPU_NUM; - } - . = _percpu_end; - . = ALIGN(4K); ebss = .; ekernel = .; diff --git a/platform/loongarch64/ls3a5000/linker.ld b/platform/loongarch64/ls3a5000/linker.ld index a226494f9..6f83d8293 100644 --- a/platform/loongarch64/ls3a5000/linker.ld +++ b/platform/loongarch64/ls3a5000/linker.ld @@ -1,7 +1,5 @@ ENTRY(arch_entry) BASE_ADDRESS = 0x90000001f0000000; -CPU_NUM = 4; - SECTIONS { @@ -47,17 +45,6 @@ SECTIONS *(.sbss .sbss.*) } - . = ALIGN(4K); - _percpu_start = .; - _percpu_end = _percpu_start + SIZEOF(.percpu); - .percpu 0x0 (NOLOAD) : AT(_percpu_start) { - _percpu_load_start = .; - *(.percpu .percpu.*) - _percpu_load_end = .; - . = _percpu_load_start + ALIGN(64) * CPU_NUM; - } - . = _percpu_end; - . = ALIGN(4K); ebss = .; diff --git a/platform/loongarch64/ls3a6000/linker.ld b/platform/loongarch64/ls3a6000/linker.ld index a226494f9..6f83d8293 100644 --- a/platform/loongarch64/ls3a6000/linker.ld +++ b/platform/loongarch64/ls3a6000/linker.ld @@ -1,7 +1,5 @@ ENTRY(arch_entry) BASE_ADDRESS = 0x90000001f0000000; -CPU_NUM = 4; - SECTIONS { @@ -47,17 +45,6 @@ SECTIONS *(.sbss .sbss.*) } - . = ALIGN(4K); - _percpu_start = .; - _percpu_end = _percpu_start + SIZEOF(.percpu); - .percpu 0x0 (NOLOAD) : AT(_percpu_start) { - _percpu_load_start = .; - *(.percpu .percpu.*) - _percpu_load_end = .; - . = _percpu_load_start + ALIGN(64) * CPU_NUM; - } - . = _percpu_end; - . = ALIGN(4K); ebss = .; diff --git a/platform/riscv64/hifive-premier-p550/linker.ld b/platform/riscv64/hifive-premier-p550/linker.ld index 6f2d2083b..3824f39ae 100644 --- a/platform/riscv64/hifive-premier-p550/linker.ld +++ b/platform/riscv64/hifive-premier-p550/linker.ld @@ -1,7 +1,5 @@ ENTRY(arch_entry) BASE_ADDRESS = 0x80200000; -CPU_NUM = 4; - SECTIONS { @@ -39,17 +37,6 @@ SECTIONS *(.sbss .sbss.*) } - . = ALIGN(4K); - _percpu_start = .; - _percpu_end = _percpu_start + SIZEOF(.percpu); - .percpu 0x0 (NOLOAD) : AT(_percpu_start) { - _percpu_load_start = .; - *(.percpu .percpu.*) - _percpu_load_end = .; - . = _percpu_load_start + ALIGN(64) * CPU_NUM; - } - . = _percpu_end; - . = ALIGN(4K); ebss = .; ekernel = .; diff --git a/platform/riscv64/k3-com260/linker.ld b/platform/riscv64/k3-com260/linker.ld index 6f4636bf8..4cf3c858a 100644 --- a/platform/riscv64/k3-com260/linker.ld +++ b/platform/riscv64/k3-com260/linker.ld @@ -1,7 +1,5 @@ ENTRY(arch_entry) BASE_ADDRESS = 0x102200000; -CPU_NUM = 8; - SECTIONS { @@ -39,17 +37,6 @@ SECTIONS *(.sbss .sbss.*) } - . = ALIGN(4K); - _percpu_start = .; - _percpu_end = _percpu_start + SIZEOF(.percpu); - .percpu 0x0 (NOLOAD) : AT(_percpu_start) { - _percpu_load_start = .; - *(.percpu .percpu.*) - _percpu_load_end = .; - . = _percpu_load_start + ALIGN(64) * CPU_NUM; - } - . = _percpu_end; - . = ALIGN(4K); ebss = .; ekernel = .; diff --git a/platform/riscv64/megrez/linker.ld b/platform/riscv64/megrez/linker.ld index 6f2d2083b..3824f39ae 100644 --- a/platform/riscv64/megrez/linker.ld +++ b/platform/riscv64/megrez/linker.ld @@ -1,7 +1,5 @@ ENTRY(arch_entry) BASE_ADDRESS = 0x80200000; -CPU_NUM = 4; - SECTIONS { @@ -39,17 +37,6 @@ SECTIONS *(.sbss .sbss.*) } - . = ALIGN(4K); - _percpu_start = .; - _percpu_end = _percpu_start + SIZEOF(.percpu); - .percpu 0x0 (NOLOAD) : AT(_percpu_start) { - _percpu_load_start = .; - *(.percpu .percpu.*) - _percpu_load_end = .; - . = _percpu_load_start + ALIGN(64) * CPU_NUM; - } - . = _percpu_end; - . = ALIGN(4K); ebss = .; ekernel = .; diff --git a/platform/riscv64/qemu-aia/linker.ld b/platform/riscv64/qemu-aia/linker.ld index 6f2d2083b..3824f39ae 100644 --- a/platform/riscv64/qemu-aia/linker.ld +++ b/platform/riscv64/qemu-aia/linker.ld @@ -1,7 +1,5 @@ ENTRY(arch_entry) BASE_ADDRESS = 0x80200000; -CPU_NUM = 4; - SECTIONS { @@ -39,17 +37,6 @@ SECTIONS *(.sbss .sbss.*) } - . = ALIGN(4K); - _percpu_start = .; - _percpu_end = _percpu_start + SIZEOF(.percpu); - .percpu 0x0 (NOLOAD) : AT(_percpu_start) { - _percpu_load_start = .; - *(.percpu .percpu.*) - _percpu_load_end = .; - . = _percpu_load_start + ALIGN(64) * CPU_NUM; - } - . = _percpu_end; - . = ALIGN(4K); ebss = .; ekernel = .; diff --git a/platform/riscv64/qemu-plic/linker.ld b/platform/riscv64/qemu-plic/linker.ld index 6f2d2083b..3824f39ae 100644 --- a/platform/riscv64/qemu-plic/linker.ld +++ b/platform/riscv64/qemu-plic/linker.ld @@ -1,7 +1,5 @@ ENTRY(arch_entry) BASE_ADDRESS = 0x80200000; -CPU_NUM = 4; - SECTIONS { @@ -39,17 +37,6 @@ SECTIONS *(.sbss .sbss.*) } - . = ALIGN(4K); - _percpu_start = .; - _percpu_end = _percpu_start + SIZEOF(.percpu); - .percpu 0x0 (NOLOAD) : AT(_percpu_start) { - _percpu_load_start = .; - *(.percpu .percpu.*) - _percpu_load_end = .; - . = _percpu_load_start + ALIGN(64) * CPU_NUM; - } - . = _percpu_end; - . = ALIGN(4K); ebss = .; ekernel = .; diff --git a/platform/riscv64/ur-dp1000/linker.ld b/platform/riscv64/ur-dp1000/linker.ld index cb2da6dfd..fabc7fb9c 100644 --- a/platform/riscv64/ur-dp1000/linker.ld +++ b/platform/riscv64/ur-dp1000/linker.ld @@ -1,7 +1,5 @@ ENTRY(arch_entry) BASE_ADDRESS = 0x80200000; -CPU_NUM = 8; - SECTIONS { @@ -39,17 +37,6 @@ SECTIONS *(.sbss .sbss.*) } - . = ALIGN(4K); - _percpu_start = .; - _percpu_end = _percpu_start + SIZEOF(.percpu); - .percpu 0x0 (NOLOAD) : AT(_percpu_start) { - _percpu_load_start = .; - *(.percpu .percpu.*) - _percpu_load_end = .; - . = _percpu_load_start + ALIGN(64) * CPU_NUM; - } - . = _percpu_end; - . = ALIGN(4K); ebss = .; ekernel = .; diff --git a/platform/x86_64/ecx-2300f-peg/linker.ld b/platform/x86_64/ecx-2300f-peg/linker.ld index 2713f2380..7b1c3b131 100644 --- a/platform/x86_64/ecx-2300f-peg/linker.ld +++ b/platform/x86_64/ecx-2300f-peg/linker.ld @@ -1,7 +1,5 @@ ENTRY(arch_entry) BASE_ADDRESS = 0xffffff8000200000; -CPU_NUM = 16; - SECTIONS { . = BASE_ADDRESS; @@ -42,17 +40,6 @@ SECTIONS *(.sbss .sbss.*) } - . = ALIGN(4K); - _percpu_start = .; - _percpu_end = _percpu_start + SIZEOF(.percpu); - .percpu 0x0 (NOLOAD) : AT(_percpu_start) { - _percpu_load_start = .; - *(.percpu .percpu.*) - _percpu_load_end = .; - . = _percpu_load_start + ALIGN(64) * CPU_NUM; - } - . = _percpu_end; - . = ALIGN(4K); ebss = .; ekernel = .; diff --git a/platform/x86_64/nuc14mnk/linker.ld b/platform/x86_64/nuc14mnk/linker.ld index 3fc54b777..ebad88e29 100644 --- a/platform/x86_64/nuc14mnk/linker.ld +++ b/platform/x86_64/nuc14mnk/linker.ld @@ -1,7 +1,5 @@ ENTRY(arch_entry) BASE_ADDRESS = 0xffffff8000200000; -CPU_NUM = 4; - SECTIONS { . = BASE_ADDRESS; @@ -42,17 +40,6 @@ SECTIONS *(.sbss .sbss.*) } - . = ALIGN(4K); - _percpu_start = .; - _percpu_end = _percpu_start + SIZEOF(.percpu); - .percpu 0x0 (NOLOAD) : AT(_percpu_start) { - _percpu_load_start = .; - *(.percpu .percpu.*) - _percpu_load_end = .; - . = _percpu_load_start + ALIGN(64) * CPU_NUM; - } - . = _percpu_end; - . = ALIGN(4K); ebss = .; ekernel = .; diff --git a/platform/x86_64/qemu/linker.ld b/platform/x86_64/qemu/linker.ld index 3fc54b777..ebad88e29 100644 --- a/platform/x86_64/qemu/linker.ld +++ b/platform/x86_64/qemu/linker.ld @@ -1,7 +1,5 @@ ENTRY(arch_entry) BASE_ADDRESS = 0xffffff8000200000; -CPU_NUM = 4; - SECTIONS { . = BASE_ADDRESS; @@ -42,17 +40,6 @@ SECTIONS *(.sbss .sbss.*) } - . = ALIGN(4K); - _percpu_start = .; - _percpu_end = _percpu_start + SIZEOF(.percpu); - .percpu 0x0 (NOLOAD) : AT(_percpu_start) { - _percpu_load_start = .; - *(.percpu .percpu.*) - _percpu_load_end = .; - . = _percpu_load_start + ALIGN(64) * CPU_NUM; - } - . = _percpu_end; - . = ALIGN(4K); ebss = .; ekernel = .; diff --git a/src/main.rs b/src/main.rs index c30abda28..9b810d187 100644 --- a/src/main.rs +++ b/src/main.rs @@ -196,14 +196,15 @@ fn rust_main(cpuid: usize, host_dtb: usize) { if MASTER_CPU.load(Ordering::Acquire) == -1 { MASTER_CPU.store(cpuid as i32, Ordering::Release); is_primary = true; - percpu::init(); memory::heap::init(); memory::heap::test(); arch::time::init_timebase(); arch_post_heap_init(host_dtb); } - percpu::init_percpu_reg(cpuid); + // PerCpu::new caches the per-CPU slot base in the architecture register + // backing this_cpu_pointer()/this_cpu_id(); nothing else needs a + // per-CPU register setup at boot. let cpu = PerCpu::new(cpuid); println!( From 915f880fed574e3e5b328ea70dd98e5d58805f7f Mon Sep 17 00:00:00 2001 From: Anlai Lu Date: Wed, 2 Sep 2026 22:12:46 +0800 Subject: [PATCH 7/8] docs: record per-CPU register cache invariants and changelog entry --- CHANGELOG.md | 4 ++++ src/cpu_data.rs | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 45d0be5c2..75aa8f7d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ > ⚠️ Please update this file for any changes to the hvisor project along with your name and GitHub profile link under the CURRENT section. +## CURRENT - next release + +- [refactor] **all archs**: Cache the per-CPU slot pointer in an architecture register (`TPIDR_EL2` / `IA32_GS_BASE` / root CSR `SAVE0` / `sscratch`) so `this_cpu_id()`/`this_cpu_data()` stop re-deriving it on every access, and remove the dead `percpu` crate with its `.percpu` link-time sections (23 boards). ([agicy](https://github.com/agicy)) + ## CURRENT - v0.6 - [feature] **PCIe/virtio**: Add emulated virtio PCI device support. ([PR #287](https://github.com/syswonder/hvisor/pull/287), [ZZJJWarth](https://github.com/ZZJJWarth)) diff --git a/src/cpu_data.rs b/src/cpu_data.rs index 89c6417a6..d6aa4714d 100644 --- a/src/cpu_data.rs +++ b/src/cpu_data.rs @@ -13,6 +13,42 @@ // // Authors: // +// Per-CPU data model +// ------------------ +// Each physical CPU owns one PerCpu slot of PER_CPU_SIZE bytes starting at +// PER_CPU_ARRAY_PTR + cpuid * PER_CPU_SIZE; the per-CPU stack sits above the +// slot. `id` is deliberately the first field: the per-arch register cache +// reads the id back from slot offset 0. +// +// `PerCpu::new` caches the slot base once per CPU in an architecture register +// (also materialized in `self_ptr` on x86_64, where a gs-relative load needs +// the pointer in memory). `this_cpu_data()`/`this_cpu_id()` are then a 1-2 +// instruction read instead of a CPU-id lookup plus table scan: +// +// | arch | register | guest can corrupt it? | +// |-------------|----------------|----------------------------------------| +// | aarch64 | TPIDR_EL2 | no - EL2-private | +// | riscv64 | CSR_SSCRATCH | no - HS level, guest uses VSSCRATCH | +// | x86_64 | IA32_GS_BASE | no - VMCS host-state reloads per exit | +// | loongarch64 | root CSR SAVE0 | no - root CSR, guest GCSR file separate| +// +// Safety invariants +// ----------------- +// 1. The register is written only in `PerCpu::new`. Log records (logging.rs +// routes every record through this_cpu_data().id) can only fire after the +// logger is installed in `primary_init_early`, which every CPU reaches +// only after `PerCpu::new` (ENTERED_CPUS gate), so no core ever reads the +// cache before writing it. `println!` does not go through the logger. +// 2. riscv64: sscratch must keep pointing at `&PerCpu.arch_cpu` because +// trap.S swaps x31/sscratch to reach guest registers at ArchCpu offset 0. +// set_this_cpu_pointer() takes the slot base and adds the field offset, so +// this invariant never depends on callers. +// 3. x86_64: setup_vmcs_host snapshots IA32_GS_BASE into the VMCS host-state +// field on every run/idle, i.e. strictly after PerCpu::new on the same +// CPU, so hardware reloads the cached base on each VM exit. +// 4. loongarch64: SAVE3/SAVE4 stay reserved for the trap handoff; SAVE0 is +// per-core root state and the guest's SAVE0 lives in the GCSR file. +// use alloc::sync::Arc; use spin::Mutex; From b2230ac79b17c9b14361c521399774148a9d2894 Mon Sep 17 00:00:00 2001 From: Anlai Lu Date: Wed, 2 Sep 2026 22:40:35 +0800 Subject: [PATCH 8/8] perf(aarch64): drop dead per-exit MPIDR lookup in arch_handle_exit --- src/arch/aarch64/trap.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/arch/aarch64/trap.rs b/src/arch/aarch64/trap.rs index 26eab6d97..898c2123f 100644 --- a/src/arch/aarch64/trap.rs +++ b/src/arch/aarch64/trap.rs @@ -108,8 +108,6 @@ pub enum TrapReturn { /*From hyp_vec->handle_vmexit x0:guest regs x1:exit_reason sp =stack_top-32*8*/ pub fn arch_handle_exit(regs: &mut GeneralRegisters) -> ! { - let mpidr = MPIDR_EL1.get(); - let _cpu_id = mpidr_to_cpuid(mpidr); trace!("cpu exit, exit_reson:{:#x?}", regs.exit_reason); match regs.exit_reason as u64 { ExceptionType::EXIT_REASON_EL1_IRQ | ExceptionType::EXIT_REASON_EL1_AARCH32_IRQ => {