1use base::RawDescriptor;
16use resources::SystemAllocator;
17use serde::Deserialize;
18use serde::Deserializer;
19use serde::Serialize;
20use serde::Serializer;
21use snapshot::AnySnapshot;
22
23use crate::pci::pci_configuration::PciBarConfiguration;
24use crate::pci::pci_configuration::PciClassCode;
25use crate::pci::pci_configuration::PciConfiguration;
26use crate::pci::pci_configuration::PciHeaderType;
27use crate::pci::pci_configuration::PciProgrammingInterface;
28use crate::pci::pci_configuration::PciSubclass;
29use crate::pci::pci_device::PciDevice;
30use crate::pci::pci_device::Result;
31use crate::pci::PciAddress;
32use crate::pci::PciBarIndex;
33use crate::pci::PciDeviceError;
34use crate::Suspendable;
35
36#[derive(Debug)]
37pub struct PciClassParameters {
38 pub class: PciClassCode,
39 pub subclass: u8,
40 pub programming_interface: u8,
41}
42
43impl Default for PciClassParameters {
44 fn default() -> Self {
45 PciClassParameters {
46 class: PciClassCode::Other,
47 subclass: 0,
48 programming_interface: 0,
49 }
50 }
51}
52
53impl<'de> Deserialize<'de> for PciClassParameters {
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)
64 .map_err(|_| serde::de::Error::custom(format!("Unknown class code {class_code:#x}")))?;
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
78impl Serialize for PciClassParameters {
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")]
93pub 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
109pub struct StubPciDevice {
110 requested_address: PciAddress,
111 assigned_address: Option<PciAddress>,
112 config_regs: PciConfiguration,
113}
114
115struct NumericPciSubClass(u8);
116
117impl PciSubclass for NumericPciSubClass {
118 fn get_register_value(&self) -> u8 {
119 self.0
120 }
121}
122
123struct NumericPciProgrammingInterface(u8);
124
125impl PciProgrammingInterface for NumericPciProgrammingInterface {
126 fn get_register_value(&self) -> u8 {
127 self.0
128 }
129}
130
131impl StubPciDevice {
132 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
155impl PciDevice for StubPciDevice {
156 fn debug_label(&self) -> String {
157 "Stub".to_owned()
158 }
159
160 fn preferred_address(&self) -> Option<PciAddress> {
161 Some(self.requested_address)
162 }
163
164 fn allocate_address(&mut self, resources: &mut SystemAllocator) -> Result<PciAddress> {
165 if self.assigned_address.is_none() {
166 if resources.reserve_pci(self.requested_address, self.debug_label()) {
167 self.assigned_address = Some(self.requested_address);
168 }
169 }
170 self.assigned_address
171 .ok_or(PciDeviceError::PciAllocationFailed)
172 }
173
174 fn keep_rds(&self) -> Vec<RawDescriptor> {
175 Vec::new()
176 }
177
178 fn get_bar_configuration(&self, bar_num: usize) -> Option<PciBarConfiguration> {
179 self.config_regs.get_bar_configuration(bar_num)
180 }
181
182 fn read_config_register(&self, reg_idx: usize) -> u32 {
183 self.config_regs.read_reg(reg_idx)
184 }
185
186 fn write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8]) {
187 self.config_regs.write_reg(reg_idx, offset, data);
188 }
189
190 fn read_bar(&mut self, _bar_index: PciBarIndex, _offset: u64, _data: &mut [u8]) {}
191
192 fn write_bar(&mut self, _bar_index: PciBarIndex, _offset: u64, _data: &[u8]) {}
193}
194
195impl Suspendable for StubPciDevice {
196 fn sleep(&mut self) -> anyhow::Result<()> {
197 Ok(())
199 }
200
201 fn wake(&mut self) -> anyhow::Result<()> {
202 Ok(())
204 }
205
206 fn snapshot(&mut self) -> anyhow::Result<AnySnapshot> {
207 self.config_regs.snapshot()
208 }
209
210 fn restore(&mut self, data: AnySnapshot) -> anyhow::Result<()> {
211 self.config_regs.restore(data)
212 }
213}
214
215#[cfg(test)]
216mod 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
244 fn from_stub_arg(options: &str) -> std::result::Result<StubPciParameters, ParseError> {
245 from_key_values(options)
246 }
247
248 #[test]
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]
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(PciAddress::new(0, 0xa, 0xb, 1).unwrap()));
284 }
285
286 #[test]
287 fn params_missing_address() {
288 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]
300 fn params_address_implicit() {
301 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]
314 fn params_address_explicit() {
315 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]
328 fn params_class() {
329 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]
337 fn params_subsystem_underscores() {
338 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]
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 #[test]
370 fn stub_pci_device_snapshot_restore() -> anyhow::Result<()> {
371 let mut device = StubPciDevice::new(&CONFIG);
372 let init_reg_value = device.read_config_register(1);
373 let snapshot_init = device.snapshot().unwrap();
374
375 let new_reg_value: u32 = 0xCAFE;
377 device.write_config_register(1, 0, &new_reg_value.to_le_bytes());
378 assert_eq!(device.read_config_register(1), new_reg_value);
379
380 let mut snapshot_modified = device.snapshot().unwrap();
382 assert_ne!(snapshot_init, snapshot_modified);
383
384 device.write_config_register(1, 0, &[0xBA, 0xBA]);
386 assert_ne!(device.read_config_register(1), new_reg_value);
387 assert_ne!(device.read_config_register(1), init_reg_value);
388 device.restore(snapshot_init.clone())?;
389 assert_eq!(device.read_config_register(1), init_reg_value);
390
391 let mut snapshot_restored = device.snapshot().unwrap();
393 assert_eq!(snapshot_init, snapshot_restored);
394
395 device.restore(snapshot_modified.clone())?;
397 assert_eq!(device.read_config_register(1), new_reg_value);
398 snapshot_restored = device.snapshot().unwrap();
399 assert_eq!(snapshot_modified, snapshot_restored);
400
401 device.restore(snapshot_init.clone())?;
408 device.requested_address = PciAddress {
409 bus: 0x0d,
410 dev: 0x0e,
411 func: 0x4,
412 };
413 snapshot_modified = device.snapshot().unwrap();
414 assert_eq!(snapshot_init, snapshot_modified);
415
416 Ok(())
417 }
418}