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