From a09de99c1dad5058f192d90b318da8d1b9b0a915 Mon Sep 17 00:00:00 2001 From: Ruihan Li Date: Sun, 18 Jan 2026 11:32:53 +0800 Subject: [PATCH] Ensure PCI access atomicity --- kernel/comps/pci/src/arch/x86/mod.rs | 36 ++++++++++++++++------------ 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/kernel/comps/pci/src/arch/x86/mod.rs b/kernel/comps/pci/src/arch/x86/mod.rs index a8f3c2087..eefb4197d 100644 --- a/kernel/comps/pci/src/arch/x86/mod.rs +++ b/kernel/comps/pci/src/arch/x86/mod.rs @@ -8,34 +8,34 @@ use ostd::{ Error, arch::device::io_port::{ReadWriteAccess, WriteOnlyAccess}, io::IoPort, + sync::SpinLock, }; use spin::Once; use crate::device_info::PciDeviceLocation; -static PCI_ADDRESS_PORT: Once> = Once::new(); -static PCI_DATA_PORT: Once> = Once::new(); +struct AddressAndDataPort { + address_port: IoPort, + data_port: IoPort, +} + +static PCI_PIO_CFG_SPACE: Once> = Once::new(); const BIT32_ALIGN_MASK: u32 = 0xFFFC; pub(crate) fn write32(location: &PciDeviceLocation, offset: u32, value: u32) -> Result<(), Error> { - PCI_ADDRESS_PORT - .get() - .ok_or(Error::IoError)? + let pio = PCI_PIO_CFG_SPACE.get().ok_or(Error::IoError)?.lock(); + pio.address_port .write(encode_as_port(location) | (offset & BIT32_ALIGN_MASK)); - PCI_DATA_PORT - .get() - .ok_or(Error::IoError)? - .write(value.to_le()); + pio.data_port.write(value.to_le()); Ok(()) } pub(crate) fn read32(location: &PciDeviceLocation, offset: u32) -> Result { - PCI_ADDRESS_PORT - .get() - .ok_or(Error::IoError)? + let pio = PCI_PIO_CFG_SPACE.get().ok_or(Error::IoError)?.lock(); + pio.address_port .write(encode_as_port(location) | (offset & BIT32_ALIGN_MASK)); - Ok(PCI_DATA_PORT.get().ok_or(Error::IoError)?.read().to_le()) + Ok(pio.data_port.read().to_le()) } /// Encodes the bus, device, and function into a port address for use with the PCI I/O port. @@ -55,8 +55,14 @@ pub(crate) fn init() -> Option> { // reset control register in the PIIX4. Although the two ports overlap in their I/O range, they // serve completely different purposes. See // . - PCI_ADDRESS_PORT.call_once(|| IoPort::acquire_overlapping(0xCF8).unwrap()); - PCI_DATA_PORT.call_once(|| IoPort::acquire(0xCFC).unwrap()); + let address_port = IoPort::acquire_overlapping(0xCF8).unwrap(); + let data_port = IoPort::acquire(0xCFC).unwrap(); + PCI_PIO_CFG_SPACE.call_once(move || { + SpinLock::new(AddressAndDataPort { + address_port, + data_port, + }) + }); Some(0..=255) }