1 use alloc::sync::Arc;
2 use log::error;
3 use system_error::SystemError;
4 use x86::apic::ApicId;
5
6 use crate::{
7 arch::{
8 driver::apic::{lapic_vector::local_apic_chip, CurrentApic, LocalAPIC},
9 smp::SMP_BOOT_DATA,
10 },
11 exception::{
12 ipi::{FlushTLBIpiHandler, IpiKind, IpiTarget, KickCpuIpiHandler},
13 irqdata::{IrqData, IrqLineStatus},
14 irqdesc::{irq_desc_manager, IrqDesc, IrqFlowHandler, IrqHandler},
15 HardwareIrqNumber, IrqNumber,
16 },
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 From<ArchIpiKind> for u8 {
from(value: ArchIpiKind) -> Self44 fn from(value: ArchIpiKind) -> Self {
45 match value {
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 From<ArchIpiTarget> for ApicId {
from(val: ArchIpiTarget) -> Self80 fn from(val: ArchIpiTarget) -> Self {
81 if let ArchIpiTarget::Specified(id) = val {
82 return id;
83 } else if CurrentApic.x2apic_enabled() {
84 return x86::apic::ApicId::X2Apic(0);
85 } else {
86 return x86::apic::ApicId::XApic(0);
87 }
88 }
89 }
90
91 impl ArchIpiTarget {
92 #[allow(dead_code)]
shorthand(&self) -> u893 pub fn shorthand(&self) -> u8 {
94 match self {
95 ArchIpiTarget::Specified(_) => 0,
96 ArchIpiTarget::Current => 1,
97 ArchIpiTarget::All => 2,
98 ArchIpiTarget::Other => 3,
99 }
100 }
101
102 #[inline(always)]
cpu_id_to_apic_id(cpu_id: ProcessorId) -> x86::apic::ApicId103 fn cpu_id_to_apic_id(cpu_id: ProcessorId) -> x86::apic::ApicId {
104 if CurrentApic.x2apic_enabled() {
105 x86::apic::ApicId::X2Apic(cpu_id.data())
106 } else {
107 x86::apic::ApicId::XApic(cpu_id.data() as u8)
108 }
109 }
110 }
111
112 impl From<ArchIpiTarget> for x86::apic::DestinationShorthand {
from(val: ArchIpiTarget) -> Self113 fn from(val: ArchIpiTarget) -> Self {
114 match val {
115 ArchIpiTarget::Specified(_) => x86::apic::DestinationShorthand::NoShorthand,
116 ArchIpiTarget::Current => x86::apic::DestinationShorthand::Myself,
117 ArchIpiTarget::All => x86::apic::DestinationShorthand::AllIncludingSelf,
118 ArchIpiTarget::Other => x86::apic::DestinationShorthand::AllExcludingSelf,
119 }
120 }
121 }
122
123 #[inline(always)]
send_ipi(kind: IpiKind, target: IpiTarget)124 pub fn send_ipi(kind: IpiKind, target: IpiTarget) {
125 // debug!("send_ipi: {:?} {:?}", kind, target);
126
127 let ipi_vec = ArchIpiKind::from(kind).into();
128 let target = ArchIpiTarget::from(target);
129 let shorthand: x86::apic::DestinationShorthand = target.into();
130 let destination: x86::apic::ApicId = target.into();
131 let icr = if CurrentApic.x2apic_enabled() {
132 // debug!("send_ipi: x2apic");
133 x86::apic::Icr::for_x2apic(
134 ipi_vec,
135 destination,
136 shorthand,
137 x86::apic::DeliveryMode::Fixed,
138 x86::apic::DestinationMode::Physical,
139 x86::apic::DeliveryStatus::Idle,
140 x86::apic::Level::Assert,
141 x86::apic::TriggerMode::Edge,
142 )
143 } else {
144 // debug!("send_ipi: xapic");
145 x86::apic::Icr::for_xapic(
146 ipi_vec,
147 destination,
148 shorthand,
149 x86::apic::DeliveryMode::Fixed,
150 x86::apic::DestinationMode::Physical,
151 x86::apic::DeliveryStatus::Idle,
152 x86::apic::Level::Assert,
153 x86::apic::TriggerMode::Edge,
154 )
155 };
156
157 CurrentApic.write_icr(icr);
158 }
159
160 /// 发送smp初始化IPI
ipi_send_smp_init()161 pub fn ipi_send_smp_init() {
162 let target = ArchIpiTarget::Other;
163 let icr = if CurrentApic.x2apic_enabled() {
164 x86::apic::Icr::for_x2apic(
165 0,
166 target.into(),
167 x86::apic::DestinationShorthand::AllExcludingSelf,
168 x86::apic::DeliveryMode::Init,
169 x86::apic::DestinationMode::Physical,
170 x86::apic::DeliveryStatus::Idle,
171 x86::apic::Level::Deassert,
172 x86::apic::TriggerMode::Edge,
173 )
174 } else {
175 x86::apic::Icr::for_xapic(
176 0,
177 target.into(),
178 x86::apic::DestinationShorthand::AllExcludingSelf,
179 x86::apic::DeliveryMode::Init,
180 x86::apic::DestinationMode::Physical,
181 x86::apic::DeliveryStatus::Idle,
182 x86::apic::Level::Deassert,
183 x86::apic::TriggerMode::Edge,
184 )
185 };
186 CurrentApic.write_icr(icr);
187 }
188
189 /// 发送smp启动IPI
190 ///
191 /// ## 参数
192 ///
193 /// * `target_cpu` - 目标CPU
ipi_send_smp_startup(target_cpu: ProcessorId) -> Result<(), SystemError>194 pub fn ipi_send_smp_startup(target_cpu: ProcessorId) -> Result<(), SystemError> {
195 if target_cpu.data() as usize >= SMP_BOOT_DATA.cpu_count() {
196 return Err(SystemError::EINVAL);
197 }
198 let target: ArchIpiTarget = IpiTarget::Specified(target_cpu).into();
199
200 let icr = if CurrentApic.x2apic_enabled() {
201 x86::apic::Icr::for_x2apic(
202 0x20,
203 target.into(),
204 x86::apic::DestinationShorthand::NoShorthand,
205 x86::apic::DeliveryMode::StartUp,
206 x86::apic::DestinationMode::Physical,
207 x86::apic::DeliveryStatus::Idle,
208 x86::apic::Level::Deassert,
209 x86::apic::TriggerMode::Edge,
210 )
211 } else {
212 x86::apic::Icr::for_xapic(
213 0x20,
214 target.into(),
215 x86::apic::DestinationShorthand::NoShorthand,
216 x86::apic::DeliveryMode::StartUp,
217 x86::apic::DestinationMode::Physical,
218 x86::apic::DeliveryStatus::Idle,
219 x86::apic::Level::Deassert,
220 x86::apic::TriggerMode::Edge,
221 )
222 };
223
224 CurrentApic.write_icr(icr);
225 return Ok(());
226 }
227
228 /// 初始化IPI处理函数
arch_ipi_handler_init()229 pub fn arch_ipi_handler_init() {
230 do_init_irq_handler(IPI_NUM_KICK_CPU);
231 do_init_irq_handler(IPI_NUM_FLUSH_TLB);
232 }
233
do_init_irq_handler(irq: IrqNumber)234 fn do_init_irq_handler(irq: IrqNumber) {
235 let desc = irq_desc_manager().lookup(irq).unwrap();
236 let irq_data: Arc<IrqData> = desc.irq_data();
237 let mut chip_info_guard = irq_data.chip_info_write_irqsave();
238 chip_info_guard.set_chip(Some(local_apic_chip().clone()));
239
240 desc.modify_status(IrqLineStatus::IRQ_LEVEL, IrqLineStatus::empty());
241 drop(chip_info_guard);
242 desc.set_handler(&X86_64IpiIrqFlowHandler);
243 }
244
245 #[derive(Debug)]
246 struct X86_64IpiIrqFlowHandler;
247
248 impl IrqFlowHandler for X86_64IpiIrqFlowHandler {
handle(&self, irq_desc: &Arc<IrqDesc>, _trap_frame: &mut TrapFrame)249 fn handle(&self, irq_desc: &Arc<IrqDesc>, _trap_frame: &mut TrapFrame) {
250 let irq = irq_desc.irq_data().irq();
251 match irq {
252 IPI_NUM_KICK_CPU => {
253 KickCpuIpiHandler.handle(irq, None, None).ok();
254 }
255 IPI_NUM_FLUSH_TLB => {
256 FlushTLBIpiHandler.handle(irq, None, None).ok();
257 CurrentApic.send_eoi();
258 }
259 _ => {
260 error!("Unknown IPI: {}", irq.data());
261 CurrentApic.send_eoi();
262 }
263 }
264 }
265 }
266