use crate::exception::ipi::{IpiKind, IpiTarget}; extern "C" { pub fn apic_write_icr(value: u64); pub fn apic_x2apic_enabled() -> bool; } /// IPI的种类(架构相关,指定了向量号) #[derive(Debug, Copy, Clone, Eq, PartialEq)] #[repr(u8)] pub enum ArchIpiKind { KickCpu = 200, FlushTLB = 201, } impl From for ArchIpiKind { fn from(kind: IpiKind) -> Self { match kind { IpiKind::KickCpu => ArchIpiKind::KickCpu, IpiKind::FlushTLB => ArchIpiKind::FlushTLB, } } } /// IPI投递目标 #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum ArchIpiTarget { /// 当前CPU Current, /// 所有CPU All, /// 除了当前CPU以外的所有CPU Other, /// 指定的CPU Specified(usize), } impl From for ArchIpiTarget { fn from(target: IpiTarget) -> Self { match target { IpiTarget::Current => ArchIpiTarget::Current, IpiTarget::All => ArchIpiTarget::All, IpiTarget::Other => ArchIpiTarget::Other, IpiTarget::Specified(cpu_id) => ArchIpiTarget::Specified(cpu_id), } } } impl ArchIpiTarget { pub fn shorthand(&self) -> u8 { match self { ArchIpiTarget::Specified(_) => 0, ArchIpiTarget::Current => 1, ArchIpiTarget::All => 2, ArchIpiTarget::Other => 3, } } } impl Into for ArchIpiTarget { fn into(self) -> x86::apic::DestinationShorthand { match self { ArchIpiTarget::Specified(_) => x86::apic::DestinationShorthand::NoShorthand, ArchIpiTarget::Current => x86::apic::DestinationShorthand::Myself, ArchIpiTarget::All => x86::apic::DestinationShorthand::AllIncludingSelf, ArchIpiTarget::Other => x86::apic::DestinationShorthand::AllExcludingSelf, } } } impl Into for ArchIpiTarget { fn into(self) -> x86::apic::ApicId { let id = match self { ArchIpiTarget::Specified(cpu_id) => cpu_id, _ => 0, }; if unsafe { apic_x2apic_enabled() } { return x86::apic::ApicId::X2Apic(id as u32); } else { return x86::apic::ApicId::XApic(id as u8); } } } #[inline(always)] pub fn send_ipi(kind: IpiKind, target: IpiTarget) { // kdebug!("send_ipi: {:?} {:?}", kind, target); let ipi_vec = ArchIpiKind::from(kind) as u8; let target = ArchIpiTarget::from(target); let shorthand: x86::apic::DestinationShorthand = target.into(); let destination: x86::apic::ApicId = target.into(); if unsafe { apic_x2apic_enabled() } { // kdebug!("send_ipi: x2apic"); let icr = x86::apic::Icr::for_x2apic( ipi_vec, destination, shorthand, x86::apic::DeliveryMode::Fixed, x86::apic::DestinationMode::Physical, x86::apic::DeliveryStatus::Idle, x86::apic::Level::Assert, x86::apic::TriggerMode::Edge, ); unsafe { apic_write_icr(((icr.upper() as u64) << 32) | icr.lower() as u64); } } else { // kdebug!("send_ipi: xapic"); let icr = x86::apic::Icr::for_xapic( ipi_vec, destination, shorthand, x86::apic::DeliveryMode::Fixed, x86::apic::DestinationMode::Physical, x86::apic::DeliveryStatus::Idle, x86::apic::Level::Assert, x86::apic::TriggerMode::Edge, ); unsafe { apic_write_icr(((icr.upper() as u64) << 32) | icr.lower() as u64); } } }