xref: /DragonOS/kernel/src/exception/softirq.rs (revision bacd691c9ef0502b5cc618aad50517f9e59df5e0)
1*bacd691cSlogin use core::{
2*bacd691cSlogin     fmt::Debug,
3*bacd691cSlogin     intrinsics::unlikely,
4*bacd691cSlogin     mem::{self, MaybeUninit},
5*bacd691cSlogin     ptr::null_mut,
6*bacd691cSlogin     sync::atomic::{compiler_fence, Ordering},
7*bacd691cSlogin };
862e46139SGou Ngai 
9*bacd691cSlogin use alloc::{boxed::Box, sync::Arc};
10*bacd691cSlogin use num_traits::FromPrimitive;
1162e46139SGou Ngai 
1262e46139SGou Ngai use crate::{
13*bacd691cSlogin     arch::{
14*bacd691cSlogin         asm::{
15*bacd691cSlogin             current::current_pcb,
16*bacd691cSlogin             irqflags::{local_irq_restore, local_irq_save},
17*bacd691cSlogin         },
18*bacd691cSlogin         interrupt::{cli, sti},
19*bacd691cSlogin     },
20*bacd691cSlogin     include::bindings::bindings::MAX_CPU_NUM,
21*bacd691cSlogin     kdebug, kinfo,
22*bacd691cSlogin     libs::rwlock::RwLock,
23*bacd691cSlogin     smp::core::smp_get_processor_id,
24*bacd691cSlogin     syscall::SystemError,
25*bacd691cSlogin     time::timer::clock,
2662e46139SGou Ngai };
2762e46139SGou Ngai 
2862e46139SGou Ngai const MAX_SOFTIRQ_NUM: u64 = 64;
29*bacd691cSlogin const MAX_SOFTIRQ_RESTART: i32 = 20;
30*bacd691cSlogin 
31*bacd691cSlogin static mut __CPU_PENDING: Option<Box<[VecStatus; MAX_CPU_NUM as usize]>> = None;
32*bacd691cSlogin static mut __SORTIRQ_VECTORS: *mut Softirq = null_mut();
33*bacd691cSlogin 
34*bacd691cSlogin #[no_mangle]
35*bacd691cSlogin pub extern "C" fn rs_softirq_init() {
36*bacd691cSlogin     softirq_init().expect("softirq_init failed");
37*bacd691cSlogin }
38*bacd691cSlogin 
39*bacd691cSlogin pub fn softirq_init() -> Result<(), SystemError> {
40*bacd691cSlogin     kinfo!("Initializing softirq...");
41*bacd691cSlogin     unsafe {
42*bacd691cSlogin         __SORTIRQ_VECTORS = Box::leak(Box::new(Softirq::new()));
43*bacd691cSlogin         __CPU_PENDING = Some(Box::new([VecStatus::default(); MAX_CPU_NUM as usize]));
44*bacd691cSlogin         let cpu_pending = __CPU_PENDING.as_mut().unwrap();
45*bacd691cSlogin         for i in 0..MAX_CPU_NUM {
46*bacd691cSlogin             cpu_pending[i as usize] = VecStatus::default();
47*bacd691cSlogin         }
48*bacd691cSlogin     }
49*bacd691cSlogin     return Ok(());
50*bacd691cSlogin }
51*bacd691cSlogin 
52*bacd691cSlogin #[inline(always)]
53*bacd691cSlogin pub fn softirq_vectors() -> &'static mut Softirq {
54*bacd691cSlogin     unsafe {
55*bacd691cSlogin         return __SORTIRQ_VECTORS.as_mut().unwrap();
56*bacd691cSlogin     }
57*bacd691cSlogin }
58*bacd691cSlogin 
59*bacd691cSlogin #[inline(always)]
60*bacd691cSlogin fn cpu_pending(cpu_id: usize) -> &'static mut VecStatus {
61*bacd691cSlogin     unsafe {
62*bacd691cSlogin         return &mut __CPU_PENDING.as_mut().unwrap()[cpu_id];
63*bacd691cSlogin     }
64*bacd691cSlogin }
6562e46139SGou Ngai 
6662e46139SGou Ngai /// 软中断向量号码
6762e46139SGou Ngai #[allow(dead_code)]
6862e46139SGou Ngai #[repr(u8)]
69*bacd691cSlogin #[derive(FromPrimitive, Copy, Clone, Debug, PartialEq, Eq)]
7062e46139SGou Ngai pub enum SoftirqNumber {
71*bacd691cSlogin     /// 时钟软中断信号
72*bacd691cSlogin     TIMER = 0,
7362e46139SGou Ngai     VideoRefresh = 1, //帧缓冲区刷新软中断
7462e46139SGou Ngai }
7562e46139SGou Ngai 
76*bacd691cSlogin impl From<u64> for SoftirqNumber {
77*bacd691cSlogin     fn from(value: u64) -> Self {
78*bacd691cSlogin         return <Self as FromPrimitive>::from_u64(value).unwrap();
7962e46139SGou Ngai     }
8062e46139SGou Ngai }
8162e46139SGou Ngai 
82*bacd691cSlogin bitflags! {
83*bacd691cSlogin     #[derive(Default)]
84*bacd691cSlogin     pub struct VecStatus: u64 {
85*bacd691cSlogin         const TIMER = 1 << 0;
86*bacd691cSlogin         const VIDEO_REFRESH = 1 << 1;
87*bacd691cSlogin     }
88*bacd691cSlogin }
89*bacd691cSlogin 
90*bacd691cSlogin impl From<SoftirqNumber> for VecStatus {
91*bacd691cSlogin     fn from(value: SoftirqNumber) -> Self {
92*bacd691cSlogin         return Self::from_bits_truncate(1 << (value as u64));
93*bacd691cSlogin     }
94*bacd691cSlogin }
95*bacd691cSlogin 
96*bacd691cSlogin pub trait SoftirqVec: Send + Sync + Debug {
97*bacd691cSlogin     fn run(&self);
98*bacd691cSlogin }
99*bacd691cSlogin 
100*bacd691cSlogin #[derive(Debug)]
10162e46139SGou Ngai pub struct Softirq {
102*bacd691cSlogin     table: RwLock<[Option<Arc<dyn SoftirqVec>>; MAX_SOFTIRQ_NUM as usize]>,
10362e46139SGou Ngai }
10462e46139SGou Ngai impl Softirq {
105*bacd691cSlogin     fn new() -> Softirq {
106*bacd691cSlogin         let mut data: [MaybeUninit<Option<Arc<dyn SoftirqVec>>>; MAX_SOFTIRQ_NUM as usize] =
107*bacd691cSlogin             unsafe { MaybeUninit::uninit().assume_init() };
108*bacd691cSlogin 
109*bacd691cSlogin         for i in 0..MAX_SOFTIRQ_NUM {
110*bacd691cSlogin             data[i as usize] = MaybeUninit::new(None);
11162e46139SGou Ngai         }
11262e46139SGou Ngai 
113*bacd691cSlogin         let data: [Option<Arc<dyn SoftirqVec>>; MAX_SOFTIRQ_NUM as usize] = unsafe {
114*bacd691cSlogin             mem::transmute::<_, [Option<Arc<dyn SoftirqVec>>; MAX_SOFTIRQ_NUM as usize]>(data)
115*bacd691cSlogin         };
11662e46139SGou Ngai 
117*bacd691cSlogin         return Softirq {
118*bacd691cSlogin             table: RwLock::new(data),
119*bacd691cSlogin         };
12062e46139SGou Ngai     }
12162e46139SGou Ngai 
12262e46139SGou Ngai     /// @brief 注册软中断向量
123*bacd691cSlogin     ///
124*bacd691cSlogin     /// @param softirq_num 中断向量号
125*bacd691cSlogin     ///
126*bacd691cSlogin     /// @param hanlder 中断函数对应的结构体
12762e46139SGou Ngai     pub fn register_softirq(
128*bacd691cSlogin         &self,
129*bacd691cSlogin         softirq_num: SoftirqNumber,
130*bacd691cSlogin         handler: Arc<dyn SoftirqVec>,
131*bacd691cSlogin     ) -> Result<i32, SystemError> {
132*bacd691cSlogin         // kdebug!("register_softirq softirq_num = {:?}", softirq_num as u64);
13362e46139SGou Ngai 
134*bacd691cSlogin         // let self = &mut SOFTIRQ_VECTORS.lock();
135*bacd691cSlogin         // 判断该软中断向量是否已经被注册
136*bacd691cSlogin         let mut table_guard = self.table.write();
137*bacd691cSlogin         if table_guard[softirq_num as usize].is_some() {
138*bacd691cSlogin             // kdebug!("register_softirq failed");
139*bacd691cSlogin 
140*bacd691cSlogin             return Err(SystemError::EINVAL);
14162e46139SGou Ngai         }
142*bacd691cSlogin         table_guard[softirq_num as usize] = Some(handler);
143*bacd691cSlogin         drop(table_guard);
144*bacd691cSlogin 
145*bacd691cSlogin         // kdebug!(
146*bacd691cSlogin         //     "register_softirq successfully, softirq_num = {:?}",
147*bacd691cSlogin         //     softirq_num as u64
148*bacd691cSlogin         // );
149*bacd691cSlogin         compiler_fence(Ordering::SeqCst);
150*bacd691cSlogin         return Ok(0);
15162e46139SGou Ngai     }
15262e46139SGou Ngai 
15362e46139SGou Ngai     /// @brief 解注册软中断向量
154*bacd691cSlogin     ///
15562e46139SGou Ngai     /// @param irq_num 中断向量号码
156*bacd691cSlogin     pub fn unregister_softirq(&self, softirq_num: SoftirqNumber) {
157*bacd691cSlogin         // kdebug!("unregister_softirq softirq_num = {:?}", softirq_num as u64);
158*bacd691cSlogin         let table_guard = &mut self.table.write();
159*bacd691cSlogin         // 将软中断向量清空
160*bacd691cSlogin         table_guard[softirq_num as usize] = None;
161*bacd691cSlogin         drop(table_guard);
162*bacd691cSlogin         // 将对应位置的pending和runing都置0
163*bacd691cSlogin         // self.running.lock().set(VecStatus::from(softirq_num), false);
164*bacd691cSlogin         // 将对应CPU的pending置0
165*bacd691cSlogin         compiler_fence(Ordering::SeqCst);
166*bacd691cSlogin         cpu_pending(smp_get_processor_id() as usize).set(VecStatus::from(softirq_num), false);
167*bacd691cSlogin         compiler_fence(Ordering::SeqCst);
16862e46139SGou Ngai     }
169*bacd691cSlogin 
170*bacd691cSlogin     pub fn do_softirq(&self) {
171*bacd691cSlogin         // TODO pcb的flags未修改
172*bacd691cSlogin         // todo: 是否需要判断在当前cpu上面,该函数的嵌套层数?(防止爆栈)
173*bacd691cSlogin         let end = clock() + 500 * 2;
174*bacd691cSlogin         let cpu_id = smp_get_processor_id();
175*bacd691cSlogin         let mut max_restart = MAX_SOFTIRQ_RESTART;
176*bacd691cSlogin         loop {
177*bacd691cSlogin             compiler_fence(Ordering::SeqCst);
178*bacd691cSlogin             let pending = cpu_pending(cpu_id as usize).bits;
179*bacd691cSlogin             cpu_pending(cpu_id as usize).bits = 0;
180*bacd691cSlogin             compiler_fence(Ordering::SeqCst);
181*bacd691cSlogin 
182*bacd691cSlogin             sti();
183*bacd691cSlogin             if pending != 0 {
184*bacd691cSlogin                 for i in 0..MAX_SOFTIRQ_NUM {
185*bacd691cSlogin                     if pending & (1 << i) == 0 {
18662e46139SGou Ngai                         continue;
18762e46139SGou Ngai                     }
188*bacd691cSlogin 
189*bacd691cSlogin                     let table_guard = self.table.read();
190*bacd691cSlogin                     let softirq_func = table_guard[i as usize].clone();
191*bacd691cSlogin                     drop(table_guard);
192*bacd691cSlogin                     if softirq_func.is_none() {
193*bacd691cSlogin                         continue;
194*bacd691cSlogin                     }
195*bacd691cSlogin 
196*bacd691cSlogin                     let prev_count = current_pcb().preempt_count;
197*bacd691cSlogin 
198*bacd691cSlogin                     softirq_func.as_ref().unwrap().run();
199*bacd691cSlogin                     if unlikely(prev_count != current_pcb().preempt_count) {
200*bacd691cSlogin                         kdebug!(
201*bacd691cSlogin                             "entered softirq {:?} with preempt_count {:?},exited with {:?}",
202*bacd691cSlogin                             i,
203*bacd691cSlogin                             prev_count,
204*bacd691cSlogin                             current_pcb().preempt_count
205*bacd691cSlogin                         );
206*bacd691cSlogin                         current_pcb().preempt_count = prev_count;
207*bacd691cSlogin                     }
208*bacd691cSlogin                 }
209*bacd691cSlogin             }
210*bacd691cSlogin             cli();
211*bacd691cSlogin             max_restart -= 1;
212*bacd691cSlogin             compiler_fence(Ordering::SeqCst);
213*bacd691cSlogin             if cpu_pending(cpu_id as usize).is_empty() {
214*bacd691cSlogin                 compiler_fence(Ordering::SeqCst);
215*bacd691cSlogin                 if clock() < end && max_restart > 0 {
216*bacd691cSlogin                     continue;
217*bacd691cSlogin                 } else {
218*bacd691cSlogin                     break;
219*bacd691cSlogin                 }
220*bacd691cSlogin             } else {
221*bacd691cSlogin                 // TODO:当有softirqd时 唤醒它
22262e46139SGou Ngai                 break;
22362e46139SGou Ngai             }
22462e46139SGou Ngai         }
22562e46139SGou Ngai     }
22662e46139SGou Ngai 
227*bacd691cSlogin     pub fn raise_softirq(&self, softirq_num: SoftirqNumber) {
228*bacd691cSlogin         let mut flags = 0;
229*bacd691cSlogin         local_irq_save(&mut flags);
230*bacd691cSlogin         let processor_id = smp_get_processor_id() as usize;
231*bacd691cSlogin 
232*bacd691cSlogin         cpu_pending(processor_id).insert(VecStatus::from(softirq_num));
233*bacd691cSlogin 
234*bacd691cSlogin         compiler_fence(Ordering::SeqCst);
235*bacd691cSlogin 
236*bacd691cSlogin         local_irq_restore(&flags);
237*bacd691cSlogin         // kdebug!("raise_softirq exited");
23862e46139SGou Ngai     }
239*bacd691cSlogin     pub fn clear_softirq_pending(&self, softirq_num: SoftirqNumber) {
240*bacd691cSlogin         compiler_fence(Ordering::SeqCst);
241*bacd691cSlogin         cpu_pending(smp_get_processor_id() as usize).remove(VecStatus::from(softirq_num));
242*bacd691cSlogin         compiler_fence(Ordering::SeqCst);
24362e46139SGou Ngai     }
24462e46139SGou Ngai }
245*bacd691cSlogin 
246*bacd691cSlogin // ======= 以下为给C提供的接口 =======
247*bacd691cSlogin #[no_mangle]
248*bacd691cSlogin pub extern "C" fn rs_raise_softirq(softirq_num: u32) {
249*bacd691cSlogin     softirq_vectors().raise_softirq(SoftirqNumber::from(softirq_num as u64));
25062e46139SGou Ngai }
251*bacd691cSlogin 
252*bacd691cSlogin #[no_mangle]
253*bacd691cSlogin pub extern "C" fn rs_unregister_softirq(softirq_num: u32) {
254*bacd691cSlogin     softirq_vectors().unregister_softirq(SoftirqNumber::from(softirq_num as u64));
25562e46139SGou Ngai }
256*bacd691cSlogin 
257*bacd691cSlogin #[no_mangle]
258*bacd691cSlogin pub extern "C" fn rs_do_softirq() {
259*bacd691cSlogin     softirq_vectors().do_softirq();
260*bacd691cSlogin }
261*bacd691cSlogin 
262*bacd691cSlogin #[no_mangle]
263*bacd691cSlogin pub extern "C" fn rs_clear_softirq_pending(softirq_num: u32) {
264*bacd691cSlogin     softirq_vectors().clear_softirq_pending(SoftirqNumber::from(softirq_num as u64));
26562e46139SGou Ngai }
266