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