xref: /DragonOS/kernel/src/exception/softirq.rs (revision 0d6cf65aa124ee55bfee44cbb5196917ea6522fa)
1bacd691cSlogin use core::{
2bacd691cSlogin     fmt::Debug,
3bacd691cSlogin     intrinsics::unlikely,
4bacd691cSlogin     mem::{self, MaybeUninit},
5bacd691cSlogin     ptr::null_mut,
6*0d6cf65aSLoGin     sync::atomic::{compiler_fence, AtomicI16, Ordering},
7bacd691cSlogin };
862e46139SGou Ngai 
9*0d6cf65aSLoGin use alloc::{boxed::Box, sync::Arc, vec::Vec};
10bacd691cSlogin use num_traits::FromPrimitive;
1191e9d4abSLoGin use system_error::SystemError;
1262e46139SGou Ngai 
1362e46139SGou Ngai use crate::{
14*0d6cf65aSLoGin     arch::CurrentIrqArch,
15*0d6cf65aSLoGin     exception::InterruptArch,
16*0d6cf65aSLoGin     kdebug, kinfo,
17*0d6cf65aSLoGin     libs::rwlock::RwLock,
18*0d6cf65aSLoGin     mm::percpu::{PerCpu, PerCpuVar},
19*0d6cf65aSLoGin     process::ProcessManager,
20*0d6cf65aSLoGin     smp::core::smp_get_processor_id,
2191e9d4abSLoGin     time::timer::clock,
2262e46139SGou Ngai };
2362e46139SGou Ngai 
2462e46139SGou Ngai const MAX_SOFTIRQ_NUM: u64 = 64;
25bacd691cSlogin const MAX_SOFTIRQ_RESTART: i32 = 20;
26bacd691cSlogin 
2746e234aeSLoGin static mut __CPU_PENDING: Option<Box<[VecStatus; PerCpu::MAX_CPU_NUM]>> = None;
28bacd691cSlogin static mut __SORTIRQ_VECTORS: *mut Softirq = null_mut();
29bacd691cSlogin 
30bacd691cSlogin #[no_mangle]
31bacd691cSlogin pub extern "C" fn rs_softirq_init() {
32bacd691cSlogin     softirq_init().expect("softirq_init failed");
33bacd691cSlogin }
34bacd691cSlogin 
35bacd691cSlogin pub fn softirq_init() -> Result<(), SystemError> {
36bacd691cSlogin     kinfo!("Initializing softirq...");
37bacd691cSlogin     unsafe {
38bacd691cSlogin         __SORTIRQ_VECTORS = Box::leak(Box::new(Softirq::new()));
3946e234aeSLoGin         __CPU_PENDING = Some(Box::new(
4046e234aeSLoGin             [VecStatus::default(); PerCpu::MAX_CPU_NUM as usize],
4146e234aeSLoGin         ));
42bacd691cSlogin         let cpu_pending = __CPU_PENDING.as_mut().unwrap();
4346e234aeSLoGin         for i in 0..PerCpu::MAX_CPU_NUM {
44bacd691cSlogin             cpu_pending[i as usize] = VecStatus::default();
45bacd691cSlogin         }
46bacd691cSlogin     }
4740fe15e0SLoGin     kinfo!("Softirq initialized.");
48bacd691cSlogin     return Ok(());
49bacd691cSlogin }
50bacd691cSlogin 
51bacd691cSlogin #[inline(always)]
52bacd691cSlogin pub fn softirq_vectors() -> &'static mut Softirq {
53bacd691cSlogin     unsafe {
54bacd691cSlogin         return __SORTIRQ_VECTORS.as_mut().unwrap();
55bacd691cSlogin     }
56bacd691cSlogin }
57bacd691cSlogin 
58bacd691cSlogin #[inline(always)]
59bacd691cSlogin fn cpu_pending(cpu_id: usize) -> &'static mut VecStatus {
60bacd691cSlogin     unsafe {
61bacd691cSlogin         return &mut __CPU_PENDING.as_mut().unwrap()[cpu_id];
62bacd691cSlogin     }
63bacd691cSlogin }
6462e46139SGou Ngai 
6562e46139SGou Ngai /// 软中断向量号码
6662e46139SGou Ngai #[allow(dead_code)]
6762e46139SGou Ngai #[repr(u8)]
68bacd691cSlogin #[derive(FromPrimitive, Copy, Clone, Debug, PartialEq, Eq)]
6962e46139SGou Ngai pub enum SoftirqNumber {
70bacd691cSlogin     /// 时钟软中断信号
71bacd691cSlogin     TIMER = 0,
7262e46139SGou Ngai     VideoRefresh = 1, //帧缓冲区刷新软中断
7362e46139SGou Ngai }
7462e46139SGou Ngai 
75bacd691cSlogin impl From<u64> for SoftirqNumber {
76bacd691cSlogin     fn from(value: u64) -> Self {
77bacd691cSlogin         return <Self as FromPrimitive>::from_u64(value).unwrap();
7862e46139SGou Ngai     }
7962e46139SGou Ngai }
8062e46139SGou Ngai 
81bacd691cSlogin bitflags! {
82bacd691cSlogin     #[derive(Default)]
83bacd691cSlogin     pub struct VecStatus: u64 {
84bacd691cSlogin         const TIMER = 1 << 0;
85bacd691cSlogin         const VIDEO_REFRESH = 1 << 1;
86bacd691cSlogin     }
87bacd691cSlogin }
88bacd691cSlogin 
89bacd691cSlogin impl From<SoftirqNumber> for VecStatus {
90bacd691cSlogin     fn from(value: SoftirqNumber) -> Self {
91bacd691cSlogin         return Self::from_bits_truncate(1 << (value as u64));
92bacd691cSlogin     }
93bacd691cSlogin }
94bacd691cSlogin 
95bacd691cSlogin pub trait SoftirqVec: Send + Sync + Debug {
96bacd691cSlogin     fn run(&self);
97bacd691cSlogin }
98bacd691cSlogin 
99bacd691cSlogin #[derive(Debug)]
10062e46139SGou Ngai pub struct Softirq {
101bacd691cSlogin     table: RwLock<[Option<Arc<dyn SoftirqVec>>; MAX_SOFTIRQ_NUM as usize]>,
102*0d6cf65aSLoGin     /// 软中断嵌套层数(per cpu)
103*0d6cf65aSLoGin     cpu_running_count: PerCpuVar<AtomicI16>,
10462e46139SGou Ngai }
10562e46139SGou Ngai impl Softirq {
106*0d6cf65aSLoGin     /// 每个CPU最大嵌套的软中断数量
107*0d6cf65aSLoGin     const MAX_RUNNING_PER_CPU: i16 = 3;
108bacd691cSlogin     fn new() -> Softirq {
109bacd691cSlogin         let mut data: [MaybeUninit<Option<Arc<dyn SoftirqVec>>>; MAX_SOFTIRQ_NUM as usize] =
110bacd691cSlogin             unsafe { MaybeUninit::uninit().assume_init() };
111bacd691cSlogin 
112bacd691cSlogin         for i in 0..MAX_SOFTIRQ_NUM {
113bacd691cSlogin             data[i as usize] = MaybeUninit::new(None);
11462e46139SGou Ngai         }
11562e46139SGou Ngai 
116bacd691cSlogin         let data: [Option<Arc<dyn SoftirqVec>>; MAX_SOFTIRQ_NUM as usize] = unsafe {
117bacd691cSlogin             mem::transmute::<_, [Option<Arc<dyn SoftirqVec>>; MAX_SOFTIRQ_NUM as usize]>(data)
118bacd691cSlogin         };
11962e46139SGou Ngai 
120*0d6cf65aSLoGin         let mut percpu_count = Vec::with_capacity(PerCpu::MAX_CPU_NUM as usize);
121*0d6cf65aSLoGin         percpu_count.resize_with(PerCpu::MAX_CPU_NUM as usize, || AtomicI16::new(0));
122*0d6cf65aSLoGin         let cpu_running_count = PerCpuVar::new(percpu_count).unwrap();
123*0d6cf65aSLoGin 
124bacd691cSlogin         return Softirq {
125bacd691cSlogin             table: RwLock::new(data),
126*0d6cf65aSLoGin             cpu_running_count,
127bacd691cSlogin         };
12862e46139SGou Ngai     }
12962e46139SGou Ngai 
130*0d6cf65aSLoGin     fn cpu_running_count(&self) -> &PerCpuVar<AtomicI16> {
131*0d6cf65aSLoGin         return &self.cpu_running_count;
132*0d6cf65aSLoGin     }
133*0d6cf65aSLoGin 
13462e46139SGou Ngai     /// @brief 注册软中断向量
135bacd691cSlogin     ///
136bacd691cSlogin     /// @param softirq_num 中断向量号
137bacd691cSlogin     ///
138bacd691cSlogin     /// @param hanlder 中断函数对应的结构体
13962e46139SGou Ngai     pub fn register_softirq(
140bacd691cSlogin         &self,
141bacd691cSlogin         softirq_num: SoftirqNumber,
142bacd691cSlogin         handler: Arc<dyn SoftirqVec>,
143bacd691cSlogin     ) -> Result<i32, SystemError> {
144bacd691cSlogin         // kdebug!("register_softirq softirq_num = {:?}", softirq_num as u64);
14562e46139SGou Ngai 
146bacd691cSlogin         // let self = &mut SOFTIRQ_VECTORS.lock();
147bacd691cSlogin         // 判断该软中断向量是否已经被注册
148*0d6cf65aSLoGin         let mut table_guard = self.table.write_irqsave();
149bacd691cSlogin         if table_guard[softirq_num as usize].is_some() {
150bacd691cSlogin             // kdebug!("register_softirq failed");
151bacd691cSlogin 
152bacd691cSlogin             return Err(SystemError::EINVAL);
15362e46139SGou Ngai         }
154bacd691cSlogin         table_guard[softirq_num as usize] = Some(handler);
155bacd691cSlogin         drop(table_guard);
156bacd691cSlogin 
157bacd691cSlogin         // kdebug!(
158bacd691cSlogin         //     "register_softirq successfully, softirq_num = {:?}",
159bacd691cSlogin         //     softirq_num as u64
160bacd691cSlogin         // );
161bacd691cSlogin         compiler_fence(Ordering::SeqCst);
162bacd691cSlogin         return Ok(0);
16362e46139SGou Ngai     }
16462e46139SGou Ngai 
16562e46139SGou Ngai     /// @brief 解注册软中断向量
166bacd691cSlogin     ///
16762e46139SGou Ngai     /// @param irq_num 中断向量号码
168bacd691cSlogin     pub fn unregister_softirq(&self, softirq_num: SoftirqNumber) {
169bacd691cSlogin         // kdebug!("unregister_softirq softirq_num = {:?}", softirq_num as u64);
170*0d6cf65aSLoGin         let mut table_guard = self.table.write_irqsave();
171bacd691cSlogin         // 将软中断向量清空
172bacd691cSlogin         table_guard[softirq_num as usize] = None;
173bacd691cSlogin         drop(table_guard);
174bacd691cSlogin         // 将对应位置的pending和runing都置0
175bacd691cSlogin         // self.running.lock().set(VecStatus::from(softirq_num), false);
176bacd691cSlogin         // 将对应CPU的pending置0
177bacd691cSlogin         compiler_fence(Ordering::SeqCst);
178bacd691cSlogin         cpu_pending(smp_get_processor_id() as usize).set(VecStatus::from(softirq_num), false);
179bacd691cSlogin         compiler_fence(Ordering::SeqCst);
18062e46139SGou Ngai     }
181bacd691cSlogin 
182bacd691cSlogin     pub fn do_softirq(&self) {
183*0d6cf65aSLoGin         if self.cpu_running_count().get().load(Ordering::SeqCst) >= Self::MAX_RUNNING_PER_CPU {
184*0d6cf65aSLoGin             // 当前CPU的软中断嵌套层数已经达到最大值,不再执行
185*0d6cf65aSLoGin             return;
186*0d6cf65aSLoGin         }
187*0d6cf65aSLoGin         // 创建一个RunningCountGuard,当退出作用域时,会自动将cpu_running_count减1
188*0d6cf65aSLoGin         let _count_guard = RunningCountGuard::new(self.cpu_running_count());
189*0d6cf65aSLoGin 
190bacd691cSlogin         // TODO pcb的flags未修改
191bacd691cSlogin         let end = clock() + 500 * 2;
192bacd691cSlogin         let cpu_id = smp_get_processor_id();
193bacd691cSlogin         let mut max_restart = MAX_SOFTIRQ_RESTART;
194bacd691cSlogin         loop {
195bacd691cSlogin             compiler_fence(Ordering::SeqCst);
196bacd691cSlogin             let pending = cpu_pending(cpu_id as usize).bits;
197bacd691cSlogin             cpu_pending(cpu_id as usize).bits = 0;
198bacd691cSlogin             compiler_fence(Ordering::SeqCst);
199bacd691cSlogin 
20046e234aeSLoGin             unsafe { CurrentIrqArch::interrupt_enable() };
201bacd691cSlogin             if pending != 0 {
202bacd691cSlogin                 for i in 0..MAX_SOFTIRQ_NUM {
203bacd691cSlogin                     if pending & (1 << i) == 0 {
20462e46139SGou Ngai                         continue;
20562e46139SGou Ngai                     }
206bacd691cSlogin 
207*0d6cf65aSLoGin                     let table_guard = self.table.read_irqsave();
208bacd691cSlogin                     let softirq_func = table_guard[i as usize].clone();
209bacd691cSlogin                     drop(table_guard);
210bacd691cSlogin                     if softirq_func.is_none() {
211bacd691cSlogin                         continue;
212bacd691cSlogin                     }
213bacd691cSlogin 
2141496ba7bSLoGin                     let prev_count: usize = ProcessManager::current_pcb().preempt_count();
215bacd691cSlogin 
216bacd691cSlogin                     softirq_func.as_ref().unwrap().run();
2171496ba7bSLoGin                     if unlikely(prev_count != ProcessManager::current_pcb().preempt_count()) {
218bacd691cSlogin                         kdebug!(
219bacd691cSlogin                             "entered softirq {:?} with preempt_count {:?},exited with {:?}",
220bacd691cSlogin                             i,
221bacd691cSlogin                             prev_count,
2221496ba7bSLoGin                             ProcessManager::current_pcb().preempt_count()
223bacd691cSlogin                         );
2241496ba7bSLoGin                         unsafe { ProcessManager::current_pcb().set_preempt_count(prev_count) };
225bacd691cSlogin                     }
226bacd691cSlogin                 }
227bacd691cSlogin             }
22846e234aeSLoGin             unsafe { CurrentIrqArch::interrupt_disable() };
229bacd691cSlogin             max_restart -= 1;
230bacd691cSlogin             compiler_fence(Ordering::SeqCst);
231bacd691cSlogin             if cpu_pending(cpu_id as usize).is_empty() {
232bacd691cSlogin                 compiler_fence(Ordering::SeqCst);
233bacd691cSlogin                 if clock() < end && max_restart > 0 {
234bacd691cSlogin                     continue;
235bacd691cSlogin                 } else {
236bacd691cSlogin                     break;
237bacd691cSlogin                 }
238bacd691cSlogin             } else {
239bacd691cSlogin                 // TODO:当有softirqd时 唤醒它
24062e46139SGou Ngai                 break;
24162e46139SGou Ngai             }
24262e46139SGou Ngai         }
24362e46139SGou Ngai     }
24462e46139SGou Ngai 
245bacd691cSlogin     pub fn raise_softirq(&self, softirq_num: SoftirqNumber) {
2469550910aSChiichen         let guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
247bacd691cSlogin         let processor_id = smp_get_processor_id() as usize;
248bacd691cSlogin 
249bacd691cSlogin         cpu_pending(processor_id).insert(VecStatus::from(softirq_num));
250bacd691cSlogin 
251bacd691cSlogin         compiler_fence(Ordering::SeqCst);
252bacd691cSlogin 
2539550910aSChiichen         drop(guard);
254bacd691cSlogin         // kdebug!("raise_softirq exited");
25562e46139SGou Ngai     }
2568fd71f27Shoumkh     pub unsafe fn clear_softirq_pending(&self, softirq_num: SoftirqNumber) {
257bacd691cSlogin         compiler_fence(Ordering::SeqCst);
258bacd691cSlogin         cpu_pending(smp_get_processor_id() as usize).remove(VecStatus::from(softirq_num));
259bacd691cSlogin         compiler_fence(Ordering::SeqCst);
26062e46139SGou Ngai     }
26162e46139SGou Ngai }
262bacd691cSlogin 
263*0d6cf65aSLoGin /// 当前CPU的软中断嵌套层数的计数器守卫
264*0d6cf65aSLoGin ///
265*0d6cf65aSLoGin /// 当进入作用域时,会自动将cpu_running_count加1,
266*0d6cf65aSLoGin /// 当退出作用域时,会自动将cpu_running_count减1
267*0d6cf65aSLoGin struct RunningCountGuard<'a> {
268*0d6cf65aSLoGin     cpu_running_count: &'a PerCpuVar<AtomicI16>,
269*0d6cf65aSLoGin }
270*0d6cf65aSLoGin 
271*0d6cf65aSLoGin impl<'a> RunningCountGuard<'a> {
272*0d6cf65aSLoGin     fn new(cpu_running_count: &'a PerCpuVar<AtomicI16>) -> RunningCountGuard {
273*0d6cf65aSLoGin         cpu_running_count.get().fetch_add(1, Ordering::SeqCst);
274*0d6cf65aSLoGin         return RunningCountGuard { cpu_running_count };
275*0d6cf65aSLoGin     }
276*0d6cf65aSLoGin }
277*0d6cf65aSLoGin 
278*0d6cf65aSLoGin impl<'a> Drop for RunningCountGuard<'a> {
279*0d6cf65aSLoGin     fn drop(&mut self) {
280*0d6cf65aSLoGin         self.cpu_running_count.get().fetch_sub(1, Ordering::SeqCst);
281*0d6cf65aSLoGin     }
282*0d6cf65aSLoGin }
283*0d6cf65aSLoGin 
284bacd691cSlogin // ======= 以下为给C提供的接口 =======
285bacd691cSlogin #[no_mangle]
286bacd691cSlogin pub extern "C" fn rs_raise_softirq(softirq_num: u32) {
287bacd691cSlogin     softirq_vectors().raise_softirq(SoftirqNumber::from(softirq_num as u64));
28862e46139SGou Ngai }
289bacd691cSlogin 
290bacd691cSlogin #[no_mangle]
291bacd691cSlogin pub extern "C" fn rs_unregister_softirq(softirq_num: u32) {
292bacd691cSlogin     softirq_vectors().unregister_softirq(SoftirqNumber::from(softirq_num as u64));
29362e46139SGou Ngai }
294bacd691cSlogin 
295bacd691cSlogin #[no_mangle]
296bacd691cSlogin pub extern "C" fn rs_do_softirq() {
297bacd691cSlogin     softirq_vectors().do_softirq();
298bacd691cSlogin }
299bacd691cSlogin 
300bacd691cSlogin #[no_mangle]
301bacd691cSlogin pub extern "C" fn rs_clear_softirq_pending(softirq_num: u32) {
3028fd71f27Shoumkh     unsafe {
303bacd691cSlogin         softirq_vectors().clear_softirq_pending(SoftirqNumber::from(softirq_num as u64));
30462e46139SGou Ngai     }
3058fd71f27Shoumkh }
306