use interrupt::IRQ_APIC_LVT_ERROR; use x86_64::registers::model_specific::Msr; /* * See: Intel SDM Table 10-1: Local APIC Register Address Map */ /* #[allow(unused, non_snake_case)] #[repr(C)] struct MappedLocalApic { _r0000: Ro, _pad00: [u32; 3], _r0010: Ro, _pad01: [u32; 3], id: Ro, /* 0020 */ _pad02: [u32; 3], version: Ro, /* 0030 */ _pad03: [u32; 3], _r0040: Ro, _pad04: [u32; 3], _r0050: Ro, _pad05: [u32; 3], _r0060: Ro, _pad06: [u32; 3], _r0070: Ro, _pad07: [u32; 3], task_priority: Ro, /* 0080 */ _pad08: [u32; 3], arbitration_priority: Ro, /* 0090 */ _pad09: [u32; 3], processor_priority: Ro, /* 00A0 */ _pad10: [u32; 3], eoi: Ro, /* 00B0 */ _pad11: [u32; 3], remote_read: Ro, /* 00C0 */ _pad12: [u32; 3], logical_destination: Ro, /* 00D0 */ _pad13: [u32; 3], destination_format: Ro, /* 00E0 */ _pad14: [u32; 3], spurious_interrupt_vector: Rw, /* 00F0 */ _pad15: [u32; 3], in_service: Ro<[u32; 32]>, /* 0100-0170 */ trigger_mode: Ro<[u32; 32]>, /* 0180-01F0 */ interrupt_request: Ro<[u32; 32]>, /* 0200-0270 */ error_status: Ro, /* 0280 */ _pad16: [u32; 3], _r0290: Ro, _pad17: [u32; 3], _r02A0: Ro, _pad18: [u32; 3], _r02B0: Ro, _pad19: [u32; 3], _r02C0: Ro, _pad20: [u32; 3], _r02D0: Ro, _pad21: [u32; 3], _r02E0: Ro, _pad22: [u32; 3], lvt_corrected_machine_check_interrupt: Rw, /* 02F0 */ _pad23: [u32; 3], interrupt_command_register: Rw<[u32; 8]>, /* 0300-0310 */ lvt_timer: Rw, /* 0320 */ _pad25: [u32; 3], lvt_thermal_sensor: Rw, /* 0330 */ _pad26: [u32; 3], lvt_performance_monitoring_counters: Rw, /* 0340 */ _pad27: [u32; 3], lvt_lint0: Rw, /* 0350 */ _pad28: [u32; 3], lvt_lint1: Rw, /* 0360 */ _pad29: [u32; 3], lvt_error: Rw, /* 0370 */ _pad30: [u32; 3], initial_count: Rw, /* 0380 */ _pad31: [u32; 3], current_count: Ro, /* 0390 */ _pad32: [u32; 3], _r03A0: Ro, _pad33: [u32; 3], _r03B0: Ro, _pad34: [u32; 3], _r03C0: Ro, _pad35: [u32; 3], _r03D0: Ro, _pad36: [u32; 3], divide_conf: Rw, /* 03E0 */ _pad37: [u32; 3], _r03F0: Ro, } */ #[allow(unused)] struct LocalVectorTable { cmci: Msr, timer: Msr, thermal_sensor: Msr, perfmon: Msr, lint0: Msr, lint1: Msr, error: Msr, } #[allow(unused)] pub struct LocalApic { /* raw: &'map mut MappedLocalApic, */ id: Msr, version: Msr, task_priority: Msr, processor_priority: Msr, eoi: Msr, logical_destination: Msr, spurious_interrupt_vector: Msr, in_service: [Msr; 8], trigger_mode: [Msr; 8], interrupt_request: [Msr; 8], error_status: Msr, local_vector_table: LocalVectorTable, interrupt_command: Msr, initial_count: Msr, current_count: Msr, divide_config: Msr, self_ipi: Msr, } #[allow(unused)] #[derive(Debug, Copy, Clone)] #[repr(u32)] pub enum IpiDestination { JustMe = 0b01 << 18, All = 0b10 << 18, AllButMe = 0b11 << 18, } #[allow(unused)] #[derive(Debug, Copy, Clone)] #[repr(u32)] pub enum IpiTriggerMode { Edge = 0 << 15, Level = 1 << 15, } #[allow(unused)] #[derive(Debug, Copy, Clone)] #[repr(u32)] pub enum IpiLevel { Deassert = 0 << 14, Assert = 1 << 14, } #[allow(unused)] #[derive(Debug, Copy, Clone)] #[repr(u32)] pub enum IpiDeliveryMode { Fixed = 0b000 << 8, LowestPriority = 0b001 << 8, Smi = 0b010 << 8, Nmi = 0b100 << 8, Init = 0b101 << 8, StartUp = 0b110 << 8, } impl LocalApic { pub fn init() -> LocalApic { const MSR_BASE: u32 = 0x800; /* Set bits 10 and 11 of IA32_APIC_BASE MSR to enable x2APIC */ let mut apic_base_msr = Msr::new(0x1b); let mut apic_base = unsafe { apic_base_msr.read() }; dprintln!("APIC BASE: 0x{:x}", apic_base); apic_base |= 0b11 << 10; unsafe { apic_base_msr.write(apic_base) }; /* * See Intel SDM Table 10-6: * Local APIC Register Address Map Supported by x2APIC */ LocalApic { id: Msr::new(MSR_BASE + 0x002), version: Msr::new(MSR_BASE + 0x003), task_priority: Msr::new(MSR_BASE + 0x008), processor_priority: Msr::new(MSR_BASE + 0x00a), eoi: Msr::new(MSR_BASE + 0x00b), logical_destination: Msr::new(MSR_BASE + 0x00d), spurious_interrupt_vector: Msr::new(MSR_BASE + 0x00f), in_service: [Msr::new(MSR_BASE + 0x010), Msr::new(MSR_BASE + 0x011), Msr::new(MSR_BASE + 0x012), Msr::new(MSR_BASE + 0x013), Msr::new(MSR_BASE + 0x014), Msr::new(MSR_BASE + 0x015), Msr::new(MSR_BASE + 0x016), Msr::new(MSR_BASE + 0x017)], trigger_mode: [Msr::new(MSR_BASE + 0x018), Msr::new(MSR_BASE + 0x019), Msr::new(MSR_BASE + 0x01a), Msr::new(MSR_BASE + 0x01b), Msr::new(MSR_BASE + 0x01c), Msr::new(MSR_BASE + 0x01d), Msr::new(MSR_BASE + 0x01e), Msr::new(MSR_BASE + 0x01f)], interrupt_request: [Msr::new(MSR_BASE + 0x020), Msr::new(MSR_BASE + 0x021), Msr::new(MSR_BASE + 0x022), Msr::new(MSR_BASE + 0x023), Msr::new(MSR_BASE + 0x024), Msr::new(MSR_BASE + 0x025), Msr::new(MSR_BASE + 0x026), Msr::new(MSR_BASE + 0x027)], error_status: Msr::new(MSR_BASE + 0x028), local_vector_table: LocalVectorTable { cmci: Msr::new(MSR_BASE + 0x02f), timer: Msr::new(MSR_BASE + 0x032), thermal_sensor: Msr::new(MSR_BASE + 0x033), perfmon: Msr::new(MSR_BASE + 0x034), lint0: Msr::new(MSR_BASE + 0x035), lint1: Msr::new(MSR_BASE + 0x036), error: Msr::new(MSR_BASE + 0x037), }, interrupt_command: Msr::new(MSR_BASE + 0x030), initial_count: Msr::new(MSR_BASE + 0x038), current_count: Msr::new(MSR_BASE + 0x039), divide_config: Msr::new(MSR_BASE + 0x03e), self_ipi: Msr::new(MSR_BASE + 0x03f), } } pub fn id(&self) -> u32 { unsafe { self.id.read() as u32 } } pub fn version(&self) -> u32 { unsafe { self.version.read() as u32 } } pub fn enable(&mut self) { /* Set bit in SVR 8 to enable local APIC */ let mut svr = unsafe { self.spurious_interrupt_vector.read() }; svr |= 1 << 8; unsafe { self.spurious_interrupt_vector.write(svr); } /* * Set Local Vector Table error register: * Directs APIC errors to interrupt #IRQ_APIC_LVT_ERROR */ let mut lvte = unsafe { self.local_vector_table.error.read() as u32 }; lvte = (lvte & 0xffffff00) | (IRQ_APIC_LVT_ERROR as u32); unsafe { self.local_vector_table.error.write(lvte as u64); } } pub fn send_ipi(&mut self, dest: IpiDestination, trigger_mode: IpiTriggerMode, level: IpiLevel, delivery_mode: IpiDeliveryMode, vector: u8) { unsafe { self.interrupt_command.write((dest as u64) | (trigger_mode as u64) | (level as u64) | (delivery_mode as u64) | (vector as u64)); } dprintln!("IPI: 0x{:x}", (dest as u64) | (trigger_mode as u64) | (level as u64) | (delivery_mode as u64) | (vector as u64)); } }