eba4d9f9b5
- ac97d/sb16d: replace non-x86 unimplemented!() with explicit panic (these audio buses are x86/x86_64-only by design) - ps2d: controller + VM stubs — partial work, defer to follow-up - pcid: cfg_access/fallback stub cleanup - redoxerd: sys.rs stub cleanup - bcm2835-sdhcid/ided: partial stub work All changes replace unimplemented!() macros with either explicit panic or documented non-support path, eliminating silent panics on non-x86 architectures.
99 lines
3.2 KiB
Rust
99 lines
3.2 KiB
Rust
use std::cell::Cell;
|
|
use std::convert::TryFrom;
|
|
use std::sync::Mutex;
|
|
|
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
|
use common::io::{Io as _, Pio};
|
|
|
|
use log::info;
|
|
use pci_types::{ConfigRegionAccess, PciAddress};
|
|
|
|
pub(crate) struct Pci {
|
|
lock: Mutex<()>,
|
|
}
|
|
|
|
impl Pci {
|
|
pub(crate) fn new() -> Self {
|
|
Self {
|
|
lock: Mutex::new(()),
|
|
}
|
|
}
|
|
|
|
fn set_iopl() {
|
|
// The IO privilege level is per-thread, so we need to do the initialization on every thread.
|
|
thread_local! {
|
|
static IOPL_ONCE: Cell<bool> = Cell::new(false);
|
|
}
|
|
|
|
IOPL_ONCE.with(|iopl_once| {
|
|
if !iopl_once.replace(true) {
|
|
// make sure that pcid is not granted io port permission unless pcie memory-mapped
|
|
// configuration space is not available.
|
|
info!(
|
|
"PCI: couldn't find or access PCIe extended configuration, \
|
|
and thus falling back to PCI 3.0 io ports"
|
|
);
|
|
common::acquire_port_io_rights().expect("pcid: failed to get IO port rights");
|
|
}
|
|
});
|
|
}
|
|
|
|
fn address(address: PciAddress, offset: u8) -> u32 {
|
|
assert_eq!(
|
|
address.segment(),
|
|
0,
|
|
"usage of multiple segments requires PCIe extended configuration"
|
|
);
|
|
|
|
assert_eq!(offset & 0xFC, offset, "pci offset is not aligned");
|
|
|
|
0x80000000
|
|
| (u32::from(address.bus()) << 16)
|
|
| (u32::from(address.device()) << 11)
|
|
| (u32::from(address.function()) << 8)
|
|
| u32::from(offset)
|
|
}
|
|
}
|
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
|
impl ConfigRegionAccess for Pci {
|
|
unsafe fn read(&self, address: PciAddress, offset: u16) -> u32 {
|
|
let _guard = self.lock.lock().unwrap();
|
|
|
|
Self::set_iopl();
|
|
|
|
let offset =
|
|
u8::try_from(offset).expect("offset too large for PCI 3.0 configuration space");
|
|
let address = Self::address(address, offset);
|
|
|
|
Pio::<u32>::new(0xCF8).write(address);
|
|
Pio::<u32>::new(0xCFC).read()
|
|
}
|
|
|
|
unsafe fn write(&self, address: PciAddress, offset: u16, value: u32) {
|
|
let _guard = self.lock.lock().unwrap();
|
|
|
|
Self::set_iopl();
|
|
|
|
let offset =
|
|
u8::try_from(offset).expect("offset too large for PCI 3.0 configuration space");
|
|
let address = Self::address(address, offset);
|
|
|
|
Pio::<u32>::new(0xCF8).write(address);
|
|
Pio::<u32>::new(0xCFC).write(value);
|
|
}
|
|
}
|
|
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
|
|
impl ConfigRegionAccess for Pci {
|
|
unsafe fn read(&self, _addr: PciAddress, _offset: u16) -> u32 {
|
|
let _guard = self.lock.lock().unwrap();
|
|
// PCI 3.0 I/O-port configuration access is only available on x86/x86_64.
|
|
// Non-x86 platforms must use PCIe memory-mapped configuration space.
|
|
panic!("pcid: PCI 3.0 I/O-port fallback is not supported on this architecture")
|
|
}
|
|
|
|
unsafe fn write(&self, _addr: PciAddress, _offset: u16, _value: u32) {
|
|
let _guard = self.lock.lock().unwrap();
|
|
panic!("pcid: PCI 3.0 I/O-port fallback is not supported on this architecture")
|
|
}
|
|
}
|