xref: /aosp_15_r20/external/crosvm/devices/src/pci/stub.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
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::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(
168                 Alloc::PciBar {
169                     bus: self.requested_address.bus,
170                     dev: self.requested_address.dev,
171                     func: self.requested_address.func,
172                     bar: 0,
173                 },
174                 self.debug_label(),
175             ) {
176                 self.assigned_address = Some(self.requested_address);
177             }
178         }
179         self.assigned_address
180             .ok_or(PciDeviceError::PciAllocationFailed)
181     }
182 
keep_rds(&self) -> Vec<RawDescriptor>183     fn keep_rds(&self) -> Vec<RawDescriptor> {
184         Vec::new()
185     }
186 
get_bar_configuration(&self, bar_num: usize) -> Option<PciBarConfiguration>187     fn get_bar_configuration(&self, bar_num: usize) -> Option<PciBarConfiguration> {
188         self.config_regs.get_bar_configuration(bar_num)
189     }
190 
read_config_register(&self, reg_idx: usize) -> u32191     fn read_config_register(&self, reg_idx: usize) -> u32 {
192         self.config_regs.read_reg(reg_idx)
193     }
194 
write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8])195     fn write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8]) {
196         self.config_regs.write_reg(reg_idx, offset, data);
197     }
198 
read_bar(&mut self, _bar_index: PciBarIndex, _offset: u64, _data: &mut [u8])199     fn read_bar(&mut self, _bar_index: PciBarIndex, _offset: u64, _data: &mut [u8]) {}
200 
write_bar(&mut self, _bar_index: PciBarIndex, _offset: u64, _data: &[u8])201     fn write_bar(&mut self, _bar_index: PciBarIndex, _offset: u64, _data: &[u8]) {}
202 }
203 
204 impl Suspendable for StubPciDevice {
sleep(&mut self) -> anyhow::Result<()>205     fn sleep(&mut self) -> anyhow::Result<()> {
206         // There are no workers to sleep/wake.
207         Ok(())
208     }
209 
wake(&mut self) -> anyhow::Result<()>210     fn wake(&mut self) -> anyhow::Result<()> {
211         // There are no workers to sleep/wake.
212         Ok(())
213     }
214 
snapshot(&mut self) -> anyhow::Result<serde_json::Value>215     fn snapshot(&mut self) -> anyhow::Result<serde_json::Value> {
216         self.config_regs.snapshot()
217     }
218 
restore(&mut self, data: serde_json::Value) -> anyhow::Result<()>219     fn restore(&mut self, data: serde_json::Value) -> anyhow::Result<()> {
220         self.config_regs.restore(data)
221     }
222 }
223 
224 #[cfg(test)]
225 mod test {
226     use resources::AddressRange;
227     use resources::SystemAllocator;
228     use resources::SystemAllocatorConfig;
229     use serde_keyvalue::from_key_values;
230     use serde_keyvalue::ErrorKind;
231     use serde_keyvalue::ParseError;
232 
233     use super::*;
234 
235     const CONFIG: StubPciParameters = StubPciParameters {
236         address: PciAddress {
237             bus: 0x0a,
238             dev: 0x0b,
239             func: 0x1,
240         },
241         vendor: 2,
242         device: 3,
243         class: PciClassParameters {
244             class: PciClassCode::MultimediaController,
245             subclass: 5,
246             programming_interface: 6,
247         },
248         subsystem_vendor: 7,
249         subsystem_device: 8,
250         revision: 9,
251     };
252 
from_stub_arg(options: &str) -> std::result::Result<StubPciParameters, ParseError>253     fn from_stub_arg(options: &str) -> std::result::Result<StubPciParameters, ParseError> {
254         from_key_values(options)
255     }
256 
257     #[test]
configuration()258     fn configuration() {
259         let device = StubPciDevice::new(&CONFIG);
260 
261         assert_eq!(device.read_config_register(0), 0x0003_0002);
262         assert_eq!(device.read_config_register(2), 0x04_05_06_09);
263         assert_eq!(device.read_config_register(11), 0x0008_0007);
264     }
265 
266     #[test]
address_allocation()267     fn address_allocation() {
268         let mut allocator = SystemAllocator::new(
269             SystemAllocatorConfig {
270                 io: Some(AddressRange {
271                     start: 0x1000,
272                     end: 0x2fff,
273                 }),
274                 low_mmio: AddressRange {
275                     start: 0x2000_0000,
276                     end: 0x2fff_ffff,
277                 },
278                 high_mmio: AddressRange {
279                     start: 0x1_0000_0000,
280                     end: 0x1_0fff_ffff,
281                 },
282                 platform_mmio: None,
283                 first_irq: 5,
284             },
285             None,
286             &[],
287         )
288         .unwrap();
289         let mut device = StubPciDevice::new(&CONFIG);
290 
291         assert!(device.allocate_address(&mut allocator).is_ok());
292         assert!(allocator.release_pci(0xa, 0xb, 1));
293     }
294 
295     #[test]
params_missing_address()296     fn params_missing_address() {
297         // PCI address argument is mandatory.
298         let err = from_stub_arg("").unwrap_err();
299         assert_eq!(
300             err,
301             ParseError {
302                 kind: ErrorKind::SerdeError("missing field `address`".into()),
303                 pos: 0,
304             }
305         );
306     }
307 
308     #[test]
params_address_implicit()309     fn params_address_implicit() {
310         // Address is the default argument.
311         let params = from_stub_arg("0000:00:01.2").unwrap();
312         assert_eq!(
313             params.address,
314             PciAddress {
315                 bus: 0,
316                 dev: 1,
317                 func: 2
318             }
319         );
320     }
321 
322     #[test]
params_address_explicit()323     fn params_address_explicit() {
324         // Explicitly-specified address.
325         let params = from_stub_arg("address=0000:00:01.2").unwrap();
326         assert_eq!(
327             params.address,
328             PciAddress {
329                 bus: 0,
330                 dev: 1,
331                 func: 2
332             }
333         );
334     }
335 
336     #[test]
params_class()337     fn params_class() {
338         // Class, subclass, and programming interface are encoded as a single number.
339         let params = from_stub_arg("address=0000:00:01.2,class=0x012345").unwrap();
340         assert_eq!(params.class.class, PciClassCode::MassStorage);
341         assert_eq!(params.class.subclass, 0x23);
342         assert_eq!(params.class.programming_interface, 0x45);
343     }
344 
345     #[test]
params_subsystem_underscores()346     fn params_subsystem_underscores() {
347         // Accept aliases with underscores rather than hyphens for compatibility.
348         let params =
349             from_stub_arg("address=0000:00:01.2,subsystem_vendor=0x8675,subsystem_device=0x309")
350                 .unwrap();
351         assert_eq!(params.subsystem_vendor, 0x8675);
352         assert_eq!(params.subsystem_device, 0x0309);
353     }
354 
355     #[test]
params_full()356     fn params_full() {
357         let params = from_stub_arg(
358             "address=0000:00:01.2,vendor=0x1234,device=0x5678,subsystem-vendor=0x8675,subsystem-device=0x309,class=0x012345,revision=52",
359         ).unwrap();
360         assert_eq!(
361             params.address,
362             PciAddress {
363                 bus: 0,
364                 dev: 1,
365                 func: 2
366             }
367         );
368         assert_eq!(params.vendor, 0x1234);
369         assert_eq!(params.device, 0x5678);
370         assert_eq!(params.subsystem_vendor, 0x8675);
371         assert_eq!(params.subsystem_device, 0x0309);
372         assert_eq!(params.class.class, PciClassCode::MassStorage);
373         assert_eq!(params.class.subclass, 0x23);
374         assert_eq!(params.class.programming_interface, 0x45);
375         assert_eq!(params.revision, 52);
376     }
377 
378     #[test]
stub_pci_device_snapshot_restore() -> anyhow::Result<()>379     fn stub_pci_device_snapshot_restore() -> anyhow::Result<()> {
380         let mut device = StubPciDevice::new(&CONFIG);
381         let init_reg_value = device.read_config_register(1);
382         let snapshot_init = device.snapshot().unwrap();
383 
384         // Modify config reg 1 and make sure it went through.
385         let new_reg_value: u32 = 0xCAFE;
386         device.write_config_register(1, 0, &new_reg_value.to_le_bytes());
387         assert_eq!(device.read_config_register(1), new_reg_value);
388 
389         // Capture a snapshot after the modification.
390         let mut snapshot_modified = device.snapshot().unwrap();
391         assert_ne!(snapshot_init, snapshot_modified);
392 
393         // Modify the same register and verify that it's restored correctly.
394         device.write_config_register(1, 0, &[0xBA, 0xBA]);
395         assert_ne!(device.read_config_register(1), new_reg_value);
396         assert_ne!(device.read_config_register(1), init_reg_value);
397         device.restore(snapshot_init.clone())?;
398         assert_eq!(device.read_config_register(1), init_reg_value);
399 
400         // Capture a snapshot after restoring the initial snapshot.
401         let mut snapshot_restored = device.snapshot().unwrap();
402         assert_eq!(snapshot_init, snapshot_restored);
403 
404         // Restore to the first modification and verify the values.
405         device.restore(snapshot_modified.clone())?;
406         assert_eq!(device.read_config_register(1), new_reg_value);
407         snapshot_restored = device.snapshot().unwrap();
408         assert_eq!(snapshot_modified, snapshot_restored);
409 
410         /*
411         Restore the initial snapshot and verify that addresses are not encoded.
412         The addresses are only configurable during VM creation so they never
413         change afterwards and are not part of the snapshot. Force a change
414         to requested_address to confirm that.
415         */
416         device.restore(snapshot_init.clone())?;
417         device.requested_address = PciAddress {
418             bus: 0x0d,
419             dev: 0x0e,
420             func: 0x4,
421         };
422         snapshot_modified = device.snapshot().unwrap();
423         assert_eq!(snapshot_init, snapshot_modified);
424 
425         Ok(())
426     }
427 }
428