diff --git a/Cargo.lock b/Cargo.lock index 8539206aef..1cf9ef8147 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -606,9 +606,9 @@ dependencies = [ [[package]] name = "axplat" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4de04c54b63bf2ca1ff202733d2516da49d7779649cdb2f9c4ecf22909e6810" +checksum = "397e19d768dbf9573cf40663d65671a98c8b8a2a3b3947191d4aab6a33e01a15" dependencies = [ "axplat-macros", "bitflags 2.9.2", @@ -621,9 +621,9 @@ dependencies = [ [[package]] name = "axplat-aarch64-bsta1000b" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af884a8e67b199c395d634e0a2fa9cd954279dd9abe9e672b84e833506f8466c" +checksum = "c2768d42cdd829ca385e4c00d048011448d6203a2982e0e2fb949a0c2cca7e5f" dependencies = [ "axconfig-macros", "axcpu", @@ -637,9 +637,9 @@ dependencies = [ [[package]] name = "axplat-aarch64-peripherals" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a9a6548290a150059eb2ae015dc58d9b3d652461760327b95a490666129974c" +checksum = "81d65e6a09f3d1f0af076efa21eb1325d675431e0b313e25df256ddf2344bf6f" dependencies = [ "aarch64-cpu 10.0.0", "arm-gic-driver", @@ -657,9 +657,9 @@ dependencies = [ [[package]] name = "axplat-aarch64-phytium-pi" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c893f78d02cfa594bbe7f5880e69c610f79c119a28a4c2d095dfca95287f0e" +checksum = "c210511ecaab4448142413197df3ce052aa1f0c93664c952b6bffb1c3f7e02c1" dependencies = [ "axconfig-macros", "axcpu", @@ -671,9 +671,9 @@ dependencies = [ [[package]] name = "axplat-aarch64-qemu-virt" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f03bfe81ebc5b2f567eecadcab221107b90f394485dd0da39334411a676d81a" +checksum = "8a67e4110907e19c3ab1353e4386f4656aab395c83656cfee22ba6b49ed35250" dependencies = [ "axconfig-macros", "axcpu", @@ -685,9 +685,9 @@ dependencies = [ [[package]] name = "axplat-aarch64-raspi" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48df7f92caad3148cceff163c7988a0eee95d5e3523ec7e0ef0d9e85255ca98a" +checksum = "b0328561d8130066093fec6f66b0fb45e8063e8832f66d36e7eb9569d2ed2d89" dependencies = [ "aarch64-cpu 10.0.0", "axconfig-macros", @@ -700,9 +700,9 @@ dependencies = [ [[package]] name = "axplat-loongarch64-qemu-virt" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c404064c74824b2c509e1d84f2ae0cbd9240a3274fb4053dc81b9ad120b5962" +checksum = "00a0c4b0a25488e6a9b536a55fae2153d14ef40bd931b2c28bf387a95ad3fb80" dependencies = [ "axconfig-macros", "axcpu", @@ -729,9 +729,9 @@ dependencies = [ [[package]] name = "axplat-riscv64-qemu-virt" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8d95d76dfa65d75d07380ac13692c3b0c5bd6ae5b68df7bbede1f2e7181027a" +checksum = "fb75b0b52fd2289ec461a3ea3aba978cb943fb07fb023d5edc2c8efe079eb724" dependencies = [ "axconfig-macros", "axcpu", @@ -744,9 +744,9 @@ dependencies = [ [[package]] name = "axplat-x86-pc" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4aef32b01b5b7e87e9f69933b64b704bc5d731adda2cdd24fc0a29cf0c359211" +checksum = "d3488a8857c3e66da47a320e4c6ebba10f6218481e31ca3f2e00f927e1ad68c1" dependencies = [ "axconfig-macros", "axcpu", diff --git a/Makefile b/Makefile index 517fc0ef37..81189c725a 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,10 @@ # - `ARCH`: Target architecture: x86_64, riscv64, aarch64, loongarch64 # - `MYPLAT`: Package name of the target platform crate. # - `PLAT_CONFIG`: Path to the platform configuration file. -# - `SMP`: Number of CPUs. If not set, use the default value from platform config. +# - `SMP`: Override maximum CPU number specified in the platform config. For +# statically configured platforms, this is also the number of CPUs to boot +# and for platforms with runtime CPU detection, this is the upper limit of +# CPUs. # - `MODE`: Build mode: release, debug # - `LOG:` Logging level: warn, error, info, debug, trace # - `V`: Verbose level: (empty), 1, 2 diff --git a/api/arceos_api/src/imp/mod.rs b/api/arceos_api/src/imp/mod.rs index a8dbdfdb74..4c80b995a7 100644 --- a/api/arceos_api/src/imp/mod.rs +++ b/api/arceos_api/src/imp/mod.rs @@ -39,6 +39,11 @@ mod stdio { } } +mod sys { + pub use axhal::cpu_num as ax_get_cpu_num; + pub use axhal::power::system_off as ax_terminate; +} + mod time { pub use axhal::time::{ TimeValue as AxTimeValue, monotonic_time as ax_monotonic_time, wall_time as ax_wall_time, @@ -47,8 +52,8 @@ mod time { pub use self::mem::*; pub use self::stdio::*; +pub use self::sys::*; pub use self::task::*; pub use self::time::*; -pub use axhal::power::system_off as ax_terminate; pub use axio::PollState as AxPollState; diff --git a/api/arceos_api/src/lib.rs b/api/arceos_api/src/lib.rs index 95658a17e6..d91da0c342 100644 --- a/api/arceos_api/src/lib.rs +++ b/api/arceos_api/src/lib.rs @@ -32,6 +32,9 @@ pub mod sys { define_api! { /// Shutdown the whole system and all CPUs. pub fn ax_terminate() -> !; + + /// Returns the number of CPUs in the system. + pub fn ax_get_cpu_num() -> usize; } } diff --git a/api/arceos_posix_api/src/imp/sys.rs b/api/arceos_posix_api/src/imp/sys.rs index 4407fdba14..de1b23362a 100644 --- a/api/arceos_posix_api/src/imp/sys.rs +++ b/api/arceos_posix_api/src/imp/sys.rs @@ -15,7 +15,7 @@ pub fn sys_sysconf(name: c_int) -> c_long { // Page size ctypes::_SC_PAGE_SIZE => Ok(PAGE_SIZE_4K), // Number of processors in use - ctypes::_SC_NPROCESSORS_ONLN => Ok(axconfig::plat::CPU_NUM), + ctypes::_SC_NPROCESSORS_ONLN => Ok(axhal::cpu_num()), // Total physical pages ctypes::_SC_PHYS_PAGES => Ok(axhal::mem::total_ram_size() / PAGE_SIZE_4K), // Avaliable physical pages diff --git a/configs/custom/x86_64-pc-oslab.toml b/configs/custom/x86_64-pc-oslab.toml index 51e4f5734b..d218baf35e 100644 --- a/configs/custom/x86_64-pc-oslab.toml +++ b/configs/custom/x86_64-pc-oslab.toml @@ -9,8 +9,9 @@ package = "axplat-x86-pc" # str # Platform configs # [plat] -# Number of CPUs. -cpu-num = 8 # uint +# Maximum number of CPUs. For platforms that do not support runtime CPU number +# detection, it's also the number of CPUs to boot (like this platform). +max-cpu-num = 8 # uint # Base address of the whole physical memory. phys-memory-base = 0 # uint # Size of the whole physical memory. (2G) diff --git a/configs/dummy.toml b/configs/dummy.toml index 877836f9f9..aee052089b 100644 --- a/configs/dummy.toml +++ b/configs/dummy.toml @@ -15,8 +15,9 @@ ticks-per-sec = 100 # uint # [plat] # Platform family. -# Number of CPUs -cpu-num = 1 # uint +# Maximum number of CPUs. For platforms that do not support runtime CPU number +# detection, it's also the number of CPUs to boot. +max-cpu-num = 1 # uint # Base address of the whole physical memory. phys-memory-base = 0 # uint # Size of the whole physical memory. diff --git a/examples/helloworld-myplat/Cargo.toml b/examples/helloworld-myplat/Cargo.toml index 2fa9c1fc77..c835011ced 100644 --- a/examples/helloworld-myplat/Cargo.toml +++ b/examples/helloworld-myplat/Cargo.toml @@ -18,16 +18,16 @@ cfg-if = "1.0" axstd = { workspace = true, features = ["myplat"], optional = true } [target.'cfg(target_arch = "x86_64")'.dependencies] -axplat-x86-pc = { version = "0.2", features = ["smp", "irq"], optional = true } +axplat-x86-pc = { version = "0.3", features = ["smp", "irq"], optional = true } [target.'cfg(target_arch = "aarch64")'.dependencies] -axplat-aarch64-qemu-virt = { version = "0.2", features = ["smp", "irq"], optional = true } -axplat-aarch64-raspi = { version = "0.2", features = ["smp", "irq"], optional = true } -axplat-aarch64-bsta1000b = { version = "0.2", features = ["smp", "irq"], optional = true } -axplat-aarch64-phytium-pi = { version = "0.2", features = ["smp", "irq"], optional = true } +axplat-aarch64-qemu-virt = { version = "0.3", features = ["smp", "irq"], optional = true } +axplat-aarch64-raspi = { version = "0.3", features = ["smp", "irq"], optional = true } +axplat-aarch64-bsta1000b = { version = "0.3", features = ["smp", "irq"], optional = true } +axplat-aarch64-phytium-pi = { version = "0.3", features = ["smp", "irq"], optional = true } [target.'cfg(target_arch = "riscv64")'.dependencies] -axplat-riscv64-qemu-virt = { version = "0.2", features = ["smp", "irq"], optional = true } +axplat-riscv64-qemu-virt = { version = "0.3", features = ["smp", "irq"], optional = true } [target.'cfg(target_arch = "loongarch64")'.dependencies] -axplat-loongarch64-qemu-virt = { version = "0.2", features = ["smp", "irq"], optional = true } \ No newline at end of file +axplat-loongarch64-qemu-virt = { version = "0.3", features = ["smp", "irq"], optional = true } \ No newline at end of file diff --git a/modules/axhal/Cargo.toml b/modules/axhal/Cargo.toml index 3b99de2e5d..bfdd8b4e92 100644 --- a/modules/axhal/Cargo.toml +++ b/modules/axhal/Cargo.toml @@ -36,23 +36,23 @@ memory_addr = "0.4" linkme = { version = "0.3.33", optional = true } page_table_multiarch = { version = "0.5", features = ["copy-from"], optional = true } axcpu = "0.2" -axplat = "0.2" +axplat = "0.3" axlog = { workspace = true } axconfig = { workspace = true } axalloc = { workspace = true, optional = true } [target.'cfg(target_arch = "x86_64")'.dependencies] -axplat-x86-pc = { version = "0.2", optional = true } +axplat-x86-pc = { version = "0.3", optional = true } [target.'cfg(target_arch = "aarch64")'.dependencies] aarch64-cpu = "10.0" -axplat-aarch64-qemu-virt = { version = "0.2", optional = true } +axplat-aarch64-qemu-virt = { version = "0.3", optional = true } [target.'cfg(target_arch = "riscv64")'.dependencies] -axplat-riscv64-qemu-virt = { version = "0.2", optional = true } +axplat-riscv64-qemu-virt = { version = "0.3", optional = true } [target.'cfg(target_arch = "loongarch64")'.dependencies] -axplat-loongarch64-qemu-virt = { version = "0.2", optional = true } +axplat-loongarch64-qemu-virt = { version = "0.3", optional = true } [build-dependencies] axconfig = { workspace = true } diff --git a/modules/axhal/build.rs b/modules/axhal/build.rs index 9c6037f382..be7002f358 100644 --- a/modules/axhal/build.rs +++ b/modules/axhal/build.rs @@ -24,7 +24,7 @@ fn gen_linker_script(arch: &str, platform: &str) -> Result<()> { "%KERNEL_BASE%", &format!("{:#x}", axconfig::plat::KERNEL_BASE_VADDR), ); - let ld_content = ld_content.replace("%CPU_NUM%", &format!("{}", axconfig::plat::CPU_NUM)); + let ld_content = ld_content.replace("%CPU_NUM%", &format!("{}", axconfig::plat::MAX_CPU_NUM)); // target///build/axhal-xxxx/out let out_dir = std::env::var("OUT_DIR").unwrap(); diff --git a/modules/axhal/src/dummy.rs b/modules/axhal/src/dummy.rs index 033b4c4408..8dccc072dd 100644 --- a/modules/axhal/src/dummy.rs +++ b/modules/axhal/src/dummy.rs @@ -95,6 +95,10 @@ impl PowerIf for DummyPower { fn system_off() -> ! { unimplemented!() } + + fn cpu_num() -> usize { + 1 + } } #[cfg(feature = "irq")] diff --git a/modules/axhal/src/lib.rs b/modules/axhal/src/lib.rs index 85b23bbf53..2b200437b8 100644 --- a/modules/axhal/src/lib.rs +++ b/modules/axhal/src/lib.rs @@ -34,6 +34,10 @@ #[macro_use] extern crate log; +#[allow(unused_imports)] +#[macro_use] +extern crate axlog; + #[allow(unused_imports)] #[macro_use] extern crate memory_addr; @@ -103,10 +107,11 @@ pub mod context { } pub use axcpu::asm; -pub use axplat::init::init_later; #[cfg(feature = "smp")] pub use axplat::init::{init_early_secondary, init_later_secondary}; +#[cfg(feature = "smp")] +use core::sync::atomic::{AtomicUsize, Ordering}; /// Initializes CPU-local data structures for the primary core. /// @@ -125,10 +130,6 @@ pub fn init_percpu_secondary(cpu_id: usize) { self::percpu::init_secondary(cpu_id); } -use lazyinit::LazyInit; - -static BOOT_ARG: LazyInit = LazyInit::new(); - /// Initializes the platform and boot argument. /// This function should be called as early as possible. pub fn init_early(cpu_id: usize, arg: usize) { @@ -136,8 +137,78 @@ pub fn init_early(cpu_id: usize, arg: usize) { axplat::init::init_early(cpu_id, arg); } +/// Initializes the platform later stage. +pub fn init_later(cpu_id: usize, arg: usize) { + axplat::init::init_later(cpu_id, arg); + init_cpu_num(); +} + +use lazyinit::LazyInit; + +static BOOT_ARG: LazyInit = LazyInit::new(); + /// Returns the boot argument. /// This is typically the device tree blob address passed from the bootloader. pub fn get_bootarg() -> usize { *BOOT_ARG } + +/// The number of CPUs in the system. Based on the number declared by the +/// platform crate and limited by the configured maximum CPU number. +#[cfg(feature = "smp")] +static CPU_NUM: AtomicUsize = AtomicUsize::new(1); + +/// Gets the number of CPUs running in the system. +/// +/// When SMP is disabled, this function always returns 1. +/// +/// When SMP is enabled, it's the smaller one between the platform-declared CPU +/// number [`axplat::power::cpu_num`] and the configured maximum CPU number +/// `axconfig::plat::MAX_CPU_NUM`. +/// +/// This value is determined during the BSP initialization phase. +pub fn cpu_num() -> usize { + #[cfg(feature = "smp")] + { + // The BSP will always see the correct value because `CPU_NUM` is set by + // itself. + // + // All APs will see the correct value because it is written with + // `Ordering::Release` and read with `Ordering::Acquire`, ensuring + // memory visibility. + // + // Acquire may result in a performance penalty, but this function is not + // expected to be called frequently in normal operation. + CPU_NUM.load(Ordering::Acquire) + } + #[cfg(not(feature = "smp"))] + { + 1 + } +} + +/// Initializes the CPU number information. +fn init_cpu_num() { + #[cfg(feature = "smp")] + { + let plat_cpu_num = axplat::power::cpu_num(); + let max_cpu_num = axconfig::plat::MAX_CPU_NUM; + let cpu_num = plat_cpu_num.min(max_cpu_num); + + info!("CPU number: max = {max_cpu_num}, platform = {plat_cpu_num}, use = {cpu_num}",); + ax_println!("smp = {}", cpu_num); // for test purposes + + if plat_cpu_num > max_cpu_num { + warn!( + "platform declares more CPUs ({plat_cpu_num}) than configured max ({max_cpu_num}), \ + only the first {max_cpu_num} CPUs will be used." + ); + } + + CPU_NUM.store(cpu_num, Ordering::Release); + } + #[cfg(not(feature = "smp"))] + { + ax_println!("smp = 1"); // for test purposes + } +} diff --git a/modules/axipi/src/lib.rs b/modules/axipi/src/lib.rs index a4bc3ec983..bb6bf42910 100644 --- a/modules/axipi/src/lib.rs +++ b/modules/axipi/src/lib.rs @@ -45,7 +45,7 @@ pub fn run_on_cpu>(dest_cpu: usize, callback: T) { pub fn run_on_each_cpu>(callback: T) { info!("Send IPI event to all other CPUs"); let current_cpu_id = this_cpu_id(); - let cpu_num = axconfig::plat::CPU_NUM; + let cpu_num = axhal::cpu_num(); let callback = callback.into(); // Execute callback on current CPU immediately diff --git a/modules/axruntime/Cargo.toml b/modules/axruntime/Cargo.toml index 13abbb59e4..53f96e967b 100644 --- a/modules/axruntime/Cargo.toml +++ b/modules/axruntime/Cargo.toml @@ -37,7 +37,7 @@ axnet = { workspace = true, optional = true } axdisplay = { workspace = true, optional = true } axtask = { workspace = true, optional = true } axipi = { workspace = true, optional = true } -axplat = "0.2" +axplat = "0.3" crate_interface = "0.1" percpu = { version = "0.2", optional = true } diff --git a/modules/axruntime/src/lib.rs b/modules/axruntime/src/lib.rs index 2a46bd4f0c..3f9a6b9b30 100644 --- a/modules/axruntime/src/lib.rs +++ b/modules/axruntime/src/lib.rs @@ -86,10 +86,11 @@ impl axlog::LogIf for LogIfImpl { use core::sync::atomic::{AtomicUsize, Ordering}; +/// Number of CPUs that have completed initialization. static INITED_CPUS: AtomicUsize = AtomicUsize::new(0); fn is_init_ok() -> bool { - INITED_CPUS.load(Ordering::Acquire) == axconfig::plat::CPU_NUM + INITED_CPUS.load(Ordering::Acquire) == axhal::cpu_num() } /// The main entry point of the ArceOS runtime. @@ -116,14 +117,12 @@ pub fn rust_main(cpu_id: usize, arg: usize) -> ! { target = {}\n\ build_mode = {}\n\ log_level = {}\n\ - smp = {}\n\ ", axconfig::ARCH, axconfig::PLATFORM, option_env!("AX_TARGET").unwrap_or(""), option_env!("AX_MODE").unwrap_or(""), option_env!("AX_LOG").unwrap_or(""), - axconfig::plat::CPU_NUM, ); #[cfg(feature = "rtc")] ax_println!( diff --git a/modules/axruntime/src/mp.rs b/modules/axruntime/src/mp.rs index 464cfd7326..a1346a690d 100644 --- a/modules/axruntime/src/mp.rs +++ b/modules/axruntime/src/mp.rs @@ -1,19 +1,20 @@ use core::sync::atomic::{AtomicUsize, Ordering}; -use axconfig::{TASK_STACK_SIZE, plat::CPU_NUM}; +use axconfig::{TASK_STACK_SIZE, plat::MAX_CPU_NUM}; use axhal::mem::{VirtAddr, virt_to_phys}; #[unsafe(link_section = ".bss.stack")] -static mut SECONDARY_BOOT_STACK: [[u8; TASK_STACK_SIZE]; CPU_NUM - 1] = - [[0; TASK_STACK_SIZE]; CPU_NUM - 1]; +static mut SECONDARY_BOOT_STACK: [[u8; TASK_STACK_SIZE]; MAX_CPU_NUM - 1] = + [[0; TASK_STACK_SIZE]; MAX_CPU_NUM - 1]; static ENTERED_CPUS: AtomicUsize = AtomicUsize::new(1); #[allow(clippy::absurd_extreme_comparisons)] pub fn start_secondary_cpus(primary_cpu_id: usize) { let mut logic_cpu_id = 0; - for i in 0..CPU_NUM { - if i != primary_cpu_id && logic_cpu_id < CPU_NUM - 1 { + let cpu_num = axhal::cpu_num(); + for i in 0..cpu_num { + if i != primary_cpu_id && logic_cpu_id < cpu_num - 1 { let stack_top = virt_to_phys(VirtAddr::from(unsafe { SECONDARY_BOOT_STACK[logic_cpu_id].as_ptr_range().end as usize })); diff --git a/modules/axtask/Cargo.toml b/modules/axtask/Cargo.toml index 138519e0cc..a68cc3a169 100644 --- a/modules/axtask/Cargo.toml +++ b/modules/axtask/Cargo.toml @@ -16,7 +16,6 @@ multitask = [ "dep:axconfig", "dep:percpu", "dep:kspin", - "dep:lazyinit", "dep:memory_addr", "dep:axsched", "dep:timer_list", @@ -42,7 +41,7 @@ axhal = { workspace = true } axconfig = { workspace = true, optional = true } percpu = { version = "0.2", optional = true } kspin = { version = "0.1", optional = true } -lazyinit = { version = "0.2", optional = true } +lazyinit = { version = "0.2" } memory_addr = { version = "0.4", optional = true } timer_list = { version = "0.1", optional = true } kernel_guard = { version = "0.1", optional = true } diff --git a/modules/axtask/src/api.rs b/modules/axtask/src/api.rs index 1e3fdca726..80f1d8dcfb 100644 --- a/modules/axtask/src/api.rs +++ b/modules/axtask/src/api.rs @@ -17,7 +17,7 @@ pub use crate::wait_queue::WaitQueue; pub type AxTaskRef = Arc; /// The wrapper type for [`cpumask::CpuMask`] with SMP configuration. -pub type AxCpuMask = cpumask::CpuMask<{ axconfig::plat::CPU_NUM }>; +pub type AxCpuMask = cpumask::CpuMask<{ axconfig::plat::MAX_CPU_NUM }>; cfg_if::cfg_if! { if #[cfg(feature = "sched-rr")] { @@ -72,6 +72,10 @@ pub fn current() -> CurrentTask { pub fn init_scheduler() { info!("Initialize scheduling..."); + // Initialize the cpu count information. + init_cpu_mask_full(); + + // Initialize the run queue. crate::run_queue::init(); #[cfg(feature = "irq")] crate::timers::init(); @@ -79,6 +83,27 @@ pub fn init_scheduler() { info!(" use {} scheduler.", Scheduler::scheduler_name()); } +/// The full CPU mask of the system. +static CPU_MASK_FULL: lazyinit::LazyInit = lazyinit::LazyInit::new(); + +/// Gets the cpu count information and initializes related data structures. +fn init_cpu_mask_full() { + let cpu_num = axhal::cpu_num(); + let mut cpumask = AxCpuMask::new(); + for cpu_id in 0..cpu_num { + cpumask.set(cpu_id, true); + } + + CPU_MASK_FULL.call_once(|| cpumask); +} + +pub(crate) fn cpu_mask_full() -> AxCpuMask { + CPU_MASK_FULL + .get() + .expect("CPU mask not initialized") + .clone() +} + /// Initializes the task scheduler for secondary CPUs. pub fn init_scheduler_secondary() { crate::run_queue::init_secondary(); diff --git a/modules/axtask/src/run_queue.rs b/modules/axtask/src/run_queue.rs index a907b4a2a9..d19452ab40 100644 --- a/modules/axtask/src/run_queue.rs +++ b/modules/axtask/src/run_queue.rs @@ -48,8 +48,8 @@ percpu_static! { /// Access to this variable is marked as `unsafe` because it contains `MaybeUninit` references, /// which require careful handling to avoid undefined behavior. The array should be fully /// initialized before being accessed to ensure safe usage. -static mut RUN_QUEUES: [MaybeUninit<&'static mut AxRunQueue>; axconfig::plat::CPU_NUM] = - [ARRAY_REPEAT_VALUE; axconfig::plat::CPU_NUM]; +static mut RUN_QUEUES: [MaybeUninit<&'static mut AxRunQueue>; axconfig::plat::MAX_CPU_NUM] = + [ARRAY_REPEAT_VALUE; axconfig::plat::MAX_CPU_NUM]; #[allow(clippy::declare_interior_mutable_const)] // It's ok because it's used only for initialization `RUN_QUEUES`. const ARRAY_REPEAT_VALUE: MaybeUninit<&'static mut AxRunQueue> = MaybeUninit::uninit(); @@ -94,7 +94,8 @@ pub(crate) fn current_run_queue() -> CurrentRunQueueRef<'static, G /// This function will panic if `cpu_mask` is empty, indicating that there are no available CPUs for task execution. /// #[cfg(feature = "smp")] -// The modulo operation is safe here because `axconfig::plat::CPU_NUM` is always greater than 1 with "smp" enabled. +// The modulo operation is safe here because `axhal::cpu_num()` is expected to be greater than 1 in SMP mode. +// If not, index selection logic would not be meaningful. #[allow(clippy::modulo_one)] #[inline] fn select_run_queue_index(cpumask: AxCpuMask) -> usize { @@ -104,8 +105,9 @@ fn select_run_queue_index(cpumask: AxCpuMask) -> usize { assert!(!cpumask.is_empty(), "No available CPU for task execution"); // Round-robin selection of the run queue index. + let cpu_num = axhal::cpu_num(); loop { - let index = RUN_QUEUE_INDEX.fetch_add(1, Ordering::SeqCst) % axconfig::plat::CPU_NUM; + let index = RUN_QUEUE_INDEX.fetch_add(1, Ordering::SeqCst) % cpu_num; if cpumask.get(index) { return index; } diff --git a/modules/axtask/src/task.rs b/modules/axtask/src/task.rs index 603717bfd9..403488012a 100644 --- a/modules/axtask/src/task.rs +++ b/modules/axtask/src/task.rs @@ -224,6 +224,8 @@ impl TaskInner { // private methods impl TaskInner { fn new_common(id: TaskId, name: String) -> Self { + let cpumask = crate::api::cpu_mask_full(); + Self { id, name, @@ -232,7 +234,7 @@ impl TaskInner { entry: None, state: AtomicU8::new(TaskState::Ready as u8), // By default, the task is allowed to run on all CPUs. - cpumask: SpinNoIrq::new(AxCpuMask::full()), + cpumask: SpinNoIrq::new(cpumask), in_wait_queue: AtomicBool::new(false), #[cfg(feature = "irq")] timer_ticket_id: AtomicU64::new(0), diff --git a/scripts/make/config.mk b/scripts/make/config.mk index 02d69a99ea..f780a4f27d 100644 --- a/scripts/make/config.mk +++ b/scripts/make/config.mk @@ -7,11 +7,12 @@ config_args := \ -o "$(OUT_CONFIG)" ifneq ($(SMP),) - config_args += -w 'plat.cpu-num=$(SMP)' + config_args += -w 'plat.max-cpu-num=$(SMP)' else - SMP := $(shell axconfig-gen $(PLAT_CONFIG) -r plat.cpu-num 2>/dev/null) + SMP := $(shell axconfig-gen $(PLAT_CONFIG) -r plat.max-cpu-num 2>/dev/null) ifeq ($(SMP),) - $(error "`plat.cpu-num` is not defined in the platform configuration file") + $(error "`plat.max-cpu-num` is not defined in the platform configuration file, \ + this option must be specified even for platforms with runtime CPU detection.") endif endif diff --git a/ulib/axstd/src/thread/mod.rs b/ulib/axstd/src/thread/mod.rs index 996a2094ad..cba228bd31 100644 --- a/ulib/axstd/src/thread/mod.rs +++ b/ulib/axstd/src/thread/mod.rs @@ -46,6 +46,6 @@ pub fn sleep_until(deadline: arceos_api::time::AxTimeValue) { /// Here we directly return the number of available logical CPUs, representing /// the theoretical maximum parallelism. pub fn available_parallelism() -> crate::io::Result> { - NonZero::new(arceos_api::modules::axconfig::plat::CPU_NUM) + NonZero::new(arceos_api::sys::ax_get_cpu_num()) .ok_or_else(|| panic!("No available CPUs found, cannot determine parallelism")) }