xref: /DragonOS/kernel/src/exception/softirq.rs (revision 1496ba7b24a5e6954291ca9643b9f3cec567479a)
1bacd691cSlogin use core::{
2bacd691cSlogin     fmt::Debug,
3bacd691cSlogin     intrinsics::unlikely,
4bacd691cSlogin     mem::{self, MaybeUninit},
5bacd691cSlogin     ptr::null_mut,
6bacd691cSlogin     sync::atomic::{compiler_fence, Ordering},
7bacd691cSlogin };
862e46139SGou Ngai 
9bacd691cSlogin use alloc::{boxed::Box, sync::Arc};
10bacd691cSlogin use num_traits::FromPrimitive;
1162e46139SGou Ngai 
1262e46139SGou Ngai use crate::{
13*1496ba7bSLoGin     arch::interrupt::{cli, sti},
149550910aSChiichen     arch::CurrentIrqArch,
159550910aSChiichen     exception::InterruptArch,
16bacd691cSlogin     include::bindings::bindings::MAX_CPU_NUM,
17bacd691cSlogin     kdebug, kinfo,
18bacd691cSlogin     libs::rwlock::RwLock,
19*1496ba7bSLoGin     process::ProcessManager,
20bacd691cSlogin     smp::core::smp_get_processor_id,
21bacd691cSlogin     syscall::SystemError,
22bacd691cSlogin     time::timer::clock,
2362e46139SGou Ngai };
2462e46139SGou Ngai 
2562e46139SGou Ngai const MAX_SOFTIRQ_NUM: u64 = 64;
26bacd691cSlogin const MAX_SOFTIRQ_RESTART: i32 = 20;
27bacd691cSlogin 
28bacd691cSlogin static mut __CPU_PENDING: Option<Box<[VecStatus; MAX_CPU_NUM as usize]>> = None;
29bacd691cSlogin static mut __SORTIRQ_VECTORS: *mut Softirq = null_mut();
30bacd691cSlogin 
31bacd691cSlogin #[no_mangle]
32bacd691cSlogin pub extern "C" fn rs_softirq_init() {
33bacd691cSlogin     softirq_init().expect("softirq_init failed");
34bacd691cSlogin }
35bacd691cSlogin 
36bacd691cSlogin pub fn softirq_init() -> Result<(), SystemError> {
37bacd691cSlogin     kinfo!("Initializing softirq...");
38bacd691cSlogin     unsafe {
39bacd691cSlogin         __SORTIRQ_VECTORS = Box::leak(Box::new(Softirq::new()));
40bacd691cSlogin         __CPU_PENDING = Some(Box::new([VecStatus::default(); MAX_CPU_NUM as usize]));
41bacd691cSlogin         let cpu_pending = __CPU_PENDING.as_mut().unwrap();
42bacd691cSlogin         for i in 0..MAX_CPU_NUM {
43bacd691cSlogin             cpu_pending[i as usize] = VecStatus::default();
44bacd691cSlogin         }
45bacd691cSlogin     }
4640fe15e0SLoGin     kinfo!("Softirq initialized.");
47bacd691cSlogin     return Ok(());
48bacd691cSlogin }
49bacd691cSlogin 
50bacd691cSlogin #[inline(always)]
51bacd691cSlogin pub fn softirq_vectors() -> &'static mut Softirq {
52bacd691cSlogin     unsafe {
53bacd691cSlogin         return __SORTIRQ_VECTORS.as_mut().unwrap();
54bacd691cSlogin     }
55bacd691cSlogin }
56bacd691cSlogin 
57bacd691cSlogin #[inline(always)]
58bacd691cSlogin fn cpu_pending(cpu_id: usize) -> &'static mut VecStatus {
59bacd691cSlogin     unsafe {
60bacd691cSlogin         return &mut __CPU_PENDING.as_mut().unwrap()[cpu_id];
61bacd691cSlogin     }
62bacd691cSlogin }
6362e46139SGou Ngai 
6462e46139SGou Ngai /// 软中断向量号码
6562e46139SGou Ngai #[allow(dead_code)]
6662e46139SGou Ngai #[repr(u8)]
67bacd691cSlogin #[derive(FromPrimitive, Copy, Clone, Debug, PartialEq, Eq)]
6862e46139SGou Ngai pub enum SoftirqNumber {
69bacd691cSlogin     /// 时钟软中断信号
70bacd691cSlogin     TIMER = 0,
7162e46139SGou Ngai     VideoRefresh = 1, //帧缓冲区刷新软中断
7262e46139SGou Ngai }
7362e46139SGou Ngai 
74bacd691cSlogin impl From<u64> for SoftirqNumber {
75bacd691cSlogin     fn from(value: u64) -> Self {
76bacd691cSlogin         return <Self as FromPrimitive>::from_u64(value).unwrap();
7762e46139SGou Ngai     }
7862e46139SGou Ngai }
7962e46139SGou Ngai 
80bacd691cSlogin bitflags! {
81bacd691cSlogin     #[derive(Default)]
82bacd691cSlogin     pub struct VecStatus: u64 {
83bacd691cSlogin         const TIMER = 1 << 0;
84bacd691cSlogin         const VIDEO_REFRESH = 1 << 1;
85bacd691cSlogin     }
86bacd691cSlogin }
87bacd691cSlogin 
88bacd691cSlogin impl From<SoftirqNumber> for VecStatus {
89bacd691cSlogin     fn from(value: SoftirqNumber) -> Self {
90bacd691cSlogin         return Self::from_bits_truncate(1 << (value as u64));
91bacd691cSlogin     }
92bacd691cSlogin }
93bacd691cSlogin 
94bacd691cSlogin pub trait SoftirqVec: Send + Sync + Debug {
95bacd691cSlogin     fn run(&self);
96bacd691cSlogin }
97bacd691cSlogin 
98bacd691cSlogin #[derive(Debug)]
9962e46139SGou Ngai pub struct Softirq {
100bacd691cSlogin     table: RwLock<[Option<Arc<dyn SoftirqVec>>; MAX_SOFTIRQ_NUM as usize]>,
10162e46139SGou Ngai }
10262e46139SGou Ngai impl Softirq {
103bacd691cSlogin     fn new() -> Softirq {
104bacd691cSlogin         let mut data: [MaybeUninit<Option<Arc<dyn SoftirqVec>>>; MAX_SOFTIRQ_NUM as usize] =
105bacd691cSlogin             unsafe { MaybeUninit::uninit().assume_init() };
106bacd691cSlogin 
107bacd691cSlogin         for i in 0..MAX_SOFTIRQ_NUM {
108bacd691cSlogin             data[i as usize] = MaybeUninit::new(None);
10962e46139SGou Ngai         }
11062e46139SGou Ngai 
111bacd691cSlogin         let data: [Option<Arc<dyn SoftirqVec>>; MAX_SOFTIRQ_NUM as usize] = unsafe {
112bacd691cSlogin             mem::transmute::<_, [Option<Arc<dyn SoftirqVec>>; MAX_SOFTIRQ_NUM as usize]>(data)
113bacd691cSlogin         };
11462e46139SGou Ngai 
115bacd691cSlogin         return Softirq {
116bacd691cSlogin             table: RwLock::new(data),
117bacd691cSlogin         };
11862e46139SGou Ngai     }
11962e46139SGou Ngai 
12062e46139SGou Ngai     /// @brief 注册软中断向量
121bacd691cSlogin     ///
122bacd691cSlogin     /// @param softirq_num 中断向量号
123bacd691cSlogin     ///
124bacd691cSlogin     /// @param hanlder 中断函数对应的结构体
12562e46139SGou Ngai     pub fn register_softirq(
126bacd691cSlogin         &self,
127bacd691cSlogin         softirq_num: SoftirqNumber,
128bacd691cSlogin         handler: Arc<dyn SoftirqVec>,
129bacd691cSlogin     ) -> Result<i32, SystemError> {
130bacd691cSlogin         // kdebug!("register_softirq softirq_num = {:?}", softirq_num as u64);
13162e46139SGou Ngai 
132bacd691cSlogin         // let self = &mut SOFTIRQ_VECTORS.lock();
133bacd691cSlogin         // 判断该软中断向量是否已经被注册
134bacd691cSlogin         let mut table_guard = self.table.write();
135bacd691cSlogin         if table_guard[softirq_num as usize].is_some() {
136bacd691cSlogin             // kdebug!("register_softirq failed");
137bacd691cSlogin 
138bacd691cSlogin             return Err(SystemError::EINVAL);
13962e46139SGou Ngai         }
140bacd691cSlogin         table_guard[softirq_num as usize] = Some(handler);
141bacd691cSlogin         drop(table_guard);
142bacd691cSlogin 
143bacd691cSlogin         // kdebug!(
144bacd691cSlogin         //     "register_softirq successfully, softirq_num = {:?}",
145bacd691cSlogin         //     softirq_num as u64
146bacd691cSlogin         // );
147bacd691cSlogin         compiler_fence(Ordering::SeqCst);
148bacd691cSlogin         return Ok(0);
14962e46139SGou Ngai     }
15062e46139SGou Ngai 
15162e46139SGou Ngai     /// @brief 解注册软中断向量
152bacd691cSlogin     ///
15362e46139SGou Ngai     /// @param irq_num 中断向量号码
154bacd691cSlogin     pub fn unregister_softirq(&self, softirq_num: SoftirqNumber) {
155bacd691cSlogin         // kdebug!("unregister_softirq softirq_num = {:?}", softirq_num as u64);
156bacd691cSlogin         let table_guard = &mut self.table.write();
157bacd691cSlogin         // 将软中断向量清空
158bacd691cSlogin         table_guard[softirq_num as usize] = None;
159bacd691cSlogin         drop(table_guard);
160bacd691cSlogin         // 将对应位置的pending和runing都置0
161bacd691cSlogin         // self.running.lock().set(VecStatus::from(softirq_num), false);
162bacd691cSlogin         // 将对应CPU的pending置0
163bacd691cSlogin         compiler_fence(Ordering::SeqCst);
164bacd691cSlogin         cpu_pending(smp_get_processor_id() as usize).set(VecStatus::from(softirq_num), false);
165bacd691cSlogin         compiler_fence(Ordering::SeqCst);
16662e46139SGou Ngai     }
167bacd691cSlogin 
168bacd691cSlogin     pub fn do_softirq(&self) {
169bacd691cSlogin         // TODO pcb的flags未修改
170bacd691cSlogin         // todo: 是否需要判断在当前cpu上面,该函数的嵌套层数?(防止爆栈)
171bacd691cSlogin         let end = clock() + 500 * 2;
172bacd691cSlogin         let cpu_id = smp_get_processor_id();
173bacd691cSlogin         let mut max_restart = MAX_SOFTIRQ_RESTART;
174bacd691cSlogin         loop {
175bacd691cSlogin             compiler_fence(Ordering::SeqCst);
176bacd691cSlogin             let pending = cpu_pending(cpu_id as usize).bits;
177bacd691cSlogin             cpu_pending(cpu_id as usize).bits = 0;
178bacd691cSlogin             compiler_fence(Ordering::SeqCst);
179bacd691cSlogin 
180bacd691cSlogin             sti();
181bacd691cSlogin             if pending != 0 {
182bacd691cSlogin                 for i in 0..MAX_SOFTIRQ_NUM {
183bacd691cSlogin                     if pending & (1 << i) == 0 {
18462e46139SGou Ngai                         continue;
18562e46139SGou Ngai                     }
186bacd691cSlogin 
187bacd691cSlogin                     let table_guard = self.table.read();
188bacd691cSlogin                     let softirq_func = table_guard[i as usize].clone();
189bacd691cSlogin                     drop(table_guard);
190bacd691cSlogin                     if softirq_func.is_none() {
191bacd691cSlogin                         continue;
192bacd691cSlogin                     }
193bacd691cSlogin 
194*1496ba7bSLoGin                     let prev_count: usize = ProcessManager::current_pcb().preempt_count();
195bacd691cSlogin 
196bacd691cSlogin                     softirq_func.as_ref().unwrap().run();
197*1496ba7bSLoGin                     if unlikely(prev_count != ProcessManager::current_pcb().preempt_count()) {
198bacd691cSlogin                         kdebug!(
199bacd691cSlogin                             "entered softirq {:?} with preempt_count {:?},exited with {:?}",
200bacd691cSlogin                             i,
201bacd691cSlogin                             prev_count,
202*1496ba7bSLoGin                             ProcessManager::current_pcb().preempt_count()
203bacd691cSlogin                         );
204*1496ba7bSLoGin                         unsafe { ProcessManager::current_pcb().set_preempt_count(prev_count) };
205bacd691cSlogin                     }
206bacd691cSlogin                 }
207bacd691cSlogin             }
208bacd691cSlogin             cli();
209bacd691cSlogin             max_restart -= 1;
210bacd691cSlogin             compiler_fence(Ordering::SeqCst);
211bacd691cSlogin             if cpu_pending(cpu_id as usize).is_empty() {
212bacd691cSlogin                 compiler_fence(Ordering::SeqCst);
213bacd691cSlogin                 if clock() < end && max_restart > 0 {
214bacd691cSlogin                     continue;
215bacd691cSlogin                 } else {
216bacd691cSlogin                     break;
217bacd691cSlogin                 }
218bacd691cSlogin             } else {
219bacd691cSlogin                 // TODO:当有softirqd时 唤醒它
22062e46139SGou Ngai                 break;
22162e46139SGou Ngai             }
22262e46139SGou Ngai         }
22362e46139SGou Ngai     }
22462e46139SGou Ngai 
225bacd691cSlogin     pub fn raise_softirq(&self, softirq_num: SoftirqNumber) {
2269550910aSChiichen         let guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
227bacd691cSlogin         let processor_id = smp_get_processor_id() as usize;
228bacd691cSlogin 
229bacd691cSlogin         cpu_pending(processor_id).insert(VecStatus::from(softirq_num));
230bacd691cSlogin 
231bacd691cSlogin         compiler_fence(Ordering::SeqCst);
232bacd691cSlogin 
2339550910aSChiichen         drop(guard);
234bacd691cSlogin         // kdebug!("raise_softirq exited");
23562e46139SGou Ngai     }
2368fd71f27Shoumkh     pub unsafe fn clear_softirq_pending(&self, softirq_num: SoftirqNumber) {
237bacd691cSlogin         compiler_fence(Ordering::SeqCst);
238bacd691cSlogin         cpu_pending(smp_get_processor_id() as usize).remove(VecStatus::from(softirq_num));
239bacd691cSlogin         compiler_fence(Ordering::SeqCst);
24062e46139SGou Ngai     }
24162e46139SGou Ngai }
242bacd691cSlogin 
243bacd691cSlogin // ======= 以下为给C提供的接口 =======
244bacd691cSlogin #[no_mangle]
245bacd691cSlogin pub extern "C" fn rs_raise_softirq(softirq_num: u32) {
246bacd691cSlogin     softirq_vectors().raise_softirq(SoftirqNumber::from(softirq_num as u64));
24762e46139SGou Ngai }
248bacd691cSlogin 
249bacd691cSlogin #[no_mangle]
250bacd691cSlogin pub extern "C" fn rs_unregister_softirq(softirq_num: u32) {
251bacd691cSlogin     softirq_vectors().unregister_softirq(SoftirqNumber::from(softirq_num as u64));
25262e46139SGou Ngai }
253bacd691cSlogin 
254bacd691cSlogin #[no_mangle]
255bacd691cSlogin pub extern "C" fn rs_do_softirq() {
256bacd691cSlogin     softirq_vectors().do_softirq();
257bacd691cSlogin }
258bacd691cSlogin 
259bacd691cSlogin #[no_mangle]
260bacd691cSlogin pub extern "C" fn rs_clear_softirq_pending(softirq_num: u32) {
2618fd71f27Shoumkh     unsafe {
262bacd691cSlogin         softirq_vectors().clear_softirq_pending(SoftirqNumber::from(softirq_num as u64));
26362e46139SGou Ngai     }
2648fd71f27Shoumkh }
265