xref: /DragonOS/kernel/src/exception/softirq.rs (revision 5e948c56506aa0554d212341a7630587d55ebb87)
1 use core::{
2     fmt::Debug,
3     intrinsics::unlikely,
4     mem::{self, MaybeUninit},
5     ptr::null_mut,
6     sync::atomic::{compiler_fence, AtomicI16, Ordering},
7 };
8 
9 use alloc::{boxed::Box, sync::Arc, vec::Vec};
10 use num_traits::FromPrimitive;
11 use system_error::SystemError;
12 
13 use crate::{
14     arch::CurrentIrqArch,
15     exception::InterruptArch,
16     kdebug, kinfo,
17     libs::rwlock::RwLock,
18     mm::percpu::{PerCpu, PerCpuVar},
19     process::ProcessManager,
20     smp::core::smp_get_processor_id,
21     time::timer::clock,
22 };
23 
24 const MAX_SOFTIRQ_NUM: u64 = 64;
25 const MAX_SOFTIRQ_RESTART: i32 = 20;
26 
27 static mut __CPU_PENDING: Option<Box<[VecStatus; PerCpu::MAX_CPU_NUM]>> = None;
28 static mut __SORTIRQ_VECTORS: *mut Softirq = null_mut();
29 
30 #[no_mangle]
31 pub extern "C" fn rs_softirq_init() {
32     softirq_init().expect("softirq_init failed");
33 }
34 
35 pub fn softirq_init() -> Result<(), SystemError> {
36     kinfo!("Initializing softirq...");
37     unsafe {
38         __SORTIRQ_VECTORS = Box::leak(Box::new(Softirq::new()));
39         __CPU_PENDING = Some(Box::new(
40             [VecStatus::default(); PerCpu::MAX_CPU_NUM as usize],
41         ));
42         let cpu_pending = __CPU_PENDING.as_mut().unwrap();
43         for i in 0..PerCpu::MAX_CPU_NUM {
44             cpu_pending[i as usize] = VecStatus::default();
45         }
46     }
47     kinfo!("Softirq initialized.");
48     return Ok(());
49 }
50 
51 #[inline(always)]
52 pub fn softirq_vectors() -> &'static mut Softirq {
53     unsafe {
54         return __SORTIRQ_VECTORS.as_mut().unwrap();
55     }
56 }
57 
58 #[inline(always)]
59 fn cpu_pending(cpu_id: usize) -> &'static mut VecStatus {
60     unsafe {
61         return &mut __CPU_PENDING.as_mut().unwrap()[cpu_id];
62     }
63 }
64 
65 /// 软中断向量号码
66 #[allow(dead_code)]
67 #[repr(u8)]
68 #[derive(FromPrimitive, Copy, Clone, Debug, PartialEq, Eq)]
69 pub enum SoftirqNumber {
70     /// 时钟软中断信号
71     TIMER = 0,
72     VideoRefresh = 1, //帧缓冲区刷新软中断
73 }
74 
75 impl From<u64> for SoftirqNumber {
76     fn from(value: u64) -> Self {
77         return <Self as FromPrimitive>::from_u64(value).unwrap();
78     }
79 }
80 
81 bitflags! {
82     #[derive(Default)]
83     pub struct VecStatus: u64 {
84         const TIMER = 1 << 0;
85         const VIDEO_REFRESH = 1 << 1;
86     }
87 }
88 
89 impl From<SoftirqNumber> for VecStatus {
90     fn from(value: SoftirqNumber) -> Self {
91         return Self::from_bits_truncate(1 << (value as u64));
92     }
93 }
94 
95 pub trait SoftirqVec: Send + Sync + Debug {
96     fn run(&self);
97 }
98 
99 #[derive(Debug)]
100 pub struct Softirq {
101     table: RwLock<[Option<Arc<dyn SoftirqVec>>; MAX_SOFTIRQ_NUM as usize]>,
102     /// 软中断嵌套层数(per cpu)
103     cpu_running_count: PerCpuVar<AtomicI16>,
104 }
105 impl Softirq {
106     /// 每个CPU最大嵌套的软中断数量
107     const MAX_RUNNING_PER_CPU: i16 = 3;
108     fn new() -> Softirq {
109         let mut data: [MaybeUninit<Option<Arc<dyn SoftirqVec>>>; MAX_SOFTIRQ_NUM as usize] =
110             unsafe { MaybeUninit::uninit().assume_init() };
111 
112         for i in 0..MAX_SOFTIRQ_NUM {
113             data[i as usize] = MaybeUninit::new(None);
114         }
115 
116         let data: [Option<Arc<dyn SoftirqVec>>; MAX_SOFTIRQ_NUM as usize] = unsafe {
117             mem::transmute::<_, [Option<Arc<dyn SoftirqVec>>; MAX_SOFTIRQ_NUM as usize]>(data)
118         };
119 
120         let mut percpu_count = Vec::with_capacity(PerCpu::MAX_CPU_NUM as usize);
121         percpu_count.resize_with(PerCpu::MAX_CPU_NUM as usize, || AtomicI16::new(0));
122         let cpu_running_count = PerCpuVar::new(percpu_count).unwrap();
123 
124         return Softirq {
125             table: RwLock::new(data),
126             cpu_running_count,
127         };
128     }
129 
130     fn cpu_running_count(&self) -> &PerCpuVar<AtomicI16> {
131         return &self.cpu_running_count;
132     }
133 
134     /// @brief 注册软中断向量
135     ///
136     /// @param softirq_num 中断向量号
137     ///
138     /// @param hanlder 中断函数对应的结构体
139     pub fn register_softirq(
140         &self,
141         softirq_num: SoftirqNumber,
142         handler: Arc<dyn SoftirqVec>,
143     ) -> Result<i32, SystemError> {
144         // kdebug!("register_softirq softirq_num = {:?}", softirq_num as u64);
145 
146         // let self = &mut SOFTIRQ_VECTORS.lock();
147         // 判断该软中断向量是否已经被注册
148         let mut table_guard = self.table.write_irqsave();
149         if table_guard[softirq_num as usize].is_some() {
150             // kdebug!("register_softirq failed");
151 
152             return Err(SystemError::EINVAL);
153         }
154         table_guard[softirq_num as usize] = Some(handler);
155         drop(table_guard);
156 
157         // kdebug!(
158         //     "register_softirq successfully, softirq_num = {:?}",
159         //     softirq_num as u64
160         // );
161         compiler_fence(Ordering::SeqCst);
162         return Ok(0);
163     }
164 
165     /// @brief 解注册软中断向量
166     ///
167     /// @param irq_num 中断向量号码
168     pub fn unregister_softirq(&self, softirq_num: SoftirqNumber) {
169         // kdebug!("unregister_softirq softirq_num = {:?}", softirq_num as u64);
170         let mut table_guard = self.table.write_irqsave();
171         // 将软中断向量清空
172         table_guard[softirq_num as usize] = None;
173         drop(table_guard);
174         // 将对应位置的pending和runing都置0
175         // self.running.lock().set(VecStatus::from(softirq_num), false);
176         // 将对应CPU的pending置0
177         compiler_fence(Ordering::SeqCst);
178         cpu_pending(smp_get_processor_id() as usize).set(VecStatus::from(softirq_num), false);
179         compiler_fence(Ordering::SeqCst);
180     }
181 
182     pub fn do_softirq(&self) {
183         if self.cpu_running_count().get().load(Ordering::SeqCst) >= Self::MAX_RUNNING_PER_CPU {
184             // 当前CPU的软中断嵌套层数已经达到最大值,不再执行
185             return;
186         }
187         // 创建一个RunningCountGuard,当退出作用域时,会自动将cpu_running_count减1
188         let _count_guard = RunningCountGuard::new(self.cpu_running_count());
189 
190         // TODO pcb的flags未修改
191         let end = clock() + 500 * 2;
192         let cpu_id = smp_get_processor_id();
193         let mut max_restart = MAX_SOFTIRQ_RESTART;
194         loop {
195             compiler_fence(Ordering::SeqCst);
196             let pending = cpu_pending(cpu_id as usize).bits;
197             cpu_pending(cpu_id as usize).bits = 0;
198             compiler_fence(Ordering::SeqCst);
199 
200             unsafe { CurrentIrqArch::interrupt_enable() };
201             if pending != 0 {
202                 for i in 0..MAX_SOFTIRQ_NUM {
203                     if pending & (1 << i) == 0 {
204                         continue;
205                     }
206 
207                     let table_guard = self.table.read_irqsave();
208                     let softirq_func = table_guard[i as usize].clone();
209                     drop(table_guard);
210                     if softirq_func.is_none() {
211                         continue;
212                     }
213 
214                     let prev_count: usize = ProcessManager::current_pcb().preempt_count();
215 
216                     softirq_func.as_ref().unwrap().run();
217                     if unlikely(prev_count != ProcessManager::current_pcb().preempt_count()) {
218                         kdebug!(
219                             "entered softirq {:?} with preempt_count {:?},exited with {:?}",
220                             i,
221                             prev_count,
222                             ProcessManager::current_pcb().preempt_count()
223                         );
224                         unsafe { ProcessManager::current_pcb().set_preempt_count(prev_count) };
225                     }
226                 }
227             }
228             unsafe { CurrentIrqArch::interrupt_disable() };
229             max_restart -= 1;
230             compiler_fence(Ordering::SeqCst);
231             if cpu_pending(cpu_id as usize).is_empty() {
232                 compiler_fence(Ordering::SeqCst);
233                 if clock() < end && max_restart > 0 {
234                     continue;
235                 } else {
236                     break;
237                 }
238             } else {
239                 // TODO:当有softirqd时 唤醒它
240                 break;
241             }
242         }
243     }
244 
245     pub fn raise_softirq(&self, softirq_num: SoftirqNumber) {
246         let guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
247         let processor_id = smp_get_processor_id() as usize;
248 
249         cpu_pending(processor_id).insert(VecStatus::from(softirq_num));
250 
251         compiler_fence(Ordering::SeqCst);
252 
253         drop(guard);
254         // kdebug!("raise_softirq exited");
255     }
256     pub unsafe fn clear_softirq_pending(&self, softirq_num: SoftirqNumber) {
257         compiler_fence(Ordering::SeqCst);
258         cpu_pending(smp_get_processor_id() as usize).remove(VecStatus::from(softirq_num));
259         compiler_fence(Ordering::SeqCst);
260     }
261 }
262 
263 /// 当前CPU的软中断嵌套层数的计数器守卫
264 ///
265 /// 当进入作用域时,会自动将cpu_running_count加1,
266 /// 当退出作用域时,会自动将cpu_running_count减1
267 struct RunningCountGuard<'a> {
268     cpu_running_count: &'a PerCpuVar<AtomicI16>,
269 }
270 
271 impl<'a> RunningCountGuard<'a> {
272     fn new(cpu_running_count: &'a PerCpuVar<AtomicI16>) -> RunningCountGuard {
273         cpu_running_count.get().fetch_add(1, Ordering::SeqCst);
274         return RunningCountGuard { cpu_running_count };
275     }
276 }
277 
278 impl<'a> Drop for RunningCountGuard<'a> {
279     fn drop(&mut self) {
280         self.cpu_running_count.get().fetch_sub(1, Ordering::SeqCst);
281     }
282 }
283 
284 // ======= 以下为给C提供的接口 =======
285 #[no_mangle]
286 pub extern "C" fn rs_raise_softirq(softirq_num: u32) {
287     softirq_vectors().raise_softirq(SoftirqNumber::from(softirq_num as u64));
288 }
289 
290 #[no_mangle]
291 pub extern "C" fn rs_unregister_softirq(softirq_num: u32) {
292     softirq_vectors().unregister_softirq(SoftirqNumber::from(softirq_num as u64));
293 }
294 
295 #[no_mangle]
296 pub extern "C" fn rs_do_softirq() {
297     softirq_vectors().do_softirq();
298 }
299 
300 #[no_mangle]
301 pub extern "C" fn rs_clear_softirq_pending(softirq_num: u32) {
302     unsafe {
303         softirq_vectors().clear_softirq_pending(SoftirqNumber::from(softirq_num as u64));
304     }
305 }
306