1*70a4e555SLoGin use core::{ 2*70a4e555SLoGin cell::RefCell, 3*70a4e555SLoGin hint::spin_loop, 4*70a4e555SLoGin ptr::{read_volatile, write_volatile}, 5*70a4e555SLoGin }; 6*70a4e555SLoGin 7*70a4e555SLoGin use crate::{ 8*70a4e555SLoGin kdebug, kerror, kinfo, 9*70a4e555SLoGin mm::{ 10*70a4e555SLoGin mmio_buddy::{mmio_pool, MMIOSpaceGuard}, 11*70a4e555SLoGin percpu::PerCpu, 12*70a4e555SLoGin PhysAddr, VirtAddr, 13*70a4e555SLoGin }, 14*70a4e555SLoGin smp::core::smp_get_processor_id, 15*70a4e555SLoGin }; 16*70a4e555SLoGin 17*70a4e555SLoGin use super::{LVTRegister, LocalAPIC, LVT}; 18*70a4e555SLoGin 19*70a4e555SLoGin /// per-cpu的xAPIC的MMIO空间起始地址 20*70a4e555SLoGin static mut XAPIC_INSTANCES: [RefCell<Option<XApic>>; PerCpu::MAX_CPU_NUM] = 21*70a4e555SLoGin [const { RefCell::new(None) }; PerCpu::MAX_CPU_NUM]; 22*70a4e555SLoGin 23*70a4e555SLoGin #[inline(always)] 24*70a4e555SLoGin pub(super) fn current_xapic_instance() -> &'static RefCell<Option<XApic>> { 25*70a4e555SLoGin unsafe { &XAPIC_INSTANCES.as_ref()[smp_get_processor_id() as usize] } 26*70a4e555SLoGin } 27*70a4e555SLoGin 28*70a4e555SLoGin /// TODO:统一变量 29*70a4e555SLoGin /// @brief local APIC 寄存器地址偏移量 30*70a4e555SLoGin #[derive(Debug)] 31*70a4e555SLoGin #[allow(dead_code)] 32*70a4e555SLoGin #[allow(non_camel_case_types)] 33*70a4e555SLoGin #[repr(u32)] 34*70a4e555SLoGin pub enum XApicOffset { 35*70a4e555SLoGin // 定义各个寄存器的地址偏移量 36*70a4e555SLoGin LOCAL_APIC_OFFSET_Local_APIC_ID = 0x20, 37*70a4e555SLoGin LOCAL_APIC_OFFSET_Local_APIC_Version = 0x30, 38*70a4e555SLoGin LOCAL_APIC_OFFSET_Local_APIC_TPR = 0x80, 39*70a4e555SLoGin LOCAL_APIC_OFFSET_Local_APIC_APR = 0x90, 40*70a4e555SLoGin LOCAL_APIC_OFFSET_Local_APIC_PPR = 0xa0, 41*70a4e555SLoGin LOCAL_APIC_OFFSET_Local_APIC_EOI = 0xb0, 42*70a4e555SLoGin LOCAL_APIC_OFFSET_Local_APIC_RRD = 0xc0, 43*70a4e555SLoGin LOCAL_APIC_OFFSET_Local_APIC_LDR = 0xd0, 44*70a4e555SLoGin LOCAL_APIC_OFFSET_Local_APIC_DFR = 0xe0, 45*70a4e555SLoGin LOCAL_APIC_OFFSET_Local_APIC_SVR = 0xf0, 46*70a4e555SLoGin 47*70a4e555SLoGin LOCAL_APIC_OFFSET_Local_APIC_ISR_31_0 = 0x100, // In-Service Register 48*70a4e555SLoGin LOCAL_APIC_OFFSET_Local_APIC_ISR_63_32 = 0x110, 49*70a4e555SLoGin LOCAL_APIC_OFFSET_Local_APIC_ISR_95_64 = 0x120, 50*70a4e555SLoGin LOCAL_APIC_OFFSET_Local_APIC_ISR_127_96 = 0x130, 51*70a4e555SLoGin LOCAL_APIC_OFFSET_Local_APIC_ISR_159_128 = 0x140, 52*70a4e555SLoGin LOCAL_APIC_OFFSET_Local_APIC_ISR_191_160 = 0x150, 53*70a4e555SLoGin LOCAL_APIC_OFFSET_Local_APIC_ISR_223_192 = 0x160, 54*70a4e555SLoGin LOCAL_APIC_OFFSET_Local_APIC_ISR_255_224 = 0x170, 55*70a4e555SLoGin 56*70a4e555SLoGin LOCAL_APIC_OFFSET_Local_APIC_TMR_31_0 = 0x180, // Trigger Mode Register 57*70a4e555SLoGin LOCAL_APIC_OFFSET_Local_APIC_TMR_63_32 = 0x190, 58*70a4e555SLoGin LOCAL_APIC_OFFSET_Local_APIC_TMR_95_64 = 0x1a0, 59*70a4e555SLoGin LOCAL_APIC_OFFSET_Local_APIC_TMR_127_96 = 0x1b0, 60*70a4e555SLoGin LOCAL_APIC_OFFSET_Local_APIC_TMR_159_128 = 0x1c0, 61*70a4e555SLoGin LOCAL_APIC_OFFSET_Local_APIC_TMR_191_160 = 0x1d0, 62*70a4e555SLoGin LOCAL_APIC_OFFSET_Local_APIC_TMR_223_192 = 0x1e0, 63*70a4e555SLoGin LOCAL_APIC_OFFSET_Local_APIC_TMR_255_224 = 0x1f0, 64*70a4e555SLoGin 65*70a4e555SLoGin LOCAL_APIC_OFFSET_Local_APIC_IRR_31_0 = 0x200, // Interrupt Request Register 66*70a4e555SLoGin LOCAL_APIC_OFFSET_Local_APIC_IRR_63_32 = 0x210, 67*70a4e555SLoGin LOCAL_APIC_OFFSET_Local_APIC_IRR_95_64 = 0x220, 68*70a4e555SLoGin LOCAL_APIC_OFFSET_Local_APIC_IRR_127_96 = 0x230, 69*70a4e555SLoGin LOCAL_APIC_OFFSET_Local_APIC_IRR_159_128 = 0x240, 70*70a4e555SLoGin LOCAL_APIC_OFFSET_Local_APIC_IRR_191_160 = 0x250, 71*70a4e555SLoGin LOCAL_APIC_OFFSET_Local_APIC_IRR_223_192 = 0x260, 72*70a4e555SLoGin LOCAL_APIC_OFFSET_Local_APIC_IRR_255_224 = 0x270, 73*70a4e555SLoGin 74*70a4e555SLoGin LOCAL_APIC_OFFSET_Local_APIC_ESR = 0x280, // Error Status Register 75*70a4e555SLoGin 76*70a4e555SLoGin LOCAL_APIC_OFFSET_Local_APIC_LVT_CMCI = 0x2f0, // Corrected Machine Check Interrupt Register 77*70a4e555SLoGin 78*70a4e555SLoGin LOCAL_APIC_OFFSET_Local_APIC_ICR_31_0 = 0x300, // Interrupt Command Register 79*70a4e555SLoGin LOCAL_APIC_OFFSET_Local_APIC_ICR_63_32 = 0x310, 80*70a4e555SLoGin 81*70a4e555SLoGin LOCAL_APIC_OFFSET_Local_APIC_LVT_TIMER = 0x320, 82*70a4e555SLoGin LOCAL_APIC_OFFSET_Local_APIC_LVT_THERMAL = 0x330, 83*70a4e555SLoGin LOCAL_APIC_OFFSET_Local_APIC_LVT_PERFORMANCE_MONITOR = 0x340, 84*70a4e555SLoGin LOCAL_APIC_OFFSET_Local_APIC_LVT_LINT0 = 0x350, 85*70a4e555SLoGin LOCAL_APIC_OFFSET_Local_APIC_LVT_LINT1 = 0x360, 86*70a4e555SLoGin LOCAL_APIC_OFFSET_Local_APIC_LVT_ERROR = 0x370, 87*70a4e555SLoGin // 初始计数寄存器(定时器专用) 88*70a4e555SLoGin LOCAL_APIC_OFFSET_Local_APIC_INITIAL_COUNT_REG = 0x380, 89*70a4e555SLoGin // 当前计数寄存器(定时器专用) 90*70a4e555SLoGin LOCAL_APIC_OFFSET_Local_APIC_CURRENT_COUNT_REG = 0x390, 91*70a4e555SLoGin LOCAL_APIC_OFFSET_Local_APIC_CLKDIV = 0x3e0, 92*70a4e555SLoGin } 93*70a4e555SLoGin 94*70a4e555SLoGin impl Into<u32> for XApicOffset { 95*70a4e555SLoGin fn into(self) -> u32 { 96*70a4e555SLoGin self as u32 97*70a4e555SLoGin } 98*70a4e555SLoGin } 99*70a4e555SLoGin 100*70a4e555SLoGin impl From<LVTRegister> for XApicOffset { 101*70a4e555SLoGin fn from(lvt: LVTRegister) -> Self { 102*70a4e555SLoGin match lvt { 103*70a4e555SLoGin LVTRegister::Timer => XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_LVT_TIMER, 104*70a4e555SLoGin LVTRegister::Thermal => XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_LVT_THERMAL, 105*70a4e555SLoGin LVTRegister::PerformanceMonitor => { 106*70a4e555SLoGin XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_LVT_PERFORMANCE_MONITOR 107*70a4e555SLoGin } 108*70a4e555SLoGin LVTRegister::LINT0 => XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_LVT_LINT0, 109*70a4e555SLoGin LVTRegister::LINT1 => XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_LVT_LINT1, 110*70a4e555SLoGin LVTRegister::ErrorReg => XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_LVT_ERROR, 111*70a4e555SLoGin LVTRegister::CMCI => XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_LVT_CMCI, 112*70a4e555SLoGin } 113*70a4e555SLoGin } 114*70a4e555SLoGin } 115*70a4e555SLoGin 116*70a4e555SLoGin #[derive(Debug)] 117*70a4e555SLoGin #[allow(dead_code)] 118*70a4e555SLoGin pub struct XApic { 119*70a4e555SLoGin /// 当前xAPIC的寄存器映射的虚拟地址。注意,每个CPU都有自己的xAPIC,所以这个地址是每个CPU都不一样的。 120*70a4e555SLoGin apic_vaddr: VirtAddr, 121*70a4e555SLoGin /// `apic_vaddr`与映射的空间起始位置之间的偏移量 122*70a4e555SLoGin offset: usize, 123*70a4e555SLoGin map_guard: MMIOSpaceGuard, 124*70a4e555SLoGin xapic_base: PhysAddr, 125*70a4e555SLoGin } 126*70a4e555SLoGin 127*70a4e555SLoGin impl XApic { 128*70a4e555SLoGin /// 读取指定寄存器的值 129*70a4e555SLoGin #[allow(dead_code)] 130*70a4e555SLoGin pub unsafe fn read(&self, reg: XApicOffset) -> u32 { 131*70a4e555SLoGin read_volatile((self.apic_vaddr.data() + reg as usize) as *const u32) 132*70a4e555SLoGin } 133*70a4e555SLoGin 134*70a4e555SLoGin /// 将指定的值写入寄存器 135*70a4e555SLoGin #[allow(dead_code)] 136*70a4e555SLoGin pub unsafe fn write(&self, reg: XApicOffset, value: u32) { 137*70a4e555SLoGin write_volatile( 138*70a4e555SLoGin (self.apic_vaddr.data() + (reg as u32) as usize) as *mut u32, 139*70a4e555SLoGin value, 140*70a4e555SLoGin ); 141*70a4e555SLoGin self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ID); // 等待写操作完成,通过读取进行同步 142*70a4e555SLoGin } 143*70a4e555SLoGin } 144*70a4e555SLoGin 145*70a4e555SLoGin impl XApic { 146*70a4e555SLoGin /// 创建新的XAPIC实例 147*70a4e555SLoGin /// 148*70a4e555SLoGin /// ## 参数 149*70a4e555SLoGin /// 150*70a4e555SLoGin /// - `xapic_base` - 当前核心的xAPIC的寄存器的物理地址 151*70a4e555SLoGin pub unsafe fn new(xapic_base: PhysAddr) -> Self { 152*70a4e555SLoGin let offset = xapic_base.data() & 0xffff; 153*70a4e555SLoGin let paddr = PhysAddr::new(xapic_base.data() & !0xffff); 154*70a4e555SLoGin let g = mmio_pool() 155*70a4e555SLoGin .create_mmio(4096) 156*70a4e555SLoGin .expect("Fail to create MMIO for XAPIC"); 157*70a4e555SLoGin g.map_phys(paddr, 4096).expect("Fail to map MMIO for XAPIC"); 158*70a4e555SLoGin let addr = g.vaddr() + offset; 159*70a4e555SLoGin 160*70a4e555SLoGin kdebug!( 161*70a4e555SLoGin "XAPIC: {:#x} -> {:#x}, offset={offset}", 162*70a4e555SLoGin xapic_base.data(), 163*70a4e555SLoGin addr.data() 164*70a4e555SLoGin ); 165*70a4e555SLoGin 166*70a4e555SLoGin let r = Self { 167*70a4e555SLoGin apic_vaddr: addr, 168*70a4e555SLoGin offset, 169*70a4e555SLoGin map_guard: g, 170*70a4e555SLoGin xapic_base, 171*70a4e555SLoGin }; 172*70a4e555SLoGin 173*70a4e555SLoGin return r; 174*70a4e555SLoGin } 175*70a4e555SLoGin } 176*70a4e555SLoGin 177*70a4e555SLoGin #[allow(dead_code)] 178*70a4e555SLoGin const X1: u32 = 0x0000000B; // 将除数设置为1,即不除频率 179*70a4e555SLoGin #[allow(dead_code)] 180*70a4e555SLoGin const PERIODIC: u32 = 0x00020000; // 周期性模式 181*70a4e555SLoGin #[allow(dead_code)] 182*70a4e555SLoGin const ENABLE: u32 = 0x00000100; // 单元使能 183*70a4e555SLoGin #[allow(dead_code)] 184*70a4e555SLoGin const MASKED: u32 = 0x00010000; // 中断屏蔽 185*70a4e555SLoGin const LEVEL: u32 = 0x00008000; // 电平触发 186*70a4e555SLoGin const BCAST: u32 = 0x00080000; // 发送到所有APIC,包括自己 187*70a4e555SLoGin const DELIVS: u32 = 0x00001000; // 传递状态 188*70a4e555SLoGin const INIT: u32 = 0x00000500; // INIT/RESET 189*70a4e555SLoGin 190*70a4e555SLoGin //中断请求 191*70a4e555SLoGin #[allow(dead_code)] 192*70a4e555SLoGin const T_IRQ0: u32 = 32; // IRQ 0 对应于 T_IRQ 中断 193*70a4e555SLoGin #[allow(dead_code)] 194*70a4e555SLoGin const IRQ_TIMER: u32 = 0; 195*70a4e555SLoGin #[allow(dead_code)] 196*70a4e555SLoGin const IRQ_KBD: u32 = 1; 197*70a4e555SLoGin #[allow(dead_code)] 198*70a4e555SLoGin const IRQ_COM1: u32 = 4; 199*70a4e555SLoGin #[allow(dead_code)] 200*70a4e555SLoGin const IRQ_IDE: u32 = 14; 201*70a4e555SLoGin #[allow(dead_code)] 202*70a4e555SLoGin const IRQ_ERROR: u32 = 19; 203*70a4e555SLoGin #[allow(dead_code)] 204*70a4e555SLoGin const IRQ_SPURIOUS: u32 = 31; 205*70a4e555SLoGin 206*70a4e555SLoGin impl LocalAPIC for XApic { 207*70a4e555SLoGin /// @brief 判断处理器是否支持apic 208*70a4e555SLoGin fn support() -> bool { 209*70a4e555SLoGin return x86::cpuid::CpuId::new() 210*70a4e555SLoGin .get_feature_info() 211*70a4e555SLoGin .expect("Fail to get CPU feature.") 212*70a4e555SLoGin .has_apic(); 213*70a4e555SLoGin } 214*70a4e555SLoGin 215*70a4e555SLoGin /// @return true -> 函数运行成功 216*70a4e555SLoGin fn init_current_cpu(&mut self) -> bool { 217*70a4e555SLoGin unsafe { 218*70a4e555SLoGin // enable xapic 219*70a4e555SLoGin x86::msr::wrmsr(x86::msr::APIC_BASE, (self.xapic_base.data() | 0x800) as u64); 220*70a4e555SLoGin let val = x86::msr::rdmsr(x86::msr::APIC_BASE); 221*70a4e555SLoGin if val & 0x800 != 0x800 { 222*70a4e555SLoGin kerror!("xAPIC enable failed: APIC_BASE & 0x800 != 0x800"); 223*70a4e555SLoGin return false; 224*70a4e555SLoGin } 225*70a4e555SLoGin // 设置 Spurious Interrupt Vector Register 226*70a4e555SLoGin let val = self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_SVR.into()); 227*70a4e555SLoGin 228*70a4e555SLoGin self.write( 229*70a4e555SLoGin XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_SVR.into(), 230*70a4e555SLoGin val | ENABLE, 231*70a4e555SLoGin ); 232*70a4e555SLoGin 233*70a4e555SLoGin let val = self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_SVR.into()); 234*70a4e555SLoGin if val & ENABLE == 0 { 235*70a4e555SLoGin kerror!("xAPIC software enable failed."); 236*70a4e555SLoGin 237*70a4e555SLoGin return false; 238*70a4e555SLoGin } else { 239*70a4e555SLoGin kinfo!("xAPIC software enabled."); 240*70a4e555SLoGin } 241*70a4e555SLoGin 242*70a4e555SLoGin if val & 0x1000 != 0 { 243*70a4e555SLoGin kinfo!("xAPIC EOI broadcast suppression enabled."); 244*70a4e555SLoGin } 245*70a4e555SLoGin 246*70a4e555SLoGin self.mask_all_lvt(); 247*70a4e555SLoGin 248*70a4e555SLoGin // 清除错误状态寄存器(需要连续写入两次) 249*70a4e555SLoGin self.write(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ESR.into(), 0); 250*70a4e555SLoGin self.write(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ESR.into(), 0); 251*70a4e555SLoGin 252*70a4e555SLoGin // 确认任何未完成的中断 253*70a4e555SLoGin self.write(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_EOI.into(), 0); 254*70a4e555SLoGin 255*70a4e555SLoGin // 发送 Init Level De-Assert 信号以同步仲裁ID 256*70a4e555SLoGin self.write( 257*70a4e555SLoGin XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ICR_63_32.into(), 258*70a4e555SLoGin 0, 259*70a4e555SLoGin ); 260*70a4e555SLoGin self.write( 261*70a4e555SLoGin XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ICR_31_0.into(), 262*70a4e555SLoGin BCAST | INIT | LEVEL, 263*70a4e555SLoGin ); 264*70a4e555SLoGin while self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ICR_31_0.into()) & DELIVS != 0 265*70a4e555SLoGin { 266*70a4e555SLoGin spin_loop(); 267*70a4e555SLoGin } 268*70a4e555SLoGin } 269*70a4e555SLoGin 270*70a4e555SLoGin true 271*70a4e555SLoGin } 272*70a4e555SLoGin 273*70a4e555SLoGin /// 发送 EOI(End Of Interrupt) 274*70a4e555SLoGin fn send_eoi(&self) { 275*70a4e555SLoGin unsafe { 276*70a4e555SLoGin let s = self as *const Self as *mut Self; 277*70a4e555SLoGin (*s).write(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_EOI.into(), 0); 278*70a4e555SLoGin } 279*70a4e555SLoGin } 280*70a4e555SLoGin 281*70a4e555SLoGin /// 获取版本号 282*70a4e555SLoGin fn version(&self) -> u8 { 283*70a4e555SLoGin unsafe { 284*70a4e555SLoGin (self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_Version.into()) & 0xff) as u8 285*70a4e555SLoGin } 286*70a4e555SLoGin } 287*70a4e555SLoGin 288*70a4e555SLoGin fn support_eoi_broadcast_suppression(&self) -> bool { 289*70a4e555SLoGin unsafe { 290*70a4e555SLoGin ((self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_Version.into()) >> 24) & 1) == 1 291*70a4e555SLoGin } 292*70a4e555SLoGin } 293*70a4e555SLoGin 294*70a4e555SLoGin fn max_lvt_entry(&self) -> u8 { 295*70a4e555SLoGin unsafe { 296*70a4e555SLoGin ((self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_Version.into()) >> 16) & 0xff) 297*70a4e555SLoGin as u8 298*70a4e555SLoGin + 1 299*70a4e555SLoGin } 300*70a4e555SLoGin } 301*70a4e555SLoGin 302*70a4e555SLoGin /// 获取ID 303*70a4e555SLoGin fn id(&self) -> u32 { 304*70a4e555SLoGin unsafe { self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ID.into()) >> 24 } 305*70a4e555SLoGin } 306*70a4e555SLoGin 307*70a4e555SLoGin /// 设置LVT寄存器的值 308*70a4e555SLoGin fn set_lvt(&mut self, lvt: LVT) { 309*70a4e555SLoGin unsafe { 310*70a4e555SLoGin self.write(lvt.register().into(), lvt.data); 311*70a4e555SLoGin } 312*70a4e555SLoGin } 313*70a4e555SLoGin 314*70a4e555SLoGin fn read_lvt(&self, reg: LVTRegister) -> LVT { 315*70a4e555SLoGin unsafe { 316*70a4e555SLoGin LVT::new( 317*70a4e555SLoGin reg, 318*70a4e555SLoGin self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_LVT_TIMER.into()), 319*70a4e555SLoGin ) 320*70a4e555SLoGin .unwrap() 321*70a4e555SLoGin } 322*70a4e555SLoGin } 323*70a4e555SLoGin 324*70a4e555SLoGin fn mask_all_lvt(&mut self) { 325*70a4e555SLoGin // self.set_lvt(LVT::new(LVTRegister::CMCI, LVT::MASKED).unwrap()); 326*70a4e555SLoGin self.set_lvt(LVT::new(LVTRegister::Timer, LVT::MASKED).unwrap()); 327*70a4e555SLoGin self.set_lvt(LVT::new(LVTRegister::Thermal, LVT::MASKED).unwrap()); 328*70a4e555SLoGin self.set_lvt(LVT::new(LVTRegister::PerformanceMonitor, LVT::MASKED).unwrap()); 329*70a4e555SLoGin self.set_lvt(LVT::new(LVTRegister::LINT0, LVT::MASKED).unwrap()); 330*70a4e555SLoGin self.set_lvt(LVT::new(LVTRegister::LINT1, LVT::MASKED).unwrap()); 331*70a4e555SLoGin self.set_lvt(LVT::new(LVTRegister::ErrorReg, LVT::MASKED).unwrap()); 332*70a4e555SLoGin } 333*70a4e555SLoGin 334*70a4e555SLoGin fn write_icr(&self, icr: x86::apic::Icr) { 335*70a4e555SLoGin unsafe { 336*70a4e555SLoGin // Wait for any previous send to finish 337*70a4e555SLoGin while self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ICR_31_0.into()) & DELIVS != 0 338*70a4e555SLoGin { 339*70a4e555SLoGin spin_loop(); 340*70a4e555SLoGin } 341*70a4e555SLoGin 342*70a4e555SLoGin self.write( 343*70a4e555SLoGin XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ICR_63_32.into(), 344*70a4e555SLoGin icr.upper(), 345*70a4e555SLoGin ); 346*70a4e555SLoGin self.write( 347*70a4e555SLoGin XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ICR_31_0.into(), 348*70a4e555SLoGin icr.lower(), 349*70a4e555SLoGin ); 350*70a4e555SLoGin 351*70a4e555SLoGin // Wait for send to finish 352*70a4e555SLoGin while self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ICR_31_0.into()) & DELIVS != 0 353*70a4e555SLoGin { 354*70a4e555SLoGin spin_loop(); 355*70a4e555SLoGin } 356*70a4e555SLoGin } 357*70a4e555SLoGin } 358*70a4e555SLoGin } 359