xref: /DragonOS/kernel/src/arch/x86_64/interrupt/ipi.rs (revision 338f6903262c5031abad3c8e361813355a27fcdb)
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() -> Result<(), SystemError> {
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     return Ok(());
190 }
191 
192 /// 发送smp启动IPI
193 ///
194 /// ## 参数
195 ///
196 /// * `target_cpu` - 目标CPU
197 pub fn ipi_send_smp_startup(target_cpu: ProcessorId) -> Result<(), SystemError> {
198     if target_cpu.data() as usize >= SMP_BOOT_DATA.cpu_count() {
199         return Err(SystemError::EINVAL);
200     }
201     let target: ArchIpiTarget = IpiTarget::Specified(target_cpu).into();
202 
203     let icr = if CurrentApic.x2apic_enabled() {
204         x86::apic::Icr::for_x2apic(
205             0x20,
206             target.into(),
207             x86::apic::DestinationShorthand::NoShorthand,
208             x86::apic::DeliveryMode::StartUp,
209             x86::apic::DestinationMode::Physical,
210             x86::apic::DeliveryStatus::Idle,
211             x86::apic::Level::Deassert,
212             x86::apic::TriggerMode::Edge,
213         )
214     } else {
215         x86::apic::Icr::for_xapic(
216             0x20,
217             target.into(),
218             x86::apic::DestinationShorthand::NoShorthand,
219             x86::apic::DeliveryMode::StartUp,
220             x86::apic::DestinationMode::Physical,
221             x86::apic::DeliveryStatus::Idle,
222             x86::apic::Level::Deassert,
223             x86::apic::TriggerMode::Edge,
224         )
225     };
226 
227     CurrentApic.write_icr(icr);
228     return Ok(());
229 }
230 
231 /// 初始化IPI处理函数
232 pub fn arch_ipi_handler_init() {
233     do_init_irq_handler(IPI_NUM_KICK_CPU);
234     do_init_irq_handler(IPI_NUM_FLUSH_TLB);
235 }
236 
237 fn do_init_irq_handler(irq: IrqNumber) {
238     let desc = irq_desc_manager().lookup(irq).unwrap();
239     let irq_data: Arc<IrqData> = desc.irq_data();
240     let mut chip_info_guard = irq_data.chip_info_write_irqsave();
241     chip_info_guard.set_chip(Some(local_apic_chip().clone()));
242 
243     desc.modify_status(IrqLineStatus::IRQ_LEVEL, IrqLineStatus::empty());
244     drop(chip_info_guard);
245     desc.set_handler(&X86_64IpiIrqFlowHandler);
246 }
247 
248 #[derive(Debug)]
249 struct X86_64IpiIrqFlowHandler;
250 
251 impl IrqFlowHandler for X86_64IpiIrqFlowHandler {
252     fn handle(&self, irq_desc: &Arc<IrqDesc>, _trap_frame: &mut TrapFrame) {
253         let irq = irq_desc.irq_data().irq();
254         match irq {
255             IPI_NUM_KICK_CPU => {
256                 KickCpuIpiHandler.handle(irq, None, None).ok();
257             }
258             IPI_NUM_FLUSH_TLB => {
259                 FlushTLBIpiHandler.handle(irq, None, None).ok();
260             }
261             _ => {
262                 kerror!("Unknown IPI: {}", irq.data());
263             }
264         }
265 
266         CurrentApic.send_eoi();
267     }
268 }
269