Skip to content

Commit c3dad00

Browse files
authored
添加per cpu变量支持 (#327)
1 parent 42c97fa commit c3dad00

File tree

5 files changed

+97
-5
lines changed

5 files changed

+97
-5
lines changed

kernel/src/arch/x86_64/cpu.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
use core::arch::asm;
22

3-
use super::asm::current::current_pcb;
3+
use x86::cpuid::{cpuid, CpuIdResult};
44

55
/// @brief 获取当前cpu的apic id
66
#[inline]
77
pub fn current_cpu_id() -> u32 {
8-
// TODO: apic重构后,使用apic id来设置这里
9-
current_pcb().cpu_id as u32
8+
let cpuid_res: CpuIdResult = cpuid!(0x1);
9+
let cpu_id = (cpuid_res.ebx >> 24) & 0xff;
10+
return cpu_id;
1011
}
1112

1213
/// @brief 通过pause指令,让cpu休息一会儿。降低空转功耗

kernel/src/filesystem/vfs/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ pub trait IndexNode: Any + Sync + Send + Debug {
162162
}
163163

164164
/// @brief 重新设置文件的大小
165-
///
165+
///
166166
/// 如果文件大小增加,则文件内容不变,但是文件的空洞部分会被填充为0
167167
/// 如果文件大小减小,则文件内容会被截断
168168
///

kernel/src/mm/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ pub mod kernel_mapper;
2828
pub mod mmio_buddy;
2929
pub mod no_init;
3030
pub mod page;
31+
pub mod percpu;
3132
pub mod syscall;
3233
pub mod ucontext;
3334

kernel/src/mm/percpu.rs

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
use core::sync::atomic::AtomicUsize;
2+
3+
use alloc::vec::Vec;
4+
5+
use crate::{
6+
include::bindings::bindings::smp_get_total_cpu, libs::lazy_init::Lazy,
7+
smp::core::smp_get_processor_id,
8+
};
9+
10+
/// 系统中的CPU数量
11+
///
12+
/// todo: 待smp模块重构后,从smp模块获取CPU数量。
13+
/// 目前由于smp模块初始化时机较晚,导致大部分内核模块无法在早期初始化PerCpu变量。
14+
const CPU_NUM: AtomicUsize = AtomicUsize::new(PerCpu::MAX_CPU_NUM);
15+
16+
#[derive(Debug)]
17+
pub struct PerCpu;
18+
19+
impl PerCpu {
20+
pub const MAX_CPU_NUM: usize = 128;
21+
/// # 初始化PerCpu
22+
///
23+
/// 该函数应该在内核初始化时调用一次。
24+
///
25+
/// 该函数会调用`smp_get_total_cpu()`获取CPU数量,然后将其存储在`CPU_NUM`中。
26+
#[allow(dead_code)]
27+
pub fn init() {
28+
if CPU_NUM.load(core::sync::atomic::Ordering::SeqCst) != 0 {
29+
panic!("PerCpu::init() called twice");
30+
}
31+
let cpus = unsafe { smp_get_total_cpu() } as usize;
32+
assert!(cpus > 0, "PerCpu::init(): smp_get_total_cpu() returned 0");
33+
CPU_NUM.store(cpus, core::sync::atomic::Ordering::SeqCst);
34+
}
35+
}
36+
37+
/// PerCpu变量
38+
///
39+
/// 该结构体的每个实例都是线程安全的,因为每个CPU都有自己的变量。
40+
///
41+
/// 一种简单的使用方法是:使用该结构体提供的`define_lazy`方法定义一个全局变量,
42+
/// 然后在内核初始化时调用`init`、`new`方法去初始化它。
43+
///
44+
/// 当然,由于Lazy<T>有运行时开销,所以也可以直接全局声明一个Option,
45+
/// 然后手动初始化然后赋值到Option中。(这样需要在初始化的时候,手动确保并发安全)
46+
#[derive(Debug)]
47+
#[allow(dead_code)]
48+
pub struct PerCpuVar<T> {
49+
inner: Vec<T>,
50+
}
51+
52+
#[allow(dead_code)]
53+
impl<T> PerCpuVar<T> {
54+
/// # 初始化PerCpu变量
55+
///
56+
/// ## 参数
57+
///
58+
/// - `data` - 每个CPU的数据的初始值。 传入的Vec的长度必须等于CPU的数量,否则返回None。
59+
pub fn new(data: Vec<T>) -> Option<Self> {
60+
let cpu_num = CPU_NUM.load(core::sync::atomic::Ordering::SeqCst);
61+
if cpu_num == 0 {
62+
panic!("PerCpu::init() not called");
63+
}
64+
65+
if data.len() != cpu_num {
66+
return None;
67+
}
68+
69+
return Some(Self { inner: data });
70+
}
71+
72+
/// 定义一个Lazy的PerCpu变量,稍后再初始化
73+
pub const fn define_lazy() -> Lazy<Self> {
74+
Lazy::<Self>::new()
75+
}
76+
77+
pub fn get(&self) -> &T {
78+
let cpu_id = smp_get_processor_id();
79+
&self.inner[cpu_id as usize]
80+
}
81+
82+
pub fn get_mut(&mut self) -> &mut T {
83+
let cpu_id = smp_get_processor_id();
84+
&mut self.inner[cpu_id as usize]
85+
}
86+
}
87+
88+
/// PerCpu变量是线程安全的,因为每个CPU都有自己的变量。
89+
unsafe impl<T> Sync for PerCpuVar<T> {}
90+
unsafe impl<T> Send for PerCpuVar<T> {}

kernel/src/mm/syscall.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ impl Syscall {
7878
if new_addr == address_space.brk {
7979
return Ok(address_space.brk);
8080
}
81-
81+
8282
unsafe {
8383
address_space
8484
.set_brk(VirtAddr::new(page_align_up(new_addr.data())))

0 commit comments

Comments
 (0)