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