From df083e306a53e6a45a5730e7059032be43cc75ff Mon Sep 17 00:00:00 2001 From: Nick Shipp Date: Sun, 30 Sep 2018 17:05:47 -0400 Subject: Dirty rotten commit full of badness Milestone: Got SMP cores booting and into long mode. The rest is all trash, but maybe trash worth a future archaeological dig. --- bunny/src/lapic.rs | 313 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 313 insertions(+) create mode 100644 bunny/src/lapic.rs (limited to 'bunny/src/lapic.rs') 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, + _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)); + } +} -- cgit v1.2.3-54-g00ecf