135 lines
3.9 KiB
Rust
135 lines
3.9 KiB
Rust
//! x86-64 APIC interface (Local + I/O)
|
|
|
|
use core::arch::global_asm;
|
|
|
|
use static_assertions::{const_assert, const_assert_eq};
|
|
|
|
use crate::{
|
|
arch::{x86_64::cpu::Cpu, Architecture, CpuAccess},
|
|
task::thread::Thread,
|
|
};
|
|
|
|
use super::{
|
|
exception::{self, IrqFrame},
|
|
ARCHITECTURE,
|
|
};
|
|
|
|
pub mod ioapic;
|
|
pub mod local;
|
|
|
|
// I/O APIC 0..MAX_EXTERNAL_VECTORS range is mapped to BSP Local APIC 2..
|
|
|
|
/// Fixed IRQ vector for Local APIC timer
|
|
pub const APIC_TIMER_VECTOR: u32 = 0x00;
|
|
/// Fixed IRQ vector for LINT0 line
|
|
pub const APIC_LINT0_VECTOR: u32 = 0x01;
|
|
/// Fixed IRQ vector for LINT1 line
|
|
pub const APIC_LINT1_VECTOR: u32 = 0x02;
|
|
/// Fixed vector for inter-processor interrupt
|
|
pub const APIC_IPI_VECTOR: u32 = 0x03;
|
|
/// Fixed vector for spurious interrupt
|
|
pub const APIC_SPURIOUS_VECTOR: u32 = 0xDF;
|
|
/// Start of the I/O APIC IRQ range
|
|
pub const APIC_EXTERNAL_OFFSET: u32 = 4;
|
|
/// Start of the MSI range
|
|
pub const APIC_MSI_OFFSET: u32 = APIC_EXTERNAL_OFFSET + MAX_EXTERNAL_VECTORS;
|
|
/// Maximum number of APIC vectors allocated for handling IRQs from I/O APIC
|
|
pub const MAX_EXTERNAL_VECTORS: u32 = APIC_SPURIOUS_VECTOR - APIC_EXTERNAL_OFFSET - MAX_MSI_VECTORS;
|
|
/// Number of I/O APIC IRQ vectors that are actually populated
|
|
pub const POPULATED_EXTERNAL_VECTORS: u32 = 16;
|
|
/// Maximum number of APIC vectors allocated for handling MSIs
|
|
pub const MAX_MSI_VECTORS: u32 = 16;
|
|
|
|
const_assert!(POPULATED_EXTERNAL_VECTORS <= MAX_EXTERNAL_VECTORS);
|
|
const_assert_eq!(APIC_MSI_OFFSET + MAX_MSI_VECTORS, APIC_SPURIOUS_VECTOR);
|
|
|
|
/// Fills the IDT with interrupt vectors for this APIC
|
|
pub fn setup_vectors(idt: &mut [exception::Entry]) {
|
|
extern "C" {
|
|
// IRQ vectors
|
|
static __x86_64_apic_vectors: [usize; 224];
|
|
}
|
|
|
|
for (i, &entry) in unsafe { __x86_64_apic_vectors.iter() }.enumerate() {
|
|
idt[i] = exception::Entry::new(
|
|
entry,
|
|
0x08,
|
|
exception::Entry::PRESENT | exception::Entry::INT32,
|
|
);
|
|
}
|
|
}
|
|
|
|
unsafe extern "C" fn irq_handler(vector: usize, frame: *mut IrqFrame) {
|
|
if vector >= POPULATED_EXTERNAL_VECTORS as _ {
|
|
todo!("Got a weird IRQ with vector {}", vector);
|
|
}
|
|
|
|
let cpu = Cpu::local();
|
|
let frame = &mut *frame;
|
|
|
|
ARCHITECTURE
|
|
.external_interrupt_controller()
|
|
.handle_specific_irq(vector);
|
|
cpu.local_apic().clear_interrupt();
|
|
|
|
if let Some(thread) = Thread::get_current() {
|
|
thread.handle_pending_signals(frame);
|
|
}
|
|
}
|
|
|
|
unsafe extern "C" fn msi_handler(vector: usize, frame: *mut IrqFrame) {
|
|
if vector >= MAX_MSI_VECTORS as _ {
|
|
todo!("Got a weird MSI with vector {}", vector);
|
|
}
|
|
|
|
let cpu = Cpu::local();
|
|
let frame = &mut *frame;
|
|
|
|
ARCHITECTURE
|
|
.message_interrupt_controller()
|
|
.handle_msi(vector);
|
|
cpu.local_apic().clear_interrupt();
|
|
|
|
if let Some(thread) = Thread::get_current() {
|
|
thread.handle_pending_signals(frame);
|
|
}
|
|
}
|
|
|
|
unsafe extern "C" fn local_timer_irq_handler(frame: *mut IrqFrame) {
|
|
let frame = &mut *frame;
|
|
let cpu = Cpu::local();
|
|
// Clear interrupt before switching, because otherwise we won't receive the next one
|
|
cpu.local_apic().clear_interrupt();
|
|
|
|
if let Some(queue) = cpu.get_queue() {
|
|
queue.yield_cpu();
|
|
}
|
|
|
|
if let Some(thread) = Thread::get_current() {
|
|
thread.handle_pending_signals(frame);
|
|
}
|
|
}
|
|
|
|
unsafe extern "C" fn dummy_irq_handler() {
|
|
todo!()
|
|
}
|
|
|
|
unsafe extern "C" fn ipi_handler() {
|
|
let cpu = Cpu::local();
|
|
todo!("Processor {} received an IPI", cpu.id());
|
|
}
|
|
|
|
global_asm!(
|
|
include_str!("vectors.S"),
|
|
local_timer_irq_handler = sym local_timer_irq_handler,
|
|
irq_handler = sym irq_handler,
|
|
msi_handler = sym msi_handler,
|
|
ipi_handler = sym ipi_handler,
|
|
dummy_irq_handler = sym dummy_irq_handler,
|
|
irq_vector_offset = const APIC_EXTERNAL_OFFSET,
|
|
irq_vector_count = const MAX_EXTERNAL_VECTORS,
|
|
msi_vector_offset = const APIC_MSI_OFFSET,
|
|
msi_vector_count = const MAX_MSI_VECTORS,
|
|
options(att_syntax)
|
|
);
|