1e8308dd1SSamuel Ortiz // Copyright 2018 The Chromium OS Authors. All rights reserved.
2e8308dd1SSamuel Ortiz // Use of this source code is governed by a BSD-style license that can be
3040ea543SSamuel Ortiz // found in the LICENSE-BSD-3-Clause file.
45e9886bbSRuslan Mstoi //
55e9886bbSRuslan Mstoi // SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
6e8308dd1SSamuel Ortiz
788a9f799SRob Bradford use std::any::Any;
888a9f799SRob Bradford use std::collections::HashMap;
988a9f799SRob Bradford use std::ops::DerefMut;
1088a9f799SRob Bradford use std::sync::{Arc, Barrier, Mutex};
1188a9f799SRob Bradford
1288a9f799SRob Bradford use byteorder::{ByteOrder, LittleEndian};
13a007b750SPhilipp Schuster use thiserror::Error;
1488a9f799SRob Bradford use vm_device::{Bus, BusDevice, BusDeviceSync};
1588a9f799SRob Bradford
1612681650SSebastien Boeuf use crate::configuration::{
1712681650SSebastien Boeuf PciBarRegionType, PciBridgeSubclass, PciClassCode, PciConfiguration, PciHeaderType,
1812681650SSebastien Boeuf };
19cb52cf91SBo Chen use crate::device::{BarReprogrammingParams, DeviceRelocation, Error as PciDeviceError, PciDevice};
2089218b6dSSebastien Boeuf use crate::PciBarConfiguration;
21e8308dd1SSamuel Ortiz
22e8308dd1SSamuel Ortiz const VENDOR_ID_INTEL: u16 = 0x8086;
23e8308dd1SSamuel Ortiz const DEVICE_ID_INTEL_VIRT_PCIE_HOST: u16 = 0x0d57;
24df71aaeeSSebastien Boeuf const NUM_DEVICE_IDS: usize = 32;
25e8308dd1SSamuel Ortiz
26e8308dd1SSamuel Ortiz /// Errors for device manager.
27a007b750SPhilipp Schuster #[derive(Error, Debug)]
28e8308dd1SSamuel Ortiz pub enum PciRootError {
29e8308dd1SSamuel Ortiz /// Could not allocate device address space for the device.
30*a3692144SPhilipp Schuster #[error("Could not allocate device address space for the device")]
31a007b750SPhilipp Schuster AllocateDeviceAddrs(#[source] PciDeviceError),
32e8308dd1SSamuel Ortiz /// Could not allocate an IRQ number.
33a007b750SPhilipp Schuster #[error("Could not allocate an IRQ number")]
34e8308dd1SSamuel Ortiz AllocateIrq,
3512681650SSebastien Boeuf /// Could not add a device to the port io bus.
36*a3692144SPhilipp Schuster #[error("Could not add a device to the port io bus")]
37a007b750SPhilipp Schuster PioInsert(#[source] vm_device::BusError),
38e8308dd1SSamuel Ortiz /// Could not add a device to the mmio bus.
39*a3692144SPhilipp Schuster #[error("Could not add a device to the mmio bus")]
40a007b750SPhilipp Schuster MmioInsert(#[source] vm_device::BusError),
41df71aaeeSSebastien Boeuf /// Could not find an available device slot on the PCI bus.
42a007b750SPhilipp Schuster #[error("Could not find an available device slot on the PCI bus")]
43df71aaeeSSebastien Boeuf NoPciDeviceSlotAvailable,
44b50cbe50SSebastien Boeuf /// Invalid PCI device identifier provided.
45a007b750SPhilipp Schuster #[error("Invalid PCI device identifier provided")]
46b50cbe50SSebastien Boeuf InvalidPciDeviceSlot(usize),
471e0ebb76SSebastien Boeuf /// Valid PCI device identifier but already used.
48a007b750SPhilipp Schuster #[error("Valid PCI device identifier but already used")]
491e0ebb76SSebastien Boeuf AlreadyInUsePciDeviceSlot(usize),
50e8308dd1SSamuel Ortiz }
51e8308dd1SSamuel Ortiz pub type Result<T> = std::result::Result<T, PciRootError>;
52e8308dd1SSamuel Ortiz
532bb0b22cSJing Liu /// Emulates the PCI Root bridge device.
54e8308dd1SSamuel Ortiz pub struct PciRoot {
552bb0b22cSJing Liu /// Configuration space.
562bb0b22cSJing Liu config: PciConfiguration,
57e8308dd1SSamuel Ortiz }
58e8308dd1SSamuel Ortiz
59e8308dd1SSamuel Ortiz impl PciRoot {
602bb0b22cSJing Liu /// Create an empty PCI root bridge.
new(config: Option<PciConfiguration>) -> Self612bb0b22cSJing Liu pub fn new(config: Option<PciConfiguration>) -> Self {
622bb0b22cSJing Liu if let Some(config) = config {
632bb0b22cSJing Liu PciRoot { config }
64e8308dd1SSamuel Ortiz } else {
65e8308dd1SSamuel Ortiz PciRoot {
662bb0b22cSJing Liu config: PciConfiguration::new(
67e8308dd1SSamuel Ortiz VENDOR_ID_INTEL,
68e8308dd1SSamuel Ortiz DEVICE_ID_INTEL_VIRT_PCIE_HOST,
699bd5ec89SRob Bradford 0,
70e8308dd1SSamuel Ortiz PciClassCode::BridgeDevice,
71e8308dd1SSamuel Ortiz &PciBridgeSubclass::HostBridge,
72e8308dd1SSamuel Ortiz None,
732b2c31d2SSamuel Ortiz PciHeaderType::Device,
74e8308dd1SSamuel Ortiz 0,
75e8308dd1SSamuel Ortiz 0,
764d98dcb0SSebastien Boeuf None,
77eae80438SSebastien Boeuf None,
78e8308dd1SSamuel Ortiz ),
79e8308dd1SSamuel Ortiz }
80e8308dd1SSamuel Ortiz }
81e8308dd1SSamuel Ortiz }
82e8308dd1SSamuel Ortiz }
83e8308dd1SSamuel Ortiz
842bb0b22cSJing Liu impl BusDevice for PciRoot {}
852bb0b22cSJing Liu
862bb0b22cSJing Liu impl PciDevice for PciRoot {
write_config_register( &mut self, reg_idx: usize, offset: u64, data: &[u8], ) -> (Vec<BarReprogrammingParams>, Option<Arc<Barrier>>)877cc729c7SRob Bradford fn write_config_register(
887cc729c7SRob Bradford &mut self,
897cc729c7SRob Bradford reg_idx: usize,
907cc729c7SRob Bradford offset: u64,
917cc729c7SRob Bradford data: &[u8],
92aaf86ef2SBo Chen ) -> (Vec<BarReprogrammingParams>, Option<Arc<Barrier>>) {
93cb52cf91SBo Chen (
94cb52cf91SBo Chen self.config.write_config_register(reg_idx, offset, data),
95cb52cf91SBo Chen None,
96cb52cf91SBo Chen )
972bb0b22cSJing Liu }
982bb0b22cSJing Liu
read_config_register(&mut self, reg_idx: usize) -> u3299db9f9b78SSebastien Boeuf fn read_config_register(&mut self, reg_idx: usize) -> u32 {
1002bb0b22cSJing Liu self.config.read_reg(reg_idx)
1012bb0b22cSJing Liu }
102de21c9baSSebastien Boeuf
as_any_mut(&mut self) -> &mut dyn Any103d99f2942SWei Liu fn as_any_mut(&mut self) -> &mut dyn Any {
104de21c9baSSebastien Boeuf self
105de21c9baSSebastien Boeuf }
1065264d545SSebastien Boeuf
id(&self) -> Option<String>1075264d545SSebastien Boeuf fn id(&self) -> Option<String> {
1085264d545SSebastien Boeuf None
1095264d545SSebastien Boeuf }
1102bb0b22cSJing Liu }
1112bb0b22cSJing Liu
112833a3d45SRob Bradford pub struct PciBus {
1132bb0b22cSJing Liu /// Devices attached to this bus.
1142bb0b22cSJing Liu /// Device 0 is host bridge.
1158d785bbdSSebastien Boeuf devices: HashMap<u32, Arc<Mutex<dyn PciDevice>>>,
11649268bffSSebastien Boeuf device_reloc: Arc<dyn DeviceRelocation>,
117df71aaeeSSebastien Boeuf device_ids: Vec<bool>,
118e8308dd1SSamuel Ortiz }
119e8308dd1SSamuel Ortiz
120833a3d45SRob Bradford impl PciBus {
new(pci_root: PciRoot, device_reloc: Arc<dyn DeviceRelocation>) -> Self12149268bffSSebastien Boeuf pub fn new(pci_root: PciRoot, device_reloc: Arc<dyn DeviceRelocation>) -> Self {
1228d785bbdSSebastien Boeuf let mut devices: HashMap<u32, Arc<Mutex<dyn PciDevice>>> = HashMap::new();
123df71aaeeSSebastien Boeuf let mut device_ids: Vec<bool> = vec![false; NUM_DEVICE_IDS];
124833a3d45SRob Bradford
1258d785bbdSSebastien Boeuf devices.insert(0, Arc::new(Mutex::new(pci_root)));
126df71aaeeSSebastien Boeuf device_ids[0] = true;
1272bb0b22cSJing Liu
12804a449d3SSebastien Boeuf PciBus {
12904a449d3SSebastien Boeuf devices,
130149b61b2SSebastien Boeuf device_reloc,
131df71aaeeSSebastien Boeuf device_ids,
13204a449d3SSebastien Boeuf }
133e8308dd1SSamuel Ortiz }
134e8308dd1SSamuel Ortiz
register_mapping( &self, dev: Arc<dyn BusDeviceSync>, io_bus: &Bus, mmio_bus: &Bus, bars: Vec<PciBarConfiguration>, ) -> Result<()>1352bb0b22cSJing Liu pub fn register_mapping(
1362bb0b22cSJing Liu &self,
137954f3dd0SYuanchu Xie dev: Arc<dyn BusDeviceSync>,
13850bac169SAlyssa Ross io_bus: &Bus,
13915025d71SRob Bradford mmio_bus: &Bus,
14089218b6dSSebastien Boeuf bars: Vec<PciBarConfiguration>,
1412bb0b22cSJing Liu ) -> Result<()> {
14289218b6dSSebastien Boeuf for bar in bars {
14389218b6dSSebastien Boeuf match bar.region_type() {
144827229d8SRob Bradford PciBarRegionType::IoRegion => {
14512681650SSebastien Boeuf io_bus
14689218b6dSSebastien Boeuf .insert(dev.clone(), bar.addr(), bar.size())
14712681650SSebastien Boeuf .map_err(PciRootError::PioInsert)?;
14812681650SSebastien Boeuf }
14912681650SSebastien Boeuf PciBarRegionType::Memory32BitRegion | PciBarRegionType::Memory64BitRegion => {
15012681650SSebastien Boeuf mmio_bus
15189218b6dSSebastien Boeuf .insert(dev.clone(), bar.addr(), bar.size())
1522bb0b22cSJing Liu .map_err(PciRootError::MmioInsert)?;
1532bb0b22cSJing Liu }
15412681650SSebastien Boeuf }
15512681650SSebastien Boeuf }
1562bb0b22cSJing Liu Ok(())
1572bb0b22cSJing Liu }
1582bb0b22cSJing Liu
add_device(&mut self, device_id: u32, device: Arc<Mutex<dyn PciDevice>>) -> Result<()>159ae83e3b3SRob Bradford pub fn add_device(&mut self, device_id: u32, device: Arc<Mutex<dyn PciDevice>>) -> Result<()> {
160ae83e3b3SRob Bradford self.devices.insert(device_id, device);
1612bb0b22cSJing Liu Ok(())
1622bb0b22cSJing Liu }
163b918220bSSebastien Boeuf
remove_by_device(&mut self, device: &Arc<Mutex<dyn PciDevice>>) -> Result<()>164f8e2008eSSebastien Boeuf pub fn remove_by_device(&mut self, device: &Arc<Mutex<dyn PciDevice>>) -> Result<()> {
1658d785bbdSSebastien Boeuf self.devices.retain(|_, dev| !Arc::ptr_eq(dev, device));
166f8e2008eSSebastien Boeuf Ok(())
167f8e2008eSSebastien Boeuf }
168f8e2008eSSebastien Boeuf
next_device_id(&mut self) -> Result<u32>169df71aaeeSSebastien Boeuf pub fn next_device_id(&mut self) -> Result<u32> {
170df71aaeeSSebastien Boeuf for (idx, device_id) in self.device_ids.iter_mut().enumerate() {
171df71aaeeSSebastien Boeuf if !(*device_id) {
172df71aaeeSSebastien Boeuf *device_id = true;
173df71aaeeSSebastien Boeuf return Ok(idx as u32);
174df71aaeeSSebastien Boeuf }
175df71aaeeSSebastien Boeuf }
176df71aaeeSSebastien Boeuf
177df71aaeeSSebastien Boeuf Err(PciRootError::NoPciDeviceSlotAvailable)
178b918220bSSebastien Boeuf }
179b50cbe50SSebastien Boeuf
get_device_id(&mut self, id: usize) -> Result<()>1801e0ebb76SSebastien Boeuf pub fn get_device_id(&mut self, id: usize) -> Result<()> {
1811e0ebb76SSebastien Boeuf if id < NUM_DEVICE_IDS {
1821e0ebb76SSebastien Boeuf if !self.device_ids[id] {
1831e0ebb76SSebastien Boeuf self.device_ids[id] = true;
1841e0ebb76SSebastien Boeuf Ok(())
1851e0ebb76SSebastien Boeuf } else {
1861e0ebb76SSebastien Boeuf Err(PciRootError::AlreadyInUsePciDeviceSlot(id))
1871e0ebb76SSebastien Boeuf }
1881e0ebb76SSebastien Boeuf } else {
1891e0ebb76SSebastien Boeuf Err(PciRootError::InvalidPciDeviceSlot(id))
1901e0ebb76SSebastien Boeuf }
1911e0ebb76SSebastien Boeuf }
1921e0ebb76SSebastien Boeuf
put_device_id(&mut self, id: usize) -> Result<()>193b50cbe50SSebastien Boeuf pub fn put_device_id(&mut self, id: usize) -> Result<()> {
194b50cbe50SSebastien Boeuf if id < NUM_DEVICE_IDS {
195b50cbe50SSebastien Boeuf self.device_ids[id] = false;
196b50cbe50SSebastien Boeuf Ok(())
197b50cbe50SSebastien Boeuf } else {
198b50cbe50SSebastien Boeuf Err(PciRootError::InvalidPciDeviceSlot(id))
199b50cbe50SSebastien Boeuf }
200b50cbe50SSebastien Boeuf }
201833a3d45SRob Bradford }
202833a3d45SRob Bradford
203833a3d45SRob Bradford pub struct PciConfigIo {
204833a3d45SRob Bradford /// Config space register.
205833a3d45SRob Bradford config_address: u32,
2060eb78ab1SRob Bradford pci_bus: Arc<Mutex<PciBus>>,
207833a3d45SRob Bradford }
208833a3d45SRob Bradford
209833a3d45SRob Bradford impl PciConfigIo {
new(pci_bus: Arc<Mutex<PciBus>>) -> Self2100eb78ab1SRob Bradford pub fn new(pci_bus: Arc<Mutex<PciBus>>) -> Self {
211833a3d45SRob Bradford PciConfigIo {
212833a3d45SRob Bradford config_address: 0,
2130eb78ab1SRob Bradford pci_bus,
214833a3d45SRob Bradford }
215833a3d45SRob Bradford }
2162bb0b22cSJing Liu
config_space_read(&self) -> u322172bb0b22cSJing Liu pub fn config_space_read(&self) -> u32 {
218e8308dd1SSamuel Ortiz let enabled = (self.config_address & 0x8000_0000) != 0;
219e8308dd1SSamuel Ortiz if !enabled {
220e8308dd1SSamuel Ortiz return 0xffff_ffff;
221e8308dd1SSamuel Ortiz }
222e8308dd1SSamuel Ortiz
223b6ae2ccdSSebastien Boeuf let (bus, device, function, register) =
224f6b9445bSQiu Wenbo parse_io_config_address(self.config_address & !0x8000_0000);
2252bb0b22cSJing Liu
2262bb0b22cSJing Liu // Only support one bus.
2272bb0b22cSJing Liu if bus != 0 {
2282bb0b22cSJing Liu return 0xffff_ffff;
229e8308dd1SSamuel Ortiz }
230e8308dd1SSamuel Ortiz
231b6ae2ccdSSebastien Boeuf // Don't support multi-function devices.
232b6ae2ccdSSebastien Boeuf if function > 0 {
233b6ae2ccdSSebastien Boeuf return 0xffff_ffff;
234b6ae2ccdSSebastien Boeuf }
235b6ae2ccdSSebastien Boeuf
236833a3d45SRob Bradford self.pci_bus
2370faa7afaSRob Bradford .as_ref()
238833a3d45SRob Bradford .lock()
239833a3d45SRob Bradford .unwrap()
240833a3d45SRob Bradford .devices
2418d785bbdSSebastien Boeuf .get(&(device as u32))
242833a3d45SRob Bradford .map_or(0xffff_ffff, |d| {
2432bb0b22cSJing Liu d.lock().unwrap().read_config_register(register)
2442bb0b22cSJing Liu })
2452bb0b22cSJing Liu }
2462bb0b22cSJing Liu
config_space_write(&mut self, offset: u64, data: &[u8]) -> Option<Arc<Barrier>>2477cc729c7SRob Bradford pub fn config_space_write(&mut self, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
2482bb0b22cSJing Liu if offset as usize + data.len() > 4 {
2497cc729c7SRob Bradford return None;
2502bb0b22cSJing Liu }
2512bb0b22cSJing Liu
252e8308dd1SSamuel Ortiz let enabled = (self.config_address & 0x8000_0000) != 0;
253e8308dd1SSamuel Ortiz if !enabled {
2547cc729c7SRob Bradford return None;
255e8308dd1SSamuel Ortiz }
256e8308dd1SSamuel Ortiz
2572bb0b22cSJing Liu let (bus, device, _function, register) =
258f6b9445bSQiu Wenbo parse_io_config_address(self.config_address & !0x8000_0000);
2592bb0b22cSJing Liu
2602bb0b22cSJing Liu // Only support one bus.
2612bb0b22cSJing Liu if bus != 0 {
2627cc729c7SRob Bradford return None;
2632bb0b22cSJing Liu }
2642bb0b22cSJing Liu
2650eb78ab1SRob Bradford let pci_bus = self.pci_bus.as_ref().lock().unwrap();
2668d785bbdSSebastien Boeuf if let Some(d) = pci_bus.devices.get(&(device as u32)) {
267149b61b2SSebastien Boeuf let mut device = d.lock().unwrap();
268149b61b2SSebastien Boeuf
269cb52cf91SBo Chen // Update the register value
270cb52cf91SBo Chen let (bar_reprogram, ret) = device.write_config_register(register, offset, data);
271cb52cf91SBo Chen
272cb52cf91SBo Chen // Move the device's BAR if needed
273aaf86ef2SBo Chen for params in &bar_reprogram {
27449268bffSSebastien Boeuf if let Err(e) = pci_bus.device_reloc.move_bar(
275149b61b2SSebastien Boeuf params.old_base,
276149b61b2SSebastien Boeuf params.new_base,
277149b61b2SSebastien Boeuf params.len,
278149b61b2SSebastien Boeuf device.deref_mut(),
279149b61b2SSebastien Boeuf params.region_type,
280d6c68e47SSebastien Boeuf ) {
28156207a03SRob Bradford error!(
28256207a03SRob Bradford "Failed moving device BAR: {}: 0x{:x}->0x{:x}(0x{:x})",
28356207a03SRob Bradford e, params.old_base, params.new_base, params.len
28456207a03SRob Bradford );
285d6c68e47SSebastien Boeuf }
286149b61b2SSebastien Boeuf }
287c7cabc88SSebastien Boeuf
288cb52cf91SBo Chen ret
2897cc729c7SRob Bradford } else {
2907cc729c7SRob Bradford None
2912bb0b22cSJing Liu }
292e8308dd1SSamuel Ortiz }
293e8308dd1SSamuel Ortiz
set_config_address(&mut self, offset: u64, data: &[u8])294e8308dd1SSamuel Ortiz fn set_config_address(&mut self, offset: u64, data: &[u8]) {
295e8308dd1SSamuel Ortiz if offset as usize + data.len() > 4 {
296e8308dd1SSamuel Ortiz return;
297e8308dd1SSamuel Ortiz }
298e8308dd1SSamuel Ortiz let (mask, value): (u32, u32) = match data.len() {
299e8308dd1SSamuel Ortiz 1 => (
300e8308dd1SSamuel Ortiz 0x0000_00ff << (offset * 8),
301e8308dd1SSamuel Ortiz u32::from(data[0]) << (offset * 8),
302e8308dd1SSamuel Ortiz ),
303e8308dd1SSamuel Ortiz 2 => (
304e8308dd1SSamuel Ortiz 0x0000_ffff << (offset * 16),
305b57cc3d7SRob Bradford ((u32::from(data[1]) << 8) | u32::from(data[0])) << (offset * 16),
306e8308dd1SSamuel Ortiz ),
307e8308dd1SSamuel Ortiz 4 => (0xffff_ffff, LittleEndian::read_u32(data)),
308e8308dd1SSamuel Ortiz _ => return,
309e8308dd1SSamuel Ortiz };
310e8308dd1SSamuel Ortiz self.config_address = (self.config_address & !mask) | value;
311e8308dd1SSamuel Ortiz }
312e8308dd1SSamuel Ortiz }
313e8308dd1SSamuel Ortiz
314e8308dd1SSamuel Ortiz impl BusDevice for PciConfigIo {
read(&mut self, _base: u64, offset: u64, data: &mut [u8])3158173e1ccSSamuel Ortiz fn read(&mut self, _base: u64, offset: u64, data: &mut [u8]) {
316e8308dd1SSamuel Ortiz // `offset` is relative to 0xcf8
317e8308dd1SSamuel Ortiz let value = match offset {
318658c076eSSebastien Boeuf 0..=3 => self.config_address,
319658c076eSSebastien Boeuf 4..=7 => self.config_space_read(),
320e8308dd1SSamuel Ortiz _ => 0xffff_ffff,
321e8308dd1SSamuel Ortiz };
322e8308dd1SSamuel Ortiz
323e8308dd1SSamuel Ortiz // Only allow reads to the register boundary.
324e8308dd1SSamuel Ortiz let start = offset as usize % 4;
325e8308dd1SSamuel Ortiz let end = start + data.len();
326e8308dd1SSamuel Ortiz if end <= 4 {
327e8308dd1SSamuel Ortiz for i in start..end {
328e8308dd1SSamuel Ortiz data[i - start] = (value >> (i * 8)) as u8;
329e8308dd1SSamuel Ortiz }
330e8308dd1SSamuel Ortiz } else {
331e8308dd1SSamuel Ortiz for d in data {
332e8308dd1SSamuel Ortiz *d = 0xff;
333e8308dd1SSamuel Ortiz }
334e8308dd1SSamuel Ortiz }
335e8308dd1SSamuel Ortiz }
336e8308dd1SSamuel Ortiz
write(&mut self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>>3371fc6d50fSRob Bradford fn write(&mut self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
338e8308dd1SSamuel Ortiz // `offset` is relative to 0xcf8
339e8308dd1SSamuel Ortiz match offset {
3407cc729c7SRob Bradford o @ 0..=3 => {
3417cc729c7SRob Bradford self.set_config_address(o, data);
3421fc6d50fSRob Bradford None
343e8308dd1SSamuel Ortiz }
3447cc729c7SRob Bradford o @ 4..=7 => self.config_space_write(o - 4, data),
3457cc729c7SRob Bradford _ => None,
3467cc729c7SRob Bradford }
3477cc729c7SRob Bradford }
348e8308dd1SSamuel Ortiz }
349e8308dd1SSamuel Ortiz
350e8308dd1SSamuel Ortiz /// Emulates PCI memory-mapped configuration access mechanism.
351e8308dd1SSamuel Ortiz pub struct PciConfigMmio {
352833a3d45SRob Bradford pci_bus: Arc<Mutex<PciBus>>,
353e8308dd1SSamuel Ortiz }
354e8308dd1SSamuel Ortiz
355e8308dd1SSamuel Ortiz impl PciConfigMmio {
new(pci_bus: Arc<Mutex<PciBus>>) -> Self356833a3d45SRob Bradford pub fn new(pci_bus: Arc<Mutex<PciBus>>) -> Self {
357833a3d45SRob Bradford PciConfigMmio { pci_bus }
358e8308dd1SSamuel Ortiz }
359e8308dd1SSamuel Ortiz
config_space_read(&self, config_address: u32) -> u32360e8308dd1SSamuel Ortiz fn config_space_read(&self, config_address: u32) -> u32 {
361f6b9445bSQiu Wenbo let (bus, device, _function, register) = parse_mmio_config_address(config_address);
3622bb0b22cSJing Liu
3632bb0b22cSJing Liu // Only support one bus.
3642bb0b22cSJing Liu if bus != 0 {
3652bb0b22cSJing Liu return 0xffff_ffff;
3662bb0b22cSJing Liu }
3672bb0b22cSJing Liu
368833a3d45SRob Bradford self.pci_bus
369833a3d45SRob Bradford .lock()
370833a3d45SRob Bradford .unwrap()
371833a3d45SRob Bradford .devices
3728d785bbdSSebastien Boeuf .get(&(device as u32))
373833a3d45SRob Bradford .map_or(0xffff_ffff, |d| {
3742bb0b22cSJing Liu d.lock().unwrap().read_config_register(register)
3752bb0b22cSJing Liu })
376e8308dd1SSamuel Ortiz }
377e8308dd1SSamuel Ortiz
config_space_write(&mut self, config_address: u32, offset: u64, data: &[u8])378e8308dd1SSamuel Ortiz fn config_space_write(&mut self, config_address: u32, offset: u64, data: &[u8]) {
3792bb0b22cSJing Liu if offset as usize + data.len() > 4 {
3802bb0b22cSJing Liu return;
3812bb0b22cSJing Liu }
3822bb0b22cSJing Liu
383f6b9445bSQiu Wenbo let (bus, device, _function, register) = parse_mmio_config_address(config_address);
3842bb0b22cSJing Liu
3852bb0b22cSJing Liu // Only support one bus.
3862bb0b22cSJing Liu if bus != 0 {
3872bb0b22cSJing Liu return;
3882bb0b22cSJing Liu }
3892bb0b22cSJing Liu
390149b61b2SSebastien Boeuf let pci_bus = self.pci_bus.lock().unwrap();
3918d785bbdSSebastien Boeuf if let Some(d) = pci_bus.devices.get(&(device as u32)) {
392149b61b2SSebastien Boeuf let mut device = d.lock().unwrap();
393149b61b2SSebastien Boeuf
394cb52cf91SBo Chen // Update the register value
395cb52cf91SBo Chen let (bar_reprogram, _) = device.write_config_register(register, offset, data);
396cb52cf91SBo Chen
397cb52cf91SBo Chen // Move the device's BAR if needed
398aaf86ef2SBo Chen for params in &bar_reprogram {
39949268bffSSebastien Boeuf if let Err(e) = pci_bus.device_reloc.move_bar(
400149b61b2SSebastien Boeuf params.old_base,
401149b61b2SSebastien Boeuf params.new_base,
402149b61b2SSebastien Boeuf params.len,
403149b61b2SSebastien Boeuf device.deref_mut(),
404149b61b2SSebastien Boeuf params.region_type,
405d6c68e47SSebastien Boeuf ) {
40656207a03SRob Bradford error!(
40756207a03SRob Bradford "Failed moving device BAR: {}: 0x{:x}->0x{:x}(0x{:x})",
40856207a03SRob Bradford e, params.old_base, params.new_base, params.len
40956207a03SRob Bradford );
410d6c68e47SSebastien Boeuf }
411149b61b2SSebastien Boeuf }
4122bb0b22cSJing Liu }
413e8308dd1SSamuel Ortiz }
414e8308dd1SSamuel Ortiz }
415e8308dd1SSamuel Ortiz
416e8308dd1SSamuel Ortiz impl BusDevice for PciConfigMmio {
read(&mut self, _base: u64, offset: u64, data: &mut [u8])4178173e1ccSSamuel Ortiz fn read(&mut self, _base: u64, offset: u64, data: &mut [u8]) {
418e8308dd1SSamuel Ortiz // Only allow reads to the register boundary.
419e8308dd1SSamuel Ortiz let start = offset as usize % 4;
420e8308dd1SSamuel Ortiz let end = start + data.len();
421f6cd3bd8SWei Liu if end > 4 || offset > u64::from(u32::MAX) {
422e8308dd1SSamuel Ortiz for d in data {
423e8308dd1SSamuel Ortiz *d = 0xff;
424e8308dd1SSamuel Ortiz }
425e8308dd1SSamuel Ortiz return;
426e8308dd1SSamuel Ortiz }
427e8308dd1SSamuel Ortiz
428e8308dd1SSamuel Ortiz let value = self.config_space_read(offset as u32);
429e8308dd1SSamuel Ortiz for i in start..end {
430e8308dd1SSamuel Ortiz data[i - start] = (value >> (i * 8)) as u8;
431e8308dd1SSamuel Ortiz }
432e8308dd1SSamuel Ortiz }
433e8308dd1SSamuel Ortiz
write(&mut self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>>4341fc6d50fSRob Bradford fn write(&mut self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
435f6cd3bd8SWei Liu if offset > u64::from(u32::MAX) {
4361fc6d50fSRob Bradford return None;
437e8308dd1SSamuel Ortiz }
4381fc6d50fSRob Bradford self.config_space_write(offset as u32, offset % 4, data);
4391fc6d50fSRob Bradford
4401fc6d50fSRob Bradford None
441e8308dd1SSamuel Ortiz }
442e8308dd1SSamuel Ortiz }
443e8308dd1SSamuel Ortiz
shift_and_mask(value: u32, offset: usize, mask: u32) -> usize444f6b9445bSQiu Wenbo fn shift_and_mask(value: u32, offset: usize, mask: u32) -> usize {
445f6b9445bSQiu Wenbo ((value >> offset) & mask) as usize
446f6b9445bSQiu Wenbo }
447f6b9445bSQiu Wenbo
448f6b9445bSQiu Wenbo // Parse the MMIO address offset to a (bus, device, function, register) tuple.
449f6b9445bSQiu Wenbo // See section 7.2.2 PCI Express Enhanced Configuration Access Mechanism (ECAM)
450f6b9445bSQiu Wenbo // from the Pci Express Base Specification Revision 5.0 Version 1.0.
parse_mmio_config_address(config_address: u32) -> (usize, usize, usize, usize)451f6b9445bSQiu Wenbo fn parse_mmio_config_address(config_address: u32) -> (usize, usize, usize, usize) {
452f6b9445bSQiu Wenbo const BUS_NUMBER_OFFSET: usize = 20;
453f6b9445bSQiu Wenbo const BUS_NUMBER_MASK: u32 = 0x00ff;
454f6b9445bSQiu Wenbo const DEVICE_NUMBER_OFFSET: usize = 15;
455f6b9445bSQiu Wenbo const DEVICE_NUMBER_MASK: u32 = 0x1f;
456f6b9445bSQiu Wenbo const FUNCTION_NUMBER_OFFSET: usize = 12;
457f6b9445bSQiu Wenbo const FUNCTION_NUMBER_MASK: u32 = 0x07;
458f6b9445bSQiu Wenbo const REGISTER_NUMBER_OFFSET: usize = 2;
459f6b9445bSQiu Wenbo const REGISTER_NUMBER_MASK: u32 = 0x3ff;
460f6b9445bSQiu Wenbo
461f6b9445bSQiu Wenbo (
462f6b9445bSQiu Wenbo shift_and_mask(config_address, BUS_NUMBER_OFFSET, BUS_NUMBER_MASK),
463f6b9445bSQiu Wenbo shift_and_mask(config_address, DEVICE_NUMBER_OFFSET, DEVICE_NUMBER_MASK),
464f6b9445bSQiu Wenbo shift_and_mask(config_address, FUNCTION_NUMBER_OFFSET, FUNCTION_NUMBER_MASK),
465f6b9445bSQiu Wenbo shift_and_mask(config_address, REGISTER_NUMBER_OFFSET, REGISTER_NUMBER_MASK),
466f6b9445bSQiu Wenbo )
467f6b9445bSQiu Wenbo }
468f6b9445bSQiu Wenbo
469e8308dd1SSamuel Ortiz // Parse the CONFIG_ADDRESS register to a (bus, device, function, register) tuple.
parse_io_config_address(config_address: u32) -> (usize, usize, usize, usize)470f6b9445bSQiu Wenbo fn parse_io_config_address(config_address: u32) -> (usize, usize, usize, usize) {
471e8308dd1SSamuel Ortiz const BUS_NUMBER_OFFSET: usize = 16;
472e8308dd1SSamuel Ortiz const BUS_NUMBER_MASK: u32 = 0x00ff;
473e8308dd1SSamuel Ortiz const DEVICE_NUMBER_OFFSET: usize = 11;
474e8308dd1SSamuel Ortiz const DEVICE_NUMBER_MASK: u32 = 0x1f;
475e8308dd1SSamuel Ortiz const FUNCTION_NUMBER_OFFSET: usize = 8;
476e8308dd1SSamuel Ortiz const FUNCTION_NUMBER_MASK: u32 = 0x07;
477e8308dd1SSamuel Ortiz const REGISTER_NUMBER_OFFSET: usize = 2;
478e8308dd1SSamuel Ortiz const REGISTER_NUMBER_MASK: u32 = 0x3f;
479e8308dd1SSamuel Ortiz
480f6b9445bSQiu Wenbo (
481f6b9445bSQiu Wenbo shift_and_mask(config_address, BUS_NUMBER_OFFSET, BUS_NUMBER_MASK),
482f6b9445bSQiu Wenbo shift_and_mask(config_address, DEVICE_NUMBER_OFFSET, DEVICE_NUMBER_MASK),
483f6b9445bSQiu Wenbo shift_and_mask(config_address, FUNCTION_NUMBER_OFFSET, FUNCTION_NUMBER_MASK),
484f6b9445bSQiu Wenbo shift_and_mask(config_address, REGISTER_NUMBER_OFFSET, REGISTER_NUMBER_MASK),
485f6b9445bSQiu Wenbo )
486e8308dd1SSamuel Ortiz }
487