1use base::RawDescriptor;
16use base::SharedMemory;
17use resources::SystemAllocator;
18use serde::Deserialize;
19use serde::Deserializer;
20use serde::Serialize;
21use serde::Serializer;
22use snapshot::AnySnapshot;
23
24use crate::pci::pci_configuration::PciBarConfiguration;
25use crate::pci::pci_configuration::PciClassCode;
26use crate::pci::pci_configuration::PciConfiguration;
27use crate::pci::pci_configuration::PciHeaderType;
28use crate::pci::pci_configuration::PciProgrammingInterface;
29use crate::pci::pci_configuration::PciSubclass;
30use crate::pci::pci_device::PciDevice;
31use crate::pci::pci_device::Result;
32use crate::pci::PciAddress;
33use crate::pci::PciBarIndex;
34use crate::pci::PciDeviceError;
35use crate::Suspendable;
36
37#[derive(Debug)]
38pub struct PciClassParameters {
39 pub class: PciClassCode,
40 pub subclass: u8,
41 pub programming_interface: u8,
42}
43
44impl Default for PciClassParameters {
45 fn default() -> Self {
46 PciClassParameters {
47 class: PciClassCode::Other,
48 subclass: 0,
49 programming_interface: 0,
50 }
51 }
52}
53
54impl<'de> Deserialize<'de> for PciClassParameters {
57 fn deserialize<D>(deserializer: D) -> std::result::Result<PciClassParameters, D::Error>
58 where
59 D: Deserializer<'de>,
60 {
61 let class_numeric = u32::deserialize(deserializer)?;
62
63 let class_code = (class_numeric >> 16) as u8;
64 let class = PciClassCode::try_from(class_code)
65 .map_err(|_| serde::de::Error::custom(format!("Unknown class code {class_code:#x}")))?;
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
79impl Serialize for PciClassParameters {
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")]
94pub 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
110pub struct StubPciDevice {
111 requested_address: PciAddress,
112 assigned_address: Option<PciAddress>,
113 config_regs: PciConfiguration,
114}
115
116struct NumericPciSubClass(u8);
117
118impl PciSubclass for NumericPciSubClass {
119 fn get_register_value(&self) -> u8 {
120 self.0
121 }
122}
123
124struct NumericPciProgrammingInterface(u8);
125
126impl PciProgrammingInterface for NumericPciProgrammingInterface {
127 fn get_register_value(&self) -> u8 {
128 self.0
129 }
130}
131
132impl StubPciDevice {
133 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
156impl PciDevice for StubPciDevice {
157 fn debug_label(&self) -> String {
158 "Stub".to_owned()
159 }
160
161 fn preferred_address(&self) -> Option<PciAddress> {
162 Some(self.requested_address)
163 }
164
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
175 fn setup_pci_config_mapping(
176 &mut self,
177 shmem: &SharedMemory,
178 base: usize,
179 len: usize,
180 ) -> Result<bool> {
181 self.config_regs
182 .setup_mapping(shmem, base, len)
183 .map(|_| true)
184 .map_err(PciDeviceError::MmioSetup)
185 }
186
187 fn keep_rds(&self) -> Vec<RawDescriptor> {
188 Vec::new()
189 }
190
191 fn get_bar_configuration(&self, bar_num: usize) -> Option<PciBarConfiguration> {
192 self.config_regs.get_bar_configuration(bar_num)
193 }
194
195 fn read_config_register(&self, reg_idx: usize) -> u32 {
196 self.config_regs.read_reg(reg_idx)
197 }
198
199 fn write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8]) {
200 self.config_regs.write_reg(reg_idx, offset, data);
201 }
202
203 fn read_bar(&mut self, _bar_index: PciBarIndex, _offset: u64, _data: &mut [u8]) {}
204
205 fn write_bar(&mut self, _bar_index: PciBarIndex, _offset: u64, _data: &[u8]) {}
206}
207
208impl Suspendable for StubPciDevice {
209 fn sleep(&mut self) -> anyhow::Result<()> {
210 Ok(())
212 }
213
214 fn wake(&mut self) -> anyhow::Result<()> {
215 Ok(())
217 }
218
219 fn snapshot(&mut self) -> anyhow::Result<AnySnapshot> {
220 self.config_regs.snapshot()
221 }
222
223 fn restore(&mut self, data: AnySnapshot) -> anyhow::Result<()> {
224 self.config_regs.restore(data)
225 }
226}
227
228#[cfg(test)]
229mod test {
230 use resources::AddressRange;
231 use resources::SystemAllocator;
232 use resources::SystemAllocatorConfig;
233 use serde_keyvalue::from_key_values;
234 use serde_keyvalue::ErrorKind;
235 use serde_keyvalue::ParseError;
236
237 use super::*;
238
239 const CONFIG: StubPciParameters = StubPciParameters {
240 address: PciAddress {
241 bus: 0x0a,
242 dev: 0x0b,
243 func: 0x1,
244 },
245 vendor: 2,
246 device: 3,
247 class: PciClassParameters {
248 class: PciClassCode::MultimediaController,
249 subclass: 5,
250 programming_interface: 6,
251 },
252 subsystem_vendor: 7,
253 subsystem_device: 8,
254 revision: 9,
255 };
256
257 fn from_stub_arg(options: &str) -> std::result::Result<StubPciParameters, ParseError> {
258 from_key_values(options)
259 }
260
261 #[test]
262 fn configuration() {
263 let device = StubPciDevice::new(&CONFIG);
264
265 assert_eq!(device.read_config_register(0), 0x0003_0002);
266 assert_eq!(device.read_config_register(2), 0x04_05_06_09);
267 assert_eq!(device.read_config_register(11), 0x0008_0007);
268 }
269
270 #[test]
271 fn address_allocation() {
272 let mut allocator = SystemAllocator::new(
273 SystemAllocatorConfig {
274 io: Some(AddressRange {
275 start: 0x1000,
276 end: 0x2fff,
277 }),
278 low_mmio: AddressRange {
279 start: 0x2000_0000,
280 end: 0x2fff_ffff,
281 },
282 high_mmio: AddressRange {
283 start: 0x1_0000_0000,
284 end: 0x1_0fff_ffff,
285 },
286 platform_mmio: None,
287 first_irq: 5,
288 },
289 None,
290 &[],
291 )
292 .unwrap();
293 let mut device = StubPciDevice::new(&CONFIG);
294
295 assert!(device.allocate_address(&mut allocator).is_ok());
296 assert!(allocator.release_pci(PciAddress::new(0, 0xa, 0xb, 1).unwrap()));
297 }
298
299 #[test]
300 fn params_missing_address() {
301 let err = from_stub_arg("").unwrap_err();
303 assert_eq!(
304 err,
305 ParseError {
306 kind: ErrorKind::SerdeError("missing field `address`".into()),
307 pos: 0,
308 }
309 );
310 }
311
312 #[test]
313 fn params_address_implicit() {
314 let params = from_stub_arg("0000:00:01.2").unwrap();
316 assert_eq!(
317 params.address,
318 PciAddress {
319 bus: 0,
320 dev: 1,
321 func: 2
322 }
323 );
324 }
325
326 #[test]
327 fn params_address_explicit() {
328 let params = from_stub_arg("address=0000:00:01.2").unwrap();
330 assert_eq!(
331 params.address,
332 PciAddress {
333 bus: 0,
334 dev: 1,
335 func: 2
336 }
337 );
338 }
339
340 #[test]
341 fn params_class() {
342 let params = from_stub_arg("address=0000:00:01.2,class=0x012345").unwrap();
344 assert_eq!(params.class.class, PciClassCode::MassStorage);
345 assert_eq!(params.class.subclass, 0x23);
346 assert_eq!(params.class.programming_interface, 0x45);
347 }
348
349 #[test]
350 fn params_subsystem_underscores() {
351 let params =
353 from_stub_arg("address=0000:00:01.2,subsystem_vendor=0x8675,subsystem_device=0x309")
354 .unwrap();
355 assert_eq!(params.subsystem_vendor, 0x8675);
356 assert_eq!(params.subsystem_device, 0x0309);
357 }
358
359 #[test]
360 fn params_full() {
361 let params = from_stub_arg(
362 "address=0000:00:01.2,vendor=0x1234,device=0x5678,subsystem-vendor=0x8675,subsystem-device=0x309,class=0x012345,revision=52",
363 ).unwrap();
364 assert_eq!(
365 params.address,
366 PciAddress {
367 bus: 0,
368 dev: 1,
369 func: 2
370 }
371 );
372 assert_eq!(params.vendor, 0x1234);
373 assert_eq!(params.device, 0x5678);
374 assert_eq!(params.subsystem_vendor, 0x8675);
375 assert_eq!(params.subsystem_device, 0x0309);
376 assert_eq!(params.class.class, PciClassCode::MassStorage);
377 assert_eq!(params.class.subclass, 0x23);
378 assert_eq!(params.class.programming_interface, 0x45);
379 assert_eq!(params.revision, 52);
380 }
381
382 #[test]
383 fn stub_pci_device_snapshot_restore() -> anyhow::Result<()> {
384 let mut device = StubPciDevice::new(&CONFIG);
385 let init_reg_value = device.read_config_register(1);
386 let snapshot_init = device.snapshot().unwrap();
387
388 let new_reg_value: u32 = 0xCAFE;
390 device.write_config_register(1, 0, &new_reg_value.to_le_bytes());
391 assert_eq!(device.read_config_register(1), new_reg_value);
392
393 let mut snapshot_modified = device.snapshot().unwrap();
395 assert_ne!(snapshot_init, snapshot_modified);
396
397 device.write_config_register(1, 0, &[0xBA, 0xBA]);
399 assert_ne!(device.read_config_register(1), new_reg_value);
400 assert_ne!(device.read_config_register(1), init_reg_value);
401 device.restore(snapshot_init.clone())?;
402 assert_eq!(device.read_config_register(1), init_reg_value);
403
404 let mut snapshot_restored = device.snapshot().unwrap();
406 assert_eq!(snapshot_init, snapshot_restored);
407
408 device.restore(snapshot_modified.clone())?;
410 assert_eq!(device.read_config_register(1), new_reg_value);
411 snapshot_restored = device.snapshot().unwrap();
412 assert_eq!(snapshot_modified, snapshot_restored);
413
414 device.restore(snapshot_init.clone())?;
421 device.requested_address = PciAddress {
422 bus: 0x0d,
423 dev: 0x0e,
424 func: 0x4,
425 };
426 snapshot_modified = device.snapshot().unwrap();
427 assert_eq!(snapshot_init, snapshot_modified);
428
429 Ok(())
430 }
431}