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 {
default() -> Self32 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的接口函数,用于初始化静态指针
softirq_init()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]
__get_softirq_handler_mut() -> &'static mut Softirq63 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)]
raise_softirq(sirq_num: u64)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)]
register_softirq( irq_num: u32, action: Option<unsafe extern "C" fn(data: *mut ::core::ffi::c_void)>, data: *mut c_void, )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)]
unregister_softirq(irq_num: u32)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)]
set_softirq_pending(irq_num: u32)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)]
clear_softirq_pending(irq_num: u32)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)]
do_softirq()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 {
default() -> Self126 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)]
get_softirq_pending(&self) -> u64139 pub fn get_softirq_pending(&self) -> u64 {
140 return self.pending;
141 }
142
143 #[inline]
144 #[allow(dead_code)]
get_softirq_running(&self) -> u64145 pub fn get_softirq_running(&self) -> u64 {
146 return self.running;
147 }
148
149 #[inline]
set_softirq_pending(&mut self, softirq_num: u32)150 pub fn set_softirq_pending(&mut self, softirq_num: u32) {
151 self.pending |= 1 << softirq_num;
152 }
153
154 #[inline]
set_softirq_running(&mut self, softirq_num: u32)155 pub fn set_softirq_running(&mut self, softirq_num: u32) {
156 self.running |= 1 << softirq_num;
157 }
158
159 #[inline]
clear_softirq_running(&mut self, softirq_num: u32)160 pub fn clear_softirq_running(&mut self, softirq_num: u32) {
161 self.running &= !(1 << softirq_num);
162 }
163
164 /// @brief 清除软中断pending标志位
165 #[inline]
clear_softirq_pending(&mut self, softirq_num: u32)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]
is_running(&mut self, softirq_num: u32) -> bool173 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]
is_pending(&mut self, softirq_num: u32) -> bool180 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 中断函数的操作数据
register_softirq( &mut self, irq_num: u32, action: Option<unsafe extern "C" fn(data: *mut ::core::ffi::c_void)>, data: *mut c_void, ) -> i32188 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 中断向量号码
unregister_softirq(&mut self, irq_num: u32) -> i32210 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 遍历执行软中断
do_softirq(&mut self)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