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