Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion os/src/arch/arch_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ macro_rules! impl_arch {
}

fn cpu_count() -> usize {
unsafe { $crate::kernel::NUM_CPU }
$crate::kernel::num_cpu()
}
}

Expand Down
11 changes: 6 additions & 5 deletions os/src/arch/loongarch/trap/trap_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use crate::arch::trap::restore;
use crate::ipc::check_signal;
use crate::kernel::syscall::dispatch::dispatch_syscall;
use crate::kernel::{TIMER, TIMER_QUEUE, schedule, send_signal_process, wake_up_task};
use crate::sync::SpinLock;

use super::TrapFrame;

Expand All @@ -22,8 +23,7 @@ macro_rules! emergency_println {
}

/// 仅在单核环境下使用的默认 TrapFrame;后续可由调度器替换为 per-CPU/任务帧
#[unsafe(no_mangle)]
pub static mut BOOT_TRAP_FRAME: TrapFrame = TrapFrame::empty();
pub static BOOT_TRAP_FRAME: SpinLock<TrapFrame> = SpinLock::new(TrapFrame::empty());

static FIRST_TRAP_LOGGED: AtomicBool = AtomicBool::new(false);
static FIRST_USER_TIMER_LOGGED: AtomicBool = AtomicBool::new(false);
Expand Down Expand Up @@ -98,16 +98,17 @@ pub(super) fn install_runtime_trap() {
fn install_trap_entry() {
// 将 TrapFrame 指针写入 KScratch0,并设置 EENTRY 指向 trap_entry
unsafe {
let mut boot_trap_frame = BOOT_TRAP_FRAME.lock();
// 设置内核栈指针用于用户态陷阱的栈切换
let sp: usize;
core::arch::asm!("addi.d {0}, $sp, 0", out(reg) sp, options(nostack, preserves_flags));
BOOT_TRAP_FRAME.kernel_sp = sp;
BOOT_TRAP_FRAME.cpu_ptr = crate::kernel::current_cpu() as *const _ as usize;
boot_trap_frame.kernel_sp = sp;
boot_trap_frame.cpu_ptr = crate::kernel::current_cpu() as *const _ as usize;

// KScratch0 <- TrapFrame 指针
core::arch::asm!(
"csrwr {0}, 0x30",
in(reg) (&raw mut BOOT_TRAP_FRAME as *mut TrapFrame as usize),
in(reg) (&mut *boot_trap_frame as *mut TrapFrame as usize),
options(nostack, preserves_flags)
);
Comment on lines +101 to 113

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-critical critical

Wrapping BOOT_TRAP_FRAME in a SpinLock is fundamentally unsafe because the lock is released when install_trap_entry returns, but the raw pointer to the inner TrapFrame is stored in KScratch0 and will be accessed asynchronously by the hardware/trap handler. To maintain consistency with the RISC-V architecture implementation, avoid using a temporary SpinLock here and instead manage the static lifetime safely as done in the RISC-V trap handler.

References
  1. Prioritize consistency with existing architecture implementations (like RISC-V) when adding support for a new architecture (like LoongArch).

// EENTRY <- trap_entry(注意 CSR 编号为 0xc)
Expand Down
20 changes: 10 additions & 10 deletions os/src/arch/riscv/boot/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ global_asm!(include_str!("entry.S"));
use crate::mm::address::UsizeConvert;
use crate::{
arch::{timer, trap},
kernel::{self, NUM_CPU, current_cpu},
kernel::{self, current_cpu, num_cpu, set_num_cpu},
pr_debug, pr_err, pr_info, pr_warn,
sync::PreemptGuard,
};
Expand All @@ -18,7 +18,7 @@ static CPU_ONLINE_MASK: AtomicUsize = AtomicUsize::new(0);

// 从核启动标志(在 entry.S 中定义)
unsafe extern "C" {
static mut secondary_boot_flag: u64;
static mut secondary_boot_flag: u64; // extern symbol from entry.S
}

/// 从核调试入口
Expand Down Expand Up @@ -57,7 +57,7 @@ fn setup_boot_cpu(_hartid: usize) {
}

fn boot_secondaries(_hartid: usize) {
let num_cpus = unsafe { NUM_CPU };
let num_cpus = num_cpu();
if num_cpus > 1 {
boot_secondary_cpus(num_cpus);
}
Expand Down Expand Up @@ -131,7 +131,7 @@ pub fn boot_secondary_cpus(num_cpus: usize) {
if num_cpus <= 1 {
pr_info!("[SMP] Single CPU mode, skipping secondary boot");
CPU_ONLINE_MASK.fetch_or(1, Ordering::Release);
unsafe { NUM_CPU = 1 };
set_num_cpu(1);
return;
}

Expand Down Expand Up @@ -167,7 +167,7 @@ pub fn boot_secondary_cpus(num_cpus: usize) {

if expected_mask == 1 {
pr_warn!("[SMP] No secondary hart could be started; falling back to single-core");
unsafe { NUM_CPU = 1 };
set_num_cpu(1);
return;
}

Expand All @@ -187,14 +187,14 @@ pub fn boot_secondary_cpus(num_cpus: usize) {

let online_mask = CPU_ONLINE_MASK.load(Ordering::Acquire);
let online_cnt = online_mask.count_ones() as usize;
unsafe { NUM_CPU = core::cmp::max(online_cnt, 1) };
set_num_cpu(core::cmp::max(online_cnt, 1));

if online_mask == expected_mask {
pr_info!("[SMP] All {} CPUs are online!", unsafe { NUM_CPU });
pr_info!("[SMP] All {} CPUs are online!", num_cpu());
} else {
pr_warn!(
"[SMP] Proceeding with {} online CPU(s), mask={:#b}",
unsafe { NUM_CPU },
num_cpu(),
online_mask
);
}
Expand All @@ -206,13 +206,13 @@ mod tests {
use crate::{kassert, test_case};

test_case!(test_num_cpu, {
let num_cpu = unsafe { crate::kernel::NUM_CPU };
let num_cpu = crate::kernel::num_cpu();
kassert!(num_cpu >= 1);
kassert!(num_cpu <= crate::config::MAX_CPU_COUNT);
});

test_case!(test_cpu_online_mask, {
let num_cpu = unsafe { crate::kernel::NUM_CPU };
let num_cpu = crate::kernel::num_cpu();
let actual_mask = CPU_ONLINE_MASK.load(Ordering::Acquire);

if actual_mask == 0 {
Expand Down
6 changes: 3 additions & 3 deletions os/src/arch/riscv/ipi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ static IPI_PENDING: [AtomicU32; MAX_CPU_COUNT] = [const { AtomicU32::new(0) }; M
///
/// 如果 target_cpu >= NUM_CPU,会 panic
pub fn send_ipi(target_cpu: usize, ipi_type: IpiType) {
let num_cpu = unsafe { crate::kernel::NUM_CPU };
let num_cpu = crate::kernel::num_cpu();
assert!(target_cpu < num_cpu, "Invalid target CPU: {}", target_cpu);

// 1. 设置目标 CPU 的待处理标志
Expand Down Expand Up @@ -78,7 +78,7 @@ pub fn send_ipi(target_cpu: usize, ipi_type: IpiType) {
/// - hart_mask: hart 位掩码,每位代表一个 CPU
/// - ipi_type: IPI 类型
pub fn send_ipi_many(hart_mask: usize, ipi_type: IpiType) {
let num_cpu = unsafe { crate::kernel::NUM_CPU };
let num_cpu = crate::kernel::num_cpu();

// 设置所有目标 CPU 的待处理标志
for (cpu, pending) in IPI_PENDING.iter().enumerate().take(num_cpu) {
Expand Down Expand Up @@ -106,7 +106,7 @@ pub fn send_reschedule_ipi(cpu: usize) {
/// 通知所有其他 CPU 刷新 TLB
pub fn send_tlb_flush_ipi_all() {
let current_cpu_id = super::kernel::cpu::cpu_id();
let num_cpu = unsafe { crate::kernel::NUM_CPU };
let num_cpu = crate::kernel::num_cpu();
let mask = ((1 << num_cpu) - 1) & !(1 << current_cpu_id);

if mask != 0 {
Expand Down
10 changes: 5 additions & 5 deletions os/src/arch/riscv/mm/page_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ impl PageTableInner {
// 2. 通知所有其他 CPU 刷新 TLB
// send_tlb_flush_ipi_all 内部会检查是否为多核环境
// 单核环境下不会发送 IPI
let num_cpu = unsafe { crate::kernel::NUM_CPU };
let num_cpu = crate::kernel::num_cpu();
if num_cpu > 1 {
send_tlb_flush_ipi_all();
}
Expand All @@ -413,7 +413,7 @@ impl PageTableInner {
<Self as PageTableInnerTrait<PageTableEntry>>::tlb_flush(vpn);
// 只有在非批处理模式下才发送 IPI
if batch.is_none() {
let num_cpu = unsafe { crate::kernel::NUM_CPU };
let num_cpu = crate::kernel::num_cpu();
if num_cpu > 1 {
send_tlb_flush_ipi_all();
}
Expand All @@ -432,7 +432,7 @@ impl PageTableInner {
<Self as PageTableInnerTrait<PageTableEntry>>::tlb_flush(vpn);
// 只有在非批处理模式下才发送 IPI
if batch.is_none() {
let num_cpu = unsafe { crate::kernel::NUM_CPU };
let num_cpu = crate::kernel::num_cpu();
if num_cpu > 1 {
send_tlb_flush_ipi_all();
}
Expand All @@ -452,7 +452,7 @@ impl PageTableInner {
<Self as PageTableInnerTrait<PageTableEntry>>::tlb_flush(vpn);
// 只有在非批处理模式下才发送 IPI
if batch.is_none() {
let num_cpu = unsafe { crate::kernel::NUM_CPU };
let num_cpu = crate::kernel::num_cpu();
if num_cpu > 1 {
send_tlb_flush_ipi_all();
}
Expand Down Expand Up @@ -493,7 +493,7 @@ impl TlbBatchContext {
core::arch::asm!("sfence.vma");
}
// 发送一次 IPI 到所有其他 CPU
let num_cpu = unsafe { crate::kernel::NUM_CPU };
let num_cpu = crate::kernel::num_cpu();
if num_cpu > 1 {
send_tlb_flush_ipi_all();
}
Expand Down
5 changes: 2 additions & 3 deletions os/src/arch/riscv/timer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//! 包含定时器初始化、时间获取和定时器中断设置等功能
use core::sync::atomic::{AtomicUsize, Ordering};

use crate::{arch::lib::set_timer, kernel::CLOCK_FREQ};
use crate::{arch::lib::set_timer, kernel};
use riscv::register::time;

/// 每秒的时钟中断次数
Expand Down Expand Up @@ -50,8 +50,7 @@ pub fn init() {
/// 获取时钟频率
#[inline]
pub fn clock_freq() -> usize {
// SAFETY: CLOCK_FREQ 在内核初始化阶段被正确设置且之后不会更改
unsafe { CLOCK_FREQ }
kernel::clock_freq()
}

#[cfg(test)]
Expand Down
18 changes: 8 additions & 10 deletions os/src/device/device_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,25 @@

use crate::{
device::{CMDLINE, irq::IntcDriver},
kernel::{CLOCK_FREQ, NUM_CPU},
kernel::{clock_freq, num_cpu, set_clock_freq, set_num_cpu},
mm::address::{ConvertablePA, PA},
pr_info, pr_warn,
sync::SpinLock,
};
use alloc::{collections::btree_map::BTreeMap, string::String, sync::Arc};
use core::sync::atomic::{AtomicUsize, Ordering};
use fdt::{Fdt, node::FdtNode};
/// 指向设备树的指针,在启动时由引导程序设置
#[unsafe(no_mangle)]
pub static mut DTP: usize = 0x114514; // 占位地址,实际由引导程序设置
pub static DTP: AtomicUsize = AtomicUsize::new(0x114514); // 占位地址,实际由引导程序设置

lazy_static::lazy_static! {
/// 设备树
/// 通过 DTP 指针解析得到
/// XXX: 是否需要这个?
pub static ref FDT: Fdt<'static> = {
unsafe {
let addr = PA::to_va(&PA::from_usize(DTP));
let addr = PA::to_va(&PA::from_usize(DTP.load(Ordering::Acquire)));
fdt::Fdt::from_ptr(addr.as_usize() as *mut u8).expect("Failed to parse device tree")
}
};
Expand All @@ -42,8 +43,7 @@ lazy_static::lazy_static! {
/// 此函数在堆分配器初始化之前调用,因此不能使用任何需要堆分配的操作。
pub fn early_init() {
let cpus = FDT.cpus().count();
// SAFETY: 这里是在单核初始化阶段设置 CPU 数量
unsafe { NUM_CPU = cpus };
set_num_cpu(cpus);

if let Some(cpu) = FDT.cpus().next() {
let timebase = cpu
Expand All @@ -55,9 +55,7 @@ pub fn early_init() {
_ => None,
});
if let Some(freq) = timebase {
unsafe {
CLOCK_FREQ = freq;
}
set_clock_freq(freq);
} else {
pr_warn!("[Device] No timebase-frequency in DTB, keeping default");
}
Expand All @@ -78,8 +76,8 @@ pub fn init() {

// 设置 NUM_CPU 和 CLOCK_FREQ
early_init();
pr_info!("[Device] now has {} CPU(s)", unsafe { NUM_CPU });
pr_info!("[Device] CLOCK_FREQ set to {} Hz", unsafe { CLOCK_FREQ });
pr_info!("[Device] now has {} CPU(s)", num_cpu());
pr_info!("[Device] CLOCK_FREQ set to {} Hz", clock_freq());

FDT.memory().regions().for_each(|region| {
pr_info!(
Expand Down
41 changes: 32 additions & 9 deletions os/src/kernel/cpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
//!
//! 包含 CPU 结构体及其相关操作
use alloc::sync::Arc;
use core::sync::atomic::{AtomicUsize, Ordering};

use crate::mm::activate;
use crate::{
Expand All @@ -11,8 +12,28 @@ use crate::{
};
use lazy_static::lazy_static;

pub static mut NUM_CPU: usize = 1;
pub static mut CLOCK_FREQ: usize = 12_500_000;
pub static NUM_CPU: AtomicUsize = AtomicUsize::new(1);
pub static CLOCK_FREQ: AtomicUsize = AtomicUsize::new(12_500_000);

#[inline]
pub fn num_cpu() -> usize {
NUM_CPU.load(Ordering::Acquire)
}

#[inline]
pub fn set_num_cpu(num_cpu: usize) {
NUM_CPU.store(num_cpu, Ordering::Release);
}

#[inline]
pub fn clock_freq() -> usize {
CLOCK_FREQ.load(Ordering::Acquire)
}

#[inline]
pub fn set_clock_freq(clock_freq: usize) {
CLOCK_FREQ.store(clock_freq, Ordering::Release);
}

lazy_static! {
/// Per-CPU 数据: 每个 CPU 的状态
Expand Down Expand Up @@ -103,7 +124,9 @@ impl Cpu {
///
/// 调用者必须确保在访问期间禁用抢占 (防止任务迁移到其他 CPU)。
#[inline]
pub fn current_cpu() -> &'static mut Cpu {
#[rustfmt::skip]
pub fn current_cpu() -> &'static
mut Cpu {
Comment on lines +127 to +129

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The return type of current_cpu is split across lines (-> &'static mut Cpu) and annotated with #[rustfmt::skip]. This is highly unidiomatic and reduces code readability. Reformat it to a single line and remove #[rustfmt::skip].

pub fn current_cpu() -> &'static mut Cpu {

CPUS.get_mut()
}

Expand All @@ -122,7 +145,7 @@ mod tests {

/// 测试 CPUS 初始化
test_case!(test_cpus_initialization, {
let num_cpu = unsafe { NUM_CPU };
let num_cpu = num_cpu();
for cpu_id in 0..num_cpu {
let cpu = CPUS.get_of(cpu_id);
kassert!(cpu.cpu_id == cpu_id);
Expand All @@ -135,7 +158,7 @@ mod tests {

let _guard = PreemptGuard::new();
let id = crate::arch::cpu_id();
kassert!(id < unsafe { NUM_CPU });
kassert!(id < num_cpu());
});

/// 测试 current_cpu() 函数
Expand All @@ -144,15 +167,15 @@ mod tests {

let _guard = PreemptGuard::new();
let cpu = current_cpu();
kassert!(cpu.cpu_id < unsafe { NUM_CPU });
kassert!(cpu.cpu_id < num_cpu());
});

/// 测试 cpu_of() 函数
test_case!(test_cpu_of, {
let cpu0 = cpu_of(0);
kassert!(cpu0.cpu_id == 0);

let num_cpu = unsafe { NUM_CPU };
let num_cpu = num_cpu();
if num_cpu > 1 {
let cpu1 = cpu_of(1);
kassert!(cpu1.cpu_id == 1);
Expand Down Expand Up @@ -181,7 +204,7 @@ mod tests {
}

// 验证其他 CPU 的值仍然是初始值
let num_cpu = unsafe { NUM_CPU };
let num_cpu = num_cpu();
let current_id = {
let _guard = PreemptGuard::new();
crate::arch::cpu_id()
Expand All @@ -201,7 +224,7 @@ mod tests {

let per_cpu: PerCpu<usize> = PerCpu::new_with_id(|cpu_id| cpu_id * 10);

let num_cpu = unsafe { NUM_CPU };
let num_cpu = num_cpu();
for cpu_id in 0..num_cpu {
let value = per_cpu.get_of(cpu_id);
kassert!(*value == cpu_id * 10);
Expand Down
2 changes: 1 addition & 1 deletion os/src/kernel/scheduler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ pub fn scheduler_of(cpu_id: usize) -> &'static SpinLock<RRScheduler> {

/// 通过轮询方式为新任务选择一个目标 CPU。
pub fn pick_cpu() -> usize {
let num_cpu = unsafe { crate::kernel::NUM_CPU };
let num_cpu = crate::kernel::num_cpu();
NEXT_CPU.fetch_add(1, Ordering::Relaxed) % num_cpu
}

Expand Down
Loading
Loading