diff --git a/drivers/ax-driver/build.rs b/drivers/ax-driver/build.rs index 897e8664f8..7dd7f5cb87 100644 --- a/drivers/ax-driver/build.rs +++ b/drivers/ax-driver/build.rs @@ -6,6 +6,17 @@ const VIRTIO_DEV_FEATURES: &[&str] = &[ "virtio-socket", ]; +const PCI_DYN_INTX_ROUTE_FEATURES: &[&str] = &[ + "intel-net", + "ixgbe", + "realtek-rtl8125", + "virtio-net", + "xhci-pci", +]; + +const PCI_DYN_ACPI_INTX_ROUTE_FEATURES: &[&str] = + &["intel-net", "ixgbe", "realtek-rtl8125", "virtio-net"]; + fn has_feature(feature: &str) -> bool { std::env::var(format!( "CARGO_FEATURE_{}", @@ -28,6 +39,7 @@ fn main() { let has_plat_static = has_feature("plat-static"); let has_plat_dyn = has_feature("plat-dyn"); let target_arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap_or_default(); + let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap_or_default(); let target_has_cvsd = matches!(target_arch.as_str(), "riscv32" | "riscv64"); if has_plat_dyn { @@ -38,6 +50,12 @@ fn main() { if has_virtio_core || has_virtio_dev { enable_cfg_flag("virtio_dev"); } + if has_plat_dyn && target_os == "none" && has_any_feature(PCI_DYN_INTX_ROUTE_FEATURES) { + enable_cfg_flag("pci_dyn_intx_route"); + } + if has_plat_dyn && target_os == "none" && has_any_feature(PCI_DYN_ACPI_INTX_ROUTE_FEATURES) { + enable_cfg_flag("pci_dyn_acpi_intx_route"); + } if has_any_feature(&["ahci", "bcm2835-sdhci"]) || (has_feature("cvsd") && target_has_cvsd) { enable_cfg_flag("sync_block_dev"); } @@ -45,5 +63,7 @@ fn main() { println!("cargo::rustc-check-cfg=cfg(plat_static)"); println!("cargo::rustc-check-cfg=cfg(plat_dyn)"); println!("cargo::rustc-check-cfg=cfg(virtio_dev)"); + println!("cargo::rustc-check-cfg=cfg(pci_dyn_intx_route)"); + println!("cargo::rustc-check-cfg=cfg(pci_dyn_acpi_intx_route)"); println!("cargo::rustc-check-cfg=cfg(sync_block_dev)"); } diff --git a/drivers/ax-driver/src/pci/acpi.rs b/drivers/ax-driver/src/pci/acpi.rs index 39afe553e7..0f73293a7a 100644 --- a/drivers/ax-driver/src/pci/acpi.rs +++ b/drivers/ax-driver/src/pci/acpi.rs @@ -1,28 +1,12 @@ extern crate alloc; -#[cfg(all( - target_os = "none", - any( - feature = "intel-net", - feature = "ixgbe", - feature = "realtek-rtl8125", - feature = "virtio-net", - feature = "xhci-pci", - ) -))] +#[cfg(pci_dyn_acpi_intx_route)] use alloc::format; use log::debug; -#[cfg(all( - target_os = "none", - any( - feature = "intel-net", - feature = "ixgbe", - feature = "realtek-rtl8125", - feature = "virtio-net", - feature = "xhci-pci", - ) -))] +#[cfg(pci_dyn_acpi_intx_route)] +use rdrive::probe::acpi::AcpiGsiRoute; +#[cfg(pci_dyn_acpi_intx_route)] use rdrive::probe::pci::PciAddress; use rdrive::{ PlatformDevice, @@ -70,16 +54,7 @@ fn probe_acpi_ecam(info: AcpiInfo<'_>, plat_dev: PlatformDevice) -> Result<(), O } } -#[cfg(all( - target_os = "none", - any( - feature = "intel-net", - feature = "ixgbe", - feature = "realtek-rtl8125", - feature = "virtio-net", - feature = "xhci-pci", - ) -))] +#[cfg(pci_dyn_acpi_intx_route)] pub(crate) fn acpi_irq_for_endpoint( address: PciAddress, interrupt_pin: u8, @@ -89,21 +64,32 @@ pub(crate) fn acpi_irq_for_endpoint( else { return Ok(None); }; - result - .map(|route| { - route.map(|route| { - log::info!( - "ACPI PCI INTx route: endpoint {} pin {} -> GSI {} IOAPIC {} input {} vector \ - {:#x}", - address, - interrupt_pin, - route.gsi, - route.io_apic_id, - route.io_apic_input, - route.vector - ); - route.vector - }) - }) - .map_err(|err| OnProbeError::other(format!("{err}"))) + let route = result.map_err(|err| OnProbeError::other(format!("{err}")))?; + let Some(route) = route else { + return Ok(None); + }; + + let irq = setup_acpi_intx_irq(&route.gsi)?; + log::info!( + "ACPI PCI INTx route: endpoint {} pin {} -> GSI {} IOAPIC {} input {} vector {:#x}", + address, + interrupt_pin, + route.gsi.gsi, + route.gsi.controller_id, + route.gsi.controller_input, + usize::from(irq) + ); + Ok(Some(usize::from(irq))) +} + +#[cfg(pci_dyn_acpi_intx_route)] +fn setup_acpi_intx_irq(route: &AcpiGsiRoute) -> Result { + let intc = rdrive::get_list::() + .into_iter() + .find(|intc| intc.descriptor().name.starts_with("ACPI IOAPIC")) + .ok_or_else(|| OnProbeError::other("ACPI IOAPIC interrupt controller is not registered"))?; + let mut intc = intc + .lock() + .map_err(|_| OnProbeError::other("ACPI IOAPIC interrupt controller is locked"))?; + Ok(intc.setup_irq_by_acpi(route)) } diff --git a/drivers/ax-driver/src/pci/fdt.rs b/drivers/ax-driver/src/pci/fdt.rs index eebeef5e56..04357731fb 100644 --- a/drivers/ax-driver/src/pci/fdt.rs +++ b/drivers/ax-driver/src/pci/fdt.rs @@ -1,41 +1,14 @@ extern crate alloc; use alloc::format; -#[cfg(all( - target_os = "none", - any( - feature = "intel-net", - feature = "ixgbe", - feature = "realtek-rtl8125", - feature = "virtio-net", - feature = "xhci-pci", - ) -))] +#[cfg(pci_dyn_intx_route)] use alloc::vec::Vec; -#[cfg(all( - target_os = "none", - any( - feature = "intel-net", - feature = "ixgbe", - feature = "realtek-rtl8125", - feature = "virtio-net", - feature = "xhci-pci", - ) -))] +#[cfg(pci_dyn_intx_route)] use fdt_edit::Fdt; use fdt_edit::{NodeType, PciRange, PciSpace}; use log::{debug, trace, warn}; -#[cfg(all( - target_os = "none", - any( - feature = "intel-net", - feature = "ixgbe", - feature = "realtek-rtl8125", - feature = "virtio-net", - feature = "xhci-pci", - ) -))] +#[cfg(pci_dyn_intx_route)] use rdrive::probe::pci::PciAddress; use rdrive::{ PlatformDevice, @@ -158,16 +131,7 @@ pub(super) fn register_fdt_legacy_irq(info: &FdtInfo<'_>, logical_bus_end: u8) { super::register_legacy_irq_route(0, logical_bus_end, irq); } -#[cfg(all( - target_os = "none", - any( - feature = "intel-net", - feature = "ixgbe", - feature = "realtek-rtl8125", - feature = "virtio-net", - feature = "xhci-pci", - ) -))] +#[cfg(pci_dyn_intx_route)] pub fn fdt_irq_for_endpoint( address: PciAddress, interrupt_pin: u8, @@ -180,16 +144,7 @@ pub fn fdt_irq_for_endpoint( result.map(Some) } -#[cfg(all( - target_os = "none", - any( - feature = "intel-net", - feature = "ixgbe", - feature = "realtek-rtl8125", - feature = "virtio-net", - feature = "xhci-pci", - ) -))] +#[cfg(pci_dyn_intx_route)] fn resolve_pci_irq_from_fdt( fdt: &Fdt, address: PciAddress, @@ -259,16 +214,7 @@ fn resolve_pci_irq_from_fdt( }) } -#[cfg(all( - target_os = "none", - any( - feature = "intel-net", - feature = "ixgbe", - feature = "realtek-rtl8125", - feature = "virtio-net", - feature = "xhci-pci", - ) -))] +#[cfg(pci_dyn_intx_route)] fn decode_irq_cells(specifier: &[u32]) -> Option { match specifier { [irq] => Some(*irq as usize), diff --git a/drivers/ax-driver/src/pci/mod.rs b/drivers/ax-driver/src/pci/mod.rs index 911593d19d..a144260836 100644 --- a/drivers/ax-driver/src/pci/mod.rs +++ b/drivers/ax-driver/src/pci/mod.rs @@ -33,29 +33,9 @@ use crate::virtio::VirtIoHalImpl; mod acpi; #[cfg(plat_dyn)] mod fdt; -#[cfg(all( - plat_dyn, - target_os = "none", - any( - feature = "intel-net", - feature = "ixgbe", - feature = "realtek-rtl8125", - feature = "virtio-net", - feature = "xhci-pci", - ) -))] +#[cfg(pci_dyn_acpi_intx_route)] pub(crate) use acpi::acpi_irq_for_endpoint; -#[cfg(all( - plat_dyn, - target_os = "none", - any( - feature = "intel-net", - feature = "ixgbe", - feature = "realtek-rtl8125", - feature = "virtio-net", - feature = "xhci-pci", - ) -))] +#[cfg(pci_dyn_intx_route)] pub(crate) use fdt::fdt_irq_for_endpoint; const MAX_PCIE_LEGACY_IRQS: usize = 8; diff --git a/drivers/interface/rdif-def/src/irq.rs b/drivers/interface/rdif-def/src/irq.rs index 4ae12e4380..e28059eadf 100644 --- a/drivers/interface/rdif-def/src/irq.rs +++ b/drivers/interface/rdif-def/src/irq.rs @@ -20,3 +20,26 @@ pub struct IrqConfig { /// Is cpu private interrupt? pub is_private: bool, } + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum AcpiIrqTrigger { + Edge, + Level, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum AcpiIrqPolarity { + ActiveHigh, + ActiveLow, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct AcpiGsiRoute { + pub gsi: u32, + pub vector: usize, + pub controller_id: u8, + pub controller_address: u32, + pub controller_input: u8, + pub trigger: AcpiIrqTrigger, + pub polarity: AcpiIrqPolarity, +} diff --git a/drivers/interface/rdif-intc/src/lib.rs b/drivers/interface/rdif-intc/src/lib.rs index 1562441438..dccf443c14 100644 --- a/drivers/interface/rdif-intc/src/lib.rs +++ b/drivers/interface/rdif-intc/src/lib.rs @@ -9,6 +9,10 @@ pub trait Interface: DriverGeneric { fn setup_irq_by_fdt(&mut self, _irq_prop: &[u32]) -> IrqId { unimplemented!(); } + + fn setup_irq_by_acpi(&mut self, _route: &AcpiGsiRoute) -> IrqId { + unimplemented!(); + } } def_driver!(Intc, Interface); diff --git a/drivers/rdrive/src/probe/acpi.rs b/drivers/rdrive/src/probe/acpi.rs index acb7ff4630..f09eff4f9f 100644 --- a/drivers/rdrive/src/probe/acpi.rs +++ b/drivers/rdrive/src/probe/acpi.rs @@ -22,6 +22,7 @@ use acpi::{ pci::PciConfigRegions, }, }; +pub use rdif_base::irq::{AcpiGsiRoute, AcpiIrqPolarity, AcpiIrqTrigger}; use spin::{Mutex, Once}; use crate::{ @@ -31,7 +32,7 @@ use crate::{ register::{DriverRegister, ProbeKind}, }; -const PCI_INTX_VECTOR_BASE: usize = 0x30; +pub const PCI_INTX_VECTOR_BASE: usize = 0x30; const PCI_ROOT_FALLBACK_PATHS: &[&str] = &["\\_SB.PCI0", "\\_SB.PCI1", "\\_SB.PC00", "\\_SB.PC01"]; static SYSTEM: Once = Once::new(); @@ -98,29 +99,6 @@ impl AcpiIoApic { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct AcpiGsiRoute { - pub gsi: u32, - pub vector: usize, - pub io_apic_id: u8, - pub io_apic_address: u32, - pub io_apic_input: u8, - pub trigger: AcpiIrqTrigger, - pub polarity: AcpiIrqPolarity, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum AcpiIrqTrigger { - Edge, - Level, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum AcpiIrqPolarity { - ActiveHigh, - ActiveLow, -} - #[derive(Debug, Clone)] pub struct AcpiRouting { io_apics: Vec, @@ -151,13 +129,18 @@ impl AcpiRouting { Some(AcpiGsiRoute { gsi, vector: PCI_INTX_VECTOR_BASE + gsi as usize, - io_apic_id: io_apic.id, - io_apic_address: io_apic.address, - io_apic_input: input, + controller_id: io_apic.id, + controller_address: io_apic.address, + controller_input: input, trigger: AcpiIrqTrigger::Level, polarity: AcpiIrqPolarity::ActiveLow, }) } + + pub fn resolve_vector(&self, vector: usize) -> Option { + let gsi = vector.checked_sub(PCI_INTX_VECTOR_BASE)?; + self.resolve_gsi(gsi as u32) + } } impl Default for AcpiRouting { @@ -170,13 +153,7 @@ impl Default for AcpiRouting { pub struct AcpiPciIrqRoute { pub address: PciAddress, pub interrupt_pin: u8, - pub gsi: u32, - pub vector: usize, - pub io_apic_id: u8, - pub io_apic_address: u32, - pub io_apic_input: u8, - pub trigger: AcpiIrqTrigger, - pub polarity: AcpiIrqPolarity, + pub gsi: AcpiGsiRoute, } pub struct AcpiInfo<'a> { @@ -507,13 +484,11 @@ impl System { Ok(Some(AcpiPciIrqRoute { address, interrupt_pin, - gsi: route.gsi, - vector: route.vector, - io_apic_id: route.io_apic_id, - io_apic_address: route.io_apic_address, - io_apic_input: route.io_apic_input, - trigger: irq_trigger(irq.trigger), - polarity: irq_polarity(irq.polarity), + gsi: AcpiGsiRoute { + trigger: irq_trigger(irq.trigger), + polarity: irq_polarity(irq.polarity), + ..route + }, })) } diff --git a/drivers/rdrive/tests/phase1.rs b/drivers/rdrive/tests/phase1.rs index 97b2500cb3..e7e8ca0bb2 100644 --- a/drivers/rdrive/tests/phase1.rs +++ b/drivers/rdrive/tests/phase1.rs @@ -54,7 +54,7 @@ fn fdt_phandle_lookup_is_none_without_fdt_source() { #[test] fn acpi_ioapic_routes_map_gsi_to_stable_vector() { - use rdrive::probe::acpi::{AcpiIoApic, AcpiRouting}; + use rdrive::probe::acpi::{AcpiIoApic, AcpiIrqPolarity, AcpiIrqTrigger, AcpiRouting}; let mut routing = AcpiRouting::new(); routing.add_io_apic(AcpiIoApic { @@ -68,8 +68,11 @@ fn acpi_ioapic_routes_map_gsi_to_stable_vector() { .resolve_gsi(16) .expect("gsi 16 should be handled by the IOAPIC"); assert_eq!(irq.gsi, 16); - assert_eq!(irq.io_apic_id, 0); - assert_eq!(irq.io_apic_input, 16); + assert_eq!(irq.controller_id, 0); + assert_eq!(irq.controller_address, 0xfec0_0000); + assert_eq!(irq.controller_input, 16); assert_eq!(irq.vector, 0x40); + assert_eq!(irq.trigger, AcpiIrqTrigger::Level); + assert_eq!(irq.polarity, AcpiIrqPolarity::ActiveLow); assert!(routing.resolve_gsi(24).is_none()); } diff --git a/platforms/somehal/src/arch/x86_64/mod.rs b/platforms/somehal/src/arch/x86_64/mod.rs index a97ac15a90..bad1f0a312 100644 --- a/platforms/somehal/src/arch/x86_64/mod.rs +++ b/platforms/somehal/src/arch/x86_64/mod.rs @@ -1,7 +1,13 @@ use alloc::vec::Vec; -use rdrive::probe::acpi::{AcpiIoApic, AcpiIrqPolarity, AcpiIrqTrigger}; -use spin::Mutex; +use rdif_intc::{AcpiGsiRoute, AcpiIrqPolarity, AcpiIrqTrigger}; +use rdrive::{ + DriverGeneric, PlatformDevice, module_driver, + probe::{ + OnProbeError, + acpi::{AcpiId, AcpiInfo, AcpiIoApic}, + }, +}; use x2apic::ioapic::{IoApic, IrqFlags, IrqMode}; use crate::{common::PlatOp, irq::_handle_irq}; @@ -9,8 +15,6 @@ use crate::{common::PlatOp, irq::_handle_irq}; pub struct Plat; const APIC_TIMER_VECTOR: usize = 0x20; -const IOAPIC_VECTOR_BASE: usize = 0x30; - const LAPIC_REG_EOI: u32 = 0x0b0; const LAPIC_REG_ICR_LOW: u32 = 0x300; const LAPIC_REG_ICR_HIGH: u32 = 0x310; @@ -19,26 +23,164 @@ const ICR_FIXED_BASE: u32 = 0x0000_4000; const ICR_DEST_SELF: u32 = 0x0004_0000; const ICR_DEST_ALL_EXCLUDING_SELF: u32 = 0x000c_0000; -static IOAPICS: Mutex> = Mutex::new(Vec::new()); +module_driver!( + name: "ACPI IOAPIC", + level: ProbeLevel::PreKernel, + priority: ProbePriority::INTC, + probe_kinds: &[ProbeKind::Acpi { + ids: &[AcpiId { + hid: "ACPIIOAP", + cids: &[], + }], + on_probe: probe_ioapic + }], +); + +struct X86IoApicIntc { + ioapics: Vec, + routes: Vec, +} + +impl X86IoApicIntc { + fn new(ioapics: &[AcpiIoApic]) -> Self { + Self { + ioapics: ioapics.iter().copied().map(X86IoApic::new).collect(), + routes: Vec::new(), + } + } + + fn remember_route(&mut self, route: AcpiGsiRoute) { + if let Some(existing) = self.routes.iter_mut().find(|r| r.vector == route.vector) { + *existing = route; + } else { + self.routes.push(route); + } + } + + fn route_for_vector(&self, vector: usize) -> Option { + self.routes + .iter() + .copied() + .find(|r| r.vector == vector) + .or_else(|| { + rdrive::probe::acpi::with_acpi(|system| system.routing().resolve_vector(vector)) + .flatten() + }) + } + + fn set_vector_enable(&mut self, vector: usize, enable: bool) -> bool { + let Some(route) = self.route_for_vector(vector) else { + return false; + }; + + self.set_route_enable(&route, enable); + true + } -struct IoApicState { + fn set_route_enable(&mut self, route: &AcpiGsiRoute, enable: bool) { + for ioapic in &mut self.ioapics { + if ioapic.contains_route(route) { + ioapic.set_route_enable(route, enable); + return; + } + } + } +} + +struct X86IoApic { info: AcpiIoApic, ioapic: IoApic, } -impl IoApicState { +impl X86IoApic { + fn new(info: AcpiIoApic) -> Self { + let ioapic_base = someboot::mem::phys_to_virt(info.address as usize) as u64; + let mut ioapic = unsafe { IoApic::new(ioapic_base) }; + let max_entry = unsafe { ioapic.max_table_entry() }; + let redirection_entries = max_entry.saturating_add(1); + + unsafe { + ioapic.init(irq_vector_base(info.gsi_base) as u8); + for input in 0..=max_entry { + let mut entry = ioapic.table_entry(input); + entry.set_flags(entry.flags() | IrqFlags::MASKED); + ioapic.set_table_entry(input, entry); + } + } + + info!( + "ACPI IOAPIC initialized: id={} base={:#x} gsi_base={} entries={}", + info.id, info.address, info.gsi_base, redirection_entries + ); + + Self { + info: AcpiIoApic { + redirection_entries, + ..info + }, + ioapic, + } + } + fn contains(&self, gsi: u32) -> bool { let start = self.info.gsi_base; let end = start.saturating_add(u32::from(self.info.redirection_entries)); (start..end).contains(&gsi) } - fn input_for(&self, gsi: u32) -> Option { - let input = gsi.checked_sub(self.info.gsi_base)?; - u8::try_from(input).ok() + fn contains_route(&self, route: &AcpiGsiRoute) -> bool { + self.info.id == route.controller_id + && self.info.address == route.controller_address + && self.contains(route.gsi) + } + + fn set_route_enable(&mut self, route: &AcpiGsiRoute, enable: bool) { + if !self.contains_route(route) { + return; + } + + unsafe { + let input = route.controller_input; + let mut entry = self.ioapic.table_entry(input); + entry.set_vector(route.vector as u8); + entry.set_mode(IrqMode::Fixed); + entry.set_flags(intx_flags(route.trigger, route.polarity)); + entry.set_dest(0); + self.ioapic.set_table_entry(input, entry); + + if enable { + self.ioapic.enable_irq(input); + } else { + self.ioapic.disable_irq(input); + } + } + } +} + +impl DriverGeneric for X86IoApicIntc { + fn name(&self) -> &str { + "x86 ACPI IOAPIC" + } +} + +impl rdif_intc::Interface for X86IoApicIntc { + fn setup_irq_by_acpi(&mut self, route: &AcpiGsiRoute) -> rdrive::IrqId { + self.remember_route(*route); + self.set_route_enable(route, false); + route.vector.into() } } +fn probe_ioapic(info: AcpiInfo<'_>, dev: PlatformDevice) -> Result<(), OnProbeError> { + let ioapics = info.root.routing().io_apics(); + if ioapics.is_empty() { + return Err(OnProbeError::NotMatch); + } + + dev.register(rdif_intc::Intc::new(X86IoApicIntc::new(ioapics))); + Ok(()) +} + impl PlatOp for Plat { fn irq_set_enable(irq: rdrive::IrqId, enable: bool) { let raw = irq.raw(); @@ -110,77 +252,14 @@ impl PlatOp for Plat { } } -pub fn init_acpi_irq() { - init_ioapics_from_acpi(); -} - -fn init_ioapics_from_acpi() { - let Some(routing) = rdrive::probe::acpi::with_acpi(|system| system.routing().clone()) else { - return; - }; - - let mut ioapics = IOAPICS.lock(); - if !ioapics.is_empty() { - return; - } - - for info in routing.io_apics().iter().copied() { - let ioapic_base = someboot::mem::phys_to_virt(info.address as usize) as u64; - let mut ioapic = unsafe { IoApic::new(ioapic_base) }; - let max_entry = unsafe { ioapic.max_table_entry() }; - let redirection_entries = max_entry.saturating_add(1); - - unsafe { - ioapic.init(IOAPIC_VECTOR_BASE as u8); - for input in 0..=max_entry { - let mut entry = ioapic.table_entry(input); - entry.set_flags(entry.flags() | IrqFlags::MASKED); - ioapic.set_table_entry(input, entry); - } - } - - info!( - "ACPI IOAPIC initialized: id={} base={:#x} gsi_base={} entries={}", - info.id, info.address, info.gsi_base, redirection_entries - ); - ioapics.push(IoApicState { - info: AcpiIoApic { - redirection_entries, - ..info - }, - ioapic, - }); - } -} - fn set_ioapic_vector_enable(vector: usize, enable: bool) { - let Some(gsi) = vector.checked_sub(IOAPIC_VECTOR_BASE).map(|gsi| gsi as u32) else { - return; - }; - - let mut ioapics = IOAPICS.lock(); - let Some(ioapic) = ioapics.iter_mut().find(|ioapic| ioapic.contains(gsi)) else { - return; - }; - let Some(input) = ioapic.input_for(gsi) else { - return; - }; - - unsafe { - let mut entry = ioapic.ioapic.table_entry(input); - entry.set_vector(vector as u8); - entry.set_mode(IrqMode::Fixed); - entry.set_flags(intx_flags( - AcpiIrqTrigger::Level, - AcpiIrqPolarity::ActiveLow, - )); - entry.set_dest(0); - ioapic.ioapic.set_table_entry(input, entry); - - if enable { - ioapic.ioapic.enable_irq(input); - } else { - ioapic.ioapic.disable_irq(input); + for intc in rdrive::get_list::() { + if intc.descriptor().name.starts_with("ACPI IOAPIC") + && let Ok(ioapic) = intc.downcast::() + && let Ok(mut ioapic) = ioapic.try_lock() + && ioapic.set_vector_enable(vector, enable) + { + return; } } } @@ -196,6 +275,10 @@ fn intx_flags(trigger: AcpiIrqTrigger, polarity: AcpiIrqPolarity) -> IrqFlags { flags } +fn irq_vector_base(gsi_base: u32) -> usize { + rdrive::probe::acpi::PCI_INTX_VECTOR_BASE + gsi_base as usize +} + fn lapic_eoi() { unsafe { lapic_write(LAPIC_REG_EOI, 0); @@ -234,3 +317,19 @@ fn lapic_ptr(offset: u32) -> *mut u32 { let base = unsafe { x86::msr::rdmsr(IA32_APIC_BASE) & LAPIC_BASE_MASK } as usize; unsafe { someboot::mem::phys_to_virt(base).add(offset as usize) }.cast() } + +#[cfg(all(test, any(unix, windows)))] +mod tests { + use super::*; + + #[test] + fn acpi_intx_flags_preserve_trigger_and_polarity() { + let level_low = intx_flags(AcpiIrqTrigger::Level, AcpiIrqPolarity::ActiveLow); + assert!(level_low.contains(IrqFlags::LEVEL_TRIGGERED)); + assert!(level_low.contains(IrqFlags::LOW_ACTIVE)); + + let edge_high = intx_flags(AcpiIrqTrigger::Edge, AcpiIrqPolarity::ActiveHigh); + assert!(!edge_high.contains(IrqFlags::LEVEL_TRIGGERED)); + assert!(!edge_high.contains(IrqFlags::LOW_ACTIVE)); + } +} diff --git a/platforms/somehal/src/lib.rs b/platforms/somehal/src/lib.rs index f69ef8b37c..bec4b660b3 100644 --- a/platforms/somehal/src/lib.rs +++ b/platforms/somehal/src/lib.rs @@ -46,8 +46,6 @@ pub fn post_paging() { someboot::post_allocator(); // note: irq controller should be initialized when probe. driver::rdrive_setup(); - #[cfg(target_arch = "x86_64")] - arch::init_acpi_irq(); } #[unsafe(no_mangle)]