aboutsummaryrefslogtreecommitdiff
path: root/bunny/src/lapic.rs
diff options
context:
space:
mode:
Diffstat (limited to 'bunny/src/lapic.rs')
-rw-r--r--bunny/src/lapic.rs313
1 files changed, 313 insertions, 0 deletions
diff --git a/bunny/src/lapic.rs b/bunny/src/lapic.rs
new file mode 100644
index 0000000..86d7a43
--- /dev/null
+++ b/bunny/src/lapic.rs
@@ -0,0 +1,313 @@
+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<u32>,
+ _pad00: [u32; 3],
+
+ _r0010: Ro<u32>,
+ _pad01: [u32; 3],
+
+ id: Ro<u32>, /* 0020 */
+ _pad02: [u32; 3],
+
+ version: Ro<u32>, /* 0030 */
+ _pad03: [u32; 3],
+
+ _r0040: Ro<u32>,
+ _pad04: [u32; 3],
+
+ _r0050: Ro<u32>,
+ _pad05: [u32; 3],
+
+ _r0060: Ro<u32>,
+ _pad06: [u32; 3],
+
+ _r0070: Ro<u32>,
+ _pad07: [u32; 3],
+
+ task_priority: Ro<u32>, /* 0080 */
+ _pad08: [u32; 3],
+
+ arbitration_priority: Ro<u32>, /* 0090 */
+ _pad09: [u32; 3],
+
+ processor_priority: Ro<u32>, /* 00A0 */
+ _pad10: [u32; 3],
+
+ eoi: Ro<u32>, /* 00B0 */
+ _pad11: [u32; 3],
+
+ remote_read: Ro<u32>, /* 00C0 */
+ _pad12: [u32; 3],
+
+ logical_destination: Ro<u32>, /* 00D0 */
+ _pad13: [u32; 3],
+
+ destination_format: Ro<u32>, /* 00E0 */
+ _pad14: [u32; 3],
+
+ spurious_interrupt_vector: Rw<u32>, /* 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<u32>, /* 0280 */
+ _pad16: [u32; 3],
+
+ _r0290: Ro<u32>,
+ _pad17: [u32; 3],
+
+ _r02A0: Ro<u32>,
+ _pad18: [u32; 3],
+
+ _r02B0: Ro<u32>,
+ _pad19: [u32; 3],
+
+ _r02C0: Ro<u32>,
+ _pad20: [u32; 3],
+
+ _r02D0: Ro<u32>,
+ _pad21: [u32; 3],
+
+ _r02E0: Ro<u32>,
+ _pad22: [u32; 3],
+
+ lvt_corrected_machine_check_interrupt: Rw<u32>, /* 02F0 */
+ _pad23: [u32; 3],
+
+ interrupt_command_register: Rw<[u32; 8]>, /* 0300-0310 */
+
+ lvt_timer: Rw<u32>, /* 0320 */
+ _pad25: [u32; 3],
+
+ lvt_thermal_sensor: Rw<u32>, /* 0330 */
+ _pad26: [u32; 3],
+
+ lvt_performance_monitoring_counters: Rw<u32>, /* 0340 */
+ _pad27: [u32; 3],
+
+ lvt_lint0: Rw<u32>, /* 0350 */
+ _pad28: [u32; 3],
+
+ lvt_lint1: Rw<u32>, /* 0360 */
+ _pad29: [u32; 3],
+
+ lvt_error: Rw<u32>, /* 0370 */
+ _pad30: [u32; 3],
+
+ initial_count: Rw<u32>, /* 0380 */
+ _pad31: [u32; 3],
+
+ current_count: Ro<u32>, /* 0390 */
+ _pad32: [u32; 3],
+
+ _r03A0: Ro<u32>,
+ _pad33: [u32; 3],
+
+ _r03B0: Ro<u32>,
+ _pad34: [u32; 3],
+
+ _r03C0: Ro<u32>,
+ _pad35: [u32; 3],
+
+ _r03D0: Ro<u32>,
+ _pad36: [u32; 3],
+
+ divide_conf: Rw<u32>, /* 03E0 */
+ _pad37: [u32; 3],
+
+ _r03F0: Ro<u32>,
+}
+*/
+
+#[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));
+ }
+}