From fb02b294051e28137316225569b81a690e554630 Mon Sep 17 00:00:00 2001 From: natrixaeria Date: Fri, 15 Nov 2019 21:37:42 +0100 Subject: Initiate timer interrupt --- kernel/src/interrupts/apic.rs | 156 +++++++++++++++++----------- kernel/src/interrupts/interrupt_handlers.rs | 5 +- kernel/src/main.rs | 3 + 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 = None; + +pub fn set_local_apic(apic: Apic) -> &mut Apic { + LOCAL_APIC.get_or_insert(apic) } -impl ApicRegisters { +pub fn get_local_apic() -> Option { + LOCAL_APIC +} + +pub struct Apic { + regs: *mut [u32; 1024], +} + +impl Apic { + pub fn new() -> Option { + 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 { - 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); -- cgit v1.2.3