From f0b5d517932a803f7a2c3d73711b55d4d9f665c8 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 18 Apr 2020 16:36:18 +0200 Subject: [PATCH] Use the I/O APIC when applicable. --- src/acpi/madt.rs | 8 +- src/acpi/mod.rs | 2 +- src/acpi/rsdp.rs | 32 ++- src/arch/x86_64/device/ioapic.rs | 382 +++++++++++++++++++++++++++++++ src/arch/x86_64/device/mod.rs | 7 +- src/arch/x86_64/device/pic.rs | 9 + src/arch/x86_64/interrupt/irq.rs | 119 ++++++++-- src/arch/x86_64/start.rs | 5 +- 8 files changed, 526 insertions(+), 38 deletions(-) create mode 100644 src/arch/x86_64/device/ioapic.rs diff --git a/src/acpi/madt.rs b/src/acpi/madt.rs index d8904899..67743589 100644 --- a/src/acpi/madt.rs +++ b/src/acpi/madt.rs @@ -15,13 +15,16 @@ use crate::interrupt; use crate::start::{kstart_ap, CPU_COUNT, AP_READY}; /// The Multiple APIC Descriptor Table -#[derive(Debug)] +#[derive(Clone, Copy, Debug)] pub struct Madt { sdt: &'static Sdt, pub local_address: u32, pub flags: u32 } +pub static mut MADT: Option<Madt> = None; +pub const FLAG_PCAT: u32 = 1; + impl Madt { pub fn init(active_table: &mut ActivePageTable) { let madt_sdt = find_sdt("APIC"); @@ -34,6 +37,9 @@ impl Madt { }; if let Some(madt) = madt { + // safe because no APs have been started yet. + unsafe { MADT = Some(madt) }; + println!(" APIC: {:>08X}: {}", madt.local_address, madt.flags); let local_apic = unsafe { &mut LOCAL_APIC }; diff --git a/src/acpi/mod.rs b/src/acpi/mod.rs index f0f82455..7d79c7ce 100644 --- a/src/acpi/mod.rs +++ b/src/acpi/mod.rs @@ -31,7 +31,7 @@ use self::aml::{parse_aml_table, AmlError, AmlValue}; pub mod hpet; mod dmar; mod fadt; -mod madt; +pub mod madt; mod rsdt; mod sdt; mod xsdt; diff --git a/src/acpi/rsdp.rs b/src/acpi/rsdp.rs index c457ef14..fa244fdf 100644 --- a/src/acpi/rsdp.rs +++ b/src/acpi/rsdp.rs @@ -1,4 +1,5 @@ use core::convert::TryFrom; +use core::mem; use crate::memory::Frame; use crate::paging::{ActivePageTable, Page, PhysicalAddress, VirtualAddress}; @@ -36,10 +37,17 @@ impl RSDP { type Item = &'a [u8]; fn next(&mut self) -> Option<Self::Item> { - let length = <[u8; 4]>::try_from(&self.buf[..4]).ok()?; + if self.buf.len() < 4 { return None } + + let length_bytes = <[u8; 4]>::try_from(&self.buf[..4]).ok()?; + let length = u32::from_ne_bytes(length_bytes) as usize; + if (4 + length as usize) > self.buf.len() { return None } - self.buf = self.buf[4 + length..]; - Ok(length) + + let buf = &self.buf[4..4 + length]; + self.buf = &self.buf[4 + length..]; + + Some(buf) } } fn slice_to_rsdp(slice: &[u8]) -> Option<&RSDP> { @@ -52,20 +60,22 @@ impl RSDP { } else { None } } - // first, find an RDSP for ACPI 2.0 - if let Some(rdsp_2_0) = Iter { buf: area }.filter_map(slice_to_rsdp).filter(|rsdp| rsdp.is_acpi_2_0()) { - return Some(rsdp_2_0); + // first, find an RSDP for ACPI 2.0 + if let Some(rsdp_2_0) = (Iter { buf: area }.filter_map(slice_to_rsdp).find(|rsdp| rsdp.is_acpi_2_0())) { + return Some(*rsdp_2_0); } - // secondly, find an RDSP for ACPI 1.0 - if let Some(rdsp_1_0) = Iter { buf: area }.filter_map(slice_to_rsdp).filter(|rsdp| rsdp.is_acpi_1_0()) { - return Some(rsdp_1_0); + // secondly, find an RSDP for ACPI 1.0 + if let Some(rsdp_1_0) = (Iter { buf: area }.filter_map(slice_to_rsdp).find(|rsdp| rsdp.is_acpi_1_0())) { + return Some(*rsdp_1_0); } + + None } pub fn get_rsdp(active_table: &mut ActivePageTable, already_supplied_rsdps: Option<(u64, u64)>) -> Option<RSDP> { if let Some((base, size)) = already_supplied_rsdps { - let area = core::slice::from_raw_parts(base as usize as *const u8, size as usize); - Self::get_already_supplied_rsdps(area) + let area = unsafe { core::slice::from_raw_parts(base as usize as *const u8, size as usize) }; + Self::get_already_supplied_rsdps(area).or_else(|| Self::get_rsdp_by_searching(active_table)) } else { Self::get_rsdp_by_searching(active_table) } diff --git a/src/arch/x86_64/device/ioapic.rs b/src/arch/x86_64/device/ioapic.rs new file mode 100644 index 00000000..2897ed92 --- /dev/null +++ b/src/arch/x86_64/device/ioapic.rs @@ -0,0 +1,382 @@ +use core::{fmt, ptr}; + +use alloc::vec::Vec; +use spin::Mutex; + +#[cfg(feature = "acpi")] +use crate::acpi::madt::{self, Madt, MadtEntry, MadtIoApic, MadtIntSrcOverride}; + +use crate::arch::interrupt::irq; +use crate::memory::Frame; +use crate::paging::{ActivePageTable, entry::EntryFlags, Page, PhysicalAddress, VirtualAddress}; +use crate::syscall::io::Mmio; + +use super::pic; + +pub struct IoApicRegs { + pointer: *const u32, +} +impl IoApicRegs { + fn ioregsel(&self) -> *const u32 { + self.pointer + } + fn iowin(&self) -> *const u32 { + // offset 0x10 + unsafe { self.pointer.offset(4) } + } + fn read_ioregsel(&self) -> u32 { + unsafe { ptr::read_volatile::<u32>(self.ioregsel()) } + } + fn write_ioregsel(&mut self, value: u32) { + unsafe { ptr::write_volatile::<u32>(self.ioregsel() as *mut u32, value) } + } + fn read_iowin(&self) -> u32 { + unsafe { ptr::read_volatile::<u32>(self.iowin()) } + } + fn write_iowin(&mut self, value: u32) { + unsafe { ptr::write_volatile::<u32>(self.iowin() as *mut u32, value) } + } + fn read_reg(&mut self, reg: u8) -> u32 { + self.write_ioregsel(reg.into()); + self.read_iowin() + } + fn write_reg(&mut self, reg: u8, value: u32) { + self.write_ioregsel(reg.into()); + self.write_iowin(value); + } + pub fn read_ioapicid(&mut self) -> u32 { + self.read_reg(0x00) + } + pub fn write_ioapicid(&mut self, value: u32) { + self.write_reg(0x00, value); + } + pub fn read_ioapicver(&mut self) -> u32 { + self.read_reg(0x01) + } + pub fn read_ioapicarb(&mut self) -> u32 { + self.read_reg(0x02) + } + pub fn read_ioredtbl(&mut self, idx: u8) -> u64 { + assert!(idx < 24); + let lo = self.read_reg(0x10 + idx * 2); + let hi = self.read_reg(0x10 + idx * 2 + 1); + + u64::from(lo) | (u64::from(hi) << 32) + } + pub fn write_ioredtbl(&mut self, idx: u8, value: u64) { + assert!(idx < 24); + + let lo = value as u32; + let hi = (value >> 32) as u32; + + self.write_reg(0x10 + idx * 2, lo); + self.write_reg(0x10 + idx * 2 + 1, hi); + } + + pub fn max_redirection_table_entries(&mut self) -> u8 { + let ver = self.read_ioapicver(); + ((ver & 0x00FF_0000) >> 16) as u8 + } + pub fn id(&mut self) -> u8 { + let id_reg = self.read_ioapicid(); + ((id_reg & 0x0F00_0000) >> 24) as u8 + } +} +pub struct IoApic { + regs: Mutex<IoApicRegs>, + gsi_start: u32, + count: u8, +} +impl IoApic { + pub fn new(regs_base: *const u32, gsi_start: u32) -> Self { + let mut regs = IoApicRegs { pointer: regs_base }; + let count = regs.max_redirection_table_entries(); + + Self { + regs: Mutex::new(regs), + gsi_start, + count, + } + } + /// Map an interrupt vector to a physical local APIC ID of a processor (thus physical mode). + pub fn map(&self, idx: u8, info: MapInfo) { + self.regs.lock().write_ioredtbl(idx, info.as_raw()) + } + pub fn set_mask(&self, gsi: u32, mask: bool) { + let idx = (gsi - self.gsi_start) as u8; + let mut guard = self.regs.lock(); + + let mut reg = guard.read_ioredtbl(idx); + reg &= !(1 << 16); + reg |= u64::from(mask) << 16; + guard.write_ioredtbl(idx, reg); + } +} +#[repr(u8)] +#[derive(Clone, Copy, Debug)] +pub enum ApicTriggerMode { + Edge = 0, + Level = 1, +} +#[repr(u8)] +#[derive(Clone, Copy, Debug)] +pub enum ApicPolarity { + ActiveHigh = 0, + ActiveLow = 1, +} +#[repr(u8)] +#[derive(Clone, Copy, Debug)] +pub enum DestinationMode { + Physical = 0, + Logical = 1, +} +#[repr(u8)] +#[derive(Clone, Copy, Debug)] +pub enum DeliveryMode { + Fixed = 0b000, + LowestPriority = 0b001, + Smi = 0b010, + Nmi = 0b100, + Init = 0b101, + ExtInt = 0b111, +} + +#[derive(Clone, Copy, Debug)] +pub struct MapInfo { + pub dest: u8, + pub mask: bool, + pub trigger_mode: ApicTriggerMode, + pub polarity: ApicPolarity, + pub dest_mode: DestinationMode, + pub delivery_mode: DeliveryMode, + pub vector: u8, +} + +impl MapInfo { + pub fn as_raw(&self) -> u64 { + assert!(self.vector >= 0x20); + assert!(self.vector <= 0xFE); + + // TODO: Check for reserved fields. + + (u64::from(self.dest) << 56) + | (u64::from(self.mask) << 16) + | ((self.trigger_mode as u64) << 15) + | ((self.polarity as u64) << 13) + | ((self.dest_mode as u64) << 11) + | ((self.delivery_mode as u64) << 8) + | u64::from(self.vector) + } +} + +impl fmt::Debug for IoApic { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + struct RedirTable<'a>(&'a Mutex<IoApicRegs>); + + impl<'a> fmt::Debug for RedirTable<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut guard = self.0.lock(); + + let count = guard.max_redirection_table_entries(); + f.debug_list().entries((0..count).map(|i| guard.read_ioredtbl(i))).finish() + } + } + + f.debug_struct("IoApic") + .field("redir_table", &RedirTable(&self.regs)) + .field("gsi_start", &self.gsi_start) + .field("count", &self.count) + .finish() + } +} + +#[derive(Clone, Copy, Debug)] +pub enum TriggerMode { + ConformsToSpecs, + Edge, + Level, +} + +#[derive(Clone, Copy, Debug)] +pub enum Polarity { + ConformsToSpecs, + ActiveHigh, + ActiveLow, +} + +#[derive(Clone, Copy, Debug)] +pub struct Override { + bus_irq: u8, + gsi: u32, + + trigger_mode: TriggerMode, + polarity: Polarity, +} + +// static mut because only the AP initializes the I/O Apic, and when that is done, it's solely +// accessed immutably. +static mut IOAPICS: Option<Vec<IoApic>> = None; + +// static mut for the same reason as above +static mut SRC_OVERRIDES: Option<Vec<Override>> = None; + +pub fn ioapics() -> &'static [IoApic] { + unsafe { + IOAPICS.as_ref().map_or(&[], |vector| &vector[..]) + } +} +pub fn src_overrides() -> &'static [Override] { + unsafe { + SRC_OVERRIDES.as_ref().map_or(&[], |vector| &vector[..]) + } +} + +#[cfg(feature = "acpi")] +pub unsafe fn handle_ioapic(active_table: &mut ActivePageTable, madt_ioapic: &'static MadtIoApic) { + // map the I/O APIC registers + let frame = Frame::containing_address(PhysicalAddress::new(madt_ioapic.address as usize)); + let page = Page::containing_address(VirtualAddress::new(madt_ioapic.address as usize + crate::KERNEL_OFFSET)); + + assert_eq!(active_table.translate_page(page), None); + + let result = active_table.map_to(page, frame, EntryFlags::PRESENT | EntryFlags::GLOBAL | EntryFlags::WRITABLE | EntryFlags::NO_CACHE); + result.flush(active_table); + + let ioapic_registers = page.start_address().get() as *const u32; + let mut ioapic = IoApic::new(ioapic_registers, madt_ioapic.gsi_base); + + assert_eq!(ioapic.regs.lock().id(), madt_ioapic.id, "mismatched ACPI MADT I/O APIC ID, and the ID reported by the I/O APIC"); + + IOAPICS.get_or_insert_with(Vec::new).push(ioapic); +} +#[cfg(feature = "acpi")] +pub unsafe fn handle_src_override(src_override: &'static MadtIntSrcOverride) { + let flags = src_override.flags; + + let polarity_raw = (flags & 0x0003) as u8; + let trigger_mode_raw = ((flags & 0x000C) >> 2) as u8; + + let polarity = match polarity_raw { + 0b00 => Polarity::ConformsToSpecs, + 0b01 => Polarity::ActiveHigh, + 0b10 => return, // reserved + 0b11 => Polarity::ActiveLow, + + _ => unreachable!(), + }; + + let trigger_mode = match trigger_mode_raw { + 0b00 => TriggerMode::ConformsToSpecs, + 0b01 => TriggerMode::Edge, + 0b10 => return, // reserved + 0b11 => TriggerMode::Level, + _ => unreachable!(), + }; + + let over = Override { + bus_irq: src_override.irq_source, + gsi: src_override.gsi_base, + polarity, + trigger_mode, + }; + SRC_OVERRIDES.get_or_insert_with(Vec::new).push(over); +} + +pub unsafe fn init(active_table: &mut ActivePageTable) { + let mut bsp_apic_id = x86::cpuid::CpuId::new().get_feature_info().unwrap().initial_local_apic_id(); // TODO + + // search the madt for all IOAPICs. + #[cfg(feature = "acpi")] + { + let madt: &'static Madt = match madt::MADT.as_ref() { + Some(m) => m, + // TODO: Parse MP tables too. + None => return, + }; + if madt.flags & madt::FLAG_PCAT != 0 { + pic::disable(); + } + + // find all I/O APICs (usually one). + + for entry in madt.iter() { + match entry { + MadtEntry::IoApic(ioapic) => handle_ioapic(active_table, ioapic), + MadtEntry::IntSrcOverride(src_override) => handle_src_override(src_override), + _ => (), + } + } + } + println!("I/O APICs: {:?}, overrides: {:?}", ioapics(), src_overrides()); + + // map the legacy PC-compatible IRQs (0-15) to 32-47, just like we did with 8259 PIC (if it + // wouldn't have been disabled due to this I/O APIC) + for legacy_irq in 0..=15 { + let (gsi, trigger_mode, polarity) = match get_override(legacy_irq) { + Some(over) => (over.gsi, over.trigger_mode, over.polarity), + None => { + if src_overrides().iter().any(|over| over.gsi == u32::from(legacy_irq) && over.bus_irq != legacy_irq) && !src_overrides().iter().any(|over| over.bus_irq == legacy_irq) { + // there's an IRQ conflict, making this legacy IRQ inaccessible. + continue; + } + (legacy_irq.into(), TriggerMode::ConformsToSpecs, Polarity::ConformsToSpecs) + } + }; + let apic = match find_ioapic(gsi) { + Some(ioapic) => ioapic, + None => { + println!("Unable to find a suitable APIC for legacy IRQ {} (GSI {}). It will not be mapped.", legacy_irq, gsi); + continue; + } + }; + let redir_tbl_index = (gsi - apic.gsi_start) as u8; + + let map_info = MapInfo { + // only send to the BSP + dest: bsp_apic_id, + dest_mode: DestinationMode::Physical, + delivery_mode: DeliveryMode::Fixed, + mask: false, + polarity: match polarity { + Polarity::ActiveHigh => ApicPolarity::ActiveHigh, + Polarity::ActiveLow => ApicPolarity::ActiveLow, + Polarity::ConformsToSpecs => ApicPolarity::ActiveHigh, + }, + trigger_mode: match trigger_mode { + TriggerMode::Edge => ApicTriggerMode::Edge, + TriggerMode::Level => ApicTriggerMode::Level, + TriggerMode::ConformsToSpecs => ApicTriggerMode::Edge, + }, + vector: 32 + legacy_irq, + }; + apic.map(redir_tbl_index, map_info); + } + println!("I/O APICs: {:?}, overrides: {:?}", ioapics(), src_overrides()); + irq::set_irq_method(irq::IrqMethod::Apic); +} +fn get_override(irq: u8) -> Option<&'static Override> { + src_overrides().iter().find(|over| over.bus_irq == irq) +} +fn resolve(irq: u8) -> u32 { + get_override(irq).map_or(u32::from(irq), |over| over.gsi) +} +fn find_ioapic(gsi: u32) -> Option<&'static IoApic> { + ioapics().iter().find(|apic| gsi >= apic.gsi_start && gsi < apic.gsi_start + u32::from(apic.count)) +} + +pub unsafe fn mask(irq: u8) { + let gsi = resolve(irq); + let apic = match find_ioapic(gsi) { + Some(a) => a, + None => return, + }; + apic.set_mask(gsi, true); +} +pub unsafe fn unmask(irq: u8) { + let gsi = resolve(irq); + let apic = match find_ioapic(gsi) { + Some(a) => a, + None => return, + }; + apic.set_mask(gsi, false); +} diff --git a/src/arch/x86_64/device/mod.rs b/src/arch/x86_64/device/mod.rs index 3c876525..656d2b25 100644 --- a/src/arch/x86_64/device/mod.rs +++ b/src/arch/x86_64/device/mod.rs @@ -1,6 +1,7 @@ use crate::paging::ActivePageTable; pub mod cpu; +pub mod ioapic; pub mod local_apic; pub mod pic; pub mod pit; @@ -9,10 +10,14 @@ pub mod serial; #[cfg(feature = "acpi")] pub mod hpet; -pub unsafe fn init(active_table: &mut ActivePageTable){ +pub unsafe fn init(active_table: &mut ActivePageTable) { pic::init(); local_apic::init(active_table); } +pub unsafe fn init_after_acpi(active_table: &mut ActivePageTable) { + // this will disable the IOAPIC if needed. + ioapic::init(active_table); +} #[cfg(feature = "acpi")] unsafe fn init_hpet() -> bool { diff --git a/src/arch/x86_64/device/pic.rs b/src/arch/x86_64/device/pic.rs index 88f57097..2518550d 100644 --- a/src/arch/x86_64/device/pic.rs +++ b/src/arch/x86_64/device/pic.rs @@ -1,4 +1,5 @@ use crate::syscall::io::{Io, Pio}; +use crate::arch::interrupt::irq; pub static mut MASTER: Pic = Pic::new(0x20); pub static mut SLAVE: Pic = Pic::new(0xA0); @@ -27,6 +28,14 @@ pub unsafe fn init() { // Ack remaining interrupts MASTER.ack(); SLAVE.ack(); + + // probably already set to PIC, but double-check + irq::set_irq_method(irq::IrqMethod::Pic); +} + +pub unsafe fn disable() { + MASTER.data.write(0xFF); + SLAVE.data.write(0xFF); } pub struct Pic { diff --git a/src/arch/x86_64/interrupt/irq.rs b/src/arch/x86_64/interrupt/irq.rs index 72c29726..9b4ba742 100644 --- a/src/arch/x86_64/interrupt/irq.rs +++ b/src/arch/x86_64/interrupt/irq.rs @@ -1,7 +1,7 @@ use core::sync::atomic::{AtomicUsize, Ordering}; use crate::context::timeout; -use crate::device::{local_apic, pic}; +use crate::device::{local_apic, ioapic, pic}; use crate::device::serial::{COM1, COM2}; use crate::ipi::{ipi, IpiKind, IpiTarget}; use crate::scheme::debug::debug_input; @@ -11,38 +11,99 @@ use crate::{context, ptrace, time}; #[thread_local] pub static PIT_TICKS: AtomicUsize = AtomicUsize::new(0); +#[repr(u8)] +pub enum IrqMethod { + Pic = 0, + Apic = 1, +} + +static IRQ_METHOD: AtomicUsize = AtomicUsize::new(IrqMethod::Pic as usize); + +pub fn set_irq_method(method: IrqMethod) { + IRQ_METHOD.store(method as usize, core::sync::atomic::Ordering::Release); +} + +fn irq_method() -> IrqMethod { + let raw = IRQ_METHOD.load(core::sync::atomic::Ordering::Acquire); + + match raw { + 0 => IrqMethod::Pic, + 1 => IrqMethod::Apic, + _ => unreachable!(), + } +} + extern { + // triggers irq scheme fn irq_trigger(irq: u8); } +/// Notify the IRQ scheme that an IRQ has been registered. This should mask the IRQ until the +/// scheme user unmasks it ("acknowledges" it). unsafe fn trigger(irq: u8) { + match irq_method() { + IrqMethod::Pic => if irq < 16 { pic_mask(irq) }, + IrqMethod::Apic => ioapic_mask(irq), + } + irq_trigger(irq); +} +/// Unmask the IRQ. This is called from the IRQ scheme, which does this when a user process has +/// processed the IRQ. +pub unsafe fn acknowledge(irq: usize) { + match irq_method() { + IrqMethod::Pic => if irq < 16 { pic_unmask(irq) }, + IrqMethod::Apic => ioapic_unmask(irq), + } +} +/// Sends an end-of-interrupt, so that the interrupt controller can go on to the next one. +pub unsafe fn eoi(irq: u8) { + match irq_method() { + IrqMethod::Pic => if irq < 16 { pic_eoi(irq) }, + IrqMethod::Apic => lapic_eoi(), + } +} - if irq < 16 { - if irq >= 8 { - pic::SLAVE.mask_set(irq - 8); - pic::MASTER.ack(); - pic::SLAVE.ack(); - } else { - pic::MASTER.mask_set(irq); - pic::MASTER.ack(); - } +unsafe fn pic_mask(irq: u8) { + debug_assert!(irq < 16); + + if irq >= 8 { + pic::SLAVE.mask_set(irq - 8); + } else { + pic::MASTER.mask_set(irq); } +} - irq_trigger(irq); +unsafe fn ioapic_mask(irq: u8) { + ioapic::mask(irq); +} + + +unsafe fn pic_eoi(irq: u8) { + debug_assert!(irq < 16); + + if irq >= 8 { + pic::MASTER.ack(); + pic::SLAVE.ack(); + } else { + pic::MASTER.ack(); + } } unsafe fn lapic_eoi() { local_apic::LOCAL_APIC.eoi() } -pub unsafe fn acknowledge(irq: usize) { - if irq < 16 { - if irq >= 8 { - pic::SLAVE.mask_clear(irq as u8 - 8); - } else { - pic::MASTER.mask_clear(irq as u8); - } +unsafe fn pic_unmask(irq: usize) { + debug_assert!(irq < 16); + + if irq >= 8 { + pic::SLAVE.mask_clear(irq as u8 - 8); + } else { + pic::MASTER.mask_clear(irq as u8); } } +unsafe fn ioapic_unmask(irq: usize) { + ioapic::unmask(irq as u8); +} interrupt_stack!(pit, stack, { // Saves CPU time by not sending IRQ event irq_trigger(0); @@ -56,7 +117,7 @@ interrupt_stack!(pit, stack, { offset.0 += sum / 1_000_000_000; } - pic::MASTER.ack(); + eoi(0); // Wake up other CPUs ipi(IpiKind::Pit, IpiTarget::Other); @@ -72,68 +133,80 @@ interrupt_stack!(pit, stack, { interrupt!(keyboard, { trigger(1); + eoi(1); }); interrupt!(cascade, { // No need to do any operations on cascade - pic::MASTER.ack(); + eoi(2); }); interrupt!(com2, { while let Some(c) = COM2.lock().receive() { debug_input(c); } - pic::MASTER.ack(); + eoi(3); }); interrupt!(com1, { while let Some(c) = COM1.lock().receive() { debug_input(c); } - pic::MASTER.ack(); + eoi(4); }); interrupt!(lpt2, { + eoi(5); trigger(5); }); interrupt!(floppy, { + eoi(6); trigger(6); }); interrupt!(lpt1, { + eoi(7); trigger(7); }); interrupt!(rtc, { + eoi(8); trigger(8); }); interrupt!(pci1, { + eoi(9); trigger(9); }); interrupt!(pci2, { + eoi(10); trigger(10); }); interrupt!(pci3, { + eoi(11); trigger(11); }); interrupt!(mouse, { + eoi(12); trigger(12); }); interrupt!(fpu, { + eoi(13); trigger(13); }); interrupt!(ata1, { + eoi(14); trigger(14); }); interrupt!(ata2, { + eoi(15); trigger(15); }); interrupt!(lapic_timer, { @@ -154,7 +227,7 @@ interrupt!(calib_pit, { offset.0 += sum / 1_000_000_000; } - pic::MASTER.ack(); + eoi(0); }); // XXX: This would look way prettier using const generics. diff --git a/src/arch/x86_64/start.rs b/src/arch/x86_64/start.rs index 4cb7333d..12afd596 100644 --- a/src/arch/x86_64/start.rs +++ b/src/arch/x86_64/start.rs @@ -176,7 +176,10 @@ pub unsafe extern fn kstart(args_ptr: *const KernelArgs) -> ! { // Read ACPI tables, starts APs #[cfg(feature = "acpi")] - acpi::init(&mut active_table, extended_kargs.as_ref().map(|kargs| (kargs.acpi_rsdps_base, kargs.acpi_rsdps_size))); + { + acpi::init(&mut active_table, extended_kargs.as_ref().map(|kargs| (kargs.acpi_rsdps_base, kargs.acpi_rsdps_size))); + device::init_after_acpi(&mut active_table); + } // Initialize all of the non-core devices not otherwise needed to complete initialization device::init_noncore(); -- GitLab