1*70a4e555SLoGin use x86::apic::ApicId; 2aa0367d6SLoGin 3*70a4e555SLoGin use crate::{ 4*70a4e555SLoGin arch::{ 5*70a4e555SLoGin driver::apic::{CurrentApic, LocalAPIC}, 6*70a4e555SLoGin smp::SMP_BOOT_DATA, 7*70a4e555SLoGin }, 8*70a4e555SLoGin exception::ipi::{IpiKind, IpiTarget}, 9*70a4e555SLoGin syscall::SystemError, 10*70a4e555SLoGin }; 11aa0367d6SLoGin 12aa0367d6SLoGin /// IPI的种类(架构相关,指定了向量号) 13aa0367d6SLoGin #[derive(Debug, Copy, Clone, Eq, PartialEq)] 14aa0367d6SLoGin #[repr(u8)] 15aa0367d6SLoGin pub enum ArchIpiKind { 16aa0367d6SLoGin KickCpu = 200, 17aa0367d6SLoGin FlushTLB = 201, 18aa0367d6SLoGin } 19aa0367d6SLoGin 20aa0367d6SLoGin impl From<IpiKind> for ArchIpiKind { 21aa0367d6SLoGin fn from(kind: IpiKind) -> Self { 22aa0367d6SLoGin match kind { 23aa0367d6SLoGin IpiKind::KickCpu => ArchIpiKind::KickCpu, 24aa0367d6SLoGin IpiKind::FlushTLB => ArchIpiKind::FlushTLB, 25aa0367d6SLoGin } 26aa0367d6SLoGin } 27aa0367d6SLoGin } 28aa0367d6SLoGin 29aa0367d6SLoGin /// IPI投递目标 30aa0367d6SLoGin #[derive(Debug, Copy, Clone, Eq, PartialEq)] 31aa0367d6SLoGin pub enum ArchIpiTarget { 32aa0367d6SLoGin /// 当前CPU 33aa0367d6SLoGin Current, 34aa0367d6SLoGin /// 所有CPU 35aa0367d6SLoGin All, 36aa0367d6SLoGin /// 除了当前CPU以外的所有CPU 37aa0367d6SLoGin Other, 38aa0367d6SLoGin /// 指定的CPU 39*70a4e555SLoGin Specified(x86::apic::ApicId), 40aa0367d6SLoGin } 41aa0367d6SLoGin 42aa0367d6SLoGin impl From<IpiTarget> for ArchIpiTarget { 43aa0367d6SLoGin fn from(target: IpiTarget) -> Self { 44aa0367d6SLoGin match target { 45aa0367d6SLoGin IpiTarget::Current => ArchIpiTarget::Current, 46aa0367d6SLoGin IpiTarget::All => ArchIpiTarget::All, 47aa0367d6SLoGin IpiTarget::Other => ArchIpiTarget::Other, 48*70a4e555SLoGin IpiTarget::Specified(cpu_id) => { 49*70a4e555SLoGin ArchIpiTarget::Specified(Self::cpu_id_to_apic_id(cpu_id as u32)) 50*70a4e555SLoGin } 51*70a4e555SLoGin } 52*70a4e555SLoGin } 53*70a4e555SLoGin } 54*70a4e555SLoGin 55*70a4e555SLoGin impl Into<ApicId> for ArchIpiTarget { 56*70a4e555SLoGin fn into(self) -> ApicId { 57*70a4e555SLoGin if let ArchIpiTarget::Specified(id) = self { 58*70a4e555SLoGin return id; 59*70a4e555SLoGin } else { 60*70a4e555SLoGin if CurrentApic.x2apic_enabled() { 61*70a4e555SLoGin return x86::apic::ApicId::X2Apic(0); 62*70a4e555SLoGin } else { 63*70a4e555SLoGin return x86::apic::ApicId::XApic(0); 64*70a4e555SLoGin } 65aa0367d6SLoGin } 66aa0367d6SLoGin } 67aa0367d6SLoGin } 68aa0367d6SLoGin 69aa0367d6SLoGin impl ArchIpiTarget { 70aa0367d6SLoGin pub fn shorthand(&self) -> u8 { 71aa0367d6SLoGin match self { 72aa0367d6SLoGin ArchIpiTarget::Specified(_) => 0, 73aa0367d6SLoGin ArchIpiTarget::Current => 1, 74aa0367d6SLoGin ArchIpiTarget::All => 2, 75aa0367d6SLoGin ArchIpiTarget::Other => 3, 76aa0367d6SLoGin } 77aa0367d6SLoGin } 78*70a4e555SLoGin 79*70a4e555SLoGin #[inline(always)] 80*70a4e555SLoGin fn cpu_id_to_apic_id(cpu_id: u32) -> x86::apic::ApicId { 81*70a4e555SLoGin if CurrentApic.x2apic_enabled() { 82*70a4e555SLoGin x86::apic::ApicId::X2Apic(cpu_id as u32) 83*70a4e555SLoGin } else { 84*70a4e555SLoGin x86::apic::ApicId::XApic(cpu_id as u8) 85*70a4e555SLoGin } 86*70a4e555SLoGin } 87aa0367d6SLoGin } 88aa0367d6SLoGin 89aa0367d6SLoGin impl Into<x86::apic::DestinationShorthand> for ArchIpiTarget { 90aa0367d6SLoGin fn into(self) -> x86::apic::DestinationShorthand { 91aa0367d6SLoGin match self { 92aa0367d6SLoGin ArchIpiTarget::Specified(_) => x86::apic::DestinationShorthand::NoShorthand, 93aa0367d6SLoGin ArchIpiTarget::Current => x86::apic::DestinationShorthand::Myself, 94aa0367d6SLoGin ArchIpiTarget::All => x86::apic::DestinationShorthand::AllIncludingSelf, 95aa0367d6SLoGin ArchIpiTarget::Other => x86::apic::DestinationShorthand::AllExcludingSelf, 96aa0367d6SLoGin } 97aa0367d6SLoGin } 98aa0367d6SLoGin } 99aa0367d6SLoGin 100aa0367d6SLoGin #[inline(always)] 101aa0367d6SLoGin pub fn send_ipi(kind: IpiKind, target: IpiTarget) { 102aa0367d6SLoGin // kdebug!("send_ipi: {:?} {:?}", kind, target); 103aa0367d6SLoGin 104aa0367d6SLoGin let ipi_vec = ArchIpiKind::from(kind) as u8; 105aa0367d6SLoGin let target = ArchIpiTarget::from(target); 106aa0367d6SLoGin let shorthand: x86::apic::DestinationShorthand = target.into(); 107aa0367d6SLoGin let destination: x86::apic::ApicId = target.into(); 108*70a4e555SLoGin let icr = if CurrentApic.x2apic_enabled() { 109aa0367d6SLoGin // kdebug!("send_ipi: x2apic"); 110*70a4e555SLoGin x86::apic::Icr::for_x2apic( 111aa0367d6SLoGin ipi_vec, 112aa0367d6SLoGin destination, 113aa0367d6SLoGin shorthand, 114aa0367d6SLoGin x86::apic::DeliveryMode::Fixed, 115aa0367d6SLoGin x86::apic::DestinationMode::Physical, 116aa0367d6SLoGin x86::apic::DeliveryStatus::Idle, 117aa0367d6SLoGin x86::apic::Level::Assert, 118aa0367d6SLoGin x86::apic::TriggerMode::Edge, 119*70a4e555SLoGin ) 120aa0367d6SLoGin } else { 121aa0367d6SLoGin // kdebug!("send_ipi: xapic"); 122*70a4e555SLoGin x86::apic::Icr::for_xapic( 123aa0367d6SLoGin ipi_vec, 124aa0367d6SLoGin destination, 125aa0367d6SLoGin shorthand, 126aa0367d6SLoGin x86::apic::DeliveryMode::Fixed, 127aa0367d6SLoGin x86::apic::DestinationMode::Physical, 128aa0367d6SLoGin x86::apic::DeliveryStatus::Idle, 129aa0367d6SLoGin x86::apic::Level::Assert, 130aa0367d6SLoGin x86::apic::TriggerMode::Edge, 131*70a4e555SLoGin ) 132*70a4e555SLoGin }; 133aa0367d6SLoGin 134*70a4e555SLoGin CurrentApic.write_icr(icr); 135aa0367d6SLoGin } 136*70a4e555SLoGin 137*70a4e555SLoGin /// 发送smp初始化IPI 138*70a4e555SLoGin pub fn ipi_send_smp_init() -> Result<(), SystemError> { 139*70a4e555SLoGin let target = ArchIpiTarget::Other; 140*70a4e555SLoGin let icr = if CurrentApic.x2apic_enabled() { 141*70a4e555SLoGin x86::apic::Icr::for_x2apic( 142*70a4e555SLoGin 0, 143*70a4e555SLoGin target.into(), 144*70a4e555SLoGin x86::apic::DestinationShorthand::AllExcludingSelf, 145*70a4e555SLoGin x86::apic::DeliveryMode::Init, 146*70a4e555SLoGin x86::apic::DestinationMode::Physical, 147*70a4e555SLoGin x86::apic::DeliveryStatus::Idle, 148*70a4e555SLoGin x86::apic::Level::Deassert, 149*70a4e555SLoGin x86::apic::TriggerMode::Edge, 150*70a4e555SLoGin ) 151*70a4e555SLoGin } else { 152*70a4e555SLoGin x86::apic::Icr::for_xapic( 153*70a4e555SLoGin 0, 154*70a4e555SLoGin target.into(), 155*70a4e555SLoGin x86::apic::DestinationShorthand::AllExcludingSelf, 156*70a4e555SLoGin x86::apic::DeliveryMode::Init, 157*70a4e555SLoGin x86::apic::DestinationMode::Physical, 158*70a4e555SLoGin x86::apic::DeliveryStatus::Idle, 159*70a4e555SLoGin x86::apic::Level::Deassert, 160*70a4e555SLoGin x86::apic::TriggerMode::Edge, 161*70a4e555SLoGin ) 162*70a4e555SLoGin }; 163*70a4e555SLoGin CurrentApic.write_icr(icr); 164*70a4e555SLoGin return Ok(()); 165aa0367d6SLoGin } 166*70a4e555SLoGin 167*70a4e555SLoGin /// 发送smp启动IPI 168*70a4e555SLoGin /// 169*70a4e555SLoGin /// ## 参数 170*70a4e555SLoGin /// 171*70a4e555SLoGin /// * `target_cpu` - 目标CPU 172*70a4e555SLoGin pub fn ipi_send_smp_startup(target_cpu: u32) -> Result<(), SystemError> { 173*70a4e555SLoGin if target_cpu as usize >= SMP_BOOT_DATA.cpu_count() { 174*70a4e555SLoGin return Err(SystemError::EINVAL); 175*70a4e555SLoGin } 176*70a4e555SLoGin let target: ArchIpiTarget = IpiTarget::Specified(target_cpu as usize).into(); 177*70a4e555SLoGin 178*70a4e555SLoGin let icr = if CurrentApic.x2apic_enabled() { 179*70a4e555SLoGin x86::apic::Icr::for_x2apic( 180*70a4e555SLoGin 0x20, 181*70a4e555SLoGin target.into(), 182*70a4e555SLoGin x86::apic::DestinationShorthand::NoShorthand, 183*70a4e555SLoGin x86::apic::DeliveryMode::StartUp, 184*70a4e555SLoGin x86::apic::DestinationMode::Physical, 185*70a4e555SLoGin x86::apic::DeliveryStatus::Idle, 186*70a4e555SLoGin x86::apic::Level::Deassert, 187*70a4e555SLoGin x86::apic::TriggerMode::Edge, 188*70a4e555SLoGin ) 189*70a4e555SLoGin } else { 190*70a4e555SLoGin x86::apic::Icr::for_xapic( 191*70a4e555SLoGin 0x20, 192*70a4e555SLoGin target.into(), 193*70a4e555SLoGin x86::apic::DestinationShorthand::NoShorthand, 194*70a4e555SLoGin x86::apic::DeliveryMode::StartUp, 195*70a4e555SLoGin x86::apic::DestinationMode::Physical, 196*70a4e555SLoGin x86::apic::DeliveryStatus::Idle, 197*70a4e555SLoGin x86::apic::Level::Deassert, 198*70a4e555SLoGin x86::apic::TriggerMode::Edge, 199*70a4e555SLoGin ) 200*70a4e555SLoGin }; 201*70a4e555SLoGin 202*70a4e555SLoGin CurrentApic.write_icr(icr); 203*70a4e555SLoGin return Ok(()); 204aa0367d6SLoGin } 205