xref: /DragonOS/kernel/src/arch/x86_64/interrupt/ipi.rs (revision 8cb2e9b344230227fe5f3ab3ebeb2522f1c5e289)
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 Into<u8> for ArchIpiKind {
44     fn into(self) -> u8 {
45         match self {
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 Into<ApicId> for ArchIpiTarget {
80     fn into(self) -> ApicId {
81         if let ArchIpiTarget::Specified(id) = self {
82             return id;
83         } else {
84             if CurrentApic.x2apic_enabled() {
85                 return x86::apic::ApicId::X2Apic(0);
86             } else {
87                 return x86::apic::ApicId::XApic(0);
88             }
89         }
90     }
91 }
92 
93 impl ArchIpiTarget {
94     #[allow(dead_code)]
95     pub fn shorthand(&self) -> u8 {
96         match self {
97             ArchIpiTarget::Specified(_) => 0,
98             ArchIpiTarget::Current => 1,
99             ArchIpiTarget::All => 2,
100             ArchIpiTarget::Other => 3,
101         }
102     }
103 
104     #[inline(always)]
105     fn cpu_id_to_apic_id(cpu_id: ProcessorId) -> x86::apic::ApicId {
106         if CurrentApic.x2apic_enabled() {
107             x86::apic::ApicId::X2Apic(cpu_id.data() as u32)
108         } else {
109             x86::apic::ApicId::XApic(cpu_id.data() as u8)
110         }
111     }
112 }
113 
114 impl Into<x86::apic::DestinationShorthand> for ArchIpiTarget {
115     fn into(self) -> x86::apic::DestinationShorthand {
116         match self {
117             ArchIpiTarget::Specified(_) => x86::apic::DestinationShorthand::NoShorthand,
118             ArchIpiTarget::Current => x86::apic::DestinationShorthand::Myself,
119             ArchIpiTarget::All => x86::apic::DestinationShorthand::AllIncludingSelf,
120             ArchIpiTarget::Other => x86::apic::DestinationShorthand::AllExcludingSelf,
121         }
122     }
123 }
124 
125 #[inline(always)]
126 pub fn send_ipi(kind: IpiKind, target: IpiTarget) {
127     // kdebug!("send_ipi: {:?} {:?}", kind, target);
128 
129     let ipi_vec = ArchIpiKind::from(kind).into();
130     let target = ArchIpiTarget::from(target);
131     let shorthand: x86::apic::DestinationShorthand = target.into();
132     let destination: x86::apic::ApicId = target.into();
133     let icr = if CurrentApic.x2apic_enabled() {
134         // kdebug!("send_ipi: x2apic");
135         x86::apic::Icr::for_x2apic(
136             ipi_vec,
137             destination,
138             shorthand,
139             x86::apic::DeliveryMode::Fixed,
140             x86::apic::DestinationMode::Physical,
141             x86::apic::DeliveryStatus::Idle,
142             x86::apic::Level::Assert,
143             x86::apic::TriggerMode::Edge,
144         )
145     } else {
146         // kdebug!("send_ipi: xapic");
147         x86::apic::Icr::for_xapic(
148             ipi_vec,
149             destination,
150             shorthand,
151             x86::apic::DeliveryMode::Fixed,
152             x86::apic::DestinationMode::Physical,
153             x86::apic::DeliveryStatus::Idle,
154             x86::apic::Level::Assert,
155             x86::apic::TriggerMode::Edge,
156         )
157     };
158 
159     CurrentApic.write_icr(icr);
160 }
161 
162 /// 发送smp初始化IPI
163 pub fn ipi_send_smp_init() {
164     let target = ArchIpiTarget::Other;
165     let icr = if CurrentApic.x2apic_enabled() {
166         x86::apic::Icr::for_x2apic(
167             0,
168             target.into(),
169             x86::apic::DestinationShorthand::AllExcludingSelf,
170             x86::apic::DeliveryMode::Init,
171             x86::apic::DestinationMode::Physical,
172             x86::apic::DeliveryStatus::Idle,
173             x86::apic::Level::Deassert,
174             x86::apic::TriggerMode::Edge,
175         )
176     } else {
177         x86::apic::Icr::for_xapic(
178             0,
179             target.into(),
180             x86::apic::DestinationShorthand::AllExcludingSelf,
181             x86::apic::DeliveryMode::Init,
182             x86::apic::DestinationMode::Physical,
183             x86::apic::DeliveryStatus::Idle,
184             x86::apic::Level::Deassert,
185             x86::apic::TriggerMode::Edge,
186         )
187     };
188     CurrentApic.write_icr(icr);
189 }
190 
191 /// 发送smp启动IPI
192 ///
193 /// ## 参数
194 ///
195 /// * `target_cpu` - 目标CPU
196 pub fn ipi_send_smp_startup(target_cpu: ProcessorId) -> Result<(), SystemError> {
197     if target_cpu.data() as usize >= SMP_BOOT_DATA.cpu_count() {
198         return Err(SystemError::EINVAL);
199     }
200     let target: ArchIpiTarget = IpiTarget::Specified(target_cpu).into();
201 
202     let icr = if CurrentApic.x2apic_enabled() {
203         x86::apic::Icr::for_x2apic(
204             0x20,
205             target.into(),
206             x86::apic::DestinationShorthand::NoShorthand,
207             x86::apic::DeliveryMode::StartUp,
208             x86::apic::DestinationMode::Physical,
209             x86::apic::DeliveryStatus::Idle,
210             x86::apic::Level::Deassert,
211             x86::apic::TriggerMode::Edge,
212         )
213     } else {
214         x86::apic::Icr::for_xapic(
215             0x20,
216             target.into(),
217             x86::apic::DestinationShorthand::NoShorthand,
218             x86::apic::DeliveryMode::StartUp,
219             x86::apic::DestinationMode::Physical,
220             x86::apic::DeliveryStatus::Idle,
221             x86::apic::Level::Deassert,
222             x86::apic::TriggerMode::Edge,
223         )
224     };
225 
226     CurrentApic.write_icr(icr);
227     return Ok(());
228 }
229 
230 /// 初始化IPI处理函数
231 pub fn arch_ipi_handler_init() {
232     do_init_irq_handler(IPI_NUM_KICK_CPU);
233     do_init_irq_handler(IPI_NUM_FLUSH_TLB);
234 }
235 
236 fn do_init_irq_handler(irq: IrqNumber) {
237     let desc = irq_desc_manager().lookup(irq).unwrap();
238     let irq_data: Arc<IrqData> = desc.irq_data();
239     let mut chip_info_guard = irq_data.chip_info_write_irqsave();
240     chip_info_guard.set_chip(Some(local_apic_chip().clone()));
241 
242     desc.modify_status(IrqLineStatus::IRQ_LEVEL, IrqLineStatus::empty());
243     drop(chip_info_guard);
244     desc.set_handler(&X86_64IpiIrqFlowHandler);
245 }
246 
247 #[derive(Debug)]
248 struct X86_64IpiIrqFlowHandler;
249 
250 impl IrqFlowHandler for X86_64IpiIrqFlowHandler {
251     fn handle(&self, irq_desc: &Arc<IrqDesc>, _trap_frame: &mut TrapFrame) {
252         let irq = irq_desc.irq_data().irq();
253         match irq {
254             IPI_NUM_KICK_CPU => {
255                 KickCpuIpiHandler.handle(irq, None, None).ok();
256             }
257             IPI_NUM_FLUSH_TLB => {
258                 FlushTLBIpiHandler.handle(irq, None, None).ok();
259             }
260             _ => {
261                 kerror!("Unknown IPI: {}", irq.data());
262             }
263         }
264 
265         CurrentApic.send_eoi();
266     }
267 }
268