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