xref: /DragonOS/kernel/src/arch/x86_64/interrupt/ipi.rs (revision 4b0170bd6bb374d0e9699a0076cc23b976ad6db7)
1 use alloc::sync::Arc;
2 use system_error::SystemError;
3 use x86::apic::ApicId;
4 
5 use crate::{
6     arch::{
7         driver::apic::{lapic_vector::local_apic_chip, CurrentApic, LocalAPIC},
8         smp::SMP_BOOT_DATA,
9     },
10     exception::{
11         ipi::{FlushTLBIpiHandler, IpiKind, IpiTarget, KickCpuIpiHandler},
12         irqdata::{IrqData, IrqLineStatus},
13         irqdesc::{irq_desc_manager, IrqDesc, IrqFlowHandler, IrqHandler},
14         HardwareIrqNumber, IrqNumber,
15     },
16     kerror,
17     smp::cpu::ProcessorId,
18 };
19 
20 use super::TrapFrame;
21 
22 pub const IPI_NUM_KICK_CPU: IrqNumber = IrqNumber::new(200);
23 pub const IPI_NUM_FLUSH_TLB: IrqNumber = IrqNumber::new(201);
24 /// IPI的种类(架构相关,指定了向量号)
25 #[derive(Debug, Copy, Clone, Eq, PartialEq)]
26 #[repr(u32)]
27 pub enum ArchIpiKind {
28     KickCpu = IPI_NUM_KICK_CPU.data(),
29     FlushTLB = IPI_NUM_FLUSH_TLB.data(),
30     SpecVector(HardwareIrqNumber),
31 }
32 
33 impl From<IpiKind> for ArchIpiKind {
34     fn from(kind: IpiKind) -> Self {
35         match kind {
36             IpiKind::KickCpu => ArchIpiKind::KickCpu,
37             IpiKind::FlushTLB => ArchIpiKind::FlushTLB,
38             IpiKind::SpecVector(vec) => ArchIpiKind::SpecVector(vec),
39         }
40     }
41 }
42 
43 impl From<ArchIpiKind> for u8 {
44     fn from(value: ArchIpiKind) -> Self {
45         match value {
46             ArchIpiKind::KickCpu => IPI_NUM_KICK_CPU.data() as u8,
47             ArchIpiKind::FlushTLB => IPI_NUM_FLUSH_TLB.data() as u8,
48             ArchIpiKind::SpecVector(vec) => (vec.data() & 0xFF) as u8,
49         }
50     }
51 }
52 
53 /// IPI投递目标
54 #[derive(Debug, Copy, Clone, Eq, PartialEq)]
55 pub enum ArchIpiTarget {
56     /// 当前CPU
57     Current,
58     /// 所有CPU
59     All,
60     /// 除了当前CPU以外的所有CPU
61     Other,
62     /// 指定的CPU
63     Specified(x86::apic::ApicId),
64 }
65 
66 impl From<IpiTarget> for ArchIpiTarget {
67     fn from(target: IpiTarget) -> Self {
68         match target {
69             IpiTarget::Current => ArchIpiTarget::Current,
70             IpiTarget::All => ArchIpiTarget::All,
71             IpiTarget::Other => ArchIpiTarget::Other,
72             IpiTarget::Specified(cpu_id) => {
73                 ArchIpiTarget::Specified(Self::cpu_id_to_apic_id(cpu_id))
74             }
75         }
76     }
77 }
78 
79 impl From<ArchIpiTarget> for ApicId {
80     fn from(val: ArchIpiTarget) -> Self {
81         if let ArchIpiTarget::Specified(id) = val {
82             return id;
83         } else if CurrentApic.x2apic_enabled() {
84             return x86::apic::ApicId::X2Apic(0);
85         } else {
86             return x86::apic::ApicId::XApic(0);
87         }
88     }
89 }
90 
91 impl ArchIpiTarget {
92     #[allow(dead_code)]
93     pub fn shorthand(&self) -> u8 {
94         match self {
95             ArchIpiTarget::Specified(_) => 0,
96             ArchIpiTarget::Current => 1,
97             ArchIpiTarget::All => 2,
98             ArchIpiTarget::Other => 3,
99         }
100     }
101 
102     #[inline(always)]
103     fn cpu_id_to_apic_id(cpu_id: ProcessorId) -> x86::apic::ApicId {
104         if CurrentApic.x2apic_enabled() {
105             x86::apic::ApicId::X2Apic(cpu_id.data())
106         } else {
107             x86::apic::ApicId::XApic(cpu_id.data() as u8)
108         }
109     }
110 }
111 
112 impl From<ArchIpiTarget> for x86::apic::DestinationShorthand {
113     fn from(val: ArchIpiTarget) -> Self {
114         match val {
115             ArchIpiTarget::Specified(_) => x86::apic::DestinationShorthand::NoShorthand,
116             ArchIpiTarget::Current => x86::apic::DestinationShorthand::Myself,
117             ArchIpiTarget::All => x86::apic::DestinationShorthand::AllIncludingSelf,
118             ArchIpiTarget::Other => x86::apic::DestinationShorthand::AllExcludingSelf,
119         }
120     }
121 }
122 
123 #[inline(always)]
124 pub fn send_ipi(kind: IpiKind, target: IpiTarget) {
125     // kdebug!("send_ipi: {:?} {:?}", kind, target);
126 
127     let ipi_vec = ArchIpiKind::from(kind).into();
128     let target = ArchIpiTarget::from(target);
129     let shorthand: x86::apic::DestinationShorthand = target.into();
130     let destination: x86::apic::ApicId = target.into();
131     let icr = if CurrentApic.x2apic_enabled() {
132         // kdebug!("send_ipi: x2apic");
133         x86::apic::Icr::for_x2apic(
134             ipi_vec,
135             destination,
136             shorthand,
137             x86::apic::DeliveryMode::Fixed,
138             x86::apic::DestinationMode::Physical,
139             x86::apic::DeliveryStatus::Idle,
140             x86::apic::Level::Assert,
141             x86::apic::TriggerMode::Edge,
142         )
143     } else {
144         // kdebug!("send_ipi: xapic");
145         x86::apic::Icr::for_xapic(
146             ipi_vec,
147             destination,
148             shorthand,
149             x86::apic::DeliveryMode::Fixed,
150             x86::apic::DestinationMode::Physical,
151             x86::apic::DeliveryStatus::Idle,
152             x86::apic::Level::Assert,
153             x86::apic::TriggerMode::Edge,
154         )
155     };
156 
157     CurrentApic.write_icr(icr);
158 }
159 
160 /// 发送smp初始化IPI
161 pub fn ipi_send_smp_init() {
162     let target = ArchIpiTarget::Other;
163     let icr = if CurrentApic.x2apic_enabled() {
164         x86::apic::Icr::for_x2apic(
165             0,
166             target.into(),
167             x86::apic::DestinationShorthand::AllExcludingSelf,
168             x86::apic::DeliveryMode::Init,
169             x86::apic::DestinationMode::Physical,
170             x86::apic::DeliveryStatus::Idle,
171             x86::apic::Level::Deassert,
172             x86::apic::TriggerMode::Edge,
173         )
174     } else {
175         x86::apic::Icr::for_xapic(
176             0,
177             target.into(),
178             x86::apic::DestinationShorthand::AllExcludingSelf,
179             x86::apic::DeliveryMode::Init,
180             x86::apic::DestinationMode::Physical,
181             x86::apic::DeliveryStatus::Idle,
182             x86::apic::Level::Deassert,
183             x86::apic::TriggerMode::Edge,
184         )
185     };
186     CurrentApic.write_icr(icr);
187 }
188 
189 /// 发送smp启动IPI
190 ///
191 /// ## 参数
192 ///
193 /// * `target_cpu` - 目标CPU
194 pub fn ipi_send_smp_startup(target_cpu: ProcessorId) -> Result<(), SystemError> {
195     if target_cpu.data() as usize >= SMP_BOOT_DATA.cpu_count() {
196         return Err(SystemError::EINVAL);
197     }
198     let target: ArchIpiTarget = IpiTarget::Specified(target_cpu).into();
199 
200     let icr = if CurrentApic.x2apic_enabled() {
201         x86::apic::Icr::for_x2apic(
202             0x20,
203             target.into(),
204             x86::apic::DestinationShorthand::NoShorthand,
205             x86::apic::DeliveryMode::StartUp,
206             x86::apic::DestinationMode::Physical,
207             x86::apic::DeliveryStatus::Idle,
208             x86::apic::Level::Deassert,
209             x86::apic::TriggerMode::Edge,
210         )
211     } else {
212         x86::apic::Icr::for_xapic(
213             0x20,
214             target.into(),
215             x86::apic::DestinationShorthand::NoShorthand,
216             x86::apic::DeliveryMode::StartUp,
217             x86::apic::DestinationMode::Physical,
218             x86::apic::DeliveryStatus::Idle,
219             x86::apic::Level::Deassert,
220             x86::apic::TriggerMode::Edge,
221         )
222     };
223 
224     CurrentApic.write_icr(icr);
225     return Ok(());
226 }
227 
228 /// 初始化IPI处理函数
229 pub fn arch_ipi_handler_init() {
230     do_init_irq_handler(IPI_NUM_KICK_CPU);
231     do_init_irq_handler(IPI_NUM_FLUSH_TLB);
232 }
233 
234 fn do_init_irq_handler(irq: IrqNumber) {
235     let desc = irq_desc_manager().lookup(irq).unwrap();
236     let irq_data: Arc<IrqData> = desc.irq_data();
237     let mut chip_info_guard = irq_data.chip_info_write_irqsave();
238     chip_info_guard.set_chip(Some(local_apic_chip().clone()));
239 
240     desc.modify_status(IrqLineStatus::IRQ_LEVEL, IrqLineStatus::empty());
241     drop(chip_info_guard);
242     desc.set_handler(&X86_64IpiIrqFlowHandler);
243 }
244 
245 #[derive(Debug)]
246 struct X86_64IpiIrqFlowHandler;
247 
248 impl IrqFlowHandler for X86_64IpiIrqFlowHandler {
249     fn handle(&self, irq_desc: &Arc<IrqDesc>, _trap_frame: &mut TrapFrame) {
250         let irq = irq_desc.irq_data().irq();
251         match irq {
252             IPI_NUM_KICK_CPU => {
253                 KickCpuIpiHandler.handle(irq, None, None).ok();
254             }
255             IPI_NUM_FLUSH_TLB => {
256                 FlushTLBIpiHandler.handle(irq, None, None).ok();
257                 CurrentApic.send_eoi();
258             }
259             _ => {
260                 kerror!("Unknown IPI: {}", irq.data());
261                 CurrentApic.send_eoi();
262             }
263         }
264     }
265 }
266