xref: /DragonOS/kernel/src/arch/x86_64/interrupt/ipi.rs (revision 83ed0ebc293d5a10245089f627f52770fd5b9dd4)
1 use x86::apic::ApicId;
2 
3 use crate::{
4     arch::{
5         driver::apic::{CurrentApic, LocalAPIC},
6         smp::SMP_BOOT_DATA,
7     },
8     exception::ipi::{IpiKind, IpiTarget},
9     syscall::SystemError,
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     pub fn shorthand(&self) -> u8 {
71         match self {
72             ArchIpiTarget::Specified(_) => 0,
73             ArchIpiTarget::Current => 1,
74             ArchIpiTarget::All => 2,
75             ArchIpiTarget::Other => 3,
76         }
77     }
78 
79     #[inline(always)]
80     fn cpu_id_to_apic_id(cpu_id: u32) -> x86::apic::ApicId {
81         if CurrentApic.x2apic_enabled() {
82             x86::apic::ApicId::X2Apic(cpu_id as u32)
83         } else {
84             x86::apic::ApicId::XApic(cpu_id as u8)
85         }
86     }
87 }
88 
89 impl Into<x86::apic::DestinationShorthand> for ArchIpiTarget {
90     fn into(self) -> x86::apic::DestinationShorthand {
91         match self {
92             ArchIpiTarget::Specified(_) => x86::apic::DestinationShorthand::NoShorthand,
93             ArchIpiTarget::Current => x86::apic::DestinationShorthand::Myself,
94             ArchIpiTarget::All => x86::apic::DestinationShorthand::AllIncludingSelf,
95             ArchIpiTarget::Other => x86::apic::DestinationShorthand::AllExcludingSelf,
96         }
97     }
98 }
99 
100 #[inline(always)]
101 pub fn send_ipi(kind: IpiKind, target: IpiTarget) {
102     // kdebug!("send_ipi: {:?} {:?}", kind, target);
103 
104     let ipi_vec = ArchIpiKind::from(kind) as u8;
105     let target = ArchIpiTarget::from(target);
106     let shorthand: x86::apic::DestinationShorthand = target.into();
107     let destination: x86::apic::ApicId = target.into();
108     let icr = if CurrentApic.x2apic_enabled() {
109         // kdebug!("send_ipi: x2apic");
110         x86::apic::Icr::for_x2apic(
111             ipi_vec,
112             destination,
113             shorthand,
114             x86::apic::DeliveryMode::Fixed,
115             x86::apic::DestinationMode::Physical,
116             x86::apic::DeliveryStatus::Idle,
117             x86::apic::Level::Assert,
118             x86::apic::TriggerMode::Edge,
119         )
120     } else {
121         // kdebug!("send_ipi: xapic");
122         x86::apic::Icr::for_xapic(
123             ipi_vec,
124             destination,
125             shorthand,
126             x86::apic::DeliveryMode::Fixed,
127             x86::apic::DestinationMode::Physical,
128             x86::apic::DeliveryStatus::Idle,
129             x86::apic::Level::Assert,
130             x86::apic::TriggerMode::Edge,
131         )
132     };
133 
134     CurrentApic.write_icr(icr);
135 }
136 
137 /// 发送smp初始化IPI
138 pub fn ipi_send_smp_init() -> Result<(), SystemError> {
139     let target = ArchIpiTarget::Other;
140     let icr = if CurrentApic.x2apic_enabled() {
141         x86::apic::Icr::for_x2apic(
142             0,
143             target.into(),
144             x86::apic::DestinationShorthand::AllExcludingSelf,
145             x86::apic::DeliveryMode::Init,
146             x86::apic::DestinationMode::Physical,
147             x86::apic::DeliveryStatus::Idle,
148             x86::apic::Level::Deassert,
149             x86::apic::TriggerMode::Edge,
150         )
151     } else {
152         x86::apic::Icr::for_xapic(
153             0,
154             target.into(),
155             x86::apic::DestinationShorthand::AllExcludingSelf,
156             x86::apic::DeliveryMode::Init,
157             x86::apic::DestinationMode::Physical,
158             x86::apic::DeliveryStatus::Idle,
159             x86::apic::Level::Deassert,
160             x86::apic::TriggerMode::Edge,
161         )
162     };
163     CurrentApic.write_icr(icr);
164     return Ok(());
165 }
166 
167 /// 发送smp启动IPI
168 ///
169 /// ## 参数
170 ///
171 /// * `target_cpu` - 目标CPU
172 pub fn ipi_send_smp_startup(target_cpu: u32) -> Result<(), SystemError> {
173     if target_cpu as usize >= SMP_BOOT_DATA.cpu_count() {
174         return Err(SystemError::EINVAL);
175     }
176     let target: ArchIpiTarget = IpiTarget::Specified(target_cpu as usize).into();
177 
178     let icr = if CurrentApic.x2apic_enabled() {
179         x86::apic::Icr::for_x2apic(
180             0x20,
181             target.into(),
182             x86::apic::DestinationShorthand::NoShorthand,
183             x86::apic::DeliveryMode::StartUp,
184             x86::apic::DestinationMode::Physical,
185             x86::apic::DeliveryStatus::Idle,
186             x86::apic::Level::Deassert,
187             x86::apic::TriggerMode::Edge,
188         )
189     } else {
190         x86::apic::Icr::for_xapic(
191             0x20,
192             target.into(),
193             x86::apic::DestinationShorthand::NoShorthand,
194             x86::apic::DeliveryMode::StartUp,
195             x86::apic::DestinationMode::Physical,
196             x86::apic::DeliveryStatus::Idle,
197             x86::apic::Level::Deassert,
198             x86::apic::TriggerMode::Edge,
199         )
200     };
201 
202     CurrentApic.write_icr(icr);
203     return Ok(());
204 }
205