summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDennis Kobert <dennis@kobert.dev>2019-11-20 03:47:08 +0100
committerDennis Kobert <dennis@kobert.dev>2019-11-20 03:47:08 +0100
commit0cb231bd3de9bcd4c39064399211fbd2fbc6237e (patch)
treec3713274ae1057afdcd6ce1f9af1f96a03503e93
parent78ed9468fb817ffa225b8af3cfdd124c8e37d320 (diff)
Fix memory mapping for LAIC and setup it's paging
-rw-r--r--kernel/src/asm/boot.asm12
-rw-r--r--kernel/src/interrupts/apic.rs131
-rw-r--r--kernel/src/main.rs14
3 files changed, 85 insertions, 72 deletions
diff --git a/kernel/src/asm/boot.asm b/kernel/src/asm/boot.asm
index 6449d66..87de35f 100644
--- a/kernel/src/asm/boot.asm
+++ b/kernel/src/asm/boot.asm
@@ -92,6 +92,16 @@ setup_page_tables:
or eax, 0b11 ; present + writable
mov [p3_table], eax
+ ; map third P3 entry to APIC P2 table
+ mov eax, apic_p2_table
+ or eax, 0b11 ; present + writable
+ mov [p3_table + 24], eax
+
+ ; map apic memory space without caching
+ mov eax, 0xFEE00000 + 0b10000111 ; huge + no caching + writable + present
+ mov [apic_p2_table + 4024], eax
+
+ ; map first page without caching
mov eax, 0b10000111 ; huge + no caching + writable + present
mov [p2_table], eax
@@ -169,6 +179,8 @@ p3_table:
resb 4096
p2_table:
resb 4096
+apic_p2_table:
+ resb 4096
alignb 4096 * 512 ; align memory into huge memory page
stack_bottom:
diff --git a/kernel/src/interrupts/apic.rs b/kernel/src/interrupts/apic.rs
index dc1177b..93fba8b 100644
--- a/kernel/src/interrupts/apic.rs
+++ b/kernel/src/interrupts/apic.rs
@@ -1,13 +1,13 @@
use x86_64::registers::model_specific::Msr;
#[cfg(target_arch = "x86_64")]
-const APIC_FLAG: u64 = 0x0800;
-const APIC_BASE_MSR: u32 = 0x001b;
+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;
+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,52 +33,52 @@ pub fn set_apic_base(v: u64) {
pub struct InterruptCommand {
low: u32,
_rsv: [u32; 3],
- high: u32
+ high: u32,
}
#[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,
- LvtLint0 = 212,
- LvtLint1 = 216,
- 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(u32)]
pub enum TimerDivideConfig {
- Div2 = 0,
- Div4 = 1,
- Div8 = 2,
- Div16 = 3,
- Div32 = 8,
- Div64 = 9,
- Div128 = 10,
- NoDivide = 11,
+ Div2 = 0,
+ Div4 = 1,
+ Div8 = 2,
+ Div16 = 3,
+ Div32 = 8,
+ Div64 = 9,
+ Div128 = 10,
+ NoDivide = 11,
}
static mut LOCAL_APIC: Option<Apic> = None;
@@ -98,15 +98,12 @@ pub struct Apic {
impl Apic {
pub fn new() -> Option<Self> {
- if !is_apic() { return None; }
+ if !is_apic() {
+ return None;
+ }
Self::disable_pic();
let mut base_apic = unsafe { Msr::new(APIC_BASE_MSR).read() };
- //panic!("msr{:x}", base_apic);
- unsafe { Msr::new(APIC_BASE_MSR).write(base_apic) };
let mut apic = Self::from_base_apic(base_apic);
- //panic!("msr{:08x}", apic.regs as usize);
-
- // let spurious = apic.get(ApicRegister::SpuriousInterruptVec) | 0x1ff;
apic.set(ApicRegister::LogicalDst, 0);
@@ -116,7 +113,10 @@ impl Apic {
apic.set(ApicRegister::LvtLint0, APIC_DISABLE);
apic.set(ApicRegister::LvtLint1, APIC_DISABLE);
apic.set(ApicRegister::DstFmt, 0x0FFFFFFF);
- apic.set(ApicRegister::LvtError, super::InterruptType::ApicError.as_u8().into());
+ apic.set(
+ ApicRegister::LvtError,
+ super::InterruptType::ApicError.as_u8().into(),
+ );
apic.set(ApicRegister::ErrorStatus, 0);
unsafe { Msr::new(APIC_BASE_MSR).write(base_apic | APIC_FLAG) };
@@ -134,23 +134,25 @@ impl Apic {
}
fn from_base_apic(base_apic: u64) -> Self {
- Self { regs:
- ((base_apic >> 12) & 0xfffffffff) as *mut [u32; 1024]
+ Self {
+ regs: ((base_apic) & 0xfffffffff << 12) as *mut [u32; 1024],
}
}
- pub fn ptr(&self) -> *const u32 { self.regs as *const u32 }
+ pub fn ptr(&self) -> *const u32 {
+ self.regs as *const u32
+ }
- fn ptr_mut(&mut self) -> *mut u32 { self.regs as *mut u32 }
+ fn ptr_mut(&mut self) -> *mut u32 {
+ self.regs as *mut u32
+ }
pub fn get(&self, register: ApicRegister) -> u32 {
- unsafe { ((self.ptr() as usize + (register as usize) * 4) as *const u32).read_volatile() }
- //unsafe { self.ptr().offset(register as isize).read_volatile() }
+ unsafe { self.ptr().offset(register as isize).read_volatile() }
}
pub fn set(&mut self, register: ApicRegister, val: u32) {
- unsafe { ((self.ptr() as usize + (register as usize) * 4) as *mut u32).write_volatile(val) }
- //unsafe { self.ptr_mut().offset(register as isize).write_volatile(val) }
+ unsafe { self.ptr_mut().offset(register as isize).write_volatile(val) }
}
pub fn set_interrupt_command(&mut self, dst: u8, v: u8) {
@@ -163,18 +165,23 @@ impl Apic {
self.set(ApicRegister::EndOfInterrupt, 0);
}
- pub fn set_timer_interrupt_handler(&mut self, divide: TimerDivideConfig, intr: super::InterruptType) {
+ pub fn set_timer_interrupt_handler(
+ &mut self,
+ divide: TimerDivideConfig,
+ intr: super::InterruptType,
+ ) {
self.set(ApicRegister::LvtTimer, intr.as_u8() as u32 | (1 << 17));
self.set(ApicRegister::TimerDivideConfig, divide as u32);
- self.set(ApicRegister::TimerInitialCount, 2048);
- self.set(ApicRegister::TimerCurrentCount, 2048)
+ self.set(ApicRegister::TimerInitialCount, 1 << 27);
}
pub fn get_timer_value(&self) -> u32 {
self.get(ApicRegister::TimerCurrentCount)
}
- pub fn get_error_code(&self) -> u32 {
+ pub fn get_error_code(&mut self) -> u32 {
+ self.set(ApicRegister::ErrorStatus, 0);
+ // write contents of apic error register to memory
self.get(ApicRegister::ErrorStatus)
}
diff --git a/kernel/src/main.rs b/kernel/src/main.rs
index a0e1e56..c6c00c2 100644
--- a/kernel/src/main.rs
+++ b/kernel/src/main.rs
@@ -23,22 +23,16 @@ extern "C" fn _start() -> ! {
let apic = interrupts::apic::Apic::new().expect("no APIC support");
let mut apic = unsafe { interrupts::apic::set_local_apic(apic) };
- apic.set_timer_interrupt_handler(interrupts::apic::TimerDivideConfig::Div16, interrupts::InterruptType::Timer);
+ apic.set_timer_interrupt_handler(
+ interrupts::apic::TimerDivideConfig::Div16,
+ interrupts::InterruptType::Timer,
+ );
x86_64::instructions::interrupts::enable();
let mut stdout = OStream::new();
stdout.print(b"apic initialisation complete\n");
- loop {
- stdout.set_col(0);
- use core::fmt::Write;
- //let n = apic.get_timer_value();
- let n = apic.get_error_code();
- write!(&mut stdout, "timer: {} ", n);
- //write!(&mut stdout, "timer: {:08x} ", apic.ptr() as usize);
- }
-
if cfg!(test) {
qemu::exit_qemu(qemu::QemuExitCode::Success);
}