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