Nothing to see here, move along meow
0

Configure Feed

Select the types of activity you want to include in your feed.

at main 4.0 kB View raw
1use x2apic::lapic::{LocalApicBuilder, TimerDivide, TimerMode, xapic_base}; 2 3use super::idt::{ERROR_VECTOR, SPURIOUS_VECTOR, TIMER_VECTOR}; 4 5const LAPIC_EOI_OFFSET: u64 = 0xB0; 6const IA32_X2APIC_EOI: u32 = 0x80B; 7 8struct ApicConfig { 9 virt_base: u64, 10 x2apic: bool, 11} 12 13static APIC_CONFIG: spin::Once<ApicConfig> = spin::Once::new(); 14 15const PIC1_DATA: u16 = 0x21; 16const PIC2_DATA: u16 = 0xA1; 17const PIC1_CMD: u16 = 0x20; 18const PIC2_CMD: u16 = 0xA0; 19 20fn disable_legacy_pic() { 21 unsafe { 22 x86_64::instructions::port::Port::<u8>::new(PIC1_CMD).write(0x11); 23 x86_64::instructions::port::Port::<u8>::new(PIC2_CMD).write(0x11); 24 x86_64::instructions::port::Port::<u8>::new(PIC1_DATA).write(0x20); 25 x86_64::instructions::port::Port::<u8>::new(PIC2_DATA).write(0x28); 26 x86_64::instructions::port::Port::<u8>::new(PIC1_DATA).write(0x04); 27 x86_64::instructions::port::Port::<u8>::new(PIC2_DATA).write(0x02); 28 x86_64::instructions::port::Port::<u8>::new(PIC1_DATA).write(0x01); 29 x86_64::instructions::port::Port::<u8>::new(PIC2_DATA).write(0x01); 30 x86_64::instructions::port::Port::<u8>::new(PIC1_DATA).write(0xFF); 31 x86_64::instructions::port::Port::<u8>::new(PIC2_DATA).write(0xFF); 32 } 33} 34 35pub fn init(hhdm_offset: u64) { 36 disable_legacy_pic(); 37 38 let apic_base = unsafe { xapic_base() }; 39 let apic_virt = apic_base + hhdm_offset; 40 41 let mut lapic = LocalApicBuilder::new() 42 .timer_vector(TIMER_VECTOR.as_usize()) 43 .error_vector(ERROR_VECTOR.as_usize()) 44 .spurious_vector(SPURIOUS_VECTOR.as_usize()) 45 .timer_mode(TimerMode::Periodic) 46 .timer_divide(TimerDivide::Div16) 47 .timer_initial(500_000) 48 .set_xapic_base(apic_virt) 49 .build() 50 .expect("Failed to build Local APIC"); 51 52 unsafe { lapic.enable() }; 53 54 let base_msr = unsafe { x86_64::registers::model_specific::Msr::new(0x1B).read() }; 55 let is_x2apic = (base_msr & (1 << 10)) != 0; 56 57 APIC_CONFIG.call_once(|| ApicConfig { 58 virt_base: apic_virt, 59 x2apic: is_x2apic, 60 }); 61 62 let pc = super::syscall::this_cpu(); 63 unsafe { core::ptr::addr_of_mut!((*pc).lapic_base).write(apic_virt) }; 64} 65 66pub fn tick() { 67 let pc = super::syscall::this_cpu(); 68 unsafe { 69 let count = 70 core::sync::atomic::AtomicU64::from_ptr(core::ptr::addr_of_mut!((*pc).tick_count)); 71 count.fetch_add(1, core::sync::atomic::Ordering::Relaxed); 72 } 73} 74 75#[allow(dead_code)] 76pub fn tick_count() -> u64 { 77 let pc = super::syscall::this_cpu(); 78 unsafe { 79 let count = 80 core::sync::atomic::AtomicU64::from_ptr(core::ptr::addr_of_mut!((*pc).tick_count)); 81 count.load(core::sync::atomic::Ordering::Relaxed) 82 } 83} 84 85#[allow(dead_code)] 86pub fn is_x2apic() -> bool { 87 APIC_CONFIG.get().expect("APIC not initialized").x2apic 88} 89 90const LAPIC_ESR_OFFSET: u64 = 0x280; 91const IA32_X2APIC_ESR: u32 = 0x828; 92 93pub unsafe fn read_and_clear_esr() -> u32 { 94 let config = APIC_CONFIG 95 .get() 96 .expect("read_and_clear_esr called before APIC init"); 97 if config.x2apic { 98 unsafe { 99 x86_64::registers::model_specific::Msr::new(IA32_X2APIC_ESR).write(0); 100 x86_64::registers::model_specific::Msr::new(IA32_X2APIC_ESR).read() as u32 101 } 102 } else { 103 unsafe { 104 core::ptr::write_volatile((config.virt_base + LAPIC_ESR_OFFSET) as *mut u32, 0); 105 core::ptr::read_volatile((config.virt_base + LAPIC_ESR_OFFSET) as *const u32) 106 } 107 } 108} 109 110pub unsafe fn end_of_interrupt() { 111 let config = APIC_CONFIG 112 .get() 113 .expect("end_of_interrupt called before APIC init"); 114 if config.x2apic { 115 unsafe { 116 x86_64::registers::model_specific::Msr::new(IA32_X2APIC_EOI).write(0); 117 } 118 } else { 119 unsafe { 120 core::ptr::write_volatile((config.virt_base + LAPIC_EOI_OFFSET) as *mut u32, 0); 121 } 122 } 123}