xref: /DragonOS/kernel/src/arch/riscv64/cpu.rs (revision 8cb2e9b344230227fe5f3ab3ebeb2522f1c5e289)
1 use alloc::vec::Vec;
2 
3 use crate::{
4     init::boot_params,
5     kdebug,
6     mm::percpu::{PerCpu, PerCpuVar},
7     smp::cpu::{ProcessorId, SmpCpuManager},
8 };
9 
10 /// 栈对齐
11 pub(super) const STACK_ALIGN: usize = 16;
12 
13 /// 获取当前cpu的id
14 #[inline]
15 pub fn current_cpu_id() -> ProcessorId {
16     let ptr: *const LocalContext = riscv::register::tp::read() as *const LocalContext;
17 
18     if core::intrinsics::unlikely(ptr.is_null()) {
19         return boot_params().read_irqsave().arch.boot_hartid;
20     }
21 
22     unsafe { (*ptr).current_cpu() }
23 }
24 
25 /// 重置cpu
26 pub unsafe fn cpu_reset() -> ! {
27     sbi_rt::system_reset(sbi_rt::WarmReboot, sbi_rt::NoReason);
28     unimplemented!("RiscV64 reset failed, manual override expected ...")
29 }
30 
31 static mut LOCAL_CONTEXT: Option<PerCpuVar<LocalContext>> = None;
32 
33 #[inline(always)]
34 pub(super) fn local_context() -> &'static PerCpuVar<LocalContext> {
35     unsafe { LOCAL_CONTEXT.as_ref().unwrap() }
36 }
37 
38 /// Per cpu的上下文数据
39 ///
40 /// 每个CPU的tp寄存器指向这个结构体
41 ///
42 /// 注意:
43 ///
44 /// - 从用户态进入内核态时,会从sscratch寄存器加载这个结构体的地址到tp寄存器,并把sscratch寄存器清零
45 /// - 从内核态进入用户态时,会将tp寄存器的值保存到sscratch寄存器
46 #[derive(Debug)]
47 pub(super) struct LocalContext {
48     /// 当前cpu的id
49     pub current_cpu: ProcessorId,
50     // 当前进程的内核栈指针(暂存,当进入中断处理程序的时候需要保存到pcb,进程切换的时候需要重新设置这个值)
51     pub kernel_sp: usize,
52     // 当前进程的用户栈指针(暂存,当进入中断处理程序的时候需要保存到pcb,进程切换的时候需要重新设置这个值)
53     pub user_sp: usize,
54 }
55 
56 impl LocalContext {
57     fn new(cpu: ProcessorId) -> Self {
58         Self {
59             current_cpu: cpu,
60             kernel_sp: 0,
61             user_sp: 0,
62         }
63     }
64     pub fn current_cpu(&self) -> ProcessorId {
65         self.current_cpu
66     }
67 
68     pub fn set_current_cpu(&mut self, cpu: ProcessorId) {
69         self.current_cpu = cpu;
70     }
71 
72     pub fn kernel_sp(&self) -> usize {
73         self.kernel_sp
74     }
75 
76     pub fn set_kernel_sp(&mut self, sp: usize) {
77         self.kernel_sp = sp;
78     }
79 
80     pub fn user_sp(&self) -> usize {
81         self.user_sp
82     }
83 
84     pub fn set_user_sp(&mut self, sp: usize) {
85         self.user_sp = sp;
86     }
87 
88     fn sync_to_cpu(&self) {
89         let ptr = self as *const Self as usize;
90         riscv::register::sscratch::write(0);
91 
92         // 写入tp寄存器
93         riscv::register::tp::write(ptr);
94     }
95 }
96 
97 /// 初始化本地上下文
98 #[inline(never)]
99 pub(super) fn init_local_context() {
100     let mut data = Vec::new();
101 
102     for i in 0..PerCpu::MAX_CPU_NUM {
103         data.push(LocalContext::new(ProcessorId::new(i)));
104     }
105     let ctx = PerCpuVar::new(data).unwrap();
106 
107     unsafe {
108         LOCAL_CONTEXT = Some(ctx);
109     }
110 
111     let hartid = boot_params().read().arch.boot_hartid;
112 
113     let ctx = unsafe { local_context().force_get(hartid) };
114     ctx.sync_to_cpu();
115 }
116 
117 impl SmpCpuManager {
118     pub fn arch_init(boot_cpu: ProcessorId) {
119         // todo: 读取所有可用的CPU
120     }
121 }
122