summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authornatrixaeria <upezu@student.kit.edu>2019-11-15 21:37:42 +0100
committernatrixaeria <upezu@student.kit.edu>2019-11-15 21:37:42 +0100
commitfb02b294051e28137316225569b81a690e554630 (patch)
treefe833150c28fd03d787266c6d60cb4dbaabb99b8 /kernel
parent6590a5acfee33bae3ca0431c8af09768248fe405 (diff)
Initiate timer interrupt
Diffstat (limited to 'kernel')
-rw-r--r--kernel/src/interrupts/apic.rs156
-rw-r--r--kernel/src/interrupts/interrupt_handlers.rs5
-rw-r--r--kernel/src/main.rs3
3 files changed, 101 insertions, 63 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)
}
}
diff --git a/kernel/src/interrupts/interrupt_handlers.rs b/kernel/src/interrupts/interrupt_handlers.rs
index 6296375..4613a40 100644
--- a/kernel/src/interrupts/interrupt_handlers.rs
+++ b/kernel/src/interrupts/interrupt_handlers.rs
@@ -3,6 +3,7 @@ use crate::io::qemu;
use x86_64::structures::idt::{InterruptStackFrame, PageFaultErrorCode};
pub extern "x86-interrupt" fn timer_handler(stack_frame: &mut InterruptStackFrame) {
- panic!("Timer interrupt recieved\n\n")
- // notify End of interrupt
+ panic!("Timer interrupt recieved\n\n");
+
+ super::apic::get_local_apic().map(|apic| apic.end_of_interrupt())
}
diff --git a/kernel/src/main.rs b/kernel/src/main.rs
index 1613292..08778f2 100644
--- a/kernel/src/main.rs
+++ b/kernel/src/main.rs
@@ -19,8 +19,11 @@ pub use io::{qemu, serial, vga_text};
#[no_mangle]
extern "C" fn _start() -> ! {
kernel::init();
+ x86_64::instructions::interrupts::enable();
let apic = interrupts::apic::Apic::new();
+ let apic = interrupts::apic::set_local_apic(apic);
+ apic.set_timer_interrupt_handler(interrupts::apic::TimerDivideConfig::Div32, interrupts::InterruptType::Timer);
if cfg!(test) {
qemu::exit_qemu(qemu::QemuExitCode::Success);