xref: /DragonOS/kernel/src/arch/x86_64/driver/apic/xapic.rs (revision e28411791f090c421fe4b6fa5956fb1bd362a8d9)
170a4e555SLoGin use core::{
270a4e555SLoGin     cell::RefCell,
370a4e555SLoGin     hint::spin_loop,
470a4e555SLoGin     ptr::{read_volatile, write_volatile},
570a4e555SLoGin };
670a4e555SLoGin 
770a4e555SLoGin use crate::{
870a4e555SLoGin     kdebug, kerror, kinfo,
970a4e555SLoGin     mm::{
1070a4e555SLoGin         mmio_buddy::{mmio_pool, MMIOSpaceGuard},
1170a4e555SLoGin         percpu::PerCpu,
1270a4e555SLoGin         PhysAddr, VirtAddr,
1370a4e555SLoGin     },
1470a4e555SLoGin     smp::core::smp_get_processor_id,
1570a4e555SLoGin };
1670a4e555SLoGin 
17*e2841179SLoGin use super::{hw_irq::ApicId, LVTRegister, LocalAPIC, LVT};
1870a4e555SLoGin 
1970a4e555SLoGin /// per-cpu的xAPIC的MMIO空间起始地址
20*e2841179SLoGin static mut XAPIC_INSTANCES: [RefCell<Option<XApic>>; PerCpu::MAX_CPU_NUM as usize] =
21*e2841179SLoGin     [const { RefCell::new(None) }; PerCpu::MAX_CPU_NUM as usize];
2270a4e555SLoGin 
2370a4e555SLoGin #[inline(always)]
2470a4e555SLoGin pub(super) fn current_xapic_instance() -> &'static RefCell<Option<XApic>> {
25*e2841179SLoGin     unsafe { &XAPIC_INSTANCES.as_ref()[smp_get_processor_id().data() as usize] }
2670a4e555SLoGin }
2770a4e555SLoGin 
2870a4e555SLoGin /// TODO:统一变量
2970a4e555SLoGin /// @brief local APIC 寄存器地址偏移量
3070a4e555SLoGin #[derive(Debug)]
3170a4e555SLoGin #[allow(dead_code)]
3270a4e555SLoGin #[allow(non_camel_case_types)]
3370a4e555SLoGin #[repr(u32)]
3470a4e555SLoGin pub enum XApicOffset {
3570a4e555SLoGin     // 定义各个寄存器的地址偏移量
3670a4e555SLoGin     LOCAL_APIC_OFFSET_Local_APIC_ID = 0x20,
3770a4e555SLoGin     LOCAL_APIC_OFFSET_Local_APIC_Version = 0x30,
3870a4e555SLoGin     LOCAL_APIC_OFFSET_Local_APIC_TPR = 0x80,
3970a4e555SLoGin     LOCAL_APIC_OFFSET_Local_APIC_APR = 0x90,
4070a4e555SLoGin     LOCAL_APIC_OFFSET_Local_APIC_PPR = 0xa0,
4170a4e555SLoGin     LOCAL_APIC_OFFSET_Local_APIC_EOI = 0xb0,
4270a4e555SLoGin     LOCAL_APIC_OFFSET_Local_APIC_RRD = 0xc0,
4370a4e555SLoGin     LOCAL_APIC_OFFSET_Local_APIC_LDR = 0xd0,
4470a4e555SLoGin     LOCAL_APIC_OFFSET_Local_APIC_DFR = 0xe0,
4570a4e555SLoGin     LOCAL_APIC_OFFSET_Local_APIC_SVR = 0xf0,
4670a4e555SLoGin 
4770a4e555SLoGin     LOCAL_APIC_OFFSET_Local_APIC_ISR_31_0 = 0x100, // In-Service Register
4870a4e555SLoGin     LOCAL_APIC_OFFSET_Local_APIC_ISR_63_32 = 0x110,
4970a4e555SLoGin     LOCAL_APIC_OFFSET_Local_APIC_ISR_95_64 = 0x120,
5070a4e555SLoGin     LOCAL_APIC_OFFSET_Local_APIC_ISR_127_96 = 0x130,
5170a4e555SLoGin     LOCAL_APIC_OFFSET_Local_APIC_ISR_159_128 = 0x140,
5270a4e555SLoGin     LOCAL_APIC_OFFSET_Local_APIC_ISR_191_160 = 0x150,
5370a4e555SLoGin     LOCAL_APIC_OFFSET_Local_APIC_ISR_223_192 = 0x160,
5470a4e555SLoGin     LOCAL_APIC_OFFSET_Local_APIC_ISR_255_224 = 0x170,
5570a4e555SLoGin 
5670a4e555SLoGin     LOCAL_APIC_OFFSET_Local_APIC_TMR_31_0 = 0x180, // Trigger Mode Register
5770a4e555SLoGin     LOCAL_APIC_OFFSET_Local_APIC_TMR_63_32 = 0x190,
5870a4e555SLoGin     LOCAL_APIC_OFFSET_Local_APIC_TMR_95_64 = 0x1a0,
5970a4e555SLoGin     LOCAL_APIC_OFFSET_Local_APIC_TMR_127_96 = 0x1b0,
6070a4e555SLoGin     LOCAL_APIC_OFFSET_Local_APIC_TMR_159_128 = 0x1c0,
6170a4e555SLoGin     LOCAL_APIC_OFFSET_Local_APIC_TMR_191_160 = 0x1d0,
6270a4e555SLoGin     LOCAL_APIC_OFFSET_Local_APIC_TMR_223_192 = 0x1e0,
6370a4e555SLoGin     LOCAL_APIC_OFFSET_Local_APIC_TMR_255_224 = 0x1f0,
6470a4e555SLoGin 
6570a4e555SLoGin     LOCAL_APIC_OFFSET_Local_APIC_IRR_31_0 = 0x200, // Interrupt Request Register
6670a4e555SLoGin     LOCAL_APIC_OFFSET_Local_APIC_IRR_63_32 = 0x210,
6770a4e555SLoGin     LOCAL_APIC_OFFSET_Local_APIC_IRR_95_64 = 0x220,
6870a4e555SLoGin     LOCAL_APIC_OFFSET_Local_APIC_IRR_127_96 = 0x230,
6970a4e555SLoGin     LOCAL_APIC_OFFSET_Local_APIC_IRR_159_128 = 0x240,
7070a4e555SLoGin     LOCAL_APIC_OFFSET_Local_APIC_IRR_191_160 = 0x250,
7170a4e555SLoGin     LOCAL_APIC_OFFSET_Local_APIC_IRR_223_192 = 0x260,
7270a4e555SLoGin     LOCAL_APIC_OFFSET_Local_APIC_IRR_255_224 = 0x270,
7370a4e555SLoGin 
7470a4e555SLoGin     LOCAL_APIC_OFFSET_Local_APIC_ESR = 0x280, // Error Status Register
7570a4e555SLoGin 
7670a4e555SLoGin     LOCAL_APIC_OFFSET_Local_APIC_LVT_CMCI = 0x2f0, // Corrected Machine Check Interrupt Register
7770a4e555SLoGin 
7870a4e555SLoGin     LOCAL_APIC_OFFSET_Local_APIC_ICR_31_0 = 0x300, // Interrupt Command Register
7970a4e555SLoGin     LOCAL_APIC_OFFSET_Local_APIC_ICR_63_32 = 0x310,
8070a4e555SLoGin 
8170a4e555SLoGin     LOCAL_APIC_OFFSET_Local_APIC_LVT_TIMER = 0x320,
8270a4e555SLoGin     LOCAL_APIC_OFFSET_Local_APIC_LVT_THERMAL = 0x330,
8370a4e555SLoGin     LOCAL_APIC_OFFSET_Local_APIC_LVT_PERFORMANCE_MONITOR = 0x340,
8470a4e555SLoGin     LOCAL_APIC_OFFSET_Local_APIC_LVT_LINT0 = 0x350,
8570a4e555SLoGin     LOCAL_APIC_OFFSET_Local_APIC_LVT_LINT1 = 0x360,
8670a4e555SLoGin     LOCAL_APIC_OFFSET_Local_APIC_LVT_ERROR = 0x370,
8770a4e555SLoGin     // 初始计数寄存器(定时器专用)
8870a4e555SLoGin     LOCAL_APIC_OFFSET_Local_APIC_INITIAL_COUNT_REG = 0x380,
8970a4e555SLoGin     // 当前计数寄存器(定时器专用)
9070a4e555SLoGin     LOCAL_APIC_OFFSET_Local_APIC_CURRENT_COUNT_REG = 0x390,
9170a4e555SLoGin     LOCAL_APIC_OFFSET_Local_APIC_CLKDIV = 0x3e0,
9270a4e555SLoGin }
9370a4e555SLoGin 
9470a4e555SLoGin impl Into<u32> for XApicOffset {
9570a4e555SLoGin     fn into(self) -> u32 {
9670a4e555SLoGin         self as u32
9770a4e555SLoGin     }
9870a4e555SLoGin }
9970a4e555SLoGin 
10070a4e555SLoGin impl From<LVTRegister> for XApicOffset {
10170a4e555SLoGin     fn from(lvt: LVTRegister) -> Self {
10270a4e555SLoGin         match lvt {
10370a4e555SLoGin             LVTRegister::Timer => XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_LVT_TIMER,
10470a4e555SLoGin             LVTRegister::Thermal => XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_LVT_THERMAL,
10570a4e555SLoGin             LVTRegister::PerformanceMonitor => {
10670a4e555SLoGin                 XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_LVT_PERFORMANCE_MONITOR
10770a4e555SLoGin             }
10870a4e555SLoGin             LVTRegister::LINT0 => XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_LVT_LINT0,
10970a4e555SLoGin             LVTRegister::LINT1 => XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_LVT_LINT1,
11070a4e555SLoGin             LVTRegister::ErrorReg => XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_LVT_ERROR,
11170a4e555SLoGin             LVTRegister::CMCI => XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_LVT_CMCI,
11270a4e555SLoGin         }
11370a4e555SLoGin     }
11470a4e555SLoGin }
11570a4e555SLoGin 
11670a4e555SLoGin #[derive(Debug)]
11770a4e555SLoGin #[allow(dead_code)]
11870a4e555SLoGin pub struct XApic {
11970a4e555SLoGin     /// 当前xAPIC的寄存器映射的虚拟地址。注意,每个CPU都有自己的xAPIC,所以这个地址是每个CPU都不一样的。
12070a4e555SLoGin     apic_vaddr: VirtAddr,
12170a4e555SLoGin     /// `apic_vaddr`与映射的空间起始位置之间的偏移量
12270a4e555SLoGin     offset: usize,
12370a4e555SLoGin     map_guard: MMIOSpaceGuard,
12470a4e555SLoGin     xapic_base: PhysAddr,
12570a4e555SLoGin }
12670a4e555SLoGin 
12770a4e555SLoGin impl XApic {
12870a4e555SLoGin     /// 读取指定寄存器的值
12970a4e555SLoGin     #[allow(dead_code)]
13070a4e555SLoGin     pub unsafe fn read(&self, reg: XApicOffset) -> u32 {
13170a4e555SLoGin         read_volatile((self.apic_vaddr.data() + reg as usize) as *const u32)
13270a4e555SLoGin     }
13370a4e555SLoGin 
13470a4e555SLoGin     /// 将指定的值写入寄存器
13570a4e555SLoGin     #[allow(dead_code)]
13670a4e555SLoGin     pub unsafe fn write(&self, reg: XApicOffset, value: u32) {
13770a4e555SLoGin         write_volatile(
13870a4e555SLoGin             (self.apic_vaddr.data() + (reg as u32) as usize) as *mut u32,
13970a4e555SLoGin             value,
14070a4e555SLoGin         );
14170a4e555SLoGin         self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ID); // 等待写操作完成,通过读取进行同步
14270a4e555SLoGin     }
14370a4e555SLoGin }
14470a4e555SLoGin 
14570a4e555SLoGin impl XApic {
14670a4e555SLoGin     /// 创建新的XAPIC实例
14770a4e555SLoGin     ///
14870a4e555SLoGin     /// ## 参数
14970a4e555SLoGin     ///
15070a4e555SLoGin     /// - `xapic_base` - 当前核心的xAPIC的寄存器的物理地址
15170a4e555SLoGin     pub unsafe fn new(xapic_base: PhysAddr) -> Self {
15270a4e555SLoGin         let offset = xapic_base.data() & 0xffff;
15370a4e555SLoGin         let paddr = PhysAddr::new(xapic_base.data() & !0xffff);
15470a4e555SLoGin         let g = mmio_pool()
15570a4e555SLoGin             .create_mmio(4096)
15670a4e555SLoGin             .expect("Fail to create MMIO for XAPIC");
15770a4e555SLoGin         g.map_phys(paddr, 4096).expect("Fail to map MMIO for XAPIC");
15870a4e555SLoGin         let addr = g.vaddr() + offset;
15970a4e555SLoGin 
16070a4e555SLoGin         kdebug!(
16170a4e555SLoGin             "XAPIC: {:#x} -> {:#x}, offset={offset}",
16270a4e555SLoGin             xapic_base.data(),
16370a4e555SLoGin             addr.data()
16470a4e555SLoGin         );
16570a4e555SLoGin 
16670a4e555SLoGin         let r = Self {
16770a4e555SLoGin             apic_vaddr: addr,
16870a4e555SLoGin             offset,
16970a4e555SLoGin             map_guard: g,
17070a4e555SLoGin             xapic_base,
17170a4e555SLoGin         };
17270a4e555SLoGin 
17370a4e555SLoGin         return r;
17470a4e555SLoGin     }
17570a4e555SLoGin }
17670a4e555SLoGin 
17770a4e555SLoGin #[allow(dead_code)]
17870a4e555SLoGin const X1: u32 = 0x0000000B; // 将除数设置为1,即不除频率
17970a4e555SLoGin #[allow(dead_code)]
18070a4e555SLoGin const PERIODIC: u32 = 0x00020000; // 周期性模式
18170a4e555SLoGin #[allow(dead_code)]
18270a4e555SLoGin const ENABLE: u32 = 0x00000100; // 单元使能
18370a4e555SLoGin #[allow(dead_code)]
18470a4e555SLoGin const MASKED: u32 = 0x00010000; // 中断屏蔽
18570a4e555SLoGin const LEVEL: u32 = 0x00008000; // 电平触发
18670a4e555SLoGin const BCAST: u32 = 0x00080000; // 发送到所有APIC,包括自己
18770a4e555SLoGin const DELIVS: u32 = 0x00001000; // 传递状态
18870a4e555SLoGin const INIT: u32 = 0x00000500; // INIT/RESET
18970a4e555SLoGin 
19070a4e555SLoGin //中断请求
19170a4e555SLoGin #[allow(dead_code)]
19270a4e555SLoGin const T_IRQ0: u32 = 32; // IRQ 0 对应于 T_IRQ 中断
19370a4e555SLoGin #[allow(dead_code)]
19470a4e555SLoGin const IRQ_TIMER: u32 = 0;
19570a4e555SLoGin #[allow(dead_code)]
19670a4e555SLoGin const IRQ_KBD: u32 = 1;
19770a4e555SLoGin #[allow(dead_code)]
19870a4e555SLoGin const IRQ_COM1: u32 = 4;
19970a4e555SLoGin #[allow(dead_code)]
20070a4e555SLoGin const IRQ_IDE: u32 = 14;
20170a4e555SLoGin #[allow(dead_code)]
20270a4e555SLoGin const IRQ_ERROR: u32 = 19;
20370a4e555SLoGin #[allow(dead_code)]
20470a4e555SLoGin const IRQ_SPURIOUS: u32 = 31;
20570a4e555SLoGin 
20670a4e555SLoGin impl LocalAPIC for XApic {
20770a4e555SLoGin     /// @brief 判断处理器是否支持apic
20870a4e555SLoGin     fn support() -> bool {
20970a4e555SLoGin         return x86::cpuid::CpuId::new()
21070a4e555SLoGin             .get_feature_info()
21170a4e555SLoGin             .expect("Fail to get CPU feature.")
21270a4e555SLoGin             .has_apic();
21370a4e555SLoGin     }
21470a4e555SLoGin 
21570a4e555SLoGin     /// @return true -> 函数运行成功
21670a4e555SLoGin     fn init_current_cpu(&mut self) -> bool {
21770a4e555SLoGin         unsafe {
21870a4e555SLoGin             // enable xapic
21970a4e555SLoGin             x86::msr::wrmsr(x86::msr::APIC_BASE, (self.xapic_base.data() | 0x800) as u64);
22070a4e555SLoGin             let val = x86::msr::rdmsr(x86::msr::APIC_BASE);
22170a4e555SLoGin             if val & 0x800 != 0x800 {
22270a4e555SLoGin                 kerror!("xAPIC enable failed: APIC_BASE & 0x800 != 0x800");
22370a4e555SLoGin                 return false;
22470a4e555SLoGin             }
22570a4e555SLoGin             // 设置 Spurious Interrupt Vector Register
22670a4e555SLoGin             let val = self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_SVR.into());
22770a4e555SLoGin 
22870a4e555SLoGin             self.write(
22970a4e555SLoGin                 XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_SVR.into(),
23070a4e555SLoGin                 val | ENABLE,
23170a4e555SLoGin             );
23270a4e555SLoGin 
23370a4e555SLoGin             let val = self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_SVR.into());
23470a4e555SLoGin             if val & ENABLE == 0 {
23570a4e555SLoGin                 kerror!("xAPIC software enable failed.");
23670a4e555SLoGin 
23770a4e555SLoGin                 return false;
23870a4e555SLoGin             } else {
23970a4e555SLoGin                 kinfo!("xAPIC software enabled.");
24070a4e555SLoGin             }
24170a4e555SLoGin 
24270a4e555SLoGin             if val & 0x1000 != 0 {
24370a4e555SLoGin                 kinfo!("xAPIC EOI broadcast suppression enabled.");
24470a4e555SLoGin             }
24570a4e555SLoGin 
24670a4e555SLoGin             self.mask_all_lvt();
24770a4e555SLoGin 
24870a4e555SLoGin             // 清除错误状态寄存器(需要连续写入两次)
24970a4e555SLoGin             self.write(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ESR.into(), 0);
25070a4e555SLoGin             self.write(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ESR.into(), 0);
25170a4e555SLoGin 
25270a4e555SLoGin             // 确认任何未完成的中断
25370a4e555SLoGin             self.write(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_EOI.into(), 0);
25470a4e555SLoGin 
25570a4e555SLoGin             // 发送 Init Level De-Assert 信号以同步仲裁ID
25670a4e555SLoGin             self.write(
25770a4e555SLoGin                 XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ICR_63_32.into(),
25870a4e555SLoGin                 0,
25970a4e555SLoGin             );
26070a4e555SLoGin             self.write(
26170a4e555SLoGin                 XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ICR_31_0.into(),
26270a4e555SLoGin                 BCAST | INIT | LEVEL,
26370a4e555SLoGin             );
26470a4e555SLoGin             while self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ICR_31_0.into()) & DELIVS != 0
26570a4e555SLoGin             {
26670a4e555SLoGin                 spin_loop();
26770a4e555SLoGin             }
26870a4e555SLoGin         }
26970a4e555SLoGin 
27070a4e555SLoGin         true
27170a4e555SLoGin     }
27270a4e555SLoGin 
27370a4e555SLoGin     /// 发送 EOI(End Of Interrupt)
27470a4e555SLoGin     fn send_eoi(&self) {
27570a4e555SLoGin         unsafe {
27670a4e555SLoGin             let s = self as *const Self as *mut Self;
27770a4e555SLoGin             (*s).write(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_EOI.into(), 0);
27870a4e555SLoGin         }
27970a4e555SLoGin     }
28070a4e555SLoGin 
28170a4e555SLoGin     /// 获取版本号
28270a4e555SLoGin     fn version(&self) -> u8 {
28370a4e555SLoGin         unsafe {
28470a4e555SLoGin             (self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_Version.into()) & 0xff) as u8
28570a4e555SLoGin         }
28670a4e555SLoGin     }
28770a4e555SLoGin 
28870a4e555SLoGin     fn support_eoi_broadcast_suppression(&self) -> bool {
28970a4e555SLoGin         unsafe {
29070a4e555SLoGin             ((self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_Version.into()) >> 24) & 1) == 1
29170a4e555SLoGin         }
29270a4e555SLoGin     }
29370a4e555SLoGin 
29470a4e555SLoGin     fn max_lvt_entry(&self) -> u8 {
29570a4e555SLoGin         unsafe {
29670a4e555SLoGin             ((self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_Version.into()) >> 16) & 0xff)
29770a4e555SLoGin                 as u8
29870a4e555SLoGin                 + 1
29970a4e555SLoGin         }
30070a4e555SLoGin     }
30170a4e555SLoGin 
30270a4e555SLoGin     /// 获取ID
303*e2841179SLoGin     fn id(&self) -> ApicId {
304*e2841179SLoGin         unsafe { ApicId::new(self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ID.into()) >> 24) }
30570a4e555SLoGin     }
30670a4e555SLoGin 
30770a4e555SLoGin     /// 设置LVT寄存器的值
30870a4e555SLoGin     fn set_lvt(&mut self, lvt: LVT) {
30970a4e555SLoGin         unsafe {
31070a4e555SLoGin             self.write(lvt.register().into(), lvt.data);
31170a4e555SLoGin         }
31270a4e555SLoGin     }
31370a4e555SLoGin 
31470a4e555SLoGin     fn read_lvt(&self, reg: LVTRegister) -> LVT {
31570a4e555SLoGin         unsafe {
31670a4e555SLoGin             LVT::new(
31770a4e555SLoGin                 reg,
31870a4e555SLoGin                 self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_LVT_TIMER.into()),
31970a4e555SLoGin             )
32070a4e555SLoGin             .unwrap()
32170a4e555SLoGin         }
32270a4e555SLoGin     }
32370a4e555SLoGin 
32470a4e555SLoGin     fn mask_all_lvt(&mut self) {
32570a4e555SLoGin         // self.set_lvt(LVT::new(LVTRegister::CMCI, LVT::MASKED).unwrap());
32670a4e555SLoGin         self.set_lvt(LVT::new(LVTRegister::Timer, LVT::MASKED).unwrap());
32770a4e555SLoGin         self.set_lvt(LVT::new(LVTRegister::Thermal, LVT::MASKED).unwrap());
32870a4e555SLoGin         self.set_lvt(LVT::new(LVTRegister::PerformanceMonitor, LVT::MASKED).unwrap());
32970a4e555SLoGin         self.set_lvt(LVT::new(LVTRegister::LINT0, LVT::MASKED).unwrap());
33070a4e555SLoGin         self.set_lvt(LVT::new(LVTRegister::LINT1, LVT::MASKED).unwrap());
33170a4e555SLoGin         self.set_lvt(LVT::new(LVTRegister::ErrorReg, LVT::MASKED).unwrap());
33270a4e555SLoGin     }
33370a4e555SLoGin 
33470a4e555SLoGin     fn write_icr(&self, icr: x86::apic::Icr) {
33570a4e555SLoGin         unsafe {
33670a4e555SLoGin             // Wait for any previous send to finish
33770a4e555SLoGin             while self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ICR_31_0.into()) & DELIVS != 0
33870a4e555SLoGin             {
33970a4e555SLoGin                 spin_loop();
34070a4e555SLoGin             }
34170a4e555SLoGin 
34270a4e555SLoGin             self.write(
34370a4e555SLoGin                 XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ICR_63_32.into(),
34470a4e555SLoGin                 icr.upper(),
34570a4e555SLoGin             );
34670a4e555SLoGin             self.write(
34770a4e555SLoGin                 XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ICR_31_0.into(),
34870a4e555SLoGin                 icr.lower(),
34970a4e555SLoGin             );
35070a4e555SLoGin 
35170a4e555SLoGin             // Wait for send to finish
35270a4e555SLoGin             while self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ICR_31_0.into()) & DELIVS != 0
35370a4e555SLoGin             {
35470a4e555SLoGin                 spin_loop();
35570a4e555SLoGin             }
35670a4e555SLoGin         }
35770a4e555SLoGin     }
35870a4e555SLoGin }
359