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