• 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::SystemAllocator;
17 use serde::Deserialize;
18 use serde::Deserializer;
19 use serde::Serialize;
20 use serde::Serializer;
21 use snapshot::AnySnapshot;
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::PciBarIndex;
33 use crate::pci::PciDeviceError;
34 use crate::Suspendable;
35 
36 #[derive(Debug)]
37 pub struct PciClassParameters {
38     pub class: PciClassCode,
39     pub subclass: u8,
40     pub programming_interface: u8,
41 }
42 
43 impl Default for PciClassParameters {
default() -> Self44     fn default() -> Self {
45         PciClassParameters {
46             class: PciClassCode::Other,
47             subclass: 0,
48             programming_interface: 0,
49         }
50     }
51 }
52 
53 // Deserialize the combined class, subclass, and programming interface as a single numeric value.
54 // This matches the numeric format used in `/sys/bus/pci/devices/*/class`.
55 impl<'de> Deserialize<'de> for PciClassParameters {
deserialize<D>(deserializer: D) -> std::result::Result<PciClassParameters, D::Error> where D: Deserializer<'de>,56     fn deserialize<D>(deserializer: D) -> std::result::Result<PciClassParameters, D::Error>
57     where
58         D: Deserializer<'de>,
59     {
60         let class_numeric = u32::deserialize(deserializer)?;
61 
62         let class_code = (class_numeric >> 16) as u8;
63         let class = PciClassCode::try_from(class_code).map_err(|_| {
64             serde::de::Error::custom(format!("Unknown class code {:#x}", class_code))
65         })?;
66 
67         let subclass = (class_numeric >> 8) as u8;
68 
69         let programming_interface = class_numeric as u8;
70 
71         Ok(PciClassParameters {
72             class,
73             subclass,
74             programming_interface,
75         })
76     }
77 }
78 
79 impl Serialize for PciClassParameters {
serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> where S: Serializer,80     fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
81     where
82         S: Serializer,
83     {
84         let class_numeric: u32 = ((self.class as u32) << 16)
85             | ((self.subclass as u32) << 8)
86             | self.programming_interface as u32;
87 
88         serializer.serialize_u32(class_numeric)
89     }
90 }
91 
92 #[derive(Serialize, Deserialize, Debug, serde_keyvalue::FromKeyValues)]
93 #[serde(deny_unknown_fields, rename_all = "kebab-case")]
94 pub struct StubPciParameters {
95     pub address: PciAddress,
96     #[serde(default)]
97     pub vendor: u16,
98     #[serde(default)]
99     pub device: u16,
100     #[serde(default)]
101     pub class: PciClassParameters,
102     #[serde(default, alias = "subsystem_vendor")]
103     pub subsystem_vendor: u16,
104     #[serde(default, alias = "subsystem_device")]
105     pub subsystem_device: u16,
106     #[serde(default)]
107     pub revision: u8,
108 }
109 
110 pub struct StubPciDevice {
111     requested_address: PciAddress,
112     assigned_address: Option<PciAddress>,
113     config_regs: PciConfiguration,
114 }
115 
116 struct NumericPciSubClass(u8);
117 
118 impl PciSubclass for NumericPciSubClass {
get_register_value(&self) -> u8119     fn get_register_value(&self) -> u8 {
120         self.0
121     }
122 }
123 
124 struct NumericPciProgrammingInterface(u8);
125 
126 impl PciProgrammingInterface for NumericPciProgrammingInterface {
get_register_value(&self) -> u8127     fn get_register_value(&self) -> u8 {
128         self.0
129     }
130 }
131 
132 impl StubPciDevice {
new(config: &StubPciParameters) -> StubPciDevice133     pub fn new(config: &StubPciParameters) -> StubPciDevice {
134         let config_regs = PciConfiguration::new(
135             config.vendor,
136             config.device,
137             config.class.class,
138             &NumericPciSubClass(config.class.subclass),
139             Some(&NumericPciProgrammingInterface(
140                 config.class.programming_interface,
141             )),
142             PciHeaderType::Device,
143             config.subsystem_vendor,
144             config.subsystem_device,
145             config.revision,
146         );
147 
148         Self {
149             requested_address: config.address,
150             assigned_address: None,
151             config_regs,
152         }
153     }
154 }
155 
156 impl PciDevice for StubPciDevice {
debug_label(&self) -> String157     fn debug_label(&self) -> String {
158         "Stub".to_owned()
159     }
160 
preferred_address(&self) -> Option<PciAddress>161     fn preferred_address(&self) -> Option<PciAddress> {
162         Some(self.requested_address)
163     }
164 
allocate_address(&mut self, resources: &mut SystemAllocator) -> Result<PciAddress>165     fn allocate_address(&mut self, resources: &mut SystemAllocator) -> Result<PciAddress> {
166         if self.assigned_address.is_none() {
167             if resources.reserve_pci(self.requested_address, self.debug_label()) {
168                 self.assigned_address = Some(self.requested_address);
169             }
170         }
171         self.assigned_address
172             .ok_or(PciDeviceError::PciAllocationFailed)
173     }
174 
keep_rds(&self) -> Vec<RawDescriptor>175     fn keep_rds(&self) -> Vec<RawDescriptor> {
176         Vec::new()
177     }
178 
get_bar_configuration(&self, bar_num: usize) -> Option<PciBarConfiguration>179     fn get_bar_configuration(&self, bar_num: usize) -> Option<PciBarConfiguration> {
180         self.config_regs.get_bar_configuration(bar_num)
181     }
182 
read_config_register(&self, reg_idx: usize) -> u32183     fn read_config_register(&self, reg_idx: usize) -> u32 {
184         self.config_regs.read_reg(reg_idx)
185     }
186 
write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8])187     fn write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8]) {
188         self.config_regs.write_reg(reg_idx, offset, data);
189     }
190 
read_bar(&mut self, _bar_index: PciBarIndex, _offset: u64, _data: &mut [u8])191     fn read_bar(&mut self, _bar_index: PciBarIndex, _offset: u64, _data: &mut [u8]) {}
192 
write_bar(&mut self, _bar_index: PciBarIndex, _offset: u64, _data: &[u8])193     fn write_bar(&mut self, _bar_index: PciBarIndex, _offset: u64, _data: &[u8]) {}
194 }
195 
196 impl Suspendable for StubPciDevice {
sleep(&mut self) -> anyhow::Result<()>197     fn sleep(&mut self) -> anyhow::Result<()> {
198         // There are no workers to sleep/wake.
199         Ok(())
200     }
201 
wake(&mut self) -> anyhow::Result<()>202     fn wake(&mut self) -> anyhow::Result<()> {
203         // There are no workers to sleep/wake.
204         Ok(())
205     }
206 
snapshot(&mut self) -> anyhow::Result<AnySnapshot>207     fn snapshot(&mut self) -> anyhow::Result<AnySnapshot> {
208         self.config_regs.snapshot()
209     }
210 
restore(&mut self, data: AnySnapshot) -> anyhow::Result<()>211     fn restore(&mut self, data: AnySnapshot) -> anyhow::Result<()> {
212         self.config_regs.restore(data)
213     }
214 }
215 
216 #[cfg(test)]
217 mod test {
218     use resources::AddressRange;
219     use resources::SystemAllocator;
220     use resources::SystemAllocatorConfig;
221     use serde_keyvalue::from_key_values;
222     use serde_keyvalue::ErrorKind;
223     use serde_keyvalue::ParseError;
224 
225     use super::*;
226 
227     const CONFIG: StubPciParameters = StubPciParameters {
228         address: PciAddress {
229             bus: 0x0a,
230             dev: 0x0b,
231             func: 0x1,
232         },
233         vendor: 2,
234         device: 3,
235         class: PciClassParameters {
236             class: PciClassCode::MultimediaController,
237             subclass: 5,
238             programming_interface: 6,
239         },
240         subsystem_vendor: 7,
241         subsystem_device: 8,
242         revision: 9,
243     };
244 
from_stub_arg(options: &str) -> std::result::Result<StubPciParameters, ParseError>245     fn from_stub_arg(options: &str) -> std::result::Result<StubPciParameters, ParseError> {
246         from_key_values(options)
247     }
248 
249     #[test]
configuration()250     fn configuration() {
251         let device = StubPciDevice::new(&CONFIG);
252 
253         assert_eq!(device.read_config_register(0), 0x0003_0002);
254         assert_eq!(device.read_config_register(2), 0x04_05_06_09);
255         assert_eq!(device.read_config_register(11), 0x0008_0007);
256     }
257 
258     #[test]
address_allocation()259     fn address_allocation() {
260         let mut allocator = SystemAllocator::new(
261             SystemAllocatorConfig {
262                 io: Some(AddressRange {
263                     start: 0x1000,
264                     end: 0x2fff,
265                 }),
266                 low_mmio: AddressRange {
267                     start: 0x2000_0000,
268                     end: 0x2fff_ffff,
269                 },
270                 high_mmio: AddressRange {
271                     start: 0x1_0000_0000,
272                     end: 0x1_0fff_ffff,
273                 },
274                 platform_mmio: None,
275                 first_irq: 5,
276             },
277             None,
278             &[],
279         )
280         .unwrap();
281         let mut device = StubPciDevice::new(&CONFIG);
282 
283         assert!(device.allocate_address(&mut allocator).is_ok());
284         assert!(allocator.release_pci(PciAddress::new(0, 0xa, 0xb, 1).unwrap()));
285     }
286 
287     #[test]
params_missing_address()288     fn params_missing_address() {
289         // PCI address argument is mandatory.
290         let err = from_stub_arg("").unwrap_err();
291         assert_eq!(
292             err,
293             ParseError {
294                 kind: ErrorKind::SerdeError("missing field `address`".into()),
295                 pos: 0,
296             }
297         );
298     }
299 
300     #[test]
params_address_implicit()301     fn params_address_implicit() {
302         // Address is the default argument.
303         let params = from_stub_arg("0000:00:01.2").unwrap();
304         assert_eq!(
305             params.address,
306             PciAddress {
307                 bus: 0,
308                 dev: 1,
309                 func: 2
310             }
311         );
312     }
313 
314     #[test]
params_address_explicit()315     fn params_address_explicit() {
316         // Explicitly-specified address.
317         let params = from_stub_arg("address=0000:00:01.2").unwrap();
318         assert_eq!(
319             params.address,
320             PciAddress {
321                 bus: 0,
322                 dev: 1,
323                 func: 2
324             }
325         );
326     }
327 
328     #[test]
params_class()329     fn params_class() {
330         // Class, subclass, and programming interface are encoded as a single number.
331         let params = from_stub_arg("address=0000:00:01.2,class=0x012345").unwrap();
332         assert_eq!(params.class.class, PciClassCode::MassStorage);
333         assert_eq!(params.class.subclass, 0x23);
334         assert_eq!(params.class.programming_interface, 0x45);
335     }
336 
337     #[test]
params_subsystem_underscores()338     fn params_subsystem_underscores() {
339         // Accept aliases with underscores rather than hyphens for compatibility.
340         let params =
341             from_stub_arg("address=0000:00:01.2,subsystem_vendor=0x8675,subsystem_device=0x309")
342                 .unwrap();
343         assert_eq!(params.subsystem_vendor, 0x8675);
344         assert_eq!(params.subsystem_device, 0x0309);
345     }
346 
347     #[test]
params_full()348     fn params_full() {
349         let params = from_stub_arg(
350             "address=0000:00:01.2,vendor=0x1234,device=0x5678,subsystem-vendor=0x8675,subsystem-device=0x309,class=0x012345,revision=52",
351         ).unwrap();
352         assert_eq!(
353             params.address,
354             PciAddress {
355                 bus: 0,
356                 dev: 1,
357                 func: 2
358             }
359         );
360         assert_eq!(params.vendor, 0x1234);
361         assert_eq!(params.device, 0x5678);
362         assert_eq!(params.subsystem_vendor, 0x8675);
363         assert_eq!(params.subsystem_device, 0x0309);
364         assert_eq!(params.class.class, PciClassCode::MassStorage);
365         assert_eq!(params.class.subclass, 0x23);
366         assert_eq!(params.class.programming_interface, 0x45);
367         assert_eq!(params.revision, 52);
368     }
369 
370     #[test]
stub_pci_device_snapshot_restore() -> anyhow::Result<()>371     fn stub_pci_device_snapshot_restore() -> anyhow::Result<()> {
372         let mut device = StubPciDevice::new(&CONFIG);
373         let init_reg_value = device.read_config_register(1);
374         let snapshot_init = device.snapshot().unwrap();
375 
376         // Modify config reg 1 and make sure it went through.
377         let new_reg_value: u32 = 0xCAFE;
378         device.write_config_register(1, 0, &new_reg_value.to_le_bytes());
379         assert_eq!(device.read_config_register(1), new_reg_value);
380 
381         // Capture a snapshot after the modification.
382         let mut snapshot_modified = device.snapshot().unwrap();
383         assert_ne!(snapshot_init, snapshot_modified);
384 
385         // Modify the same register and verify that it's restored correctly.
386         device.write_config_register(1, 0, &[0xBA, 0xBA]);
387         assert_ne!(device.read_config_register(1), new_reg_value);
388         assert_ne!(device.read_config_register(1), init_reg_value);
389         device.restore(snapshot_init.clone())?;
390         assert_eq!(device.read_config_register(1), init_reg_value);
391 
392         // Capture a snapshot after restoring the initial snapshot.
393         let mut snapshot_restored = device.snapshot().unwrap();
394         assert_eq!(snapshot_init, snapshot_restored);
395 
396         // Restore to the first modification and verify the values.
397         device.restore(snapshot_modified.clone())?;
398         assert_eq!(device.read_config_register(1), new_reg_value);
399         snapshot_restored = device.snapshot().unwrap();
400         assert_eq!(snapshot_modified, snapshot_restored);
401 
402         /*
403         Restore the initial snapshot and verify that addresses are not encoded.
404         The addresses are only configurable during VM creation so they never
405         change afterwards and are not part of the snapshot. Force a change
406         to requested_address to confirm that.
407         */
408         device.restore(snapshot_init.clone())?;
409         device.requested_address = PciAddress {
410             bus: 0x0d,
411             dev: 0x0e,
412             func: 0x4,
413         };
414         snapshot_modified = device.snapshot().unwrap();
415         assert_eq!(snapshot_init, snapshot_modified);
416 
417         Ok(())
418     }
419 }
420