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