• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 //! Implements a stub PCI device. This can be used to put a device on the PCI bus that will
6 //! show up in PCI device enumeration with the configured parameters. The device will otherwise be
7 //! non-functional, in particular it doesn't have any BARs, IRQs etc. and neither will it handle
8 //! config register interactions.
9 //!
10 //! The motivation for stub PCI devices is the case of multifunction PCI devices getting passed
11 //! through via VFIO to the guest. Per PCI device enumeration, functions other than 0 will only be
12 //! scanned if function 0 is present. A stub PCI device is useful in that situation to present
13 //! something to the guest on function 0.
14 
15 use base::RawDescriptor;
16 use resources::Alloc;
17 use resources::SystemAllocator;
18 use serde::Deserialize;
19 use serde::Deserializer;
20 use serde::Serialize;
21 use serde::Serializer;
22 
23 use crate::pci::pci_configuration::PciBarConfiguration;
24 use crate::pci::pci_configuration::PciClassCode;
25 use crate::pci::pci_configuration::PciConfiguration;
26 use crate::pci::pci_configuration::PciHeaderType;
27 use crate::pci::pci_configuration::PciProgrammingInterface;
28 use crate::pci::pci_configuration::PciSubclass;
29 use crate::pci::pci_device::PciDevice;
30 use crate::pci::pci_device::Result;
31 use crate::pci::PciAddress;
32 use crate::pci::PciDeviceError;
33 use crate::Suspendable;
34 
35 #[derive(Debug)]
36 pub struct PciClassParameters {
37     pub class: PciClassCode,
38     pub subclass: u8,
39     pub programming_interface: u8,
40 }
41 
42 impl Default for PciClassParameters {
default() -> Self43     fn default() -> Self {
44         PciClassParameters {
45             class: PciClassCode::Other,
46             subclass: 0,
47             programming_interface: 0,
48         }
49     }
50 }
51 
52 // Deserialize the combined class, subclass, and programming interface as a single numeric value.
53 // This matches the numeric format used in `/sys/bus/pci/devices/*/class`.
54 impl<'de> Deserialize<'de> for PciClassParameters {
deserialize<D>(deserializer: D) -> std::result::Result<PciClassParameters, D::Error> where D: Deserializer<'de>,55     fn deserialize<D>(deserializer: D) -> std::result::Result<PciClassParameters, D::Error>
56     where
57         D: Deserializer<'de>,
58     {
59         let class_numeric = u32::deserialize(deserializer)?;
60 
61         let class_code = (class_numeric >> 16) as u8;
62         let class = PciClassCode::try_from(class_code as u8).map_err(|_| {
63             serde::de::Error::custom(format!("Unknown class code {:#x}", class_code))
64         })?;
65 
66         let subclass = (class_numeric >> 8) as u8;
67 
68         let programming_interface = class_numeric as u8;
69 
70         Ok(PciClassParameters {
71             class,
72             subclass,
73             programming_interface,
74         })
75     }
76 }
77 
78 impl Serialize for PciClassParameters {
serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> where S: Serializer,79     fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
80     where
81         S: Serializer,
82     {
83         let class_numeric: u32 = ((self.class as u32) << 16)
84             | ((self.subclass as u32) << 8)
85             | self.programming_interface as u32;
86 
87         serializer.serialize_u32(class_numeric)
88     }
89 }
90 
91 #[derive(Serialize, Deserialize, Debug, serde_keyvalue::FromKeyValues)]
92 #[serde(deny_unknown_fields, rename_all = "kebab-case")]
93 pub struct StubPciParameters {
94     pub address: PciAddress,
95     #[serde(default)]
96     pub vendor: u16,
97     #[serde(default)]
98     pub device: u16,
99     #[serde(default)]
100     pub class: PciClassParameters,
101     #[serde(default, alias = "subsystem_vendor")]
102     pub subsystem_vendor: u16,
103     #[serde(default, alias = "subsystem_device")]
104     pub subsystem_device: u16,
105     #[serde(default)]
106     pub revision: u8,
107 }
108 
109 pub struct StubPciDevice {
110     requested_address: PciAddress,
111     assigned_address: Option<PciAddress>,
112     config_regs: PciConfiguration,
113 }
114 
115 struct NumericPciSubClass(u8);
116 
117 impl PciSubclass for NumericPciSubClass {
get_register_value(&self) -> u8118     fn get_register_value(&self) -> u8 {
119         self.0
120     }
121 }
122 
123 struct NumericPciProgrammingInterface(u8);
124 
125 impl PciProgrammingInterface for NumericPciProgrammingInterface {
get_register_value(&self) -> u8126     fn get_register_value(&self) -> u8 {
127         self.0
128     }
129 }
130 
131 impl StubPciDevice {
new(config: &StubPciParameters) -> StubPciDevice132     pub fn new(config: &StubPciParameters) -> StubPciDevice {
133         let config_regs = PciConfiguration::new(
134             config.vendor,
135             config.device,
136             config.class.class,
137             &NumericPciSubClass(config.class.subclass),
138             Some(&NumericPciProgrammingInterface(
139                 config.class.programming_interface,
140             )),
141             PciHeaderType::Device,
142             config.subsystem_vendor,
143             config.subsystem_device,
144             config.revision,
145         );
146 
147         Self {
148             requested_address: config.address,
149             assigned_address: None,
150             config_regs,
151         }
152     }
153 }
154 
155 impl PciDevice for StubPciDevice {
debug_label(&self) -> String156     fn debug_label(&self) -> String {
157         "Stub".to_owned()
158     }
159 
preferred_address(&self) -> Option<PciAddress>160     fn preferred_address(&self) -> Option<PciAddress> {
161         Some(self.requested_address)
162     }
163 
allocate_address(&mut self, resources: &mut SystemAllocator) -> Result<PciAddress>164     fn allocate_address(&mut self, resources: &mut SystemAllocator) -> Result<PciAddress> {
165         if self.assigned_address.is_none() {
166             if resources.reserve_pci(
167                 Alloc::PciBar {
168                     bus: self.requested_address.bus,
169                     dev: self.requested_address.dev,
170                     func: self.requested_address.func,
171                     bar: 0,
172                 },
173                 self.debug_label(),
174             ) {
175                 self.assigned_address = Some(self.requested_address);
176             }
177         }
178         self.assigned_address
179             .ok_or(PciDeviceError::PciAllocationFailed)
180     }
181 
keep_rds(&self) -> Vec<RawDescriptor>182     fn keep_rds(&self) -> Vec<RawDescriptor> {
183         Vec::new()
184     }
185 
get_bar_configuration(&self, bar_num: usize) -> Option<PciBarConfiguration>186     fn get_bar_configuration(&self, bar_num: usize) -> Option<PciBarConfiguration> {
187         self.config_regs.get_bar_configuration(bar_num)
188     }
189 
read_config_register(&self, reg_idx: usize) -> u32190     fn read_config_register(&self, reg_idx: usize) -> u32 {
191         self.config_regs.read_reg(reg_idx)
192     }
193 
write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8])194     fn write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8]) {
195         self.config_regs.write_reg(reg_idx, offset, data)
196     }
197 
read_bar(&mut self, _addr: u64, _data: &mut [u8])198     fn read_bar(&mut self, _addr: u64, _data: &mut [u8]) {}
199 
write_bar(&mut self, _addr: u64, _data: &[u8])200     fn write_bar(&mut self, _addr: u64, _data: &[u8]) {}
201 }
202 
203 impl Suspendable for StubPciDevice {
sleep(&mut self) -> anyhow::Result<()>204     fn sleep(&mut self) -> anyhow::Result<()> {
205         // There are no workers to sleep/wake.
206         Ok(())
207     }
208 
wake(&mut self) -> anyhow::Result<()>209     fn wake(&mut self) -> anyhow::Result<()> {
210         // There are no workers to sleep/wake.
211         Ok(())
212     }
213 }
214 
215 #[cfg(test)]
216 mod test {
217     use resources::AddressRange;
218     use resources::SystemAllocator;
219     use resources::SystemAllocatorConfig;
220     use serde_keyvalue::from_key_values;
221     use serde_keyvalue::ErrorKind;
222     use serde_keyvalue::ParseError;
223 
224     use super::*;
225 
226     const CONFIG: StubPciParameters = StubPciParameters {
227         address: PciAddress {
228             bus: 0x0a,
229             dev: 0x0b,
230             func: 0x1,
231         },
232         vendor: 2,
233         device: 3,
234         class: PciClassParameters {
235             class: PciClassCode::MultimediaController,
236             subclass: 5,
237             programming_interface: 6,
238         },
239         subsystem_vendor: 7,
240         subsystem_device: 8,
241         revision: 9,
242     };
243 
from_stub_arg(options: &str) -> std::result::Result<StubPciParameters, ParseError>244     fn from_stub_arg(options: &str) -> std::result::Result<StubPciParameters, ParseError> {
245         from_key_values(options)
246     }
247 
248     #[test]
configuration()249     fn configuration() {
250         let device = StubPciDevice::new(&CONFIG);
251 
252         assert_eq!(device.read_config_register(0), 0x0003_0002);
253         assert_eq!(device.read_config_register(2), 0x04_05_06_09);
254         assert_eq!(device.read_config_register(11), 0x0008_0007);
255     }
256 
257     #[test]
address_allocation()258     fn address_allocation() {
259         let mut allocator = SystemAllocator::new(
260             SystemAllocatorConfig {
261                 io: Some(AddressRange {
262                     start: 0x1000,
263                     end: 0x2fff,
264                 }),
265                 low_mmio: AddressRange {
266                     start: 0x2000_0000,
267                     end: 0x2fff_ffff,
268                 },
269                 high_mmio: AddressRange {
270                     start: 0x1_0000_0000,
271                     end: 0x1_0fff_ffff,
272                 },
273                 platform_mmio: None,
274                 first_irq: 5,
275             },
276             None,
277             &[],
278         )
279         .unwrap();
280         let mut device = StubPciDevice::new(&CONFIG);
281 
282         assert!(device.allocate_address(&mut allocator).is_ok());
283         assert!(allocator.release_pci(0xa, 0xb, 1));
284     }
285 
286     #[test]
params_missing_address()287     fn params_missing_address() {
288         // PCI address argument is mandatory.
289         let err = from_stub_arg("").unwrap_err();
290         assert_eq!(
291             err,
292             ParseError {
293                 kind: ErrorKind::SerdeError("missing field `address`".into()),
294                 pos: 0,
295             }
296         );
297     }
298 
299     #[test]
params_address_implicit()300     fn params_address_implicit() {
301         // Address is the default argument.
302         let params = from_stub_arg("0000:00:01.2").unwrap();
303         assert_eq!(
304             params.address,
305             PciAddress {
306                 bus: 0,
307                 dev: 1,
308                 func: 2
309             }
310         );
311     }
312 
313     #[test]
params_address_explicit()314     fn params_address_explicit() {
315         // Explicitly-specified address.
316         let params = from_stub_arg("address=0000:00:01.2").unwrap();
317         assert_eq!(
318             params.address,
319             PciAddress {
320                 bus: 0,
321                 dev: 1,
322                 func: 2
323             }
324         );
325     }
326 
327     #[test]
params_class()328     fn params_class() {
329         // Class, subclass, and programming interface are encoded as a single number.
330         let params = from_stub_arg("address=0000:00:01.2,class=0x012345").unwrap();
331         assert_eq!(params.class.class, PciClassCode::MassStorage);
332         assert_eq!(params.class.subclass, 0x23);
333         assert_eq!(params.class.programming_interface, 0x45);
334     }
335 
336     #[test]
params_subsystem_underscores()337     fn params_subsystem_underscores() {
338         // Accept aliases with underscores rather than hyphens for compatibility.
339         let params =
340             from_stub_arg("address=0000:00:01.2,subsystem_vendor=0x8675,subsystem_device=0x309")
341                 .unwrap();
342         assert_eq!(params.subsystem_vendor, 0x8675);
343         assert_eq!(params.subsystem_device, 0x0309);
344     }
345 
346     #[test]
params_full()347     fn params_full() {
348         let params = from_stub_arg(
349             "address=0000:00:01.2,vendor=0x1234,device=0x5678,subsystem-vendor=0x8675,subsystem-device=0x309,class=0x012345,revision=52",
350         ).unwrap();
351         assert_eq!(
352             params.address,
353             PciAddress {
354                 bus: 0,
355                 dev: 1,
356                 func: 2
357             }
358         );
359         assert_eq!(params.vendor, 0x1234);
360         assert_eq!(params.device, 0x5678);
361         assert_eq!(params.subsystem_vendor, 0x8675);
362         assert_eq!(params.subsystem_device, 0x0309);
363         assert_eq!(params.class.class, PciClassCode::MassStorage);
364         assert_eq!(params.class.subclass, 0x23);
365         assert_eq!(params.class.programming_interface, 0x45);
366         assert_eq!(params.revision, 52);
367     }
368 }
369