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 {
from(kind: IpiKind) -> Self34 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 {
into(self) -> u844 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 {
from(target: IpiTarget) -> Self67 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 {
into(self) -> ApicId80 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)]
shorthand(&self) -> u895 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)]
cpu_id_to_apic_id(cpu_id: ProcessorId) -> x86::apic::ApicId105 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 {
into(self) -> x86::apic::DestinationShorthand115 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)]
send_ipi(kind: IpiKind, target: IpiTarget)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
ipi_send_smp_init() -> Result<(), SystemError>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
ipi_send_smp_startup(target_cpu: ProcessorId) -> Result<(), SystemError>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处理函数
arch_ipi_handler_init()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
do_init_irq_handler(irq: IrqNumber)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 {
handle(&self, irq_desc: &Arc<IrqDesc>, _trap_frame: &mut TrapFrame)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