xref: /DragonOS/kernel/src/arch/x86_64/interrupt/ipi.rs (revision e28411791f090c421fe4b6fa5956fb1bd362a8d9)
1*e2841179SLoGin use alloc::sync::Arc;
291e9d4abSLoGin use system_error::SystemError;
370a4e555SLoGin use x86::apic::ApicId;
4aa0367d6SLoGin 
570a4e555SLoGin use crate::{
670a4e555SLoGin     arch::{
7*e2841179SLoGin         driver::apic::{lapic_vector::local_apic_chip, CurrentApic, LocalAPIC},
870a4e555SLoGin         smp::SMP_BOOT_DATA,
970a4e555SLoGin     },
10*e2841179SLoGin     exception::{
11*e2841179SLoGin         ipi::{FlushTLBIpiHandler, IpiKind, IpiTarget, KickCpuIpiHandler},
12*e2841179SLoGin         irqdata::{IrqData, IrqLineStatus},
13*e2841179SLoGin         irqdesc::{irq_desc_manager, IrqDesc, IrqFlowHandler, IrqHandler},
14*e2841179SLoGin         HardwareIrqNumber, IrqNumber,
15*e2841179SLoGin     },
16*e2841179SLoGin     kerror,
17*e2841179SLoGin     smp::cpu::ProcessorId,
1870a4e555SLoGin };
19aa0367d6SLoGin 
20*e2841179SLoGin use super::TrapFrame;
21*e2841179SLoGin 
22*e2841179SLoGin pub const IPI_NUM_KICK_CPU: IrqNumber = IrqNumber::new(200);
23*e2841179SLoGin pub const IPI_NUM_FLUSH_TLB: IrqNumber = IrqNumber::new(201);
24aa0367d6SLoGin /// IPI的种类(架构相关,指定了向量号)
25aa0367d6SLoGin #[derive(Debug, Copy, Clone, Eq, PartialEq)]
26*e2841179SLoGin #[repr(u32)]
27aa0367d6SLoGin pub enum ArchIpiKind {
28*e2841179SLoGin     KickCpu = IPI_NUM_KICK_CPU.data(),
29*e2841179SLoGin     FlushTLB = IPI_NUM_FLUSH_TLB.data(),
30*e2841179SLoGin     SpecVector(HardwareIrqNumber),
31aa0367d6SLoGin }
32aa0367d6SLoGin 
33aa0367d6SLoGin impl From<IpiKind> for ArchIpiKind {
34aa0367d6SLoGin     fn from(kind: IpiKind) -> Self {
35aa0367d6SLoGin         match kind {
36aa0367d6SLoGin             IpiKind::KickCpu => ArchIpiKind::KickCpu,
37aa0367d6SLoGin             IpiKind::FlushTLB => ArchIpiKind::FlushTLB,
38*e2841179SLoGin             IpiKind::SpecVector(vec) => ArchIpiKind::SpecVector(vec),
39*e2841179SLoGin         }
40*e2841179SLoGin     }
41*e2841179SLoGin }
42*e2841179SLoGin 
43*e2841179SLoGin impl Into<u8> for ArchIpiKind {
44*e2841179SLoGin     fn into(self) -> u8 {
45*e2841179SLoGin         match self {
46*e2841179SLoGin             ArchIpiKind::KickCpu => IPI_NUM_KICK_CPU.data() as u8,
47*e2841179SLoGin             ArchIpiKind::FlushTLB => IPI_NUM_FLUSH_TLB.data() as u8,
48*e2841179SLoGin             ArchIpiKind::SpecVector(vec) => (vec.data() & 0xFF) as u8,
49aa0367d6SLoGin         }
50aa0367d6SLoGin     }
51aa0367d6SLoGin }
52aa0367d6SLoGin 
53aa0367d6SLoGin /// IPI投递目标
54aa0367d6SLoGin #[derive(Debug, Copy, Clone, Eq, PartialEq)]
55aa0367d6SLoGin pub enum ArchIpiTarget {
56aa0367d6SLoGin     /// 当前CPU
57aa0367d6SLoGin     Current,
58aa0367d6SLoGin     /// 所有CPU
59aa0367d6SLoGin     All,
60aa0367d6SLoGin     /// 除了当前CPU以外的所有CPU
61aa0367d6SLoGin     Other,
62aa0367d6SLoGin     /// 指定的CPU
6370a4e555SLoGin     Specified(x86::apic::ApicId),
64aa0367d6SLoGin }
65aa0367d6SLoGin 
66aa0367d6SLoGin impl From<IpiTarget> for ArchIpiTarget {
67aa0367d6SLoGin     fn from(target: IpiTarget) -> Self {
68aa0367d6SLoGin         match target {
69aa0367d6SLoGin             IpiTarget::Current => ArchIpiTarget::Current,
70aa0367d6SLoGin             IpiTarget::All => ArchIpiTarget::All,
71aa0367d6SLoGin             IpiTarget::Other => ArchIpiTarget::Other,
7270a4e555SLoGin             IpiTarget::Specified(cpu_id) => {
73*e2841179SLoGin                 ArchIpiTarget::Specified(Self::cpu_id_to_apic_id(cpu_id))
7470a4e555SLoGin             }
7570a4e555SLoGin         }
7670a4e555SLoGin     }
7770a4e555SLoGin }
7870a4e555SLoGin 
7970a4e555SLoGin impl Into<ApicId> for ArchIpiTarget {
8070a4e555SLoGin     fn into(self) -> ApicId {
8170a4e555SLoGin         if let ArchIpiTarget::Specified(id) = self {
8270a4e555SLoGin             return id;
8370a4e555SLoGin         } else {
8470a4e555SLoGin             if CurrentApic.x2apic_enabled() {
8570a4e555SLoGin                 return x86::apic::ApicId::X2Apic(0);
8670a4e555SLoGin             } else {
8770a4e555SLoGin                 return x86::apic::ApicId::XApic(0);
8870a4e555SLoGin             }
89aa0367d6SLoGin         }
90aa0367d6SLoGin     }
91aa0367d6SLoGin }
92aa0367d6SLoGin 
93aa0367d6SLoGin impl ArchIpiTarget {
94f2022a8aSLoGin     #[allow(dead_code)]
95aa0367d6SLoGin     pub fn shorthand(&self) -> u8 {
96aa0367d6SLoGin         match self {
97aa0367d6SLoGin             ArchIpiTarget::Specified(_) => 0,
98aa0367d6SLoGin             ArchIpiTarget::Current => 1,
99aa0367d6SLoGin             ArchIpiTarget::All => 2,
100aa0367d6SLoGin             ArchIpiTarget::Other => 3,
101aa0367d6SLoGin         }
102aa0367d6SLoGin     }
10370a4e555SLoGin 
10470a4e555SLoGin     #[inline(always)]
105*e2841179SLoGin     fn cpu_id_to_apic_id(cpu_id: ProcessorId) -> x86::apic::ApicId {
10670a4e555SLoGin         if CurrentApic.x2apic_enabled() {
107*e2841179SLoGin             x86::apic::ApicId::X2Apic(cpu_id.data() as u32)
10870a4e555SLoGin         } else {
109*e2841179SLoGin             x86::apic::ApicId::XApic(cpu_id.data() as u8)
11070a4e555SLoGin         }
11170a4e555SLoGin     }
112aa0367d6SLoGin }
113aa0367d6SLoGin 
114aa0367d6SLoGin impl Into<x86::apic::DestinationShorthand> for ArchIpiTarget {
115aa0367d6SLoGin     fn into(self) -> x86::apic::DestinationShorthand {
116aa0367d6SLoGin         match self {
117aa0367d6SLoGin             ArchIpiTarget::Specified(_) => x86::apic::DestinationShorthand::NoShorthand,
118aa0367d6SLoGin             ArchIpiTarget::Current => x86::apic::DestinationShorthand::Myself,
119aa0367d6SLoGin             ArchIpiTarget::All => x86::apic::DestinationShorthand::AllIncludingSelf,
120aa0367d6SLoGin             ArchIpiTarget::Other => x86::apic::DestinationShorthand::AllExcludingSelf,
121aa0367d6SLoGin         }
122aa0367d6SLoGin     }
123aa0367d6SLoGin }
124aa0367d6SLoGin 
125aa0367d6SLoGin #[inline(always)]
126aa0367d6SLoGin pub fn send_ipi(kind: IpiKind, target: IpiTarget) {
127aa0367d6SLoGin     // kdebug!("send_ipi: {:?} {:?}", kind, target);
128aa0367d6SLoGin 
129*e2841179SLoGin     let ipi_vec = ArchIpiKind::from(kind).into();
130aa0367d6SLoGin     let target = ArchIpiTarget::from(target);
131aa0367d6SLoGin     let shorthand: x86::apic::DestinationShorthand = target.into();
132aa0367d6SLoGin     let destination: x86::apic::ApicId = target.into();
13370a4e555SLoGin     let icr = if CurrentApic.x2apic_enabled() {
134aa0367d6SLoGin         // kdebug!("send_ipi: x2apic");
13570a4e555SLoGin         x86::apic::Icr::for_x2apic(
136aa0367d6SLoGin             ipi_vec,
137aa0367d6SLoGin             destination,
138aa0367d6SLoGin             shorthand,
139aa0367d6SLoGin             x86::apic::DeliveryMode::Fixed,
140aa0367d6SLoGin             x86::apic::DestinationMode::Physical,
141aa0367d6SLoGin             x86::apic::DeliveryStatus::Idle,
142aa0367d6SLoGin             x86::apic::Level::Assert,
143aa0367d6SLoGin             x86::apic::TriggerMode::Edge,
14470a4e555SLoGin         )
145aa0367d6SLoGin     } else {
146aa0367d6SLoGin         // kdebug!("send_ipi: xapic");
14770a4e555SLoGin         x86::apic::Icr::for_xapic(
148aa0367d6SLoGin             ipi_vec,
149aa0367d6SLoGin             destination,
150aa0367d6SLoGin             shorthand,
151aa0367d6SLoGin             x86::apic::DeliveryMode::Fixed,
152aa0367d6SLoGin             x86::apic::DestinationMode::Physical,
153aa0367d6SLoGin             x86::apic::DeliveryStatus::Idle,
154aa0367d6SLoGin             x86::apic::Level::Assert,
155aa0367d6SLoGin             x86::apic::TriggerMode::Edge,
15670a4e555SLoGin         )
15770a4e555SLoGin     };
158aa0367d6SLoGin 
15970a4e555SLoGin     CurrentApic.write_icr(icr);
160aa0367d6SLoGin }
16170a4e555SLoGin 
16270a4e555SLoGin /// 发送smp初始化IPI
16370a4e555SLoGin pub fn ipi_send_smp_init() -> Result<(), SystemError> {
16470a4e555SLoGin     let target = ArchIpiTarget::Other;
16570a4e555SLoGin     let icr = if CurrentApic.x2apic_enabled() {
16670a4e555SLoGin         x86::apic::Icr::for_x2apic(
16770a4e555SLoGin             0,
16870a4e555SLoGin             target.into(),
16970a4e555SLoGin             x86::apic::DestinationShorthand::AllExcludingSelf,
17070a4e555SLoGin             x86::apic::DeliveryMode::Init,
17170a4e555SLoGin             x86::apic::DestinationMode::Physical,
17270a4e555SLoGin             x86::apic::DeliveryStatus::Idle,
17370a4e555SLoGin             x86::apic::Level::Deassert,
17470a4e555SLoGin             x86::apic::TriggerMode::Edge,
17570a4e555SLoGin         )
17670a4e555SLoGin     } else {
17770a4e555SLoGin         x86::apic::Icr::for_xapic(
17870a4e555SLoGin             0,
17970a4e555SLoGin             target.into(),
18070a4e555SLoGin             x86::apic::DestinationShorthand::AllExcludingSelf,
18170a4e555SLoGin             x86::apic::DeliveryMode::Init,
18270a4e555SLoGin             x86::apic::DestinationMode::Physical,
18370a4e555SLoGin             x86::apic::DeliveryStatus::Idle,
18470a4e555SLoGin             x86::apic::Level::Deassert,
18570a4e555SLoGin             x86::apic::TriggerMode::Edge,
18670a4e555SLoGin         )
18770a4e555SLoGin     };
18870a4e555SLoGin     CurrentApic.write_icr(icr);
18970a4e555SLoGin     return Ok(());
190aa0367d6SLoGin }
19170a4e555SLoGin 
19270a4e555SLoGin /// 发送smp启动IPI
19370a4e555SLoGin ///
19470a4e555SLoGin /// ## 参数
19570a4e555SLoGin ///
19670a4e555SLoGin /// * `target_cpu` - 目标CPU
197*e2841179SLoGin pub fn ipi_send_smp_startup(target_cpu: ProcessorId) -> Result<(), SystemError> {
198*e2841179SLoGin     if target_cpu.data() as usize >= SMP_BOOT_DATA.cpu_count() {
19970a4e555SLoGin         return Err(SystemError::EINVAL);
20070a4e555SLoGin     }
201*e2841179SLoGin     let target: ArchIpiTarget = IpiTarget::Specified(target_cpu).into();
20270a4e555SLoGin 
20370a4e555SLoGin     let icr = if CurrentApic.x2apic_enabled() {
20470a4e555SLoGin         x86::apic::Icr::for_x2apic(
20570a4e555SLoGin             0x20,
20670a4e555SLoGin             target.into(),
20770a4e555SLoGin             x86::apic::DestinationShorthand::NoShorthand,
20870a4e555SLoGin             x86::apic::DeliveryMode::StartUp,
20970a4e555SLoGin             x86::apic::DestinationMode::Physical,
21070a4e555SLoGin             x86::apic::DeliveryStatus::Idle,
21170a4e555SLoGin             x86::apic::Level::Deassert,
21270a4e555SLoGin             x86::apic::TriggerMode::Edge,
21370a4e555SLoGin         )
21470a4e555SLoGin     } else {
21570a4e555SLoGin         x86::apic::Icr::for_xapic(
21670a4e555SLoGin             0x20,
21770a4e555SLoGin             target.into(),
21870a4e555SLoGin             x86::apic::DestinationShorthand::NoShorthand,
21970a4e555SLoGin             x86::apic::DeliveryMode::StartUp,
22070a4e555SLoGin             x86::apic::DestinationMode::Physical,
22170a4e555SLoGin             x86::apic::DeliveryStatus::Idle,
22270a4e555SLoGin             x86::apic::Level::Deassert,
22370a4e555SLoGin             x86::apic::TriggerMode::Edge,
22470a4e555SLoGin         )
22570a4e555SLoGin     };
22670a4e555SLoGin 
22770a4e555SLoGin     CurrentApic.write_icr(icr);
22870a4e555SLoGin     return Ok(());
229aa0367d6SLoGin }
230*e2841179SLoGin 
231*e2841179SLoGin /// 初始化IPI处理函数
232*e2841179SLoGin pub fn arch_ipi_handler_init() {
233*e2841179SLoGin     do_init_irq_handler(IPI_NUM_KICK_CPU);
234*e2841179SLoGin     do_init_irq_handler(IPI_NUM_FLUSH_TLB);
235*e2841179SLoGin }
236*e2841179SLoGin 
237*e2841179SLoGin fn do_init_irq_handler(irq: IrqNumber) {
238*e2841179SLoGin     let desc = irq_desc_manager().lookup(irq).unwrap();
239*e2841179SLoGin     let irq_data: Arc<IrqData> = desc.irq_data();
240*e2841179SLoGin     let mut chip_info_guard = irq_data.chip_info_write_irqsave();
241*e2841179SLoGin     chip_info_guard.set_chip(Some(local_apic_chip().clone()));
242*e2841179SLoGin 
243*e2841179SLoGin     desc.modify_status(IrqLineStatus::IRQ_LEVEL, IrqLineStatus::empty());
244*e2841179SLoGin     drop(chip_info_guard);
245*e2841179SLoGin     desc.set_handler(&X86_64IpiIrqFlowHandler);
246*e2841179SLoGin }
247*e2841179SLoGin 
248*e2841179SLoGin #[derive(Debug)]
249*e2841179SLoGin struct X86_64IpiIrqFlowHandler;
250*e2841179SLoGin 
251*e2841179SLoGin impl IrqFlowHandler for X86_64IpiIrqFlowHandler {
252*e2841179SLoGin     fn handle(&self, irq_desc: &Arc<IrqDesc>, _trap_frame: &mut TrapFrame) {
253*e2841179SLoGin         let irq = irq_desc.irq_data().irq();
254*e2841179SLoGin         match irq {
255*e2841179SLoGin             IPI_NUM_KICK_CPU => {
256*e2841179SLoGin                 KickCpuIpiHandler.handle(irq, None, None).ok();
257*e2841179SLoGin             }
258*e2841179SLoGin             IPI_NUM_FLUSH_TLB => {
259*e2841179SLoGin                 FlushTLBIpiHandler.handle(irq, None, None).ok();
260*e2841179SLoGin             }
261*e2841179SLoGin             _ => {
262*e2841179SLoGin                 kerror!("Unknown IPI: {}", irq.data());
263*e2841179SLoGin             }
264*e2841179SLoGin         }
265*e2841179SLoGin 
266*e2841179SLoGin         CurrentApic.send_eoi();
267*e2841179SLoGin     }
268*e2841179SLoGin }
269