Skip to content
Snippets Groups Projects
Commit c154effd authored by Jacob Lorentzon's avatar Jacob Lorentzon
Browse files

Get a working local apic timer.

parent c11d6d9e
No related branches found
No related tags found
1 merge request!115Extend the IRQ scheme to allow allocation of all available interrupt vectors.
......@@ -47,6 +47,8 @@ impl LocalApic {
} else {
self.write(0xF0, 0x100);
}
self.setup_error_int();
self.setup_timer();
}
unsafe fn read(&self, reg: u32) -> u32 {
......@@ -113,4 +115,101 @@ impl LocalApic {
self.write(0xB0, 0);
}
}
/// Reads the Error Status Register.
pub unsafe fn esr(&mut self) -> u32 {
if self.x2 {
// update the ESR to the current state of the local apic.
wrmsr(IA32_X2APIC_ESR, 0);
// read the updated value
rdmsr(IA32_X2APIC_ESR) as u32
} else {
self.write(0x280, 0);
self.read(0x280)
}
}
pub unsafe fn lvt_timer(&mut self) -> u32 {
if self.x2 {
rdmsr(IA32_X2APIC_LVT_TIMER) as u32
} else {
self.read(0x320)
}
}
pub unsafe fn set_lvt_timer(&mut self, value: u32) {
if self.x2 {
wrmsr(IA32_X2APIC_LVT_TIMER, u64::from(value));
} else {
self.write(0x320, value);
}
}
pub unsafe fn init_count(&mut self) -> u32 {
if self.x2 {
rdmsr(IA32_X2APIC_INIT_COUNT) as u32
} else {
self.read(0x380)
}
}
pub unsafe fn set_init_count(&mut self, initial_count: u32) {
if self.x2 {
wrmsr(IA32_X2APIC_INIT_COUNT, u64::from(initial_count));
} else {
self.write(0x380, initial_count);
}
}
pub unsafe fn cur_count(&mut self) -> u32 {
if self.x2 {
rdmsr(IA32_X2APIC_CUR_COUNT) as u32
} else {
self.read(0x390)
}
}
pub unsafe fn div_conf(&mut self) -> u32 {
if self.x2 {
rdmsr(IA32_X2APIC_DIV_CONF) as u32
} else {
self.read(0x3E0)
}
}
pub unsafe fn set_div_conf(&mut self, div_conf: u32) {
if self.x2 {
wrmsr(IA32_X2APIC_DIV_CONF, u64::from(div_conf));
} else {
self.write(0x3E0, div_conf);
}
}
pub unsafe fn lvt_error(&mut self) -> u32 {
if self.x2 {
rdmsr(IA32_X2APIC_LVT_ERROR) as u32
} else {
self.read(0x370)
}
}
pub unsafe fn set_lvt_error(&mut self, lvt_error: u32) {
if self.x2 {
wrmsr(IA32_X2APIC_LVT_ERROR, u64::from(lvt_error));
} else {
self.write(0x370, lvt_error);
}
}
unsafe fn setup_error_int(&mut self) {
let vector = 49u32;
self.set_lvt_error(vector);
}
unsafe fn setup_timer(&mut self) {
let div_conf_value = 0b1010; // divide by 128
self.set_div_conf(div_conf_value);
let init_count_value = 1_000_000;
self.set_init_count(init_count_value);
let lvt_timer_value = ((LvtTimerMode::Periodic as u32) << 17) | 48u32;
self.set_lvt_timer(lvt_timer_value);
// TODO: Get the correct frequency, use the local apic timer instead of the PIT.
}
}
#[repr(u8)]
pub enum LvtTimerMode {
OneShot = 0b00,
Periodic = 0b01,
TscDeadline = 0b10,
}
......@@ -69,6 +69,8 @@ pub unsafe fn init_paging() {
IDT[45].set_func(irq::fpu);
IDT[46].set_func(irq::ata1);
IDT[47].set_func(irq::ata2);
IDT[48].set_func(irq::lapic_timer);
IDT[49].set_func(irq::lapic_error);
// Set IPI handlers
IDT[IpiKind::Wakeup as usize].set_func(ipi::wakeup);
......
use core::sync::atomic::{AtomicUsize, Ordering};
use crate::context::timeout;
use crate::device::pic;
use crate::device::{local_apic, pic};
use crate::device::serial::{COM1, COM2};
use crate::ipi::{ipi, IpiKind, IpiTarget};
use crate::scheme::debug::debug_input;
......@@ -29,6 +29,9 @@ unsafe fn trigger(irq: u8) {
irq_trigger(irq);
}
unsafe fn lapic_eoi() {
local_apic::LOCAL_APIC.eoi()
}
pub unsafe fn acknowledge(irq: usize) {
if irq < 16 {
......@@ -132,3 +135,11 @@ interrupt!(ata1, {
interrupt!(ata2, {
trigger(15);
});
interrupt!(lapic_timer, {
println!("Local apic timer interrupt");
lapic_eoi();
});
interrupt!(lapic_error, {
println!("Local apic internal error: ESR={:#0x}", local_apic::LOCAL_APIC.esr());
lapic_eoi();
});
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment