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