mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-29 04:13:24 +00:00
94 lines
2.5 KiB
Rust
94 lines
2.5 KiB
Rust
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
#![allow(dead_code)]
|
|
|
|
use alloc::sync::Arc;
|
|
|
|
use log::info;
|
|
use spin::Once;
|
|
|
|
use crate::sync::SpinLock;
|
|
|
|
pub mod ioapic;
|
|
pub mod x2apic;
|
|
pub mod xapic;
|
|
|
|
pub static APIC_INSTANCE: Once<Arc<SpinLock<dyn Apic + 'static>>> = Once::new();
|
|
|
|
pub trait Apic: ApicTimer + Sync + Send {
|
|
fn id(&self) -> u32;
|
|
|
|
fn version(&self) -> u32;
|
|
|
|
/// End of Interrupt, this function will inform APIC that this interrupt has been processed.
|
|
fn eoi(&mut self);
|
|
}
|
|
|
|
pub trait ApicTimer: Sync + Send {
|
|
/// Sets the initial timer count, the APIC timer will count down from this value.
|
|
fn set_timer_init_count(&mut self, value: u64);
|
|
|
|
/// Gets the current count of the timer.
|
|
/// The interval can be expressed by the expression: `init_count` - `current_count`.
|
|
fn timer_current_count(&self) -> u64;
|
|
|
|
/// Sets the timer register in the APIC.
|
|
/// Bit 0-7: The interrupt vector of timer interrupt.
|
|
/// Bit 12: Delivery Status, 0 for Idle, 1 for Send Pending.
|
|
/// Bit 16: Mask bit.
|
|
/// Bit 17-18: Timer Mode, 0 for One-shot, 1 for Periodic, 2 for TSC-Deadline.
|
|
fn set_lvt_timer(&mut self, value: u64);
|
|
|
|
/// Sets timer divide config register.
|
|
fn set_timer_div_config(&mut self, div_config: DivideConfig);
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub enum ApicInitError {
|
|
/// No x2APIC or xAPIC found.
|
|
NoApic,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
#[repr(u32)]
|
|
pub enum DivideConfig {
|
|
Divide1 = 0b1011,
|
|
Divide2 = 0b0000,
|
|
Divide4 = 0b0001,
|
|
Divide8 = 0b0010,
|
|
Divide16 = 0b0011,
|
|
Divide32 = 0b1000,
|
|
Divide64 = 0b1001,
|
|
Divide128 = 0b1010,
|
|
}
|
|
|
|
pub fn init() -> Result<(), ApicInitError> {
|
|
crate::arch::x86::kernel::pic::disable_temp();
|
|
if let Some(mut x2apic) = x2apic::X2Apic::new() {
|
|
x2apic.enable();
|
|
let version = x2apic.version();
|
|
info!(
|
|
"x2APIC ID:{:x}, Version:{:x}, Max LVT:{:x}",
|
|
x2apic.id(),
|
|
version & 0xff,
|
|
(version >> 16) & 0xff
|
|
);
|
|
APIC_INSTANCE.call_once(|| Arc::new(SpinLock::new(x2apic)));
|
|
Ok(())
|
|
} else if let Some(mut xapic) = xapic::XApic::new() {
|
|
xapic.enable();
|
|
let version = xapic.version();
|
|
info!(
|
|
"xAPIC ID:{:x}, Version:{:x}, Max LVT:{:x}",
|
|
xapic.id(),
|
|
version & 0xff,
|
|
(version >> 16) & 0xff
|
|
);
|
|
APIC_INSTANCE.call_once(|| Arc::new(SpinLock::new(xapic)));
|
|
Ok(())
|
|
} else {
|
|
log::warn!("Not found x2APIC or xAPIC");
|
|
Err(ApicInitError::NoApic)
|
|
}
|
|
}
|