xref: /DragonOS/kernel/src/exception/softirq.rs (revision 62e4613978193aaf5d949a331df0398f2d085a30)
1*62e46139SGou Ngai use core::{ffi::c_void, ptr::null_mut};
2*62e46139SGou Ngai 
3*62e46139SGou Ngai use alloc::boxed::Box;
4*62e46139SGou Ngai 
5*62e46139SGou Ngai use crate::{
6*62e46139SGou Ngai     arch::interrupt::{cli, sti},
7*62e46139SGou Ngai     include::bindings::bindings::{verify_area, EBUSY, EEXIST, EPERM},
8*62e46139SGou Ngai     kBUG,
9*62e46139SGou Ngai     libs::spinlock::RawSpinlock,
10*62e46139SGou Ngai };
11*62e46139SGou Ngai 
12*62e46139SGou Ngai const MAX_SOFTIRQ_NUM: u64 = 64;
13*62e46139SGou Ngai const MAX_LOCK_TRIAL_TIME: u64 = 50;
14*62e46139SGou Ngai pub static mut SOFTIRQ_HANDLER_PTR: *mut Softirq = null_mut();
15*62e46139SGou Ngai 
16*62e46139SGou Ngai /// 软中断向量号码
17*62e46139SGou Ngai #[allow(dead_code)]
18*62e46139SGou Ngai #[repr(u8)]
19*62e46139SGou Ngai pub enum SoftirqNumber {
20*62e46139SGou Ngai     TIMER = 0,        //时钟软中断信号
21*62e46139SGou Ngai     VideoRefresh = 1, //帧缓冲区刷新软中断
22*62e46139SGou Ngai }
23*62e46139SGou Ngai 
24*62e46139SGou Ngai #[repr(C)]
25*62e46139SGou Ngai #[derive(Clone, Copy)]
26*62e46139SGou Ngai pub struct SoftirqVector {
27*62e46139SGou Ngai     pub action: Option<unsafe extern "C" fn(data: *mut ::core::ffi::c_void)>, //软中断处理函数
28*62e46139SGou Ngai     pub data: *mut c_void,
29*62e46139SGou Ngai }
30*62e46139SGou Ngai 
31*62e46139SGou Ngai impl Default for SoftirqVector {
32*62e46139SGou Ngai     fn default() -> Self {
33*62e46139SGou Ngai         Self {
34*62e46139SGou Ngai             action: None,
35*62e46139SGou Ngai             data: null_mut(),
36*62e46139SGou Ngai         }
37*62e46139SGou Ngai     }
38*62e46139SGou Ngai }
39*62e46139SGou Ngai 
40*62e46139SGou Ngai pub struct Softirq {
41*62e46139SGou Ngai     modify_lock: RawSpinlock,
42*62e46139SGou Ngai     pending: u64,
43*62e46139SGou Ngai     running: u64,
44*62e46139SGou Ngai     table: [SoftirqVector; MAX_SOFTIRQ_NUM as usize],
45*62e46139SGou Ngai }
46*62e46139SGou Ngai 
47*62e46139SGou Ngai #[no_mangle]
48*62e46139SGou Ngai #[allow(dead_code)]
49*62e46139SGou Ngai /// @brief 提供给c的接口函数,用于初始化静态指针
50*62e46139SGou Ngai pub extern "C" fn softirq_init() {
51*62e46139SGou Ngai     if unsafe { SOFTIRQ_HANDLER_PTR.is_null() } {
52*62e46139SGou Ngai         unsafe {
53*62e46139SGou Ngai             SOFTIRQ_HANDLER_PTR = Box::leak(Box::new(Softirq::default()));
54*62e46139SGou Ngai         }
55*62e46139SGou Ngai     } else {
56*62e46139SGou Ngai         kBUG!("Try to init SOFTIRQ_HANDLER_PTR twice.");
57*62e46139SGou Ngai         panic!("Try to init SOFTIRQ_HANDLER_PTR twice.");
58*62e46139SGou Ngai     }
59*62e46139SGou Ngai }
60*62e46139SGou Ngai 
61*62e46139SGou Ngai /// @brief 将raw pointer转换为指针,减少unsafe块
62*62e46139SGou Ngai #[inline]
63*62e46139SGou Ngai pub fn __get_softirq_handler_mut() -> &'static mut Softirq {
64*62e46139SGou Ngai     return unsafe { SOFTIRQ_HANDLER_PTR.as_mut().unwrap() };
65*62e46139SGou Ngai }
66*62e46139SGou Ngai 
67*62e46139SGou Ngai #[no_mangle]
68*62e46139SGou Ngai #[allow(dead_code)]
69*62e46139SGou Ngai pub extern "C" fn raise_softirq(sirq_num: u64) {
70*62e46139SGou Ngai     let softirq_handler = __get_softirq_handler_mut();
71*62e46139SGou Ngai     softirq_handler.set_softirq_pending(1 << sirq_num);
72*62e46139SGou Ngai }
73*62e46139SGou Ngai 
74*62e46139SGou Ngai /// @brief 软中断注册函数
75*62e46139SGou Ngai ///
76*62e46139SGou Ngai /// @param irq_num 软中断号
77*62e46139SGou Ngai /// @param action 响应函数
78*62e46139SGou Ngai /// @param data 响应数据结构体
79*62e46139SGou Ngai #[no_mangle]
80*62e46139SGou Ngai #[allow(dead_code)]
81*62e46139SGou Ngai pub extern "C" fn register_softirq(
82*62e46139SGou Ngai     irq_num: u32,
83*62e46139SGou Ngai     action: Option<unsafe extern "C" fn(data: *mut ::core::ffi::c_void)>,
84*62e46139SGou Ngai     data: *mut c_void,
85*62e46139SGou Ngai ) {
86*62e46139SGou Ngai     let softirq_handler = __get_softirq_handler_mut();
87*62e46139SGou Ngai     softirq_handler.register_softirq(irq_num, action, data);
88*62e46139SGou Ngai }
89*62e46139SGou Ngai 
90*62e46139SGou Ngai /// @brief 卸载软中断
91*62e46139SGou Ngai /// @param irq_num 软中断号
92*62e46139SGou Ngai #[no_mangle]
93*62e46139SGou Ngai #[allow(dead_code)]
94*62e46139SGou Ngai pub extern "C" fn unregister_softirq(irq_num: u32) {
95*62e46139SGou Ngai     let softirq_handler = __get_softirq_handler_mut();
96*62e46139SGou Ngai     softirq_handler.unregister_softirq(irq_num);
97*62e46139SGou Ngai }
98*62e46139SGou Ngai 
99*62e46139SGou Ngai /// 设置软中断的运行状态(只应在do_softirq中调用此宏)
100*62e46139SGou Ngai #[no_mangle]
101*62e46139SGou Ngai #[allow(dead_code)]
102*62e46139SGou Ngai pub extern "C" fn set_softirq_pending(irq_num: u32) {
103*62e46139SGou Ngai     let softirq_handler = __get_softirq_handler_mut();
104*62e46139SGou Ngai     softirq_handler.set_softirq_pending(irq_num);
105*62e46139SGou Ngai }
106*62e46139SGou Ngai 
107*62e46139SGou Ngai /// @brief 设置软中断运行结束
108*62e46139SGou Ngai ///
109*62e46139SGou Ngai /// @param softirq_num
110*62e46139SGou Ngai #[no_mangle]
111*62e46139SGou Ngai #[allow(dead_code)]
112*62e46139SGou Ngai pub extern "C" fn clear_softirq_pending(irq_num: u32) {
113*62e46139SGou Ngai     let softirq_handler = __get_softirq_handler_mut();
114*62e46139SGou Ngai     softirq_handler.clear_softirq_pending(irq_num);
115*62e46139SGou Ngai }
116*62e46139SGou Ngai 
117*62e46139SGou Ngai /// @brief 软中断处理程序
118*62e46139SGou Ngai #[no_mangle]
119*62e46139SGou Ngai #[allow(dead_code)]
120*62e46139SGou Ngai pub extern "C" fn do_softirq() {
121*62e46139SGou Ngai     let softirq_handler = __get_softirq_handler_mut();
122*62e46139SGou Ngai     softirq_handler.do_softirq();
123*62e46139SGou Ngai }
124*62e46139SGou Ngai 
125*62e46139SGou Ngai impl Default for Softirq {
126*62e46139SGou Ngai     fn default() -> Self {
127*62e46139SGou Ngai         Self {
128*62e46139SGou Ngai             modify_lock: RawSpinlock::INIT,
129*62e46139SGou Ngai             pending: (0),
130*62e46139SGou Ngai             running: (0),
131*62e46139SGou Ngai             table: [Default::default(); MAX_SOFTIRQ_NUM as usize],
132*62e46139SGou Ngai         }
133*62e46139SGou Ngai     }
134*62e46139SGou Ngai }
135*62e46139SGou Ngai 
136*62e46139SGou Ngai impl Softirq {
137*62e46139SGou Ngai     #[inline]
138*62e46139SGou Ngai     #[allow(dead_code)]
139*62e46139SGou Ngai     pub fn get_softirq_pending(&self) -> u64 {
140*62e46139SGou Ngai         return self.pending;
141*62e46139SGou Ngai     }
142*62e46139SGou Ngai 
143*62e46139SGou Ngai     #[inline]
144*62e46139SGou Ngai     #[allow(dead_code)]
145*62e46139SGou Ngai     pub fn get_softirq_running(&self) -> u64 {
146*62e46139SGou Ngai         return self.running;
147*62e46139SGou Ngai     }
148*62e46139SGou Ngai 
149*62e46139SGou Ngai     #[inline]
150*62e46139SGou Ngai     pub fn set_softirq_pending(&mut self, softirq_num: u32) {
151*62e46139SGou Ngai         self.pending |= 1 << softirq_num;
152*62e46139SGou Ngai     }
153*62e46139SGou Ngai 
154*62e46139SGou Ngai     #[inline]
155*62e46139SGou Ngai     pub fn set_softirq_running(&mut self, softirq_num: u32) {
156*62e46139SGou Ngai         self.running |= 1 << softirq_num;
157*62e46139SGou Ngai     }
158*62e46139SGou Ngai 
159*62e46139SGou Ngai     #[inline]
160*62e46139SGou Ngai     pub fn clear_softirq_running(&mut self, softirq_num: u32) {
161*62e46139SGou Ngai         self.running &= !(1 << softirq_num);
162*62e46139SGou Ngai     }
163*62e46139SGou Ngai 
164*62e46139SGou Ngai     /// @brief 清除软中断pending标志位
165*62e46139SGou Ngai     #[inline]
166*62e46139SGou Ngai     pub fn clear_softirq_pending(&mut self, softirq_num: u32) {
167*62e46139SGou Ngai         self.pending &= !(1 << softirq_num);
168*62e46139SGou Ngai     }
169*62e46139SGou Ngai 
170*62e46139SGou Ngai     /// @brief 判断对应running标志位是否为0
171*62e46139SGou Ngai     /// @return true: 标志位为1; false: 标志位为0
172*62e46139SGou Ngai     #[inline]
173*62e46139SGou Ngai     pub fn is_running(&mut self, softirq_num: u32) -> bool {
174*62e46139SGou Ngai         return (self.running & (1 << softirq_num)).ne(&0);
175*62e46139SGou Ngai     }
176*62e46139SGou Ngai 
177*62e46139SGou Ngai     /// @brief 判断对应pending标志位是否为0
178*62e46139SGou Ngai     /// @return true: 标志位为1; false: 标志位为0
179*62e46139SGou Ngai     #[inline]
180*62e46139SGou Ngai     pub fn is_pending(&mut self, softirq_num: u32) -> bool {
181*62e46139SGou Ngai         return (self.pending & (1 << softirq_num)).ne(&0);
182*62e46139SGou Ngai     }
183*62e46139SGou Ngai 
184*62e46139SGou Ngai     /// @brief 注册软中断向量
185*62e46139SGou Ngai     /// @param irq_num 中断向量号码
186*62e46139SGou Ngai     /// @param action 中断函数的入口地址
187*62e46139SGou Ngai     /// @param data 中断函数的操作数据
188*62e46139SGou Ngai     pub fn register_softirq(
189*62e46139SGou Ngai         &mut self,
190*62e46139SGou Ngai         irq_num: u32,
191*62e46139SGou Ngai         action: Option<unsafe extern "C" fn(data: *mut ::core::ffi::c_void)>,
192*62e46139SGou Ngai         data: *mut c_void,
193*62e46139SGou Ngai     ) -> i32 {
194*62e46139SGou Ngai         if self.table[irq_num as usize].action.is_some() {
195*62e46139SGou Ngai             return -(EEXIST as i32);
196*62e46139SGou Ngai         }
197*62e46139SGou Ngai 
198*62e46139SGou Ngai         if unsafe { verify_area(action.unwrap() as u64, 1) } {
199*62e46139SGou Ngai             return -(EPERM as i32);
200*62e46139SGou Ngai         }
201*62e46139SGou Ngai         self.modify_lock.lock();
202*62e46139SGou Ngai         self.table[irq_num as usize].action = action;
203*62e46139SGou Ngai         self.table[irq_num as usize].data = data;
204*62e46139SGou Ngai         self.modify_lock.unlock();
205*62e46139SGou Ngai         return 0;
206*62e46139SGou Ngai     }
207*62e46139SGou Ngai 
208*62e46139SGou Ngai     /// @brief 解注册软中断向量
209*62e46139SGou Ngai     /// @param irq_num 中断向量号码
210*62e46139SGou Ngai     pub fn unregister_softirq(&mut self, irq_num: u32) -> i32 {
211*62e46139SGou Ngai         for _trial_time in 0..MAX_LOCK_TRIAL_TIME {
212*62e46139SGou Ngai             if self.is_running(irq_num) {
213*62e46139SGou Ngai                 continue; //running标志位为1
214*62e46139SGou Ngai             }
215*62e46139SGou Ngai             if self.modify_lock.try_lock() {
216*62e46139SGou Ngai                 if self.is_running(irq_num) {
217*62e46139SGou Ngai                     self.modify_lock.unlock();
218*62e46139SGou Ngai                     continue;
219*62e46139SGou Ngai                 }
220*62e46139SGou Ngai                 break;
221*62e46139SGou Ngai             }
222*62e46139SGou Ngai         }
223*62e46139SGou Ngai         // 存在尝试加锁规定次数后仍加锁失败的情况,报告错误并退出
224*62e46139SGou Ngai         if !self.modify_lock.is_locked() {
225*62e46139SGou Ngai             return -(EBUSY as i32);
226*62e46139SGou Ngai         }
227*62e46139SGou Ngai         self.clear_softirq_running(irq_num);
228*62e46139SGou Ngai         self.clear_softirq_pending(irq_num);
229*62e46139SGou Ngai         self.table[irq_num as usize].action = None;
230*62e46139SGou Ngai         self.table[irq_num as usize].data = null_mut();
231*62e46139SGou Ngai         self.modify_lock.unlock();
232*62e46139SGou Ngai         return 0;
233*62e46139SGou Ngai     }
234*62e46139SGou Ngai 
235*62e46139SGou Ngai     /// @brief 遍历执行软中断
236*62e46139SGou Ngai     pub fn do_softirq(&mut self) {
237*62e46139SGou Ngai         sti();
238*62e46139SGou Ngai         let mut softirq_index: u32 = 0; //软中断向量号码
239*62e46139SGou Ngai         while (softirq_index as u64) < MAX_SOFTIRQ_NUM && self.pending != 0 {
240*62e46139SGou Ngai             if self.is_pending(softirq_index)
241*62e46139SGou Ngai                 && self.table[softirq_index as usize].action.is_some()
242*62e46139SGou Ngai                 && !self.is_running(softirq_index)
243*62e46139SGou Ngai             {
244*62e46139SGou Ngai                 if self.modify_lock.try_lock() {
245*62e46139SGou Ngai                     if self.is_running(softirq_index)
246*62e46139SGou Ngai                         || self.table[softirq_index as usize].action.is_none()
247*62e46139SGou Ngai                     {
248*62e46139SGou Ngai                         self.modify_lock.unlock();
249*62e46139SGou Ngai                         continue;
250*62e46139SGou Ngai                     }
251*62e46139SGou Ngai                     self.clear_softirq_pending(softirq_index);
252*62e46139SGou Ngai                     self.set_softirq_running(softirq_index);
253*62e46139SGou Ngai                     self.modify_lock.unlock();
254*62e46139SGou Ngai                     unsafe {
255*62e46139SGou Ngai                         (self.table[softirq_index as usize].action.unwrap())(
256*62e46139SGou Ngai                             self.table[softirq_index as usize].data,
257*62e46139SGou Ngai                         );
258*62e46139SGou Ngai                     }
259*62e46139SGou Ngai                     self.clear_softirq_running(softirq_index);
260*62e46139SGou Ngai                 }
261*62e46139SGou Ngai             }
262*62e46139SGou Ngai             softirq_index += 1;
263*62e46139SGou Ngai         }
264*62e46139SGou Ngai         cli();
265*62e46139SGou Ngai     }
266*62e46139SGou Ngai }
267