summaryrefslogtreecommitdiff
path: root/kernel/src/interrupts/apic.rs
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/src/interrupts/apic.rs')
-rw-r--r--kernel/src/interrupts/apic.rs156
1 files changed, 95 insertions, 61 deletions
diff --git a/kernel/src/interrupts/apic.rs b/kernel/src/interrupts/apic.rs
index 519caf2..5c236ea 100644
--- a/kernel/src/interrupts/apic.rs
+++ b/kernel/src/interrupts/apic.rs
@@ -1,8 +1,13 @@
use x86_64::registers::model_specific::Msr;
#[cfg(target_arch = "x86_64")]
-const APIC_FLAG: u64 = 0x0800;
-const APIC_BASE_MSR: u32 = 0x1b;
+const APIC_FLAG: u64 = 0x0800;
+const APIC_BASE_MSR: u32 = 0x001b;
+
+// APIC constant register values
+const APIC_DISABLE: u32 = 0x0001_0000;
+const APIC_NMI: u32 = 0x0000_0400;
+const APIC_SW_ENABLE: u32 = 0x0000_0100;
pub fn is_x2apic() -> bool {
let info: u32;
@@ -33,50 +38,96 @@ pub struct InterruptCommand {
#[repr(isize)]
pub enum ApicRegister {
- ApicId=8,
- ApicVer=12,
- TaskPriority=32,
- ArbitrationPriority=36,
- ProcessorPriority=40,
- EndOfInterrupt=44,
- LogicalDst=52,
- DstFmt=56,
- SpuriousInterruptVec=60,
- InService=64,
- TriggerMode=96,
- InterruptRequest=128,
- ErrorStatus=160,
- InterruptCommand=192,
- InterruptCommandHigh=196,
- LvtTimer=200,
- LvtThermalSensor=204,
- LvtPerformanceMonitor=208,
- LvtLint1=212,
- LvtError=220,
- TimerInitialCount=224,
- TimerCurrentCount=228,
- TimerDivideConfig=248,
- ExtApicFeature=256,
- ExtApicControl=260,
- SpecificEndOfInterrupt=264,
- InterruptEnable=288,
- ExtInterruptLocalVectorTable=320,
+ ApicId = 8,
+ ApicVer = 12,
+ TaskPriority = 32,
+ ArbitrationPriority = 36,
+ ProcessorPriority = 40,
+ EndOfInterrupt = 44,
+ LogicalDst = 52,
+ DstFmt = 56,
+ SpuriousInterruptVec = 60,
+ InService = 64,
+ TriggerMode = 96,
+ InterruptRequest = 128,
+ ErrorStatus = 160,
+ InterruptCommand = 192,
+ InterruptCommandHigh = 196,
+ LvtTimer = 200,
+ LvtThermalSensor = 204,
+ LvtPerformanceMonitor = 208,
+ LvtLint0 = 212,
+ LvtLint1 = 216,
+ LvtError = 220,
+ TimerInitialCount = 224,
+ TimerCurrentCount = 228,
+ TimerDivideConfig = 248,
+ ExtApicFeature = 256,
+ ExtApicControl = 260,
+ SpecificEndOfInterrupt = 264,
+ InterruptEnable = 288,
+ ExtInterruptLocalVectorTable = 320,
}
-#[repr(C)]
-pub struct ApicRegisters {
- regs32: *mut [u32; 1024],
+#[repr(u32)]
+pub enum TimerDivideConfig {
+ Div2 = 0,
+ Div4 = 1,
+ Div8 = 2,
+ Div16 = 3,
+ Div32 = 8,
+ Div64 = 9,
+ Div128 = 10,
+ NoDivide = 11,
+}
+
+static mut LOCAL_APIC: Option<Apic> = None;
+
+pub fn set_local_apic(apic: Apic) -> &mut Apic {
+ LOCAL_APIC.get_or_insert(apic)
}
-impl ApicRegisters {
+pub fn get_local_apic() -> Option<Apic> {
+ LOCAL_APIC
+}
+
+pub struct Apic {
+ regs: *mut [u32; 1024],
+}
+
+impl Apic {
+ pub fn new() -> Option<Self> {
+ use core::fmt::Write;
+ let mut stdout = crate::io::vga_text::OStream::new();
+ stdout.clear();
+
+ if !is_apic() { return None; }
+ let mut base_apic = unsafe { Msr::new(APIC_BASE_MSR).read() };
+ let apic = Self::from_base_apic(base_apic);
+
+ let spurious = apic.get(ApicRegister::SpuriousInterruptVec) | 0x1ff;
+
+ unsafe { Msr::new(APIC_BASE_MSR).write(base_apic | APIC_FLAG) };
+
+ apic.set(ApicRegister::SpuriousInterruptVec, spurious);
+
+ apic.set(ApicRegister::TaskPriority, 0);
+ apic.set(ApicRegister::LvtPerformanceMonitor, APIC_NMI);
+ apic.set(ApicRegister::LvtLint0, 0);
+ apic.set(ApicRegister::LvtLint1, 0);
+
+ apic
+ }
+
fn from_base_apic(base_apic: u64) -> Self {
- Self { regs32:
+ Self { reg32:
((base_apic >> 12) & 0xfffffffff) as *mut [u32; 1024]
}
}
- fn ptr(&self) -> *const u32 { self.regs32 as *const u32 }
- fn ptr_mut(&mut self) -> *mut u32 { self.regs32 as *mut u32 }
+ fn ptr(&self) -> *const u32 { self.regs as *const u32 }
+
+ fn ptr_mut(&mut self) -> *mut u32 { self.regs as *mut u32 }
pub fn get(&self, register: ApicRegister) -> u32 {
unsafe { self.ptr().offset(register as isize).read_volatile() }
@@ -91,31 +142,14 @@ impl ApicRegisters {
self.set(ApicRegister::InterruptCommandHigh, dst << 24);
self.set(ApicRegister::InterruptCommand, v)
}
-}
-
-pub struct Apic {
- base_apic: u64,
- regs: ApicRegisters,
-}
-
-impl Apic {
- pub fn new() -> Option<Self> {
- use core::fmt::Write;
- let mut stdout = crate::io::vga_text::OStream::new();
- stdout.clear();
- if !is_apic() { return None; }
- let mut base_apic = unsafe { Msr::new(APIC_BASE_MSR).read() };
- let mut regs = ApicRegisters::from_base_apic(base_apic);
-
- let spurious = regs.get(ApicRegister::SpuriousInterruptVec) | 0x1ff;
-
- unsafe { Msr::new(APIC_BASE_MSR).write(base_apic | APIC_FLAG) };
-
- regs.set(ApicRegister::SpuriousInterruptVec, spurious);
+ pub fn end_of_interrupt(&mut self) {
+ self.set(ApicRegister::EndOfInterrupt, 0);
+ }
- Some(Self {
- base_apic, regs
- })
+ pub fn set_timer_interrupt_handler(&mut self, divide: TimerDivideConfig, intr: super::InterruptType) {
+ apic.set(ApicRegister::LvtTimer, intr.into());
+ apic.set(ApicRegister::TimerDivideConfig, divide);
+ apic.set(ApicRegister::TimerInitialCount, 0xFFFFFFFF)
}
}