xref: /cloud-hypervisor/pci/src/bus.rs (revision 190a11f2124b0b60a2d44e85b7c9988373acfb6d)
1 // Copyright 2018 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE-BSD-3-Clause file.
4 //
5 // SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
6 
7 use std::any::Any;
8 use std::collections::HashMap;
9 use std::ops::DerefMut;
10 use std::sync::{Arc, Barrier, Mutex};
11 
12 use byteorder::{ByteOrder, LittleEndian};
13 use thiserror::Error;
14 use vm_device::{Bus, BusDevice, BusDeviceSync};
15 
16 use crate::configuration::{
17     PciBarRegionType, PciBridgeSubclass, PciClassCode, PciConfiguration, PciHeaderType,
18 };
19 use crate::device::{BarReprogrammingParams, DeviceRelocation, Error as PciDeviceError, PciDevice};
20 use crate::PciBarConfiguration;
21 
22 const VENDOR_ID_INTEL: u16 = 0x8086;
23 const DEVICE_ID_INTEL_VIRT_PCIE_HOST: u16 = 0x0d57;
24 const NUM_DEVICE_IDS: usize = 32;
25 
26 /// Errors for device manager.
27 #[derive(Error, Debug)]
28 pub enum PciRootError {
29     /// Could not allocate device address space for the device.
30     #[error("Could not allocate device address space for the device")]
31     AllocateDeviceAddrs(#[source] PciDeviceError),
32     /// Could not allocate an IRQ number.
33     #[error("Could not allocate an IRQ number")]
34     AllocateIrq,
35     /// Could not add a device to the port io bus.
36     #[error("Could not add a device to the port io bus")]
37     PioInsert(#[source] vm_device::BusError),
38     /// Could not add a device to the mmio bus.
39     #[error("Could not add a device to the mmio bus")]
40     MmioInsert(#[source] vm_device::BusError),
41     /// Could not find an available device slot on the PCI bus.
42     #[error("Could not find an available device slot on the PCI bus")]
43     NoPciDeviceSlotAvailable,
44     /// Invalid PCI device identifier provided.
45     #[error("Invalid PCI device identifier provided")]
46     InvalidPciDeviceSlot(usize),
47     /// Valid PCI device identifier but already used.
48     #[error("Valid PCI device identifier but already used")]
49     AlreadyInUsePciDeviceSlot(usize),
50 }
51 pub type Result<T> = std::result::Result<T, PciRootError>;
52 
53 /// Emulates the PCI Root bridge device.
54 pub struct PciRoot {
55     /// Configuration space.
56     config: PciConfiguration,
57 }
58 
59 impl PciRoot {
60     /// Create an empty PCI root bridge.
61     pub fn new(config: Option<PciConfiguration>) -> Self {
62         if let Some(config) = config {
63             PciRoot { config }
64         } else {
65             PciRoot {
66                 config: PciConfiguration::new(
67                     VENDOR_ID_INTEL,
68                     DEVICE_ID_INTEL_VIRT_PCIE_HOST,
69                     0,
70                     PciClassCode::BridgeDevice,
71                     &PciBridgeSubclass::HostBridge,
72                     None,
73                     PciHeaderType::Device,
74                     0,
75                     0,
76                     None,
77                     None,
78                 ),
79             }
80         }
81     }
82 }
83 
84 impl BusDevice for PciRoot {}
85 
86 impl PciDevice for PciRoot {
87     fn write_config_register(
88         &mut self,
89         reg_idx: usize,
90         offset: u64,
91         data: &[u8],
92     ) -> (Vec<BarReprogrammingParams>, Option<Arc<Barrier>>) {
93         (
94             self.config.write_config_register(reg_idx, offset, data),
95             None,
96         )
97     }
98 
99     fn read_config_register(&mut self, reg_idx: usize) -> u32 {
100         self.config.read_reg(reg_idx)
101     }
102 
103     fn as_any_mut(&mut self) -> &mut dyn Any {
104         self
105     }
106 
107     fn id(&self) -> Option<String> {
108         None
109     }
110 }
111 
112 pub struct PciBus {
113     /// Devices attached to this bus.
114     /// Device 0 is host bridge.
115     devices: HashMap<u32, Arc<Mutex<dyn PciDevice>>>,
116     device_reloc: Arc<dyn DeviceRelocation>,
117     device_ids: Vec<bool>,
118 }
119 
120 impl PciBus {
121     pub fn new(pci_root: PciRoot, device_reloc: Arc<dyn DeviceRelocation>) -> Self {
122         let mut devices: HashMap<u32, Arc<Mutex<dyn PciDevice>>> = HashMap::new();
123         let mut device_ids: Vec<bool> = vec![false; NUM_DEVICE_IDS];
124 
125         devices.insert(0, Arc::new(Mutex::new(pci_root)));
126         device_ids[0] = true;
127 
128         PciBus {
129             devices,
130             device_reloc,
131             device_ids,
132         }
133     }
134 
135     pub fn register_mapping(
136         &self,
137         dev: Arc<dyn BusDeviceSync>,
138         io_bus: &Bus,
139         mmio_bus: &Bus,
140         bars: Vec<PciBarConfiguration>,
141     ) -> Result<()> {
142         for bar in bars {
143             match bar.region_type() {
144                 PciBarRegionType::IoRegion => {
145                     io_bus
146                         .insert(dev.clone(), bar.addr(), bar.size())
147                         .map_err(PciRootError::PioInsert)?;
148                 }
149                 PciBarRegionType::Memory32BitRegion | PciBarRegionType::Memory64BitRegion => {
150                     mmio_bus
151                         .insert(dev.clone(), bar.addr(), bar.size())
152                         .map_err(PciRootError::MmioInsert)?;
153                 }
154             }
155         }
156         Ok(())
157     }
158 
159     pub fn add_device(&mut self, device_id: u32, device: Arc<Mutex<dyn PciDevice>>) -> Result<()> {
160         self.devices.insert(device_id, device);
161         Ok(())
162     }
163 
164     pub fn remove_by_device(&mut self, device: &Arc<Mutex<dyn PciDevice>>) -> Result<()> {
165         self.devices.retain(|_, dev| !Arc::ptr_eq(dev, device));
166         Ok(())
167     }
168 
169     pub fn next_device_id(&mut self) -> Result<u32> {
170         for (idx, device_id) in self.device_ids.iter_mut().enumerate() {
171             if !(*device_id) {
172                 *device_id = true;
173                 return Ok(idx as u32);
174             }
175         }
176 
177         Err(PciRootError::NoPciDeviceSlotAvailable)
178     }
179 
180     pub fn get_device_id(&mut self, id: usize) -> Result<()> {
181         if id < NUM_DEVICE_IDS {
182             if !self.device_ids[id] {
183                 self.device_ids[id] = true;
184                 Ok(())
185             } else {
186                 Err(PciRootError::AlreadyInUsePciDeviceSlot(id))
187             }
188         } else {
189             Err(PciRootError::InvalidPciDeviceSlot(id))
190         }
191     }
192 
193     pub fn put_device_id(&mut self, id: usize) -> Result<()> {
194         if id < NUM_DEVICE_IDS {
195             self.device_ids[id] = false;
196             Ok(())
197         } else {
198             Err(PciRootError::InvalidPciDeviceSlot(id))
199         }
200     }
201 }
202 
203 pub struct PciConfigIo {
204     /// Config space register.
205     config_address: u32,
206     pci_bus: Arc<Mutex<PciBus>>,
207 }
208 
209 impl PciConfigIo {
210     pub fn new(pci_bus: Arc<Mutex<PciBus>>) -> Self {
211         PciConfigIo {
212             config_address: 0,
213             pci_bus,
214         }
215     }
216 
217     pub fn config_space_read(&self) -> u32 {
218         let enabled = (self.config_address & 0x8000_0000) != 0;
219         if !enabled {
220             return 0xffff_ffff;
221         }
222 
223         let (bus, device, function, register) =
224             parse_io_config_address(self.config_address & !0x8000_0000);
225 
226         // Only support one bus.
227         if bus != 0 {
228             return 0xffff_ffff;
229         }
230 
231         // Don't support multi-function devices.
232         if function > 0 {
233             return 0xffff_ffff;
234         }
235 
236         self.pci_bus
237             .as_ref()
238             .lock()
239             .unwrap()
240             .devices
241             .get(&(device as u32))
242             .map_or(0xffff_ffff, |d| {
243                 d.lock().unwrap().read_config_register(register)
244             })
245     }
246 
247     pub fn config_space_write(&mut self, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
248         if offset as usize + data.len() > 4 {
249             return None;
250         }
251 
252         let enabled = (self.config_address & 0x8000_0000) != 0;
253         if !enabled {
254             return None;
255         }
256 
257         let (bus, device, _function, register) =
258             parse_io_config_address(self.config_address & !0x8000_0000);
259 
260         // Only support one bus.
261         if bus != 0 {
262             return None;
263         }
264 
265         let pci_bus = self.pci_bus.as_ref().lock().unwrap();
266         if let Some(d) = pci_bus.devices.get(&(device as u32)) {
267             let mut device = d.lock().unwrap();
268 
269             // Update the register value
270             let (bar_reprogram, ret) = device.write_config_register(register, offset, data);
271 
272             // Move the device's BAR if needed
273             for params in &bar_reprogram {
274                 if let Err(e) = pci_bus.device_reloc.move_bar(
275                     params.old_base,
276                     params.new_base,
277                     params.len,
278                     device.deref_mut(),
279                     params.region_type,
280                 ) {
281                     error!(
282                         "Failed moving device BAR: {}: 0x{:x}->0x{:x}(0x{:x})",
283                         e, params.old_base, params.new_base, params.len
284                     );
285                 }
286             }
287 
288             ret
289         } else {
290             None
291         }
292     }
293 
294     fn set_config_address(&mut self, offset: u64, data: &[u8]) {
295         if offset as usize + data.len() > 4 {
296             return;
297         }
298         let (mask, value): (u32, u32) = match data.len() {
299             1 => (
300                 0x0000_00ff << (offset * 8),
301                 u32::from(data[0]) << (offset * 8),
302             ),
303             2 => (
304                 0x0000_ffff << (offset * 16),
305                 ((u32::from(data[1]) << 8) | u32::from(data[0])) << (offset * 16),
306             ),
307             4 => (0xffff_ffff, LittleEndian::read_u32(data)),
308             _ => return,
309         };
310         self.config_address = (self.config_address & !mask) | value;
311     }
312 }
313 
314 impl BusDevice for PciConfigIo {
315     fn read(&mut self, _base: u64, offset: u64, data: &mut [u8]) {
316         // `offset` is relative to 0xcf8
317         let value = match offset {
318             0..=3 => self.config_address,
319             4..=7 => self.config_space_read(),
320             _ => 0xffff_ffff,
321         };
322 
323         // Only allow reads to the register boundary.
324         let start = offset as usize % 4;
325         let end = start + data.len();
326         if end <= 4 {
327             for i in start..end {
328                 data[i - start] = (value >> (i * 8)) as u8;
329             }
330         } else {
331             for d in data {
332                 *d = 0xff;
333             }
334         }
335     }
336 
337     fn write(&mut self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
338         // `offset` is relative to 0xcf8
339         match offset {
340             o @ 0..=3 => {
341                 self.set_config_address(o, data);
342                 None
343             }
344             o @ 4..=7 => self.config_space_write(o - 4, data),
345             _ => None,
346         }
347     }
348 }
349 
350 /// Emulates PCI memory-mapped configuration access mechanism.
351 pub struct PciConfigMmio {
352     pci_bus: Arc<Mutex<PciBus>>,
353 }
354 
355 impl PciConfigMmio {
356     pub fn new(pci_bus: Arc<Mutex<PciBus>>) -> Self {
357         PciConfigMmio { pci_bus }
358     }
359 
360     fn config_space_read(&self, config_address: u32) -> u32 {
361         let (bus, device, _function, register) = parse_mmio_config_address(config_address);
362 
363         // Only support one bus.
364         if bus != 0 {
365             return 0xffff_ffff;
366         }
367 
368         self.pci_bus
369             .lock()
370             .unwrap()
371             .devices
372             .get(&(device as u32))
373             .map_or(0xffff_ffff, |d| {
374                 d.lock().unwrap().read_config_register(register)
375             })
376     }
377 
378     fn config_space_write(&mut self, config_address: u32, offset: u64, data: &[u8]) {
379         if offset as usize + data.len() > 4 {
380             return;
381         }
382 
383         let (bus, device, _function, register) = parse_mmio_config_address(config_address);
384 
385         // Only support one bus.
386         if bus != 0 {
387             return;
388         }
389 
390         let pci_bus = self.pci_bus.lock().unwrap();
391         if let Some(d) = pci_bus.devices.get(&(device as u32)) {
392             let mut device = d.lock().unwrap();
393 
394             // Update the register value
395             let (bar_reprogram, _) = device.write_config_register(register, offset, data);
396 
397             // Move the device's BAR if needed
398             for params in &bar_reprogram {
399                 if let Err(e) = pci_bus.device_reloc.move_bar(
400                     params.old_base,
401                     params.new_base,
402                     params.len,
403                     device.deref_mut(),
404                     params.region_type,
405                 ) {
406                     error!(
407                         "Failed moving device BAR: {}: 0x{:x}->0x{:x}(0x{:x})",
408                         e, params.old_base, params.new_base, params.len
409                     );
410                 }
411             }
412         }
413     }
414 }
415 
416 impl BusDevice for PciConfigMmio {
417     fn read(&mut self, _base: u64, offset: u64, data: &mut [u8]) {
418         // Only allow reads to the register boundary.
419         let start = offset as usize % 4;
420         let end = start + data.len();
421         if end > 4 || offset > u64::from(u32::MAX) {
422             for d in data {
423                 *d = 0xff;
424             }
425             return;
426         }
427 
428         let value = self.config_space_read(offset as u32);
429         for i in start..end {
430             data[i - start] = (value >> (i * 8)) as u8;
431         }
432     }
433 
434     fn write(&mut self, _base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
435         if offset > u64::from(u32::MAX) {
436             return None;
437         }
438         self.config_space_write(offset as u32, offset % 4, data);
439 
440         None
441     }
442 }
443 
444 fn shift_and_mask(value: u32, offset: usize, mask: u32) -> usize {
445     ((value >> offset) & mask) as usize
446 }
447 
448 // Parse the MMIO address offset to a (bus, device, function, register) tuple.
449 // See section 7.2.2 PCI Express Enhanced Configuration Access Mechanism (ECAM)
450 // from the Pci Express Base Specification Revision 5.0 Version 1.0.
451 fn parse_mmio_config_address(config_address: u32) -> (usize, usize, usize, usize) {
452     const BUS_NUMBER_OFFSET: usize = 20;
453     const BUS_NUMBER_MASK: u32 = 0x00ff;
454     const DEVICE_NUMBER_OFFSET: usize = 15;
455     const DEVICE_NUMBER_MASK: u32 = 0x1f;
456     const FUNCTION_NUMBER_OFFSET: usize = 12;
457     const FUNCTION_NUMBER_MASK: u32 = 0x07;
458     const REGISTER_NUMBER_OFFSET: usize = 2;
459     const REGISTER_NUMBER_MASK: u32 = 0x3ff;
460 
461     (
462         shift_and_mask(config_address, BUS_NUMBER_OFFSET, BUS_NUMBER_MASK),
463         shift_and_mask(config_address, DEVICE_NUMBER_OFFSET, DEVICE_NUMBER_MASK),
464         shift_and_mask(config_address, FUNCTION_NUMBER_OFFSET, FUNCTION_NUMBER_MASK),
465         shift_and_mask(config_address, REGISTER_NUMBER_OFFSET, REGISTER_NUMBER_MASK),
466     )
467 }
468 
469 // Parse the CONFIG_ADDRESS register to a (bus, device, function, register) tuple.
470 fn parse_io_config_address(config_address: u32) -> (usize, usize, usize, usize) {
471     const BUS_NUMBER_OFFSET: usize = 16;
472     const BUS_NUMBER_MASK: u32 = 0x00ff;
473     const DEVICE_NUMBER_OFFSET: usize = 11;
474     const DEVICE_NUMBER_MASK: u32 = 0x1f;
475     const FUNCTION_NUMBER_OFFSET: usize = 8;
476     const FUNCTION_NUMBER_MASK: u32 = 0x07;
477     const REGISTER_NUMBER_OFFSET: usize = 2;
478     const REGISTER_NUMBER_MASK: u32 = 0x3f;
479 
480     (
481         shift_and_mask(config_address, BUS_NUMBER_OFFSET, BUS_NUMBER_MASK),
482         shift_and_mask(config_address, DEVICE_NUMBER_OFFSET, DEVICE_NUMBER_MASK),
483         shift_and_mask(config_address, FUNCTION_NUMBER_OFFSET, FUNCTION_NUMBER_MASK),
484         shift_and_mask(config_address, REGISTER_NUMBER_OFFSET, REGISTER_NUMBER_MASK),
485     )
486 }
487