mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2025-01-12 16:45:31 +00:00
devices: pci: add MMIO config access mechanism
This will be used on ARM. Change-Id: I61206b761f49f963f0cce706268379ceae1a0239 Signed-off-by: Daniel Verkamp <dverkamp@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/1241540 Reviewed-by: Dylan Reid <dgreid@chromium.org>
This commit is contained in:
parent
28a671a95f
commit
f3a3a870b1
3 changed files with 52 additions and 2 deletions
|
@ -32,7 +32,7 @@ pub use self::bus::Error as BusError;
|
|||
pub use self::cmos::Cmos;
|
||||
pub use self::pl030::Pl030;
|
||||
pub use self::i8042::I8042Device;
|
||||
pub use self::pci::{PciConfigIo, PciDevice, PciDeviceError, PciInterruptPin, PciRoot};
|
||||
pub use self::pci::{PciConfigIo, PciConfigMmio, PciDevice, PciDeviceError, PciInterruptPin, PciRoot};
|
||||
pub use self::proxy::ProxyDevice;
|
||||
pub use self::proxy::Error as ProxyError;
|
||||
pub use self::serial::Serial;
|
||||
|
|
|
@ -11,7 +11,7 @@ mod pci_root;
|
|||
pub use self::pci_configuration::{PciCapability, PciCapabilityID, PciClassCode, PciConfiguration, PciHeaderType, PciProgrammingInterface, PciSubclass};
|
||||
pub use self::pci_device::Error as PciDeviceError;
|
||||
pub use self::pci_device::PciDevice;
|
||||
pub use self::pci_root::{PciConfigIo, PciRoot};
|
||||
pub use self::pci_root::{PciConfigIo, PciConfigMmio, PciRoot};
|
||||
|
||||
/// PCI has four interrupt pins A->D.
|
||||
#[derive(Copy, Clone)]
|
||||
|
|
|
@ -222,6 +222,56 @@ impl BusDevice for PciConfigIo {
|
|||
}
|
||||
}
|
||||
|
||||
/// Emulates PCI memory-mapped configuration access mechanism.
|
||||
pub struct PciConfigMmio {
|
||||
/// PCI root bridge.
|
||||
pci_root: PciRoot,
|
||||
}
|
||||
|
||||
impl PciConfigMmio {
|
||||
pub fn new(pci_root: PciRoot) -> Self {
|
||||
PciConfigMmio {
|
||||
pci_root,
|
||||
}
|
||||
}
|
||||
|
||||
fn config_space_read(&self, config_address: u32) -> u32 {
|
||||
let (bus, device, function, register) = parse_config_address(config_address);
|
||||
self.pci_root.config_space_read(bus, device, function, register)
|
||||
}
|
||||
|
||||
fn config_space_write(&mut self, config_address: u32, offset: u64, data: &[u8]) {
|
||||
let (bus, device, function, register) = parse_config_address(config_address);
|
||||
self.pci_root.config_space_write(bus, device, function, register, offset, data)
|
||||
}
|
||||
}
|
||||
|
||||
impl BusDevice for PciConfigMmio {
|
||||
fn read(&mut self, offset: u64, data: &mut [u8]) {
|
||||
// Only allow reads to the register boundary.
|
||||
let start = offset as usize % 4;
|
||||
let end = start + data.len();
|
||||
if end > 4 || offset > u32::max_value() as u64 {
|
||||
for d in data {
|
||||
*d = 0xff;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let value = self.config_space_read(offset as u32);
|
||||
for i in start..end {
|
||||
data[i - start] = (value >> (i * 8)) as u8;
|
||||
}
|
||||
}
|
||||
|
||||
fn write(&mut self, offset: u64, data: &[u8]) {
|
||||
if offset > u32::max_value() as u64 {
|
||||
return;
|
||||
}
|
||||
self.config_space_write(offset as u32, offset % 4, data)
|
||||
}
|
||||
}
|
||||
|
||||
// Parse the CONFIG_ADDRESS register to a (bus, device, function, register) tuple.
|
||||
fn parse_config_address(config_address: u32) -> (usize, usize, usize, usize) {
|
||||
const BUS_NUMBER_OFFSET: usize = 16;
|
||||
|
|
Loading…
Reference in a new issue