191e9d4abSLoGin use system_error::SystemError; 270a4e555SLoGin use x86::apic::ApicId; 3aa0367d6SLoGin 470a4e555SLoGin use crate::{ 570a4e555SLoGin arch::{ 670a4e555SLoGin driver::apic::{CurrentApic, LocalAPIC}, 770a4e555SLoGin smp::SMP_BOOT_DATA, 870a4e555SLoGin }, 970a4e555SLoGin exception::ipi::{IpiKind, IpiTarget}, 1070a4e555SLoGin }; 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 3970a4e555SLoGin 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, 4870a4e555SLoGin IpiTarget::Specified(cpu_id) => { 4970a4e555SLoGin ArchIpiTarget::Specified(Self::cpu_id_to_apic_id(cpu_id as u32)) 5070a4e555SLoGin } 5170a4e555SLoGin } 5270a4e555SLoGin } 5370a4e555SLoGin } 5470a4e555SLoGin 5570a4e555SLoGin impl Into<ApicId> for ArchIpiTarget { 5670a4e555SLoGin fn into(self) -> ApicId { 5770a4e555SLoGin if let ArchIpiTarget::Specified(id) = self { 5870a4e555SLoGin return id; 5970a4e555SLoGin } else { 6070a4e555SLoGin if CurrentApic.x2apic_enabled() { 6170a4e555SLoGin return x86::apic::ApicId::X2Apic(0); 6270a4e555SLoGin } else { 6370a4e555SLoGin return x86::apic::ApicId::XApic(0); 6470a4e555SLoGin } 65aa0367d6SLoGin } 66aa0367d6SLoGin } 67aa0367d6SLoGin } 68aa0367d6SLoGin 69aa0367d6SLoGin impl ArchIpiTarget { 70*f2022a8aSLoGin #[allow(dead_code)] 71aa0367d6SLoGin pub fn shorthand(&self) -> u8 { 72aa0367d6SLoGin match self { 73aa0367d6SLoGin ArchIpiTarget::Specified(_) => 0, 74aa0367d6SLoGin ArchIpiTarget::Current => 1, 75aa0367d6SLoGin ArchIpiTarget::All => 2, 76aa0367d6SLoGin ArchIpiTarget::Other => 3, 77aa0367d6SLoGin } 78aa0367d6SLoGin } 7970a4e555SLoGin 8070a4e555SLoGin #[inline(always)] 8170a4e555SLoGin fn cpu_id_to_apic_id(cpu_id: u32) -> x86::apic::ApicId { 8270a4e555SLoGin if CurrentApic.x2apic_enabled() { 8370a4e555SLoGin x86::apic::ApicId::X2Apic(cpu_id as u32) 8470a4e555SLoGin } else { 8570a4e555SLoGin x86::apic::ApicId::XApic(cpu_id as u8) 8670a4e555SLoGin } 8770a4e555SLoGin } 88aa0367d6SLoGin } 89aa0367d6SLoGin 90aa0367d6SLoGin impl Into<x86::apic::DestinationShorthand> for ArchIpiTarget { 91aa0367d6SLoGin fn into(self) -> x86::apic::DestinationShorthand { 92aa0367d6SLoGin match self { 93aa0367d6SLoGin ArchIpiTarget::Specified(_) => x86::apic::DestinationShorthand::NoShorthand, 94aa0367d6SLoGin ArchIpiTarget::Current => x86::apic::DestinationShorthand::Myself, 95aa0367d6SLoGin ArchIpiTarget::All => x86::apic::DestinationShorthand::AllIncludingSelf, 96aa0367d6SLoGin ArchIpiTarget::Other => x86::apic::DestinationShorthand::AllExcludingSelf, 97aa0367d6SLoGin } 98aa0367d6SLoGin } 99aa0367d6SLoGin } 100aa0367d6SLoGin 101aa0367d6SLoGin #[inline(always)] 102aa0367d6SLoGin pub fn send_ipi(kind: IpiKind, target: IpiTarget) { 103aa0367d6SLoGin // kdebug!("send_ipi: {:?} {:?}", kind, target); 104aa0367d6SLoGin 105aa0367d6SLoGin let ipi_vec = ArchIpiKind::from(kind) as u8; 106aa0367d6SLoGin let target = ArchIpiTarget::from(target); 107aa0367d6SLoGin let shorthand: x86::apic::DestinationShorthand = target.into(); 108aa0367d6SLoGin let destination: x86::apic::ApicId = target.into(); 10970a4e555SLoGin let icr = if CurrentApic.x2apic_enabled() { 110aa0367d6SLoGin // kdebug!("send_ipi: x2apic"); 11170a4e555SLoGin x86::apic::Icr::for_x2apic( 112aa0367d6SLoGin ipi_vec, 113aa0367d6SLoGin destination, 114aa0367d6SLoGin shorthand, 115aa0367d6SLoGin x86::apic::DeliveryMode::Fixed, 116aa0367d6SLoGin x86::apic::DestinationMode::Physical, 117aa0367d6SLoGin x86::apic::DeliveryStatus::Idle, 118aa0367d6SLoGin x86::apic::Level::Assert, 119aa0367d6SLoGin x86::apic::TriggerMode::Edge, 12070a4e555SLoGin ) 121aa0367d6SLoGin } else { 122aa0367d6SLoGin // kdebug!("send_ipi: xapic"); 12370a4e555SLoGin x86::apic::Icr::for_xapic( 124aa0367d6SLoGin ipi_vec, 125aa0367d6SLoGin destination, 126aa0367d6SLoGin shorthand, 127aa0367d6SLoGin x86::apic::DeliveryMode::Fixed, 128aa0367d6SLoGin x86::apic::DestinationMode::Physical, 129aa0367d6SLoGin x86::apic::DeliveryStatus::Idle, 130aa0367d6SLoGin x86::apic::Level::Assert, 131aa0367d6SLoGin x86::apic::TriggerMode::Edge, 13270a4e555SLoGin ) 13370a4e555SLoGin }; 134aa0367d6SLoGin 13570a4e555SLoGin CurrentApic.write_icr(icr); 136aa0367d6SLoGin } 13770a4e555SLoGin 13870a4e555SLoGin /// 发送smp初始化IPI 13970a4e555SLoGin pub fn ipi_send_smp_init() -> Result<(), SystemError> { 14070a4e555SLoGin let target = ArchIpiTarget::Other; 14170a4e555SLoGin let icr = if CurrentApic.x2apic_enabled() { 14270a4e555SLoGin x86::apic::Icr::for_x2apic( 14370a4e555SLoGin 0, 14470a4e555SLoGin target.into(), 14570a4e555SLoGin x86::apic::DestinationShorthand::AllExcludingSelf, 14670a4e555SLoGin x86::apic::DeliveryMode::Init, 14770a4e555SLoGin x86::apic::DestinationMode::Physical, 14870a4e555SLoGin x86::apic::DeliveryStatus::Idle, 14970a4e555SLoGin x86::apic::Level::Deassert, 15070a4e555SLoGin x86::apic::TriggerMode::Edge, 15170a4e555SLoGin ) 15270a4e555SLoGin } else { 15370a4e555SLoGin x86::apic::Icr::for_xapic( 15470a4e555SLoGin 0, 15570a4e555SLoGin target.into(), 15670a4e555SLoGin x86::apic::DestinationShorthand::AllExcludingSelf, 15770a4e555SLoGin x86::apic::DeliveryMode::Init, 15870a4e555SLoGin x86::apic::DestinationMode::Physical, 15970a4e555SLoGin x86::apic::DeliveryStatus::Idle, 16070a4e555SLoGin x86::apic::Level::Deassert, 16170a4e555SLoGin x86::apic::TriggerMode::Edge, 16270a4e555SLoGin ) 16370a4e555SLoGin }; 16470a4e555SLoGin CurrentApic.write_icr(icr); 16570a4e555SLoGin return Ok(()); 166aa0367d6SLoGin } 16770a4e555SLoGin 16870a4e555SLoGin /// 发送smp启动IPI 16970a4e555SLoGin /// 17070a4e555SLoGin /// ## 参数 17170a4e555SLoGin /// 17270a4e555SLoGin /// * `target_cpu` - 目标CPU 17370a4e555SLoGin pub fn ipi_send_smp_startup(target_cpu: u32) -> Result<(), SystemError> { 17470a4e555SLoGin if target_cpu as usize >= SMP_BOOT_DATA.cpu_count() { 17570a4e555SLoGin return Err(SystemError::EINVAL); 17670a4e555SLoGin } 17770a4e555SLoGin let target: ArchIpiTarget = IpiTarget::Specified(target_cpu as usize).into(); 17870a4e555SLoGin 17970a4e555SLoGin let icr = if CurrentApic.x2apic_enabled() { 18070a4e555SLoGin x86::apic::Icr::for_x2apic( 18170a4e555SLoGin 0x20, 18270a4e555SLoGin target.into(), 18370a4e555SLoGin x86::apic::DestinationShorthand::NoShorthand, 18470a4e555SLoGin x86::apic::DeliveryMode::StartUp, 18570a4e555SLoGin x86::apic::DestinationMode::Physical, 18670a4e555SLoGin x86::apic::DeliveryStatus::Idle, 18770a4e555SLoGin x86::apic::Level::Deassert, 18870a4e555SLoGin x86::apic::TriggerMode::Edge, 18970a4e555SLoGin ) 19070a4e555SLoGin } else { 19170a4e555SLoGin x86::apic::Icr::for_xapic( 19270a4e555SLoGin 0x20, 19370a4e555SLoGin target.into(), 19470a4e555SLoGin x86::apic::DestinationShorthand::NoShorthand, 19570a4e555SLoGin x86::apic::DeliveryMode::StartUp, 19670a4e555SLoGin x86::apic::DestinationMode::Physical, 19770a4e555SLoGin x86::apic::DeliveryStatus::Idle, 19870a4e555SLoGin x86::apic::Level::Deassert, 19970a4e555SLoGin x86::apic::TriggerMode::Edge, 20070a4e555SLoGin ) 20170a4e555SLoGin }; 20270a4e555SLoGin 20370a4e555SLoGin CurrentApic.write_icr(icr); 20470a4e555SLoGin return Ok(()); 205aa0367d6SLoGin } 206