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