xref: /DragonOS/kernel/src/arch/x86_64/interrupt/ipi.rs (revision 70a4e5550a9fb49b537092287c3ddc36448c5b78)
1*70a4e555SLoGin use x86::apic::ApicId;
2aa0367d6SLoGin 
3*70a4e555SLoGin use crate::{
4*70a4e555SLoGin     arch::{
5*70a4e555SLoGin         driver::apic::{CurrentApic, LocalAPIC},
6*70a4e555SLoGin         smp::SMP_BOOT_DATA,
7*70a4e555SLoGin     },
8*70a4e555SLoGin     exception::ipi::{IpiKind, IpiTarget},
9*70a4e555SLoGin     syscall::SystemError,
10*70a4e555SLoGin };
11aa0367d6SLoGin 
12aa0367d6SLoGin /// IPI的种类(架构相关,指定了向量号)
13aa0367d6SLoGin #[derive(Debug, Copy, Clone, Eq, PartialEq)]
14aa0367d6SLoGin #[repr(u8)]
15aa0367d6SLoGin pub enum ArchIpiKind {
16aa0367d6SLoGin     KickCpu = 200,
17aa0367d6SLoGin     FlushTLB = 201,
18aa0367d6SLoGin }
19aa0367d6SLoGin 
20aa0367d6SLoGin impl From<IpiKind> for ArchIpiKind {
21aa0367d6SLoGin     fn from(kind: IpiKind) -> Self {
22aa0367d6SLoGin         match kind {
23aa0367d6SLoGin             IpiKind::KickCpu => ArchIpiKind::KickCpu,
24aa0367d6SLoGin             IpiKind::FlushTLB => ArchIpiKind::FlushTLB,
25aa0367d6SLoGin         }
26aa0367d6SLoGin     }
27aa0367d6SLoGin }
28aa0367d6SLoGin 
29aa0367d6SLoGin /// IPI投递目标
30aa0367d6SLoGin #[derive(Debug, Copy, Clone, Eq, PartialEq)]
31aa0367d6SLoGin pub enum ArchIpiTarget {
32aa0367d6SLoGin     /// 当前CPU
33aa0367d6SLoGin     Current,
34aa0367d6SLoGin     /// 所有CPU
35aa0367d6SLoGin     All,
36aa0367d6SLoGin     /// 除了当前CPU以外的所有CPU
37aa0367d6SLoGin     Other,
38aa0367d6SLoGin     /// 指定的CPU
39*70a4e555SLoGin     Specified(x86::apic::ApicId),
40aa0367d6SLoGin }
41aa0367d6SLoGin 
42aa0367d6SLoGin impl From<IpiTarget> for ArchIpiTarget {
43aa0367d6SLoGin     fn from(target: IpiTarget) -> Self {
44aa0367d6SLoGin         match target {
45aa0367d6SLoGin             IpiTarget::Current => ArchIpiTarget::Current,
46aa0367d6SLoGin             IpiTarget::All => ArchIpiTarget::All,
47aa0367d6SLoGin             IpiTarget::Other => ArchIpiTarget::Other,
48*70a4e555SLoGin             IpiTarget::Specified(cpu_id) => {
49*70a4e555SLoGin                 ArchIpiTarget::Specified(Self::cpu_id_to_apic_id(cpu_id as u32))
50*70a4e555SLoGin             }
51*70a4e555SLoGin         }
52*70a4e555SLoGin     }
53*70a4e555SLoGin }
54*70a4e555SLoGin 
55*70a4e555SLoGin impl Into<ApicId> for ArchIpiTarget {
56*70a4e555SLoGin     fn into(self) -> ApicId {
57*70a4e555SLoGin         if let ArchIpiTarget::Specified(id) = self {
58*70a4e555SLoGin             return id;
59*70a4e555SLoGin         } else {
60*70a4e555SLoGin             if CurrentApic.x2apic_enabled() {
61*70a4e555SLoGin                 return x86::apic::ApicId::X2Apic(0);
62*70a4e555SLoGin             } else {
63*70a4e555SLoGin                 return x86::apic::ApicId::XApic(0);
64*70a4e555SLoGin             }
65aa0367d6SLoGin         }
66aa0367d6SLoGin     }
67aa0367d6SLoGin }
68aa0367d6SLoGin 
69aa0367d6SLoGin impl ArchIpiTarget {
70aa0367d6SLoGin     pub fn shorthand(&self) -> u8 {
71aa0367d6SLoGin         match self {
72aa0367d6SLoGin             ArchIpiTarget::Specified(_) => 0,
73aa0367d6SLoGin             ArchIpiTarget::Current => 1,
74aa0367d6SLoGin             ArchIpiTarget::All => 2,
75aa0367d6SLoGin             ArchIpiTarget::Other => 3,
76aa0367d6SLoGin         }
77aa0367d6SLoGin     }
78*70a4e555SLoGin 
79*70a4e555SLoGin     #[inline(always)]
80*70a4e555SLoGin     fn cpu_id_to_apic_id(cpu_id: u32) -> x86::apic::ApicId {
81*70a4e555SLoGin         if CurrentApic.x2apic_enabled() {
82*70a4e555SLoGin             x86::apic::ApicId::X2Apic(cpu_id as u32)
83*70a4e555SLoGin         } else {
84*70a4e555SLoGin             x86::apic::ApicId::XApic(cpu_id as u8)
85*70a4e555SLoGin         }
86*70a4e555SLoGin     }
87aa0367d6SLoGin }
88aa0367d6SLoGin 
89aa0367d6SLoGin impl Into<x86::apic::DestinationShorthand> for ArchIpiTarget {
90aa0367d6SLoGin     fn into(self) -> x86::apic::DestinationShorthand {
91aa0367d6SLoGin         match self {
92aa0367d6SLoGin             ArchIpiTarget::Specified(_) => x86::apic::DestinationShorthand::NoShorthand,
93aa0367d6SLoGin             ArchIpiTarget::Current => x86::apic::DestinationShorthand::Myself,
94aa0367d6SLoGin             ArchIpiTarget::All => x86::apic::DestinationShorthand::AllIncludingSelf,
95aa0367d6SLoGin             ArchIpiTarget::Other => x86::apic::DestinationShorthand::AllExcludingSelf,
96aa0367d6SLoGin         }
97aa0367d6SLoGin     }
98aa0367d6SLoGin }
99aa0367d6SLoGin 
100aa0367d6SLoGin #[inline(always)]
101aa0367d6SLoGin pub fn send_ipi(kind: IpiKind, target: IpiTarget) {
102aa0367d6SLoGin     // kdebug!("send_ipi: {:?} {:?}", kind, target);
103aa0367d6SLoGin 
104aa0367d6SLoGin     let ipi_vec = ArchIpiKind::from(kind) as u8;
105aa0367d6SLoGin     let target = ArchIpiTarget::from(target);
106aa0367d6SLoGin     let shorthand: x86::apic::DestinationShorthand = target.into();
107aa0367d6SLoGin     let destination: x86::apic::ApicId = target.into();
108*70a4e555SLoGin     let icr = if CurrentApic.x2apic_enabled() {
109aa0367d6SLoGin         // kdebug!("send_ipi: x2apic");
110*70a4e555SLoGin         x86::apic::Icr::for_x2apic(
111aa0367d6SLoGin             ipi_vec,
112aa0367d6SLoGin             destination,
113aa0367d6SLoGin             shorthand,
114aa0367d6SLoGin             x86::apic::DeliveryMode::Fixed,
115aa0367d6SLoGin             x86::apic::DestinationMode::Physical,
116aa0367d6SLoGin             x86::apic::DeliveryStatus::Idle,
117aa0367d6SLoGin             x86::apic::Level::Assert,
118aa0367d6SLoGin             x86::apic::TriggerMode::Edge,
119*70a4e555SLoGin         )
120aa0367d6SLoGin     } else {
121aa0367d6SLoGin         // kdebug!("send_ipi: xapic");
122*70a4e555SLoGin         x86::apic::Icr::for_xapic(
123aa0367d6SLoGin             ipi_vec,
124aa0367d6SLoGin             destination,
125aa0367d6SLoGin             shorthand,
126aa0367d6SLoGin             x86::apic::DeliveryMode::Fixed,
127aa0367d6SLoGin             x86::apic::DestinationMode::Physical,
128aa0367d6SLoGin             x86::apic::DeliveryStatus::Idle,
129aa0367d6SLoGin             x86::apic::Level::Assert,
130aa0367d6SLoGin             x86::apic::TriggerMode::Edge,
131*70a4e555SLoGin         )
132*70a4e555SLoGin     };
133aa0367d6SLoGin 
134*70a4e555SLoGin     CurrentApic.write_icr(icr);
135aa0367d6SLoGin }
136*70a4e555SLoGin 
137*70a4e555SLoGin /// 发送smp初始化IPI
138*70a4e555SLoGin pub fn ipi_send_smp_init() -> Result<(), SystemError> {
139*70a4e555SLoGin     let target = ArchIpiTarget::Other;
140*70a4e555SLoGin     let icr = if CurrentApic.x2apic_enabled() {
141*70a4e555SLoGin         x86::apic::Icr::for_x2apic(
142*70a4e555SLoGin             0,
143*70a4e555SLoGin             target.into(),
144*70a4e555SLoGin             x86::apic::DestinationShorthand::AllExcludingSelf,
145*70a4e555SLoGin             x86::apic::DeliveryMode::Init,
146*70a4e555SLoGin             x86::apic::DestinationMode::Physical,
147*70a4e555SLoGin             x86::apic::DeliveryStatus::Idle,
148*70a4e555SLoGin             x86::apic::Level::Deassert,
149*70a4e555SLoGin             x86::apic::TriggerMode::Edge,
150*70a4e555SLoGin         )
151*70a4e555SLoGin     } else {
152*70a4e555SLoGin         x86::apic::Icr::for_xapic(
153*70a4e555SLoGin             0,
154*70a4e555SLoGin             target.into(),
155*70a4e555SLoGin             x86::apic::DestinationShorthand::AllExcludingSelf,
156*70a4e555SLoGin             x86::apic::DeliveryMode::Init,
157*70a4e555SLoGin             x86::apic::DestinationMode::Physical,
158*70a4e555SLoGin             x86::apic::DeliveryStatus::Idle,
159*70a4e555SLoGin             x86::apic::Level::Deassert,
160*70a4e555SLoGin             x86::apic::TriggerMode::Edge,
161*70a4e555SLoGin         )
162*70a4e555SLoGin     };
163*70a4e555SLoGin     CurrentApic.write_icr(icr);
164*70a4e555SLoGin     return Ok(());
165aa0367d6SLoGin }
166*70a4e555SLoGin 
167*70a4e555SLoGin /// 发送smp启动IPI
168*70a4e555SLoGin ///
169*70a4e555SLoGin /// ## 参数
170*70a4e555SLoGin ///
171*70a4e555SLoGin /// * `target_cpu` - 目标CPU
172*70a4e555SLoGin pub fn ipi_send_smp_startup(target_cpu: u32) -> Result<(), SystemError> {
173*70a4e555SLoGin     if target_cpu as usize >= SMP_BOOT_DATA.cpu_count() {
174*70a4e555SLoGin         return Err(SystemError::EINVAL);
175*70a4e555SLoGin     }
176*70a4e555SLoGin     let target: ArchIpiTarget = IpiTarget::Specified(target_cpu as usize).into();
177*70a4e555SLoGin 
178*70a4e555SLoGin     let icr = if CurrentApic.x2apic_enabled() {
179*70a4e555SLoGin         x86::apic::Icr::for_x2apic(
180*70a4e555SLoGin             0x20,
181*70a4e555SLoGin             target.into(),
182*70a4e555SLoGin             x86::apic::DestinationShorthand::NoShorthand,
183*70a4e555SLoGin             x86::apic::DeliveryMode::StartUp,
184*70a4e555SLoGin             x86::apic::DestinationMode::Physical,
185*70a4e555SLoGin             x86::apic::DeliveryStatus::Idle,
186*70a4e555SLoGin             x86::apic::Level::Deassert,
187*70a4e555SLoGin             x86::apic::TriggerMode::Edge,
188*70a4e555SLoGin         )
189*70a4e555SLoGin     } else {
190*70a4e555SLoGin         x86::apic::Icr::for_xapic(
191*70a4e555SLoGin             0x20,
192*70a4e555SLoGin             target.into(),
193*70a4e555SLoGin             x86::apic::DestinationShorthand::NoShorthand,
194*70a4e555SLoGin             x86::apic::DeliveryMode::StartUp,
195*70a4e555SLoGin             x86::apic::DestinationMode::Physical,
196*70a4e555SLoGin             x86::apic::DeliveryStatus::Idle,
197*70a4e555SLoGin             x86::apic::Level::Deassert,
198*70a4e555SLoGin             x86::apic::TriggerMode::Edge,
199*70a4e555SLoGin         )
200*70a4e555SLoGin     };
201*70a4e555SLoGin 
202*70a4e555SLoGin     CurrentApic.write_icr(icr);
203*70a4e555SLoGin     return Ok(());
204aa0367d6SLoGin }
205