xref: /DragonOS/kernel/src/exception/handle.rs (revision 4b0170bd6bb374d0e9699a0076cc23b976ad6db7)
1 use core::{intrinsics::unlikely, ops::BitAnd};
2 
3 use alloc::sync::Arc;
4 use system_error::SystemError;
5 
6 use crate::{
7     arch::{interrupt::TrapFrame, CurrentIrqArch},
8     exception::irqdesc::InnerIrqDesc,
9     libs::{once::Once, spinlock::SpinLockGuard},
10     process::{ProcessFlags, ProcessManager},
11     smp::core::smp_get_processor_id,
12 };
13 
14 use super::{
15     irqdata::{IrqData, IrqHandlerData, IrqStatus},
16     irqdesc::{
17         InnerIrqAction, IrqDesc, IrqDescState, IrqFlowHandler, IrqReturn, ThreadedHandlerFlags,
18     },
19     manage::{irq_manager, IrqManager},
20     InterruptArch, IrqNumber,
21 };
22 
23 /// 获取用于处理错误的中断的处理程序
24 #[inline(always)]
25 pub fn bad_irq_handler() -> &'static dyn IrqFlowHandler {
26     &HandleBadIrq
27 }
28 
29 /// 获取用于处理快速EOI的中断的处理程序
30 #[inline(always)]
31 pub fn fast_eoi_irq_handler() -> &'static dyn IrqFlowHandler {
32     &FastEOIIrqHandler
33 }
34 
35 /// 获取用于处理边沿触发中断的处理程序
36 #[inline(always)]
37 pub fn edge_irq_handler() -> &'static dyn IrqFlowHandler {
38     &EdgeIrqHandler
39 }
40 
41 /// handle spurious and unhandled irqs
42 #[derive(Debug)]
43 struct HandleBadIrq;
44 
45 impl IrqFlowHandler for HandleBadIrq {
46     /// 参考: https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/irq/handle.c?fi=handle_bad_irq#33
47     fn handle(&self, irq_desc: &Arc<IrqDesc>, _trap_frame: &mut TrapFrame) {
48         // todo: print_irq_desc
49         // todo: 增加kstat计数
50         CurrentIrqArch::ack_bad_irq(irq_desc.irq());
51     }
52 }
53 
54 #[derive(Debug)]
55 struct FastEOIIrqHandler;
56 
57 impl IrqFlowHandler for FastEOIIrqHandler {
58     fn handle(&self, _irq_desc: &Arc<IrqDesc>, _trap_frame: &mut TrapFrame) {
59         // https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/irq/chip.c?r=&mo=17578&fi=689#689
60         todo!("FastEOIIrqHandler");
61     }
62 }
63 
64 #[derive(Debug)]
65 struct EdgeIrqHandler;
66 
67 impl IrqFlowHandler for EdgeIrqHandler {
68     // https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/irq/chip.c?fi=handle_edge_irq#775
69     fn handle(&self, irq_desc: &Arc<IrqDesc>, _trap_frame: &mut TrapFrame) {
70         let mut desc_inner_guard: SpinLockGuard<'_, InnerIrqDesc> = irq_desc.inner();
71         if !irq_may_run(&desc_inner_guard) {
72             // kdebug!("!irq_may_run");
73             desc_inner_guard
74                 .internal_state_mut()
75                 .insert(IrqDescState::IRQS_PENDING);
76             mask_ack_irq(desc_inner_guard.irq_data());
77             return;
78         }
79 
80         if desc_inner_guard.common_data().disabled() {
81             // kdebug!("desc_inner_guard.common_data().disabled()");
82             desc_inner_guard
83                 .internal_state_mut()
84                 .insert(IrqDescState::IRQS_PENDING);
85             mask_ack_irq(desc_inner_guard.irq_data());
86             return;
87         }
88 
89         let irq_data = desc_inner_guard.irq_data().clone();
90 
91         irq_data.chip_info_read_irqsave().chip().irq_ack(&irq_data);
92 
93         loop {
94             if unlikely(desc_inner_guard.actions().is_empty()) {
95                 kdebug!("no action for irq {}", irq_data.irq().data());
96                 irq_manager().mask_irq(&irq_data);
97                 return;
98             }
99 
100             // 当我们在处理一个中断时,如果另一个中断到来,我们本可以屏蔽它.
101             // 如果在此期间没有被禁用,请重新启用它。
102             if desc_inner_guard
103                 .internal_state()
104                 .contains(IrqDescState::IRQS_PENDING)
105             {
106                 let status = desc_inner_guard.common_data().status();
107                 if !status.disabled() && status.masked() {
108                     // kdebug!("re-enable irq");
109                     irq_manager().unmask_irq(&desc_inner_guard);
110                 }
111             }
112 
113             // kdebug!("handle_irq_event");
114 
115             desc_inner_guard
116                 .internal_state_mut()
117                 .remove(IrqDescState::IRQS_PENDING);
118             desc_inner_guard.common_data().set_inprogress();
119 
120             drop(desc_inner_guard);
121 
122             let _r = do_handle_irq_event(irq_desc);
123 
124             desc_inner_guard = irq_desc.inner();
125             desc_inner_guard.common_data().clear_inprogress();
126 
127             if !desc_inner_guard
128                 .internal_state()
129                 .contains(IrqDescState::IRQS_PENDING)
130                 || desc_inner_guard.common_data().disabled()
131             {
132                 break;
133             }
134         }
135     }
136 }
137 
138 /// 判断中断是否可以运行
139 fn irq_may_run(desc_inner_guard: &SpinLockGuard<'_, InnerIrqDesc>) -> bool {
140     let mask = IrqStatus::IRQD_IRQ_INPROGRESS | IrqStatus::IRQD_WAKEUP_ARMED;
141     let status = desc_inner_guard.common_data().status();
142 
143     // 如果中断不在处理中并且没有被唤醒,则可以运行
144     if status.bitand(mask).is_empty() {
145         return true;
146     }
147 
148     // todo: 检查其他处理器是否在轮询当前中断
149     return false;
150 }
151 
152 pub(super) fn mask_ack_irq(irq_data: &Arc<IrqData>) {
153     let chip = irq_data.chip_info_read_irqsave().chip();
154     if chip.can_mask_ack() {
155         chip.irq_mask_ack(irq_data);
156         irq_data.common_data().set_masked();
157     } else {
158         irq_manager().mask_irq(irq_data);
159         chip.irq_ack(irq_data);
160     }
161 }
162 
163 impl IrqManager {
164     pub(super) fn do_irq_wake_thread(
165         &self,
166         desc: &Arc<IrqDesc>,
167         action_inner: &mut SpinLockGuard<'_, InnerIrqAction>,
168     ) {
169         let thread = action_inner.thread();
170 
171         if thread.is_none() {
172             return;
173         }
174 
175         let thread = thread.unwrap();
176         if thread.flags().contains(ProcessFlags::EXITING) {
177             return;
178         }
179 
180         // 如果线程已经在运行,我们不需要唤醒它
181         if action_inner
182             .thread_flags_mut()
183             .test_and_set_bit(ThreadedHandlerFlags::IRQTF_RUNTHREAD)
184         {
185             return;
186         }
187 
188         desc.inc_threads_active();
189 
190         ProcessManager::wakeup(&thread).ok();
191     }
192 }
193 
194 /// 处理中断事件
195 ///
196 /// https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/irq/handle.c?fi=handle_irq_event#139
197 #[inline(never)]
198 fn do_handle_irq_event(desc: &Arc<IrqDesc>) -> Result<(), SystemError> {
199     let desc_inner_guard = desc.inner();
200     let irq_data = desc_inner_guard.irq_data().clone();
201     let actions = desc_inner_guard.actions().clone();
202     drop(desc_inner_guard);
203 
204     let irq = irq_data.irq();
205     let mut r = Ok(IrqReturn::NotHandled);
206 
207     for action in actions {
208         let mut action_inner: SpinLockGuard<'_, InnerIrqAction> = action.inner();
209         // kdebug!("do_handle_irq_event: action: {:?}", action_inner.name());
210         let dynamic_data = action_inner
211             .dev_id()
212             .clone()
213             .map(|d| d as Arc<dyn IrqHandlerData>);
214         r = action_inner
215             .handler()
216             .unwrap()
217             .handle(irq, None, dynamic_data);
218 
219         if let Ok(IrqReturn::WakeThread) = r {
220             if unlikely(action_inner.thread_fn().is_none()) {
221                 warn_no_thread(irq, &mut action_inner);
222             } else {
223                 irq_manager().do_irq_wake_thread(desc, &mut action_inner);
224             }
225         };
226     }
227 
228     return r.map(|_| ());
229 }
230 
231 fn warn_no_thread(irq: IrqNumber, action_inner: &mut SpinLockGuard<'_, InnerIrqAction>) {
232     // warn on once
233     if action_inner
234         .thread_flags_mut()
235         .test_and_set_bit(ThreadedHandlerFlags::IRQTF_WARNED)
236     {
237         return;
238     }
239 
240     kwarn!(
241         "irq {}, device {} returned IRQ_WAKE_THREAD, but no threaded handler",
242         irq.data(),
243         action_inner.name()
244     );
245 }
246 
247 /// `handle_percpu_devid_irq` - 带有per-CPU设备id的perCPU本地中断处理程序
248 ///
249 ///
250 /// * `desc`: 此中断的中断描述结构
251 ///
252 /// 在没有锁定要求的SMP机器上的每个CPU中断。与linux的`handle_percpu_irq()`相同,但有以下额外内容:
253 ///
254 /// `action->percpu_dev_id`是一个指向per-cpu变量的指针,这些变量
255 /// 包含调用此处理程序的cpu的真实设备id
256 #[derive(Debug)]
257 pub struct PerCpuDevIdIrqHandler;
258 
259 impl IrqFlowHandler for PerCpuDevIdIrqHandler {
260     fn handle(&self, irq_desc: &Arc<IrqDesc>, _trap_frame: &mut TrapFrame) {
261         let desc_inner_guard = irq_desc.inner();
262         let irq_data = desc_inner_guard.irq_data().clone();
263         let chip = irq_data.chip_info_read().chip();
264 
265         chip.irq_ack(&irq_data);
266 
267         let irq = irq_data.irq();
268 
269         let action = desc_inner_guard.actions().first().cloned();
270 
271         drop(desc_inner_guard);
272 
273         if let Some(action) = action {
274             let action_inner = action.inner();
275             let per_cpu_devid = action_inner.per_cpu_dev_id().cloned();
276 
277             let handler = action_inner.handler().unwrap();
278             drop(action_inner);
279 
280             let _r = handler.handle(
281                 irq,
282                 None,
283                 per_cpu_devid.map(|d| d as Arc<dyn IrqHandlerData>),
284             );
285         } else {
286             let cpu = smp_get_processor_id();
287 
288             let enabled = irq_desc
289                 .inner()
290                 .percpu_enabled()
291                 .as_ref()
292                 .unwrap()
293                 .get(cpu)
294                 .unwrap_or(false);
295 
296             if enabled {
297                 irq_manager().irq_percpu_disable(irq_desc, &irq_data, &chip, cpu);
298             }
299             static ONCE: Once = Once::new();
300 
301             ONCE.call_once(|| {
302                 kerror!(
303                     "Spurious percpu irq {} on cpu {:?}, enabled: {}",
304                     irq.data(),
305                     cpu,
306                     enabled
307                 );
308             });
309         }
310 
311         chip.irq_eoi(&irq_data);
312     }
313 }
314