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