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 From<ArchIpiKind> for u8 { 44 fn from(value: ArchIpiKind) -> Self { 45 match value { 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 From<ArchIpiTarget> for ApicId { 80 fn from(val: ArchIpiTarget) -> Self { 81 if let ArchIpiTarget::Specified(id) = val { 82 return id; 83 } else if CurrentApic.x2apic_enabled() { 84 return x86::apic::ApicId::X2Apic(0); 85 } else { 86 return x86::apic::ApicId::XApic(0); 87 } 88 } 89 } 90 91 impl ArchIpiTarget { 92 #[allow(dead_code)] 93 pub fn shorthand(&self) -> u8 { 94 match self { 95 ArchIpiTarget::Specified(_) => 0, 96 ArchIpiTarget::Current => 1, 97 ArchIpiTarget::All => 2, 98 ArchIpiTarget::Other => 3, 99 } 100 } 101 102 #[inline(always)] 103 fn cpu_id_to_apic_id(cpu_id: ProcessorId) -> x86::apic::ApicId { 104 if CurrentApic.x2apic_enabled() { 105 x86::apic::ApicId::X2Apic(cpu_id.data()) 106 } else { 107 x86::apic::ApicId::XApic(cpu_id.data() as u8) 108 } 109 } 110 } 111 112 impl From<ArchIpiTarget> for x86::apic::DestinationShorthand { 113 fn from(val: ArchIpiTarget) -> Self { 114 match val { 115 ArchIpiTarget::Specified(_) => x86::apic::DestinationShorthand::NoShorthand, 116 ArchIpiTarget::Current => x86::apic::DestinationShorthand::Myself, 117 ArchIpiTarget::All => x86::apic::DestinationShorthand::AllIncludingSelf, 118 ArchIpiTarget::Other => x86::apic::DestinationShorthand::AllExcludingSelf, 119 } 120 } 121 } 122 123 #[inline(always)] 124 pub fn send_ipi(kind: IpiKind, target: IpiTarget) { 125 // kdebug!("send_ipi: {:?} {:?}", kind, target); 126 127 let ipi_vec = ArchIpiKind::from(kind).into(); 128 let target = ArchIpiTarget::from(target); 129 let shorthand: x86::apic::DestinationShorthand = target.into(); 130 let destination: x86::apic::ApicId = target.into(); 131 let icr = if CurrentApic.x2apic_enabled() { 132 // kdebug!("send_ipi: x2apic"); 133 x86::apic::Icr::for_x2apic( 134 ipi_vec, 135 destination, 136 shorthand, 137 x86::apic::DeliveryMode::Fixed, 138 x86::apic::DestinationMode::Physical, 139 x86::apic::DeliveryStatus::Idle, 140 x86::apic::Level::Assert, 141 x86::apic::TriggerMode::Edge, 142 ) 143 } else { 144 // kdebug!("send_ipi: xapic"); 145 x86::apic::Icr::for_xapic( 146 ipi_vec, 147 destination, 148 shorthand, 149 x86::apic::DeliveryMode::Fixed, 150 x86::apic::DestinationMode::Physical, 151 x86::apic::DeliveryStatus::Idle, 152 x86::apic::Level::Assert, 153 x86::apic::TriggerMode::Edge, 154 ) 155 }; 156 157 CurrentApic.write_icr(icr); 158 } 159 160 /// 发送smp初始化IPI 161 pub fn ipi_send_smp_init() { 162 let target = ArchIpiTarget::Other; 163 let icr = if CurrentApic.x2apic_enabled() { 164 x86::apic::Icr::for_x2apic( 165 0, 166 target.into(), 167 x86::apic::DestinationShorthand::AllExcludingSelf, 168 x86::apic::DeliveryMode::Init, 169 x86::apic::DestinationMode::Physical, 170 x86::apic::DeliveryStatus::Idle, 171 x86::apic::Level::Deassert, 172 x86::apic::TriggerMode::Edge, 173 ) 174 } else { 175 x86::apic::Icr::for_xapic( 176 0, 177 target.into(), 178 x86::apic::DestinationShorthand::AllExcludingSelf, 179 x86::apic::DeliveryMode::Init, 180 x86::apic::DestinationMode::Physical, 181 x86::apic::DeliveryStatus::Idle, 182 x86::apic::Level::Deassert, 183 x86::apic::TriggerMode::Edge, 184 ) 185 }; 186 CurrentApic.write_icr(icr); 187 } 188 189 /// 发送smp启动IPI 190 /// 191 /// ## 参数 192 /// 193 /// * `target_cpu` - 目标CPU 194 pub fn ipi_send_smp_startup(target_cpu: ProcessorId) -> Result<(), SystemError> { 195 if target_cpu.data() as usize >= SMP_BOOT_DATA.cpu_count() { 196 return Err(SystemError::EINVAL); 197 } 198 let target: ArchIpiTarget = IpiTarget::Specified(target_cpu).into(); 199 200 let icr = if CurrentApic.x2apic_enabled() { 201 x86::apic::Icr::for_x2apic( 202 0x20, 203 target.into(), 204 x86::apic::DestinationShorthand::NoShorthand, 205 x86::apic::DeliveryMode::StartUp, 206 x86::apic::DestinationMode::Physical, 207 x86::apic::DeliveryStatus::Idle, 208 x86::apic::Level::Deassert, 209 x86::apic::TriggerMode::Edge, 210 ) 211 } else { 212 x86::apic::Icr::for_xapic( 213 0x20, 214 target.into(), 215 x86::apic::DestinationShorthand::NoShorthand, 216 x86::apic::DeliveryMode::StartUp, 217 x86::apic::DestinationMode::Physical, 218 x86::apic::DeliveryStatus::Idle, 219 x86::apic::Level::Deassert, 220 x86::apic::TriggerMode::Edge, 221 ) 222 }; 223 224 CurrentApic.write_icr(icr); 225 return Ok(()); 226 } 227 228 /// 初始化IPI处理函数 229 pub fn arch_ipi_handler_init() { 230 do_init_irq_handler(IPI_NUM_KICK_CPU); 231 do_init_irq_handler(IPI_NUM_FLUSH_TLB); 232 } 233 234 fn do_init_irq_handler(irq: IrqNumber) { 235 let desc = irq_desc_manager().lookup(irq).unwrap(); 236 let irq_data: Arc<IrqData> = desc.irq_data(); 237 let mut chip_info_guard = irq_data.chip_info_write_irqsave(); 238 chip_info_guard.set_chip(Some(local_apic_chip().clone())); 239 240 desc.modify_status(IrqLineStatus::IRQ_LEVEL, IrqLineStatus::empty()); 241 drop(chip_info_guard); 242 desc.set_handler(&X86_64IpiIrqFlowHandler); 243 } 244 245 #[derive(Debug)] 246 struct X86_64IpiIrqFlowHandler; 247 248 impl IrqFlowHandler for X86_64IpiIrqFlowHandler { 249 fn handle(&self, irq_desc: &Arc<IrqDesc>, _trap_frame: &mut TrapFrame) { 250 let irq = irq_desc.irq_data().irq(); 251 match irq { 252 IPI_NUM_KICK_CPU => { 253 KickCpuIpiHandler.handle(irq, None, None).ok(); 254 } 255 IPI_NUM_FLUSH_TLB => { 256 FlushTLBIpiHandler.handle(irq, None, None).ok(); 257 } 258 _ => { 259 kerror!("Unknown IPI: {}", irq.data()); 260 } 261 } 262 263 CurrentApic.send_eoi(); 264 } 265 } 266