use std::sync::Arc;
use std::sync::atomic::AtomicU32;
use assert_matches::assert_matches;
use crate::mem::emulated::{Action, Mmio};
use crate::pci::Bdf;
use crate::pci::bus::{Address, PciBus, PciIoBus};
use crate::pci::config::{BAR_MEM64, BAR_PREFETCHABLE, CommonHeader, offset_bar};
use crate::pci::pvpanic::{PVPANIC_DEVICE_ID, PVPANIC_VENDOR_ID, PvPanic};
use crate::pci::segment::PciSegment;
#[test]
fn test_pci_bus() {
let pci_bus = PciBus::default();
assert_eq!(
pci_bus.reserve(Some(Bdf::new(0, 1, 0))),
Some(Bdf::new(0, 1, 0))
);
let test_dev = Arc::new(PvPanic::new());
assert_matches!(pci_bus.add(Bdf::new(0, 1, 0), test_dev), None);
}
#[test]
fn test_pci_io_bus() {
let test_dev = Arc::new(PvPanic::new());
let segment = PciSegment::new();
assert_matches!(segment.add(Bdf::new(0, 1, 0), test_dev), None);
let io_bus = PciIoBus {
address: AtomicU32::new(0),
segment: Arc::new(segment),
};
assert_eq!(io_bus.size(), 8);
let reg_addr = Address::new(true, 0, 1, 0, CommonHeader::OFFSET_VENDOR as u8);
assert_matches!(io_bus.write(0, 4, reg_addr.0 as u64), Ok(Action::None));
assert_eq!(io_bus.read(0, 4).unwrap(), reg_addr.0 as u64);
assert_eq!(io_bus.read(4, 2).unwrap(), PVPANIC_VENDOR_ID as u64);
assert_eq!(io_bus.read(6, 2).unwrap(), PVPANIC_DEVICE_ID as u64);
let reg_addr = Address::new(true, 0, 1, 0, offset_bar(0) as u8);
assert_matches!(io_bus.write(0, 4, reg_addr.0 as u64), Ok(Action::None));
assert_matches!(io_bus.write(4, 4, 0xec00_0000), Ok(Action::None));
assert_eq!(
io_bus.read(4, 4).unwrap(),
(0xec00_0000 | BAR_MEM64 | BAR_PREFETCHABLE) as u64
);
assert_matches!(io_bus.read(8, 1), Ok(0));
assert_matches!(io_bus.write(8, 1, 1), Ok(Action::None));
}
#[test]
fn test_pci_io_bus_unaligned_address_access() {
let io_bus = PciIoBus {
address: AtomicU32::new(0),
segment: Arc::new(PciSegment::new()),
};
let reg_addr = Address::new(true, 0, 1, 0, offset_bar(0) as u8);
assert_matches!(io_bus.write(0, 4, reg_addr.0 as u64), Ok(Action::None));
assert_matches!(io_bus.write(0, 2, 0x12345678), Ok(Action::None));
assert_matches!(io_bus.read(0, 2), Ok(0));
assert_eq!(io_bus.read(0, 4).unwrap(), reg_addr.0 as u64);
}
#[test]
fn test_pci_io_bus_disabled_address() {
let test_dev = Arc::new(PvPanic::new());
let segment = PciSegment::new();
assert_matches!(segment.add(Bdf::new(0, 1, 0), test_dev), None);
let io_bus = PciIoBus {
address: AtomicU32::new(0),
segment: Arc::new(segment),
};
let reg_addr = Address::new(false, 0, 1, 0, offset_bar(0) as u8);
assert_matches!(io_bus.write(0, 4, reg_addr.0 as u64), Ok(Action::None));
assert_matches!(io_bus.read(4, 4), Ok(0));
assert_matches!(io_bus.write(4, 4, 0), Ok(Action::None));
}
#[cfg(target_arch = "x86_64")]
#[test]
fn test_host_bridge() {
let bus = PciBus::new();
let offset = CommonHeader::OFFSET_CLASS;
let reg_addr = Address::new(true, 0, 0, 0, offset as u8);
assert_matches!(bus.io_bus.write(0, 4, reg_addr.0 as u64), Ok(Action::None));
assert_matches!(bus.io_bus.read(4 + (offset as u64 & 0b11), 1), Ok(0x06));
}