414 lines
12 KiB
Rust
Raw Normal View History

//! x86-64 Local APIC driver implementation
use core::sync::atomic::{AtomicUsize, Ordering};
2023-08-31 13:40:17 +03:00
use abi::error::Error;
use alloc::{sync::Arc, vec, vec::Vec};
2023-08-31 13:40:17 +03:00
use device_api::{
device::Device,
interrupt::{
InterruptAffinity, InterruptHandler, IpiDeliveryTarget, IpiMessage, IrqVector,
2024-02-07 13:06:17 +02:00
LocalInterruptController, MessageInterruptController, MsiInfo,
},
2023-08-31 13:40:17 +03:00
};
2024-10-12 20:43:16 +03:00
use kernel_arch_x86::registers::MSR_IA32_APIC_BASE;
use kernel_arch_x86_64::{mem::table::L3, LocalApicInterface, CPU_COUNT};
use libk::arch::Cpu;
2024-07-25 11:58:47 +03:00
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIo, table::EntryLevelExt};
2024-02-05 12:59:23 +02:00
use libk_util::{
sync::{spin_rwlock::IrqSafeRwLock, IrqGuard},
2024-02-05 12:59:23 +02:00
OneTimeInit,
};
use tock_registers::{
interfaces::{ReadWriteable, Readable, Writeable},
register_bitfields, register_structs,
registers::{ReadOnly, ReadWrite, WriteOnly},
};
use crate::arch::x86_64::apic::APIC_MSI_OFFSET;
2023-08-31 13:40:17 +03:00
use super::{
APIC_IPI_VECTOR, APIC_LINT0_VECTOR, APIC_LINT1_VECTOR, APIC_SPURIOUS_VECTOR, APIC_TIMER_VECTOR,
2023-12-11 21:13:33 +02:00
MAX_MSI_VECTORS,
2023-08-31 13:40:17 +03:00
};
const TIMER_INTERVAL: u32 = 15000;
/// When initialized, contains the Local APIC ID of the bootstrap processor
pub static BSP_APIC_ID: OneTimeInit<u32> = OneTimeInit::new();
register_bitfields! {
u32,
Id [
ApicId OFFSET(24) NUMBITS(8) []
],
SpuriousVector [
2023-08-05 16:32:12 +03:00
Vector OFFSET(0) NUMBITS(8) [],
SoftwareEnable OFFSET(8) NUMBITS(1) [],
],
TimerLocalVectorEntry [
Vector OFFSET(0) NUMBITS(8) [],
Mask OFFSET(16) NUMBITS(1) [
Masked = 1,
Unmasked = 0
],
TimerMode OFFSET(17) NUMBITS(1) [
Periodic = 1,
OneShot = 0
]
2023-08-03 18:49:29 +03:00
],
LocalVectorEntry [
Vector OFFSET(0) NUMBITS(8) [],
Mask OFFSET(16) NUMBITS(1) [
Masked = 1,
Unmasked = 0,
],
2023-08-05 16:32:12 +03:00
DeliveryMode OFFSET(8) NUMBITS(3) [
Nmi = 4,
ExtINT = 7
],
],
ICR0 [
Vector OFFSET(0) NUMBITS(8) [],
Destination OFFSET(8) NUMBITS(3) [
Normal = 1,
Lowest = 2,
SMI = 3,
NMI = 4,
INIT = 5,
SIPI = 6
],
DeliveryStatus OFFSET(12) NUMBITS(1) [],
INIT0 OFFSET(14) NUMBITS(1) [
Deassert = 0,
Assert = 1,
2023-08-03 18:49:29 +03:00
],
2023-08-05 16:32:12 +03:00
INIT1 OFFSET(15) NUMBITS(1) [
Deassert = 1,
Assert = 0,
],
DestinationType OFFSET(18) NUMBITS(3) [
Physical = 0,
This = 1,
All = 2,
AllExceptThis = 3,
]
],
ICR1 [
PhysicalDestination OFFSET(24) NUMBITS(4) []
],
}
register_structs! {
#[allow(non_snake_case, missing_docs)]
Regs {
(0x00 => _0),
(0x20 => Id: ReadOnly<u32, Id::Register>),
(0x24 => _1),
2023-08-05 16:32:12 +03:00
(0x80 => TaskPriorityRegister: ReadWrite<u32>),
(0x84 => _13),
(0xB0 => EndOfInterrupt: WriteOnly<u32>),
(0xB4 => _2),
(0xF0 => SpuriousVector: ReadWrite<u32, SpuriousVector::Register>),
(0xF4 => _3),
2023-08-05 16:32:12 +03:00
(0x100 => ISR0: ReadOnly<u32>),
(0x104 => _14),
(0x280 => ErrorStatus: ReadOnly<u32>),
(0x284 => _4),
(0x300 => ICR0: ReadWrite<u32, ICR0::Register>),
(0x304 => _5),
(0x310 => ICR1: ReadWrite<u32, ICR1::Register>),
(0x314 => _6),
(0x320 => TimerLocalVectorEntry: ReadWrite<u32, TimerLocalVectorEntry::Register>),
2023-08-05 16:32:12 +03:00
(0x324 => _7),
2023-08-03 18:49:29 +03:00
(0x350 => LInt0: ReadWrite<u32, LocalVectorEntry::Register>),
2023-08-05 16:32:12 +03:00
(0x354 => _8),
2023-08-03 18:49:29 +03:00
(0x360 => LInt1: ReadWrite<u32, LocalVectorEntry::Register>),
2023-08-05 16:32:12 +03:00
(0x364 => _9),
(0x380 => TimerInitCount: ReadWrite<u32>),
2023-08-05 16:32:12 +03:00
(0x384 => _10),
(0x390 => TimerCurrentCount: ReadOnly<u32>),
2023-08-05 16:32:12 +03:00
(0x394 => _11),
(0x3E0 => TimerDivideConfig: ReadWrite<u32>),
2023-08-05 16:32:12 +03:00
(0x3E4 => _12),
(0x530 => @END),
}
}
#[derive(Clone)]
struct MsiVector {
logical: usize,
handler: Arc<dyn InterruptHandler>,
}
struct MsiVectorTable {
// MSI_MAX_VECTORS * vectors per row
msi_vectors: IrqSafeRwLock<Vec<Vec<MsiVector>>>,
last_msi_allocated: AtomicUsize,
}
impl MsiVectorTable {
pub fn new(physical_vectors: usize) -> Self {
let rows = vec![Vec::new(); physical_vectors];
Self {
msi_vectors: IrqSafeRwLock::new(rows),
last_msi_allocated: AtomicUsize::new(0),
}
}
pub fn map(
&self,
apic_id: usize,
range: &mut [MsiInfo],
handler: Arc<dyn InterruptHandler>,
) -> Result<(), Error> {
if range.is_empty() {
return Err(Error::InvalidArgument);
}
let seq = self
.last_msi_allocated
.fetch_add(range.len(), Ordering::AcqRel);
let mut rows = self.msi_vectors.write();
let physical_start = seq % rows.len();
let physical_end = seq.wrapping_add(range.len()) % rows.len();
if range.len() == 1 {
log::info!("Map MSI {:?} -> {}", handler.display_name(), physical_start);
} else {
log::info!(
"Map MSI {:?} -> {:?}",
handler.display_name(),
physical_start..physical_end - 1
);
}
for (logical, info) in range.iter_mut().enumerate() {
let physical = logical.wrapping_add(seq) % rows.len();
rows[physical].push(MsiVector {
logical,
handler: handler.clone(),
});
let address = 0xFEE00000 | (apic_id << 12);
let value = 32 + APIC_MSI_OFFSET + physical as u32;
*info = MsiInfo {
vector: logical,
affinity: InterruptAffinity::Specific(0),
address,
value,
};
}
Ok(())
}
pub fn invoke(&self, physical_vector: usize) {
let rows = self.msi_vectors.read();
let row = &rows[physical_vector];
for col in row.iter() {
col.handler.clone().handle_irq(IrqVector::Msi(col.logical));
}
}
}
/// Per-processor local APIC interface
pub struct LocalApic {
regs: DeviceMemoryIo<'static, Regs>,
2023-12-11 21:13:33 +02:00
id: u32,
msi_table: MsiVectorTable,
}
unsafe impl Send for LocalApic {}
unsafe impl Sync for LocalApic {}
impl Device for LocalApic {
fn display_name(&self) -> &str {
"Local APIC"
}
}
2024-02-08 15:50:25 +02:00
impl LocalApicInterface for LocalApic {
2024-12-05 19:25:18 +02:00
#[inline]
2024-02-08 15:50:25 +02:00
fn clear_interrupt(&self) {
self.regs.EndOfInterrupt.set(0);
}
unsafe fn wakeup_cpu(&self, apic_id: u32, entry_vector: PhysicalAddress) {
2024-11-30 23:51:02 +02:00
log::info!("Waking up apic{}, entry = {:#x}", apic_id, entry_vector);
2024-02-08 15:50:25 +02:00
while self.regs.ICR0.matches_all(ICR0::DeliveryStatus::SET) {
core::hint::spin_loop();
}
let entry_vector = entry_vector.page_index::<L3>();
// INIT assert
self.regs.ICR1.write(ICR1::PhysicalDestination.val(apic_id));
self.regs.ICR0.write(
ICR0::Destination::INIT
+ ICR0::DestinationType::Physical
+ ICR0::INIT0::Assert
+ ICR0::INIT1::Assert,
);
while self.regs.ICR0.matches_all(ICR0::DeliveryStatus::SET) {
core::hint::spin_loop();
}
// INIT deassert
self.regs.ICR1.write(ICR1::PhysicalDestination.val(apic_id));
self.regs.ICR0.write(
ICR0::Destination::INIT
+ ICR0::DestinationType::Physical
+ ICR0::INIT0::Deassert
+ ICR0::INIT1::Deassert,
);
while self.regs.ICR0.matches_all(ICR0::DeliveryStatus::SET) {
core::hint::spin_loop();
}
// Send another SIPI type IPI because the spec says so
self.regs.ICR1.write(ICR1::PhysicalDestination.val(apic_id));
self.regs.ICR0.write(
ICR0::Vector.val(entry_vector as u32)
+ ICR0::Destination::SIPI
+ ICR0::DestinationType::Physical,
);
while self.regs.ICR0.matches_all(ICR0::DeliveryStatus::SET) {
core::hint::spin_loop();
}
}
}
impl MessageInterruptController for LocalApic {
fn handle_msi(&self, vector: usize) {
self.msi_table.invoke(vector);
}
2023-12-11 21:13:33 +02:00
fn register_msi_range(
self: Arc<Self>,
2023-12-11 21:13:33 +02:00
range: &mut [MsiInfo],
handler: Arc<dyn InterruptHandler>,
2023-12-11 21:13:33 +02:00
) -> Result<(), Error> {
let _guard = IrqGuard::acquire();
self.msi_table.map(self.id as usize, range, handler)
}
}
impl LocalInterruptController for LocalApic {
2024-02-07 13:06:17 +02:00
fn send_ipi(&self, target: IpiDeliveryTarget, msg: IpiMessage) -> Result<(), Error> {
2023-08-31 13:40:17 +03:00
while self.regs.ICR0.matches_all(ICR0::DeliveryStatus::SET) {
core::hint::spin_loop();
}
// TODO use NMI or regular interrupt depending on severity of the message
match target {
IpiDeliveryTarget::OtherCpus => {
let local = Cpu::local();
let local_id = local.id() as usize;
2023-08-31 13:40:17 +03:00
for i in 0..CPU_COUNT.load(Ordering::Acquire) {
if i != local_id {
2023-08-31 13:40:17 +03:00
Cpu::push_ipi_queue(i as u32, msg);
}
}
self.regs.ICR1.write(ICR1::PhysicalDestination.val(0));
self.regs.ICR0.write(
ICR0::Vector.val(APIC_IPI_VECTOR + 32)
+ ICR0::Destination::NMI
+ ICR0::DestinationType::AllExceptThis,
);
Ok(())
}
2024-11-05 22:00:10 +02:00
IpiDeliveryTarget::ThisCpu => unimplemented!(),
IpiDeliveryTarget::Specific(_) => unimplemented!(),
2023-08-31 13:40:17 +03:00
}
}
unsafe fn init_ap(&self) -> Result<(), Error> {
2024-11-05 22:00:10 +02:00
unreachable!()
}
}
impl LocalApic {
/// Constructs a new instance of Local APIC.
///
/// # Safety
///
/// Only meant to be called once per processor during their init.
pub unsafe fn new() -> Self {
2024-02-03 20:44:04 +02:00
let regs = DeviceMemoryIo::<Regs>::map(Self::base(), Default::default()).unwrap();
let id = regs.Id.read(Id::ApicId);
if Self::is_bootstrap_cpu() {
BSP_APIC_ID.init(id);
}
Self::enable();
2023-08-05 16:32:12 +03:00
// Configure spurious interrupt handler
regs.SpuriousVector.write(
SpuriousVector::SoftwareEnable::SET
+ SpuriousVector::Vector.val(APIC_SPURIOUS_VECTOR + 32),
);
// Configure task priority register
regs.TaskPriorityRegister.set(0);
// Enable timer
regs.TimerDivideConfig.set(0x2);
2023-08-05 16:32:12 +03:00
regs.TimerInitCount.set(TIMER_INTERVAL);
2023-08-05 16:32:12 +03:00
// Configure local interrupt vectors
regs.TimerLocalVectorEntry.write(
TimerLocalVectorEntry::Vector.val(APIC_TIMER_VECTOR + 32)
+ TimerLocalVectorEntry::Mask::Unmasked
+ TimerLocalVectorEntry::TimerMode::Periodic,
);
2023-08-05 16:32:12 +03:00
// LINT0 unmasked, leave LINT1 masked
regs.LInt0.write(
LocalVectorEntry::Mask::Unmasked
+ LocalVectorEntry::Vector.val(APIC_LINT0_VECTOR + 32)
+ LocalVectorEntry::DeliveryMode::ExtINT,
);
regs.LInt1.write(
LocalVectorEntry::Mask::Masked + LocalVectorEntry::Vector.val(APIC_LINT1_VECTOR + 32),
);
let msi_table = MsiVectorTable::new(MAX_MSI_VECTORS as _);
2023-12-11 21:13:33 +02:00
Self {
2023-12-11 21:13:33 +02:00
id,
regs,
msi_table,
}
}
#[inline]
fn base() -> PhysicalAddress {
2024-07-25 11:58:47 +03:00
PhysicalAddress::from_u64(MSR_IA32_APIC_BASE.read_base())
}
#[inline]
fn is_bootstrap_cpu() -> bool {
MSR_IA32_APIC_BASE.read(MSR_IA32_APIC_BASE::BootstrapCpuCore) != 0
}
#[inline]
fn enable() {
2023-08-05 16:32:12 +03:00
MSR_IA32_APIC_BASE.modify(
MSR_IA32_APIC_BASE::ApicEnable::SET + MSR_IA32_APIC_BASE::ExtendedEnable::CLEAR,
);
}
}