1 use alloc::sync::Arc; 2 use system_error::SystemError; 3 use x86::apic::ApicId; 4 5 use crate::{ 6 arch::{ 7 driver::apic::{lapic_vector::local_apic_chip, CurrentApic, LocalAPIC}, 8 smp::SMP_BOOT_DATA, 9 }, 10 exception::{ 11 ipi::{FlushTLBIpiHandler, IpiKind, IpiTarget, KickCpuIpiHandler}, 12 irqdata::{IrqData, IrqLineStatus}, 13 irqdesc::{irq_desc_manager, IrqDesc, IrqFlowHandler, IrqHandler}, 14 HardwareIrqNumber, IrqNumber, 15 }, 16 kerror, 17 smp::cpu::ProcessorId, 18 }; 19 20 use super::TrapFrame; 21 22 pub const IPI_NUM_KICK_CPU: IrqNumber = IrqNumber::new(200); 23 pub const IPI_NUM_FLUSH_TLB: IrqNumber = IrqNumber::new(201); 24 /// IPI的种类(架构相关,指定了向量号) 25 #[derive(Debug, Copy, Clone, Eq, PartialEq)] 26 #[repr(u32)] 27 pub enum ArchIpiKind { 28 KickCpu = IPI_NUM_KICK_CPU.data(), 29 FlushTLB = IPI_NUM_FLUSH_TLB.data(), 30 SpecVector(HardwareIrqNumber), 31 } 32 33 impl From<IpiKind> for ArchIpiKind { 34 fn from(kind: IpiKind) -> Self { 35 match kind { 36 IpiKind::KickCpu => ArchIpiKind::KickCpu, 37 IpiKind::FlushTLB => ArchIpiKind::FlushTLB, 38 IpiKind::SpecVector(vec) => ArchIpiKind::SpecVector(vec), 39 } 40 } 41 } 42 43 impl Into<u8> for ArchIpiKind { 44 fn into(self) -> u8 { 45 match self { 46 ArchIpiKind::KickCpu => IPI_NUM_KICK_CPU.data() as u8, 47 ArchIpiKind::FlushTLB => IPI_NUM_FLUSH_TLB.data() as u8, 48 ArchIpiKind::SpecVector(vec) => (vec.data() & 0xFF) as u8, 49 } 50 } 51 } 52 53 /// IPI投递目标 54 #[derive(Debug, Copy, Clone, Eq, PartialEq)] 55 pub enum ArchIpiTarget { 56 /// 当前CPU 57 Current, 58 /// 所有CPU 59 All, 60 /// 除了当前CPU以外的所有CPU 61 Other, 62 /// 指定的CPU 63 Specified(x86::apic::ApicId), 64 } 65 66 impl From<IpiTarget> for ArchIpiTarget { 67 fn from(target: IpiTarget) -> Self { 68 match target { 69 IpiTarget::Current => ArchIpiTarget::Current, 70 IpiTarget::All => ArchIpiTarget::All, 71 IpiTarget::Other => ArchIpiTarget::Other, 72 IpiTarget::Specified(cpu_id) => { 73 ArchIpiTarget::Specified(Self::cpu_id_to_apic_id(cpu_id)) 74 } 75 } 76 } 77 } 78 79 impl Into<ApicId> for ArchIpiTarget { 80 fn into(self) -> ApicId { 81 if let ArchIpiTarget::Specified(id) = self { 82 return id; 83 } else { 84 if CurrentApic.x2apic_enabled() { 85 return x86::apic::ApicId::X2Apic(0); 86 } else { 87 return x86::apic::ApicId::XApic(0); 88 } 89 } 90 } 91 } 92 93 impl ArchIpiTarget { 94 #[allow(dead_code)] 95 pub fn shorthand(&self) -> u8 { 96 match self { 97 ArchIpiTarget::Specified(_) => 0, 98 ArchIpiTarget::Current => 1, 99 ArchIpiTarget::All => 2, 100 ArchIpiTarget::Other => 3, 101 } 102 } 103 104 #[inline(always)] 105 fn cpu_id_to_apic_id(cpu_id: ProcessorId) -> x86::apic::ApicId { 106 if CurrentApic.x2apic_enabled() { 107 x86::apic::ApicId::X2Apic(cpu_id.data() as u32) 108 } else { 109 x86::apic::ApicId::XApic(cpu_id.data() as u8) 110 } 111 } 112 } 113 114 impl Into<x86::apic::DestinationShorthand> for ArchIpiTarget { 115 fn into(self) -> x86::apic::DestinationShorthand { 116 match self { 117 ArchIpiTarget::Specified(_) => x86::apic::DestinationShorthand::NoShorthand, 118 ArchIpiTarget::Current => x86::apic::DestinationShorthand::Myself, 119 ArchIpiTarget::All => x86::apic::DestinationShorthand::AllIncludingSelf, 120 ArchIpiTarget::Other => x86::apic::DestinationShorthand::AllExcludingSelf, 121 } 122 } 123 } 124 125 #[inline(always)] 126 pub fn send_ipi(kind: IpiKind, target: IpiTarget) { 127 // kdebug!("send_ipi: {:?} {:?}", kind, target); 128 129 let ipi_vec = ArchIpiKind::from(kind).into(); 130 let target = ArchIpiTarget::from(target); 131 let shorthand: x86::apic::DestinationShorthand = target.into(); 132 let destination: x86::apic::ApicId = target.into(); 133 let icr = if CurrentApic.x2apic_enabled() { 134 // kdebug!("send_ipi: x2apic"); 135 x86::apic::Icr::for_x2apic( 136 ipi_vec, 137 destination, 138 shorthand, 139 x86::apic::DeliveryMode::Fixed, 140 x86::apic::DestinationMode::Physical, 141 x86::apic::DeliveryStatus::Idle, 142 x86::apic::Level::Assert, 143 x86::apic::TriggerMode::Edge, 144 ) 145 } else { 146 // kdebug!("send_ipi: xapic"); 147 x86::apic::Icr::for_xapic( 148 ipi_vec, 149 destination, 150 shorthand, 151 x86::apic::DeliveryMode::Fixed, 152 x86::apic::DestinationMode::Physical, 153 x86::apic::DeliveryStatus::Idle, 154 x86::apic::Level::Assert, 155 x86::apic::TriggerMode::Edge, 156 ) 157 }; 158 159 CurrentApic.write_icr(icr); 160 } 161 162 /// 发送smp初始化IPI 163 pub fn ipi_send_smp_init() -> Result<(), SystemError> { 164 let target = ArchIpiTarget::Other; 165 let icr = if CurrentApic.x2apic_enabled() { 166 x86::apic::Icr::for_x2apic( 167 0, 168 target.into(), 169 x86::apic::DestinationShorthand::AllExcludingSelf, 170 x86::apic::DeliveryMode::Init, 171 x86::apic::DestinationMode::Physical, 172 x86::apic::DeliveryStatus::Idle, 173 x86::apic::Level::Deassert, 174 x86::apic::TriggerMode::Edge, 175 ) 176 } else { 177 x86::apic::Icr::for_xapic( 178 0, 179 target.into(), 180 x86::apic::DestinationShorthand::AllExcludingSelf, 181 x86::apic::DeliveryMode::Init, 182 x86::apic::DestinationMode::Physical, 183 x86::apic::DeliveryStatus::Idle, 184 x86::apic::Level::Deassert, 185 x86::apic::TriggerMode::Edge, 186 ) 187 }; 188 CurrentApic.write_icr(icr); 189 return Ok(()); 190 } 191 192 /// 发送smp启动IPI 193 /// 194 /// ## 参数 195 /// 196 /// * `target_cpu` - 目标CPU 197 pub fn ipi_send_smp_startup(target_cpu: ProcessorId) -> Result<(), SystemError> { 198 if target_cpu.data() as usize >= SMP_BOOT_DATA.cpu_count() { 199 return Err(SystemError::EINVAL); 200 } 201 let target: ArchIpiTarget = IpiTarget::Specified(target_cpu).into(); 202 203 let icr = if CurrentApic.x2apic_enabled() { 204 x86::apic::Icr::for_x2apic( 205 0x20, 206 target.into(), 207 x86::apic::DestinationShorthand::NoShorthand, 208 x86::apic::DeliveryMode::StartUp, 209 x86::apic::DestinationMode::Physical, 210 x86::apic::DeliveryStatus::Idle, 211 x86::apic::Level::Deassert, 212 x86::apic::TriggerMode::Edge, 213 ) 214 } else { 215 x86::apic::Icr::for_xapic( 216 0x20, 217 target.into(), 218 x86::apic::DestinationShorthand::NoShorthand, 219 x86::apic::DeliveryMode::StartUp, 220 x86::apic::DestinationMode::Physical, 221 x86::apic::DeliveryStatus::Idle, 222 x86::apic::Level::Deassert, 223 x86::apic::TriggerMode::Edge, 224 ) 225 }; 226 227 CurrentApic.write_icr(icr); 228 return Ok(()); 229 } 230 231 /// 初始化IPI处理函数 232 pub fn arch_ipi_handler_init() { 233 do_init_irq_handler(IPI_NUM_KICK_CPU); 234 do_init_irq_handler(IPI_NUM_FLUSH_TLB); 235 } 236 237 fn do_init_irq_handler(irq: IrqNumber) { 238 let desc = irq_desc_manager().lookup(irq).unwrap(); 239 let irq_data: Arc<IrqData> = desc.irq_data(); 240 let mut chip_info_guard = irq_data.chip_info_write_irqsave(); 241 chip_info_guard.set_chip(Some(local_apic_chip().clone())); 242 243 desc.modify_status(IrqLineStatus::IRQ_LEVEL, IrqLineStatus::empty()); 244 drop(chip_info_guard); 245 desc.set_handler(&X86_64IpiIrqFlowHandler); 246 } 247 248 #[derive(Debug)] 249 struct X86_64IpiIrqFlowHandler; 250 251 impl IrqFlowHandler for X86_64IpiIrqFlowHandler { 252 fn handle(&self, irq_desc: &Arc<IrqDesc>, _trap_frame: &mut TrapFrame) { 253 let irq = irq_desc.irq_data().irq(); 254 match irq { 255 IPI_NUM_KICK_CPU => { 256 KickCpuIpiHandler.handle(irq, None, None).ok(); 257 } 258 IPI_NUM_FLUSH_TLB => { 259 FlushTLBIpiHandler.handle(irq, None, None).ok(); 260 } 261 _ => { 262 kerror!("Unknown IPI: {}", irq.data()); 263 } 264 } 265 266 CurrentApic.send_eoi(); 267 } 268 } 269