Local APIC

This commit is contained in:
mii443
2025-08-02 21:55:00 +09:00
parent 7a9bf54477
commit 962ff20a8b
4 changed files with 138 additions and 6 deletions

View File

@ -0,0 +1,100 @@
use acpi::PlatformInfo;
use alloc::alloc::Global;
use spin::{Lazy, Once};
use x86_64::instructions::port::Port;
use crate::interrupt::idt::IRQ_TIMER;
pub static LAPIC: Once<LocalApic> = Once::new();
pub fn disable_pic_8259() {
unsafe {
Port::new(0xa1).write(0xffu8);
Port::new(0x21).write(0xffu8);
}
}
pub struct LocalApic {
pub ptr: *mut u32,
}
unsafe impl Send for LocalApic {}
unsafe impl Sync for LocalApic {}
impl LocalApic {
fn new(base: u64) -> Self {
LocalApic {
ptr: base as *mut u32,
}
}
pub fn read(&self, offset: u32) -> u32 {
unsafe { self.ptr.add(offset as usize).read_volatile() }
}
pub fn write(&self, offset: u32, value: u32) {
unsafe { self.ptr.add(offset as usize).write_volatile(value) }
}
}
const SVR: u32 = 0x00f0 / 4;
const ENABLE: u32 = 0x100;
const TDCR: u32 = 0x03e0 / 4;
const TICR: u32 = 0x0380 / 4;
const TIMER: u32 = 0x0320 / 4;
const X1: u32 = 0b1011;
const PERIODIC: u32 = 0x20000;
const MASKED: u32 = 0x10000;
const ICRLO: u32 = 0x0300 / 4;
const BCAST: u32 = 0x80000;
const INIT: u32 = 0x500;
const LEVEL: u32 = 0x8000;
const DELIVS: u32 = 0x1000;
const ICRHI: u32 = 0x0310 / 4;
const PCINT: u32 = 0x0340 / 4;
const LINT0: u32 = 0x0350 / 4;
const LINT1: u32 = 0x0360 / 4;
pub const EOI: u32 = 0x00b0 / 4;
const TPR: u32 = 0x0080 / 4;
pub fn init_local_apic(platform_info: PlatformInfo<'_, Global>) {
disable_pic_8259();
let apic_info = match platform_info.interrupt_model {
acpi::InterruptModel::Apic(ref apic) => apic,
_ => panic!("APIC not found in ACPI tables"),
};
let local_apic_base = apic_info.local_apic_address;
let local_apic = LocalApic::new(local_apic_base);
LAPIC.call_once(|| LocalApic::new(local_apic_base));
local_apic.write(SVR, ENABLE | 0xff);
local_apic.write(TDCR, X1);
local_apic.write(TIMER, PERIODIC | IRQ_TIMER);
local_apic.write(TICR, 10000000); //TODO
local_apic.write(LINT0, MASKED);
local_apic.write(LINT1, MASKED);
if (local_apic.read(0x30 / 4) >> 16) & 0xFF >= 4 {
local_apic.write(PCINT, MASKED);
}
local_apic.write(EOI, 0);
local_apic.write(ICRHI, 0);
local_apic.write(ICRLO, BCAST | INIT | LEVEL);
while local_apic.read(ICRLO) & DELIVS != 0 {}
local_apic.write(TPR, 0);
}

View File

@ -1,18 +1,37 @@
use lazy_static::lazy_static;
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode};
use crate::{interrupt::gdt, warn};
use crate::{
info_w_int,
interrupt::{
apic::{EOI, LAPIC},
gdt,
},
warn,
};
const PIC_8259_IRQ_OFFSET: u32 = 32;
pub const IRQ_TIMER: u32 = PIC_8259_IRQ_OFFSET + 16;
lazy_static! {
static ref IDT: InterruptDescriptorTable = {
let mut idt = InterruptDescriptorTable::new();
idt.breakpoint.set_handler_fn(breakpoint_handler);
idt.breakpoint
.set_handler_fn(breakpoint_handler)
.disable_interrupts(true);
unsafe {
idt.double_fault
.set_handler_fn(double_fault_handler)
.set_stack_index(gdt::DOUBLE_FAULT_IST_INDEX);
.set_stack_index(gdt::DOUBLE_FAULT_IST_INDEX)
.disable_interrupts(true);
}
idt.page_fault.set_handler_fn(page_fault_handler);
idt.page_fault
.set_handler_fn(page_fault_handler)
.disable_interrupts(true);
idt[IRQ_TIMER as u8]
.set_handler_fn(timer_handler)
.disable_interrupts(true);
idt
};
}
@ -44,3 +63,8 @@ extern "x86-interrupt" fn page_fault_handler(
Cr2::read().unwrap().as_u64()
);
}
extern "x86-interrupt" fn timer_handler(_stack_frame: InterruptStackFrame) {
LAPIC.get().unwrap().write(EOI, 0);
info_w_int!("Timer interrupt received");
}

View File

@ -1,2 +1,3 @@
pub mod apic;
pub mod gdt;
pub mod idt;

View File

@ -1,6 +1,7 @@
#![no_std]
#![no_main]
#![feature(abi_x86_interrupt)]
#![feature(allocator_api)]
extern crate alloc;
@ -24,6 +25,7 @@ use crate::{
acpi::KernelAcpiHandler,
constant::{KERNEL_STACK_SIZE, PKG_VERSION},
graphics::{FrameBuffer, FRAME_BUFFER},
interrupt::apic,
memory::{allocator, memory::BitmapMemoryTable, paging},
};
@ -144,8 +146,13 @@ pub extern "sysv64" fn main(boot_info: &nel_os_common::BootInfo) {
let acpi_tables =
unsafe { AcpiTables::from_rsdp(KernelAcpiHandler, boot_info.rsdp as usize) }.unwrap();
let platform_info = acpi_tables.platform_info().unwrap();
let processor_info = platform_info.processor_info;
info!("Processor info: {:#x?}", processor_info);
apic::init_local_apic(platform_info);
info!("Local APIC initialized",);
x86_64::instructions::interrupts::enable();
info!("Interrupts enabled");
hlt_loop();
}