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