diff --git a/kernel/src/arch/x86_64/cpu.rs b/kernel/src/arch/x86_64/cpu.rs index 1e15bc06c..ac1be208d 100644 --- a/kernel/src/arch/x86_64/cpu.rs +++ b/kernel/src/arch/x86_64/cpu.rs @@ -1,12 +1,13 @@ use core::arch::asm; -use super::asm::current::current_pcb; +use x86::cpuid::{cpuid, CpuIdResult}; /// @brief 获取当前cpu的apic id #[inline] pub fn current_cpu_id() -> u32 { - // TODO: apic重构后,使用apic id来设置这里 - current_pcb().cpu_id as u32 + let cpuid_res: CpuIdResult = cpuid!(0x1); + let cpu_id = (cpuid_res.ebx >> 24) & 0xff; + return cpu_id; } /// @brief 通过pause指令,让cpu休息一会儿。降低空转功耗 diff --git a/kernel/src/filesystem/vfs/mod.rs b/kernel/src/filesystem/vfs/mod.rs index 0e4a1c1e0..d037e068f 100644 --- a/kernel/src/filesystem/vfs/mod.rs +++ b/kernel/src/filesystem/vfs/mod.rs @@ -162,7 +162,7 @@ pub trait IndexNode: Any + Sync + Send + Debug { } /// @brief 重新设置文件的大小 - /// + /// /// 如果文件大小增加,则文件内容不变,但是文件的空洞部分会被填充为0 /// 如果文件大小减小,则文件内容会被截断 /// diff --git a/kernel/src/mm/mod.rs b/kernel/src/mm/mod.rs index 8364e3c9f..6d1facddc 100644 --- a/kernel/src/mm/mod.rs +++ b/kernel/src/mm/mod.rs @@ -28,6 +28,7 @@ pub mod kernel_mapper; pub mod mmio_buddy; pub mod no_init; pub mod page; +pub mod percpu; pub mod syscall; pub mod ucontext; diff --git a/kernel/src/mm/percpu.rs b/kernel/src/mm/percpu.rs new file mode 100644 index 000000000..b2c2b2ee0 --- /dev/null +++ b/kernel/src/mm/percpu.rs @@ -0,0 +1,90 @@ +use core::sync::atomic::AtomicUsize; + +use alloc::vec::Vec; + +use crate::{ + include::bindings::bindings::smp_get_total_cpu, libs::lazy_init::Lazy, + smp::core::smp_get_processor_id, +}; + +/// 系统中的CPU数量 +/// +/// todo: 待smp模块重构后,从smp模块获取CPU数量。 +/// 目前由于smp模块初始化时机较晚,导致大部分内核模块无法在早期初始化PerCpu变量。 +const CPU_NUM: AtomicUsize = AtomicUsize::new(PerCpu::MAX_CPU_NUM); + +#[derive(Debug)] +pub struct PerCpu; + +impl PerCpu { + pub const MAX_CPU_NUM: usize = 128; + /// # 初始化PerCpu + /// + /// 该函数应该在内核初始化时调用一次。 + /// + /// 该函数会调用`smp_get_total_cpu()`获取CPU数量,然后将其存储在`CPU_NUM`中。 + #[allow(dead_code)] + pub fn init() { + if CPU_NUM.load(core::sync::atomic::Ordering::SeqCst) != 0 { + panic!("PerCpu::init() called twice"); + } + let cpus = unsafe { smp_get_total_cpu() } as usize; + assert!(cpus > 0, "PerCpu::init(): smp_get_total_cpu() returned 0"); + CPU_NUM.store(cpus, core::sync::atomic::Ordering::SeqCst); + } +} + +/// PerCpu变量 +/// +/// 该结构体的每个实例都是线程安全的,因为每个CPU都有自己的变量。 +/// +/// 一种简单的使用方法是:使用该结构体提供的`define_lazy`方法定义一个全局变量, +/// 然后在内核初始化时调用`init`、`new`方法去初始化它。 +/// +/// 当然,由于Lazy有运行时开销,所以也可以直接全局声明一个Option, +/// 然后手动初始化然后赋值到Option中。(这样需要在初始化的时候,手动确保并发安全) +#[derive(Debug)] +#[allow(dead_code)] +pub struct PerCpuVar { + inner: Vec, +} + +#[allow(dead_code)] +impl PerCpuVar { + /// # 初始化PerCpu变量 + /// + /// ## 参数 + /// + /// - `data` - 每个CPU的数据的初始值。 传入的Vec的长度必须等于CPU的数量,否则返回None。 + pub fn new(data: Vec) -> Option { + let cpu_num = CPU_NUM.load(core::sync::atomic::Ordering::SeqCst); + if cpu_num == 0 { + panic!("PerCpu::init() not called"); + } + + if data.len() != cpu_num { + return None; + } + + return Some(Self { inner: data }); + } + + /// 定义一个Lazy的PerCpu变量,稍后再初始化 + pub const fn define_lazy() -> Lazy { + Lazy::::new() + } + + pub fn get(&self) -> &T { + let cpu_id = smp_get_processor_id(); + &self.inner[cpu_id as usize] + } + + pub fn get_mut(&mut self) -> &mut T { + let cpu_id = smp_get_processor_id(); + &mut self.inner[cpu_id as usize] + } +} + +/// PerCpu变量是线程安全的,因为每个CPU都有自己的变量。 +unsafe impl Sync for PerCpuVar {} +unsafe impl Send for PerCpuVar {} diff --git a/kernel/src/mm/syscall.rs b/kernel/src/mm/syscall.rs index 233d858a1..48b2aafd8 100644 --- a/kernel/src/mm/syscall.rs +++ b/kernel/src/mm/syscall.rs @@ -78,7 +78,7 @@ impl Syscall { if new_addr == address_space.brk { return Ok(address_space.brk); } - + unsafe { address_space .set_brk(VirtAddr::new(page_align_up(new_addr.data())))