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