From 496ccaaf750a4ec1c537c463eff56108e1cc0bb4 Mon Sep 17 00:00:00 2001 From: Dennis Kobert Date: Sun, 18 Apr 2021 19:01:54 +0200 Subject: Further cleanup * Bump x86_64 dep to version 0.1.14 * Rewrite LOCAL_APIC handling * Remove warnings --- kernel/src/interrupts/apic.rs | 67 +++++++++++++++++++++++++++++++------------ 1 file changed, 48 insertions(+), 19 deletions(-) (limited to 'kernel/src/interrupts/apic.rs') diff --git a/kernel/src/interrupts/apic.rs b/kernel/src/interrupts/apic.rs index 0e89943..836af20 100644 --- a/kernel/src/interrupts/apic.rs +++ b/kernel/src/interrupts/apic.rs @@ -1,8 +1,11 @@ +use core::sync::atomic::{AtomicU64, Ordering}; use x86_64::registers::model_specific::Msr; #[cfg(target_arch = "x86_64")] const APIC_FLAG: u64 = 0x0800; const APIC_BASE_MSR: u32 = 0x001b; +const CPU_COUNT: usize = 255; +const APIC_BASE_ADDR: u64 = 0xfee0_0000; // APIC constant register values const APIC_DISABLE: u32 = 0x0001_0000; @@ -20,8 +23,13 @@ pub fn is_apic() -> bool { info & (1 << 9) != 0 } -pub fn set_apic_base(v: u64) { - unsafe { Msr::new(APIC_BASE_MSR).write(v) } +pub fn cpu_id() -> u32 { + let mut info: u32; + unsafe { asm!("cpuid", inout("eax") 1 => _, out("ebx") info) } + if !is_x2apic() { + info >>= 24; + } + info } #[repr(C)] @@ -75,27 +83,48 @@ pub enum TimerDivideConfig { Div128 = 10, NoDivide = 11, } +const NONE_APIC: Option = None; -static mut LOCAL_APIC: Option = None; +static mut APIC_INIT: [Option; CPU_COUNT] = [NONE_APIC; CPU_COUNT]; -pub unsafe fn set_local_apic(apic: Apic) -> &'static mut Apic { - LOCAL_APIC = Some(apic); - LOCAL_APIC.as_mut().unwrap() +pub fn move_local_apic(v: u64) -> bool { + match get_local_apic() { + None => return false, + Some(apic) => apic.regs.store(v, Ordering::Release), + } + unsafe { Msr::new(APIC_BASE_MSR).write(v) }; + true } -pub unsafe fn get_local_apic() -> Option<&'static mut Apic> { - LOCAL_APIC.as_mut() +/// Tries to initialize the local apic at it's default location. +/// returns false if no apic is available +/// +/// # Safety +/// Calling this function in a running system might cause the loss of interrupts or other weird +/// behaviour +pub unsafe fn try_initialize_local_apic() -> &'static mut Option { + if is_apic() { + let cpu_id = cpu_id() as usize; + if APIC_INIT[cpu_id].is_none() { + APIC_INIT[cpu_id] = Some(Apic::from_base_apic(APIC_BASE_ADDR)); + Apic::disable_pic(); + } + APIC_INIT[cpu_id].as_mut().map(|x| x.initialize()); + } + get_local_apic() +} + +pub fn get_local_apic() -> &'static mut Option { + let cpu_id = cpu_id() as usize; + unsafe { &mut APIC_INIT[cpu_id] } } pub struct Apic { - regs: *mut [u32; 1024], + regs: AtomicU64, } impl Apic { - pub fn new() -> Option { - if !is_apic() { - return None; - } + fn initialize(&mut self) -> Self { Self::disable_pic(); let base_apic = unsafe { Msr::new(APIC_BASE_MSR).read() }; let mut apic = Self::from_base_apic(base_apic); @@ -118,28 +147,28 @@ impl Apic { apic.set(ApicRegister::SpuriousInterruptVec, 0x1ff); - Some(apic) + apic } - pub fn disable_pic() { + fn disable_pic() { unsafe { x86_64::instructions::port::PortWriteOnly::new(0xa1).write(0xffu8); x86_64::instructions::port::PortWriteOnly::new(0x21).write(0xffu8); } } - fn from_base_apic(base_apic: u64) -> Self { + const fn from_base_apic(base_apic: u64) -> Self { Self { - regs: ((base_apic) & 0xfffffffff << 12) as *mut [u32; 1024], + regs: AtomicU64::new((base_apic) & 0xfffffffff << 12), } } pub fn ptr(&self) -> *const u32 { - self.regs as *const u32 + self.regs.load(Ordering::Acquire) as *const u32 } fn ptr_mut(&mut self) -> *mut u32 { - self.regs as *mut u32 + self.regs.load(Ordering::SeqCst) as *mut u32 } pub fn get(&self, register: ApicRegister) -> u32 { -- cgit v1.2.3-70-g09d2