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 #[allow(dead_code)] 71 pub fn shorthand(&self) -> u8 { 72 match self { 73 ArchIpiTarget::Specified(_) => 0, 74 ArchIpiTarget::Current => 1, 75 ArchIpiTarget::All => 2, 76 ArchIpiTarget::Other => 3, 77 } 78 } 79 80 #[inline(always)] 81 fn cpu_id_to_apic_id(cpu_id: u32) -> x86::apic::ApicId { 82 if CurrentApic.x2apic_enabled() { 83 x86::apic::ApicId::X2Apic(cpu_id as u32) 84 } else { 85 x86::apic::ApicId::XApic(cpu_id as u8) 86 } 87 } 88 } 89 90 impl Into<x86::apic::DestinationShorthand> for ArchIpiTarget { 91 fn into(self) -> x86::apic::DestinationShorthand { 92 match self { 93 ArchIpiTarget::Specified(_) => x86::apic::DestinationShorthand::NoShorthand, 94 ArchIpiTarget::Current => x86::apic::DestinationShorthand::Myself, 95 ArchIpiTarget::All => x86::apic::DestinationShorthand::AllIncludingSelf, 96 ArchIpiTarget::Other => x86::apic::DestinationShorthand::AllExcludingSelf, 97 } 98 } 99 } 100 101 #[inline(always)] 102 pub fn send_ipi(kind: IpiKind, target: IpiTarget) { 103 // kdebug!("send_ipi: {:?} {:?}", kind, target); 104 105 let ipi_vec = ArchIpiKind::from(kind) as u8; 106 let target = ArchIpiTarget::from(target); 107 let shorthand: x86::apic::DestinationShorthand = target.into(); 108 let destination: x86::apic::ApicId = target.into(); 109 let icr = if CurrentApic.x2apic_enabled() { 110 // kdebug!("send_ipi: x2apic"); 111 x86::apic::Icr::for_x2apic( 112 ipi_vec, 113 destination, 114 shorthand, 115 x86::apic::DeliveryMode::Fixed, 116 x86::apic::DestinationMode::Physical, 117 x86::apic::DeliveryStatus::Idle, 118 x86::apic::Level::Assert, 119 x86::apic::TriggerMode::Edge, 120 ) 121 } else { 122 // kdebug!("send_ipi: xapic"); 123 x86::apic::Icr::for_xapic( 124 ipi_vec, 125 destination, 126 shorthand, 127 x86::apic::DeliveryMode::Fixed, 128 x86::apic::DestinationMode::Physical, 129 x86::apic::DeliveryStatus::Idle, 130 x86::apic::Level::Assert, 131 x86::apic::TriggerMode::Edge, 132 ) 133 }; 134 135 CurrentApic.write_icr(icr); 136 } 137 138 /// 发送smp初始化IPI 139 pub fn ipi_send_smp_init() -> Result<(), SystemError> { 140 let target = ArchIpiTarget::Other; 141 let icr = if CurrentApic.x2apic_enabled() { 142 x86::apic::Icr::for_x2apic( 143 0, 144 target.into(), 145 x86::apic::DestinationShorthand::AllExcludingSelf, 146 x86::apic::DeliveryMode::Init, 147 x86::apic::DestinationMode::Physical, 148 x86::apic::DeliveryStatus::Idle, 149 x86::apic::Level::Deassert, 150 x86::apic::TriggerMode::Edge, 151 ) 152 } else { 153 x86::apic::Icr::for_xapic( 154 0, 155 target.into(), 156 x86::apic::DestinationShorthand::AllExcludingSelf, 157 x86::apic::DeliveryMode::Init, 158 x86::apic::DestinationMode::Physical, 159 x86::apic::DeliveryStatus::Idle, 160 x86::apic::Level::Deassert, 161 x86::apic::TriggerMode::Edge, 162 ) 163 }; 164 CurrentApic.write_icr(icr); 165 return Ok(()); 166 } 167 168 /// 发送smp启动IPI 169 /// 170 /// ## 参数 171 /// 172 /// * `target_cpu` - 目标CPU 173 pub fn ipi_send_smp_startup(target_cpu: u32) -> Result<(), SystemError> { 174 if target_cpu as usize >= SMP_BOOT_DATA.cpu_count() { 175 return Err(SystemError::EINVAL); 176 } 177 let target: ArchIpiTarget = IpiTarget::Specified(target_cpu as usize).into(); 178 179 let icr = if CurrentApic.x2apic_enabled() { 180 x86::apic::Icr::for_x2apic( 181 0x20, 182 target.into(), 183 x86::apic::DestinationShorthand::NoShorthand, 184 x86::apic::DeliveryMode::StartUp, 185 x86::apic::DestinationMode::Physical, 186 x86::apic::DeliveryStatus::Idle, 187 x86::apic::Level::Deassert, 188 x86::apic::TriggerMode::Edge, 189 ) 190 } else { 191 x86::apic::Icr::for_xapic( 192 0x20, 193 target.into(), 194 x86::apic::DestinationShorthand::NoShorthand, 195 x86::apic::DeliveryMode::StartUp, 196 x86::apic::DestinationMode::Physical, 197 x86::apic::DeliveryStatus::Idle, 198 x86::apic::Level::Deassert, 199 x86::apic::TriggerMode::Edge, 200 ) 201 }; 202 203 CurrentApic.write_icr(icr); 204 return Ok(()); 205 } 206