From 18f42a265bf1e372776ff914b648ce1e911cdc6d Mon Sep 17 00:00:00 2001 From: miiyakumo Date: Thu, 28 May 2026 23:24:29 +0800 Subject: [PATCH] Refactor kernel CPU and clock frequency management - Replace static mutable NUM_CPU and CLOCK_FREQ with AtomicUsize for thread-safe access. - Introduce num_cpu() and set_num_cpu() functions for better encapsulation. - Update various modules to use the new atomic access methods for CPU count. - Refactor device tree and boot modules to utilize the new clock frequency management. - Enhance trap handler to use SpinLock for BOOT_TRAP_FRAME. - Improve error handling in syscall implementations by introducing copy_user_bytes and copy_user_array functions. - Update test macros to use SpinLock for thread-safe assertion recording. - Refactor Dentry full_path method to avoid unsafe pointer dereferencing. - Transition global file lock manager to lazy_static for better initialization. - Clean up unused zeroed variable assignments in character device file implementations. - Add AGENT.md for project maintenance guidelines and refactoring priorities. --- os/src/arch/arch_impl.rs | 2 +- os/src/arch/loongarch/trap/trap_handler.rs | 11 +- os/src/arch/riscv/boot/mod.rs | 20 +-- os/src/arch/riscv/ipi.rs | 6 +- os/src/arch/riscv/mm/page_table.rs | 10 +- os/src/arch/riscv/timer.rs | 5 +- os/src/device/device_tree.rs | 18 +-- os/src/kernel/cpu.rs | 41 +++-- os/src/kernel/scheduler/mod.rs | 2 +- os/src/kernel/syscall/io.rs | 165 ++++++++++----------- os/src/kernel/syscall/ioctl.rs | 4 - os/src/kernel/syscall/task/futex_ops.rs | 22 ++- os/src/kernel/task/task_struct.rs | 7 +- os/src/sync/per_cpu.rs | 4 +- os/src/test/macros.rs | 60 ++++---- os/src/vfs/dentry.rs | 16 +- os/src/vfs/file_lock.rs | 6 +- os/src/vfs/impls/char_dev_file.rs | 9 -- os/src/vfs/impls/stdio_file.rs | 6 - 19 files changed, 212 insertions(+), 202 deletions(-) diff --git a/os/src/arch/arch_impl.rs b/os/src/arch/arch_impl.rs index ee0ac8b0..a2e04c80 100644 --- a/os/src/arch/arch_impl.rs +++ b/os/src/arch/arch_impl.rs @@ -135,7 +135,7 @@ macro_rules! impl_arch { } fn cpu_count() -> usize { - unsafe { $crate::kernel::NUM_CPU } + $crate::kernel::num_cpu() } } diff --git a/os/src/arch/loongarch/trap/trap_handler.rs b/os/src/arch/loongarch/trap/trap_handler.rs index 039a1629..c270dcb4 100644 --- a/os/src/arch/loongarch/trap/trap_handler.rs +++ b/os/src/arch/loongarch/trap/trap_handler.rs @@ -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; @@ -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 = SpinLock::new(TrapFrame::empty()); static FIRST_TRAP_LOGGED: AtomicBool = AtomicBool::new(false); static FIRST_USER_TIMER_LOGGED: AtomicBool = AtomicBool::new(false); @@ -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) ); // EENTRY <- trap_entry(注意 CSR 编号为 0xc) diff --git a/os/src/arch/riscv/boot/mod.rs b/os/src/arch/riscv/boot/mod.rs index 0b9a37ed..5f8ad0c6 100644 --- a/os/src/arch/riscv/boot/mod.rs +++ b/os/src/arch/riscv/boot/mod.rs @@ -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, }; @@ -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 } /// 从核调试入口 @@ -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); } @@ -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; } @@ -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; } @@ -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 ); } @@ -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 { diff --git a/os/src/arch/riscv/ipi.rs b/os/src/arch/riscv/ipi.rs index fcfeb91b..3c180487 100644 --- a/os/src/arch/riscv/ipi.rs +++ b/os/src/arch/riscv/ipi.rs @@ -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 的待处理标志 @@ -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) { @@ -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 { diff --git a/os/src/arch/riscv/mm/page_table.rs b/os/src/arch/riscv/mm/page_table.rs index 554aba4e..6939f23b 100644 --- a/os/src/arch/riscv/mm/page_table.rs +++ b/os/src/arch/riscv/mm/page_table.rs @@ -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(); } @@ -413,7 +413,7 @@ impl PageTableInner { >::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(); } @@ -432,7 +432,7 @@ impl PageTableInner { >::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(); } @@ -452,7 +452,7 @@ impl PageTableInner { >::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(); } @@ -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(); } diff --git a/os/src/arch/riscv/timer.rs b/os/src/arch/riscv/timer.rs index eb4ac0e8..3a78015b 100644 --- a/os/src/arch/riscv/timer.rs +++ b/os/src/arch/riscv/timer.rs @@ -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; /// 每秒的时钟中断次数 @@ -50,8 +50,7 @@ pub fn init() { /// 获取时钟频率 #[inline] pub fn clock_freq() -> usize { - // SAFETY: CLOCK_FREQ 在内核初始化阶段被正确设置且之后不会更改 - unsafe { CLOCK_FREQ } + kernel::clock_freq() } #[cfg(test)] diff --git a/os/src/device/device_tree.rs b/os/src/device/device_tree.rs index ca6a2407..8f12e620 100644 --- a/os/src/device/device_tree.rs +++ b/os/src/device/device_tree.rs @@ -2,16 +2,17 @@ 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! { /// 设备树 @@ -19,7 +20,7 @@ lazy_static::lazy_static! { /// 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") } }; @@ -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 @@ -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"); } @@ -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!( diff --git a/os/src/kernel/cpu.rs b/os/src/kernel/cpu.rs index 1b987436..5832ef0f 100644 --- a/os/src/kernel/cpu.rs +++ b/os/src/kernel/cpu.rs @@ -2,6 +2,7 @@ //! //! 包含 CPU 结构体及其相关操作 use alloc::sync::Arc; +use core::sync::atomic::{AtomicUsize, Ordering}; use crate::mm::activate; use crate::{ @@ -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 的状态 @@ -103,7 +124,9 @@ impl Cpu { /// /// 调用者必须确保在访问期间禁用抢占 (防止任务迁移到其他 CPU)。 #[inline] -pub fn current_cpu() -> &'static mut Cpu { +#[rustfmt::skip] +pub fn current_cpu() -> &'static +mut Cpu { CPUS.get_mut() } @@ -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); @@ -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() 函数 @@ -144,7 +167,7 @@ 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() 函数 @@ -152,7 +175,7 @@ mod tests { 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); @@ -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() @@ -201,7 +224,7 @@ mod tests { let per_cpu: PerCpu = 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); diff --git a/os/src/kernel/scheduler/mod.rs b/os/src/kernel/scheduler/mod.rs index 0ffc191e..482ef8d8 100644 --- a/os/src/kernel/scheduler/mod.rs +++ b/os/src/kernel/scheduler/mod.rs @@ -94,7 +94,7 @@ pub fn scheduler_of(cpu_id: usize) -> &'static SpinLock { /// 通过轮询方式为新任务选择一个目标 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 } diff --git a/os/src/kernel/syscall/io.rs b/os/src/kernel/syscall/io.rs index 489b1b0e..20f0a404 100644 --- a/os/src/kernel/syscall/io.rs +++ b/os/src/kernel/syscall/io.rs @@ -1,10 +1,7 @@ //! IO 相关的系统调用实现 -// set_len 后立即通过 copy_from_user / copy_from_user_mut 从用户空间填充数据, -// 在第一次读取前已完全初始化,符合安全语义。 -#![allow(clippy::uninit_vec)] - use crate::arch::Arch; +use crate::arch::address::UA; use crate::kernel::current_task; use crate::uapi::errno::EFAULT; use crate::uapi::errno::EINVAL; @@ -21,6 +18,35 @@ fn empty_iovec() -> IoVec { } } +fn copy_user_bytes(src: *const u8, len: usize) -> Result, isize> { + let mut buf = alloc::vec![0u8; len]; + unsafe { + crate::arch::ArchImpl::copy_from_user(UA::from_usize(src as usize), buf.as_mut_ptr(), len) + .map_err(|_| -(EFAULT as isize))?; + } + Ok(buf) +} + +fn copy_user_array( + src: *const T, + len: usize, + empty: T, +) -> Result, isize> { + let mut buf = alloc::vec![empty; len]; + let size = len + .checked_mul(core::mem::size_of::()) + .ok_or(-(EFAULT as isize))?; + unsafe { + crate::arch::ArchImpl::copy_from_user( + UA::from_usize(src as usize), + buf.as_mut_ptr() as *mut u8, + size, + ) + .map_err(|_| -(EFAULT as isize))?; + } + Ok(buf) +} + /// 向文件描述符写入数据 pub fn write(fd: usize, buf: *const u8, count: usize) -> isize { loop { @@ -30,15 +56,10 @@ pub fn write(fd: usize, buf: *const u8, count: usize) -> isize { Err(e) => return e.to_errno(), }; - let mut kernel_buf = alloc::vec![0u8; count]; - unsafe { - crate::arch::ArchImpl::copy_from_user( - crate::arch::address::UA::from_usize(buf as usize), - kernel_buf.as_mut_ptr(), - count, - ) - .ok(); - } + let kernel_buf = match copy_user_bytes(buf, count) { + Ok(buf) => buf, + Err(e) => return e, + }; let result = match file.write(&kernel_buf) { Ok(n) => n as isize, @@ -118,16 +139,10 @@ pub fn readv(fd: usize, iov: *const IoVec, iovcnt: usize) -> isize { return -(EFAULT as isize); } - // 读取 iovec 数组 - let mut iovec_array = alloc::vec![empty_iovec(); iovcnt]; - unsafe { - crate::arch::ArchImpl::copy_from_user( - crate::arch::address::UA::from_usize(iov as usize), - iovec_array.as_mut_ptr() as *mut u8, - iovcnt * core::mem::size_of::(), - ) - .ok(); - } + let iovec_array = match copy_user_array(iov, iovcnt, empty_iovec()) { + Ok(iovecs) => iovecs, + Err(e) => return e, + }; let task = current_task(); let file = match task.lock().fd_table.get(fd) { @@ -188,15 +203,10 @@ pub fn writev(fd: usize, iov: *const IoVec, iovcnt: usize) -> isize { return -(EFAULT as isize); } - let mut iovec_array = alloc::vec![empty_iovec(); iovcnt]; - unsafe { - crate::arch::ArchImpl::copy_from_user( - crate::arch::address::UA::from_usize(iov as usize), - iovec_array.as_mut_ptr() as *mut u8, - iovcnt * core::mem::size_of::(), - ) - .ok(); - } + let iovec_array = match copy_user_array(iov, iovcnt, empty_iovec()) { + Ok(iovecs) => iovecs, + Err(e) => return e, + }; let task = current_task(); let file = match task.lock().fd_table.get(fd) { @@ -218,15 +228,16 @@ pub fn writev(fd: usize, iov: *const IoVec, iovcnt: usize) -> isize { }; } - let mut kernel_buf = alloc::vec![0u8; vec.iov_len]; - unsafe { - crate::arch::ArchImpl::copy_from_user( - crate::arch::address::UA::from_usize(vec.iov_base as usize), - kernel_buf.as_mut_ptr(), - vec.iov_len, - ) - .ok(); - } + let kernel_buf = match copy_user_bytes(vec.iov_base, vec.iov_len) { + Ok(buf) => buf, + Err(e) => { + return if total_written > 0 { + total_written as isize + } else { + e + }; + } + }; match file.write(&kernel_buf) { Ok(n) => { total_written += n; @@ -298,15 +309,10 @@ pub fn pwrite64(fd: usize, buf: *const u8, count: usize, offset: i64) -> isize { Err(e) => return e.to_errno(), }; - let mut kernel_buf = alloc::vec![0u8; count]; - unsafe { - crate::arch::ArchImpl::copy_from_user( - crate::arch::address::UA::from_usize(buf as usize), - kernel_buf.as_mut_ptr(), - count, - ) - .ok(); - } + let kernel_buf = match copy_user_bytes(buf, count) { + Ok(buf) => buf, + Err(e) => return e, + }; match file.write_at(offset as usize, &kernel_buf) { Ok(n) => n as isize, Err(e) => e.to_errno(), @@ -335,15 +341,10 @@ pub fn preadv(fd: usize, iov: *const IoVec, iovcnt: usize, offset: i64) -> isize Err(e) => return e.to_errno(), }; - let mut iovec_array = alloc::vec![empty_iovec(); iovcnt]; - unsafe { - crate::arch::ArchImpl::copy_from_user( - crate::arch::address::UA::from_usize(iov as usize), - iovec_array.as_mut_ptr() as *mut u8, - iovcnt * core::mem::size_of::(), - ) - .ok(); - } + let iovec_array = match copy_user_array(iov, iovcnt, empty_iovec()) { + Ok(iovecs) => iovecs, + Err(e) => return e, + }; let mut total_read = 0usize; let mut current_offset = offset as usize; @@ -412,15 +413,10 @@ pub fn pwritev(fd: usize, iov: *const IoVec, iovcnt: usize, offset: i64) -> isiz Err(e) => return e.to_errno(), }; - let mut iovec_array = alloc::vec![empty_iovec(); iovcnt]; - unsafe { - crate::arch::ArchImpl::copy_from_user( - crate::arch::address::UA::from_usize(iov as usize), - iovec_array.as_mut_ptr() as *mut u8, - iovcnt * core::mem::size_of::(), - ) - .ok(); - } + let iovec_array = match copy_user_array(iov, iovcnt, empty_iovec()) { + Ok(iovecs) => iovecs, + Err(e) => return e, + }; let mut total_written = 0usize; let mut current_offset = offset as usize; @@ -437,15 +433,16 @@ pub fn pwritev(fd: usize, iov: *const IoVec, iovcnt: usize, offset: i64) -> isiz }; } - let mut kernel_buf = alloc::vec![0u8; vec.iov_len]; - unsafe { - crate::arch::ArchImpl::copy_from_user( - crate::arch::address::UA::from_usize(vec.iov_base as usize), - kernel_buf.as_mut_ptr(), - vec.iov_len, - ) - .ok(); - } + let kernel_buf = match copy_user_bytes(vec.iov_base, vec.iov_len) { + Ok(buf) => buf, + Err(e) => { + return if total_written > 0 { + total_written as isize + } else { + e + }; + } + }; match file.write_at(current_offset, &kernel_buf) { Ok(n) => { total_written += n; @@ -627,15 +624,11 @@ fn poll_with_timeout( { let size = nfds * core::mem::size_of::(); - let mut pollfds_buf = alloc::vec![empty_pollfd(); nfds]; - unsafe { - crate::arch::ArchImpl::copy_from_user( - crate::arch::address::UA::from_usize(fds), - pollfds_buf.as_mut_ptr() as *mut u8, - size, - ) - .ok(); - } + let mut pollfds_buf = match copy_user_array(fds as *const PollFd, nfds, empty_pollfd()) + { + Ok(pollfds) => pollfds, + Err(e) => return e, + }; for pollfd in pollfds_buf.iter_mut() { pollfd.revents = 0; diff --git a/os/src/kernel/syscall/ioctl.rs b/os/src/kernel/syscall/ioctl.rs index f962ee6d..1a8a4a04 100644 --- a/os/src/kernel/syscall/ioctl.rs +++ b/os/src/kernel/syscall/ioctl.rs @@ -283,10 +283,6 @@ fn handle_siocgifconf(arg: usize) -> isize { let ifconf = unsafe { read_from_user(ifconf_ptr as *const Ifconf) }; - // 先清零原结构体,避免泄露内核栈数据 - let zeroed = unsafe { core::mem::MaybeUninit::::zeroed().assume_init() }; - unsafe { write_to_user(ifconf_ptr, zeroed) }; - // TODO: 填充实际的网络接口列表 let mut new_ifconf = ifconf; new_ifconf.ifc_len = 0; diff --git a/os/src/kernel/syscall/task/futex_ops.rs b/os/src/kernel/syscall/task/futex_ops.rs index 5736d2ff..fe14f8d2 100644 --- a/os/src/kernel/syscall/task/futex_ops.rs +++ b/os/src/kernel/syscall/task/futex_ops.rs @@ -1,4 +1,5 @@ use super::*; +use crate::arch::Arch; /// Futex 系统调用实现 /// # 参数 @@ -25,9 +26,9 @@ pub fn futex( let mut fm = FUTEX_MANAGER.lock(); match op as u32 { FUTEX_WAIT => { - // 必须保证获 取锁 → 读取用户数据 → 比较 → 释放锁 整个序列是原子的 - let user_val = unsafe { read_from_user(uaddr) }; - let memory_space = current_task() + // 必须保证获取锁 → 定位等待队列 → 读取用户数据 → 比较 → 入队/释放锁 的序列是原子的 + let task = current_task(); + let memory_space = task .lock() .memory_space .as_ref() @@ -41,11 +42,24 @@ pub fn futex( } else { return -EFAULT; }; + let user_val = { + let mut val = core::mem::MaybeUninit::::uninit(); + let copy_result = unsafe { + crate::arch::ArchImpl::copy_from_user( + UA::from_usize(uaddr as usize), + val.as_mut_ptr() as *mut u8, + core::mem::size_of::(), + ) + }; + if copy_result.is_err() { + return -EFAULT; + } + unsafe { val.assume_init() } + }; if user_val != val { return -EAGAIN; } - let task = current_task(); let waitq = fm.get_wait_queue(paddr); waitq.sleep(task.clone()); sleep_task(task.clone(), true); diff --git a/os/src/kernel/task/task_struct.rs b/os/src/kernel/task/task_struct.rs index ccadd6a6..4bd4232e 100644 --- a/os/src/kernel/task/task_struct.rs +++ b/os/src/kernel/task/task_struct.rs @@ -2,7 +2,10 @@ //! //! 包含任务的核心信息,如上下文、状态、内存空间等 #![allow(dead_code)] -use core::sync::atomic::{AtomicPtr, Ordering}; +use core::{ + mem::size_of, + sync::atomic::{AtomicPtr, Ordering}, +}; use alloc::{string::String, sync::Arc, vec::Vec}; @@ -307,7 +310,7 @@ impl Task { // SAFETY: tfptr 指向的内存已经被分配且可写,并由 task 拥有 unsafe { // 清零整个 TrapFrame,避免旧值泄漏到用户态 - core::ptr::write_bytes(tf_ptr, 0, 1); + core::ptr::write_bytes(tf_ptr, 0, size_of::()); ::set_exec_trap_frame_from_layout( &mut *tf_ptr, initial_pc.as_usize(), diff --git a/os/src/sync/per_cpu.rs b/os/src/sync/per_cpu.rs index 05d2c246..dd30ae7e 100644 --- a/os/src/sync/per_cpu.rs +++ b/os/src/sync/per_cpu.rs @@ -40,7 +40,7 @@ pub struct PerCpu { impl PerCpu { pub fn new T>(init: F) -> Self { - let num_cpu = unsafe { crate::kernel::NUM_CPU }; + let num_cpu = crate::kernel::num_cpu(); assert!(num_cpu > 0, "NUM_CPU must be set before creating PerCpu"); let mut data = Vec::with_capacity(num_cpu); @@ -54,7 +54,7 @@ impl PerCpu { } pub fn new_with_id T>(init: F) -> Self { - let num_cpu = unsafe { crate::kernel::NUM_CPU }; + let num_cpu = crate::kernel::num_cpu(); assert!(num_cpu > 0, "NUM_CPU must be set before creating PerCpu"); let mut data = Vec::with_capacity(num_cpu); diff --git a/os/src/test/macros.rs b/os/src/test/macros.rs index 12fefd3a..bc292e15 100644 --- a/os/src/test/macros.rs +++ b/os/src/test/macros.rs @@ -1,6 +1,7 @@ #![allow(dead_code)] use crate::println; -use core::sync::atomic::AtomicUsize; +use crate::sync::SpinLock; +use core::sync::atomic::{AtomicUsize, Ordering}; #[derive(Copy, Clone, Debug)] pub struct FailedAssertion { @@ -16,9 +17,10 @@ impl FailedAssertion { } } -pub static mut FAILED_LIST: [Option; 32] = [None; 32]; pub const FAILED_LIST_CAPACITY: usize = 32; -pub static mut FAILED_INDEX: usize = 0; +pub static FAILED_LIST: SpinLock<[Option; FAILED_LIST_CAPACITY]> = + SpinLock::new([None; FAILED_LIST_CAPACITY]); +pub static FAILED_INDEX: AtomicUsize = AtomicUsize::new(0); pub static TEST_FAILED: AtomicUsize = AtomicUsize::new(0); /// 安全地记录一个失败的断言。 /// @@ -29,14 +31,10 @@ pub static TEST_FAILED: AtomicUsize = AtomicUsize::new(0); /// /// * `assertion`: 要记录的 `FailedAssertion` 实例。 pub fn record_failed_assertion(assertion: FailedAssertion) { - let index = TEST_FAILED.fetch_add(1, core::sync::atomic::Ordering::SeqCst); + let index = TEST_FAILED.fetch_add(1, Ordering::SeqCst); if index < FAILED_LIST_CAPACITY { - unsafe { - FAILED_LIST[index] = Some(assertion); - if index + 1 > FAILED_INDEX { - FAILED_INDEX = index + 1; - } - } + FAILED_LIST.lock()[index] = Some(assertion); + FAILED_INDEX.fetch_max(index + 1, Ordering::SeqCst); } else { println!( "\x1b[91m[warn] Failed assertion list is full (capacity {}). Cannot record: {}\x1b[0m", @@ -45,6 +43,20 @@ pub fn record_failed_assertion(assertion: FailedAssertion) { } } +pub fn print_failed_assertions(start: usize, end: usize) { + let failed_list = FAILED_LIST.lock(); + let failed_limit = core::cmp::min(end, FAILED_LIST_CAPACITY); + for i in start..failed_limit { + let Some(fail) = failed_list[i] else { + continue; + }; + println!( + "\x1b[31mFailed assertion: {} at {}:{}\x1b[0m", + fail.cond, fail.file, fail.line + ); + } +} + /// 判断条件是否为真,如果为假则记录一个失败的断言。 #[macro_export] macro_rules! kassert { @@ -139,16 +151,10 @@ macro_rules! test_case { let failed_after = $crate::test::macros::TEST_FAILED.load(core::sync::atomic::Ordering::SeqCst); let failed_count = failed_after - failed_before; - unsafe { - for i in failed_before..$crate::test::macros::FAILED_INDEX { - if let Some(fail) = $crate::test::macros::FAILED_LIST[i] { - $crate::println!( - "\x1b[31mFailed assertion: {} at {}:{}\x1b[0m", - fail.cond, fail.file, fail.line - ); - } - } - } + $crate::test::macros::print_failed_assertions( + failed_before, + $crate::test::macros::FAILED_INDEX.load(core::sync::atomic::Ordering::SeqCst), + ); if failed_count == 0 { $crate::println!("\x1b[32m[ok] Test passed\x1b[0m\n"); @@ -187,19 +193,7 @@ fn run_test(test_name: &str, env_name: Option<&str>, test_fn: impl FnOnce()) { let failed_after = TEST_FAILED.load(core::sync::atomic::Ordering::SeqCst); let failed_count = failed_after - failed_before; - unsafe { - let failed_limit = FAILED_INDEX; - let failed_list = core::ptr::addr_of!(FAILED_LIST).cast::>(); - for i in failed_before..failed_limit { - let Some(fail) = failed_list.add(i).read() else { - continue; - }; - println!( - "\x1b[31mFailed assertion: {} at {}:{}\x1b[0m", - fail.cond, fail.file, fail.line - ); - } - } + print_failed_assertions(failed_before, FAILED_INDEX.load(Ordering::SeqCst)); if failed_count == 0 { println!("\x1b[32m[ok] Test passed\x1b[0m\n"); diff --git a/os/src/vfs/dentry.rs b/os/src/vfs/dentry.rs index 8b73cc0c..d4e1db5a 100644 --- a/os/src/vfs/dentry.rs +++ b/os/src/vfs/dentry.rs @@ -195,22 +195,24 @@ impl Dentry { /// 获取完整路径(通过向上遍历父节点直到根目录) pub fn full_path(&self) -> String { let mut components = alloc::vec::Vec::new(); - let mut current: *const Dentry = self; + let mut current_name = self.name.clone(); + let mut current_parent = self.parent(); // 向上遍历到根目录 loop { - let dentry = unsafe { &*current }; - // 根目录的名字是 "/" - if dentry.name == "/" { + if current_name == "/" { break; } - components.push(dentry.name.clone()); + components.push(current_name); // 获取父节点 - match dentry.parent() { - Some(parent) => current = Arc::as_ptr(&parent), + match current_parent { + Some(parent) => { + current_name = parent.name.clone(); + current_parent = parent.parent(); + } None => break, // 到达根或孤立节点 } } diff --git a/os/src/vfs/file_lock.rs b/os/src/vfs/file_lock.rs index 5d544ae7..8e73fef1 100644 --- a/os/src/vfs/file_lock.rs +++ b/os/src/vfs/file_lock.rs @@ -222,8 +222,10 @@ impl FileLockManager { } } -/// 全局文件锁管理器实例 -static FILE_LOCK_MANAGER: FileLockManager = FileLockManager::new(); +lazy_static::lazy_static! { + /// 全局文件锁管理器实例 + static ref FILE_LOCK_MANAGER: FileLockManager = FileLockManager::new(); +} /// 获取全局文件锁管理器 pub fn file_lock_manager() -> &'static FileLockManager { diff --git a/os/src/vfs/impls/char_dev_file.rs b/os/src/vfs/impls/char_dev_file.rs index bc875fdb..c9cd6bdc 100644 --- a/os/src/vfs/impls/char_dev_file.rs +++ b/os/src/vfs/impls/char_dev_file.rs @@ -347,8 +347,6 @@ impl CharDeviceFile { } let termios = *self.termios.lock(); - let zeroed = unsafe { core::mem::MaybeUninit::::zeroed().assume_init() }; - unsafe { write_to_user(termios_ptr, zeroed) }; unsafe { write_to_user(termios_ptr, termios) }; Ok(0) } @@ -379,10 +377,6 @@ impl CharDeviceFile { } let winsize = *self.winsize.lock(); - let zeroed = unsafe { - core::mem::MaybeUninit::::zeroed().assume_init() - }; - unsafe { write_to_user(winsize_ptr, zeroed) }; unsafe { write_to_user(winsize_ptr, winsize) }; Ok(0) } @@ -446,9 +440,6 @@ impl CharDeviceFile { tm_isdst: 0, }; - let zeroed = - unsafe { core::mem::MaybeUninit::::zeroed().assume_init() }; - unsafe { write_to_user(rtc_time_ptr, zeroed) }; unsafe { write_to_user(rtc_time_ptr, rtc_time) }; return Ok(0); } diff --git a/os/src/vfs/impls/stdio_file.rs b/os/src/vfs/impls/stdio_file.rs index 16280a10..95f38a2a 100644 --- a/os/src/vfs/impls/stdio_file.rs +++ b/os/src/vfs/impls/stdio_file.rs @@ -259,8 +259,6 @@ fn stdio_ioctl(request: u32, arg: usize) -> Result { } let termios = *STDIO_TERMIOS.lock(); - let zeroed = unsafe { core::mem::MaybeUninit::::zeroed().assume_init() }; - unsafe { write_to_user(termios_ptr, zeroed) }; unsafe { write_to_user(termios_ptr, termios) }; crate::pr_debug!( @@ -312,10 +310,6 @@ fn stdio_ioctl(request: u32, arg: usize) -> Result { } let winsize = *STDIO_WINSIZE.lock(); - let zeroed = unsafe { - core::mem::MaybeUninit::::zeroed().assume_init() - }; - unsafe { write_to_user(winsize_ptr, zeroed) }; unsafe { write_to_user(winsize_ptr, winsize) }; crate::pr_debug!(