xref: /cloud-hypervisor/pci/src/configuration.rs (revision 7d7bfb2034001d4cb15df2ddc56d2d350c8da30f)
1 // Copyright 2018 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE-BSD-3-Clause file.
4 
5 use crate::device::BarReprogrammingParams;
6 use crate::{MsixConfig, PciInterruptPin};
7 use byteorder::{ByteOrder, LittleEndian};
8 use std::fmt::{self, Display};
9 use std::sync::{Arc, Mutex};
10 use versionize::{VersionMap, Versionize, VersionizeError, VersionizeResult};
11 use versionize_derive::Versionize;
12 use vm_migration::{MigratableError, Pausable, Snapshot, Snapshottable, VersionMapped};
13 
14 // The number of 32bit registers in the config space, 4096 bytes.
15 const NUM_CONFIGURATION_REGISTERS: usize = 1024;
16 
17 const STATUS_REG: usize = 1;
18 const STATUS_REG_CAPABILITIES_USED_MASK: u32 = 0x0010_0000;
19 const BAR0_REG: usize = 4;
20 const ROM_BAR_REG: usize = 12;
21 const BAR_IO_ADDR_MASK: u32 = 0xffff_fffc;
22 const BAR_MEM_ADDR_MASK: u32 = 0xffff_fff0;
23 const ROM_BAR_ADDR_MASK: u32 = 0xffff_f800;
24 const MSI_CAPABILITY_REGISTER_MASK: u32 = 0x0071_0000;
25 const MSIX_CAPABILITY_REGISTER_MASK: u32 = 0xc000_0000;
26 const NUM_BAR_REGS: usize = 6;
27 const CAPABILITY_LIST_HEAD_OFFSET: usize = 0x34;
28 const FIRST_CAPABILITY_OFFSET: usize = 0x40;
29 const CAPABILITY_MAX_OFFSET: usize = 192;
30 
31 const INTERRUPT_LINE_PIN_REG: usize = 15;
32 
33 /// Represents the types of PCI headers allowed in the configuration registers.
34 #[derive(Copy, Clone)]
35 pub enum PciHeaderType {
36     Device,
37     Bridge,
38 }
39 
40 /// Classes of PCI nodes.
41 #[allow(dead_code)]
42 #[derive(Copy, Clone)]
43 pub enum PciClassCode {
44     TooOld,
45     MassStorage,
46     NetworkController,
47     DisplayController,
48     MultimediaController,
49     MemoryController,
50     BridgeDevice,
51     SimpleCommunicationController,
52     BaseSystemPeripheral,
53     InputDevice,
54     DockingStation,
55     Processor,
56     SerialBusController,
57     WirelessController,
58     IntelligentIoController,
59     EncryptionController,
60     DataAcquisitionSignalProcessing,
61     Other = 0xff,
62 }
63 
64 impl PciClassCode {
65     pub fn get_register_value(self) -> u8 {
66         self as u8
67     }
68 }
69 
70 /// A PCI subclass. Each class in `PciClassCode` can specify a unique set of subclasses. This trait
71 /// is implemented by each subclass. It allows use of a trait object to generate configurations.
72 pub trait PciSubclass {
73     /// Convert this subclass to the value used in the PCI specification.
74     fn get_register_value(&self) -> u8;
75 }
76 
77 /// Subclasses of the MultimediaController class.
78 #[allow(dead_code)]
79 #[derive(Copy, Clone)]
80 pub enum PciMultimediaSubclass {
81     VideoController = 0x00,
82     AudioController = 0x01,
83     TelephonyDevice = 0x02,
84     AudioDevice = 0x03,
85     Other = 0x80,
86 }
87 
88 impl PciSubclass for PciMultimediaSubclass {
89     fn get_register_value(&self) -> u8 {
90         *self as u8
91     }
92 }
93 
94 /// Subclasses of the BridgeDevice
95 #[allow(dead_code)]
96 #[derive(Copy, Clone)]
97 pub enum PciBridgeSubclass {
98     HostBridge = 0x00,
99     IsaBridge = 0x01,
100     EisaBridge = 0x02,
101     McaBridge = 0x03,
102     PciToPciBridge = 0x04,
103     PcmciaBridge = 0x05,
104     NuBusBridge = 0x06,
105     CardBusBridge = 0x07,
106     RacEwayBridge = 0x08,
107     PciToPciSemiTransparentBridge = 0x09,
108     InfiniBrandToPciHostBridge = 0x0a,
109     OtherBridgeDevice = 0x80,
110 }
111 
112 impl PciSubclass for PciBridgeSubclass {
113     fn get_register_value(&self) -> u8 {
114         *self as u8
115     }
116 }
117 
118 /// Subclass of the SerialBus
119 #[allow(dead_code)]
120 #[derive(Copy, Clone)]
121 pub enum PciSerialBusSubClass {
122     Firewire = 0x00,
123     Accessbus = 0x01,
124     Ssa = 0x02,
125     Usb = 0x03,
126 }
127 
128 impl PciSubclass for PciSerialBusSubClass {
129     fn get_register_value(&self) -> u8 {
130         *self as u8
131     }
132 }
133 
134 /// Mass Storage Sub Classes
135 #[allow(dead_code)]
136 #[derive(Copy, Clone)]
137 pub enum PciMassStorageSubclass {
138     ScsiStorage = 0x00,
139     IdeInterface = 0x01,
140     FloppyController = 0x02,
141     IpiController = 0x03,
142     RaidController = 0x04,
143     AtaController = 0x05,
144     SataController = 0x06,
145     SerialScsiController = 0x07,
146     NvmController = 0x08,
147     MassStorage = 0x80,
148 }
149 
150 impl PciSubclass for PciMassStorageSubclass {
151     fn get_register_value(&self) -> u8 {
152         *self as u8
153     }
154 }
155 
156 /// Network Controller Sub Classes
157 #[allow(dead_code)]
158 #[derive(Copy, Clone)]
159 pub enum PciNetworkControllerSubclass {
160     EthernetController = 0x00,
161     TokenRingController = 0x01,
162     FddiController = 0x02,
163     AtmController = 0x03,
164     IsdnController = 0x04,
165     WorldFipController = 0x05,
166     PicmgController = 0x06,
167     InfinibandController = 0x07,
168     FabricController = 0x08,
169     NetworkController = 0x80,
170 }
171 
172 impl PciSubclass for PciNetworkControllerSubclass {
173     fn get_register_value(&self) -> u8 {
174         *self as u8
175     }
176 }
177 
178 /// A PCI class programming interface. Each combination of `PciClassCode` and
179 /// `PciSubclass` can specify a set of register-level programming interfaces.
180 /// This trait is implemented by each programming interface.
181 /// It allows use of a trait object to generate configurations.
182 pub trait PciProgrammingInterface {
183     /// Convert this programming interface to the value used in the PCI specification.
184     fn get_register_value(&self) -> u8;
185 }
186 
187 /// Types of PCI capabilities.
188 #[derive(PartialEq, Copy, Clone)]
189 #[allow(dead_code)]
190 #[allow(non_camel_case_types)]
191 #[repr(C)]
192 pub enum PciCapabilityId {
193     ListId = 0,
194     PowerManagement = 0x01,
195     AcceleratedGraphicsPort = 0x02,
196     VitalProductData = 0x03,
197     SlotIdentification = 0x04,
198     MessageSignalledInterrupts = 0x05,
199     CompactPciHotSwap = 0x06,
200     PciX = 0x07,
201     HyperTransport = 0x08,
202     VendorSpecific = 0x09,
203     Debugport = 0x0A,
204     CompactPciCentralResourceControl = 0x0B,
205     PciStandardHotPlugController = 0x0C,
206     BridgeSubsystemVendorDeviceId = 0x0D,
207     AgpTargetPciPcibridge = 0x0E,
208     SecureDevice = 0x0F,
209     PciExpress = 0x10,
210     MsiX = 0x11,
211     SataDataIndexConf = 0x12,
212     PciAdvancedFeatures = 0x13,
213     PciEnhancedAllocation = 0x14,
214 }
215 
216 impl From<u8> for PciCapabilityId {
217     fn from(c: u8) -> Self {
218         match c {
219             0 => PciCapabilityId::ListId,
220             0x01 => PciCapabilityId::PowerManagement,
221             0x02 => PciCapabilityId::AcceleratedGraphicsPort,
222             0x03 => PciCapabilityId::VitalProductData,
223             0x04 => PciCapabilityId::SlotIdentification,
224             0x05 => PciCapabilityId::MessageSignalledInterrupts,
225             0x06 => PciCapabilityId::CompactPciHotSwap,
226             0x07 => PciCapabilityId::PciX,
227             0x08 => PciCapabilityId::HyperTransport,
228             0x09 => PciCapabilityId::VendorSpecific,
229             0x0A => PciCapabilityId::Debugport,
230             0x0B => PciCapabilityId::CompactPciCentralResourceControl,
231             0x0C => PciCapabilityId::PciStandardHotPlugController,
232             0x0D => PciCapabilityId::BridgeSubsystemVendorDeviceId,
233             0x0E => PciCapabilityId::AgpTargetPciPcibridge,
234             0x0F => PciCapabilityId::SecureDevice,
235             0x10 => PciCapabilityId::PciExpress,
236             0x11 => PciCapabilityId::MsiX,
237             0x12 => PciCapabilityId::SataDataIndexConf,
238             0x13 => PciCapabilityId::PciAdvancedFeatures,
239             0x14 => PciCapabilityId::PciEnhancedAllocation,
240             _ => PciCapabilityId::ListId,
241         }
242     }
243 }
244 
245 /// A PCI capability list. Devices can optionally specify capabilities in their configuration space.
246 pub trait PciCapability {
247     fn bytes(&self) -> &[u8];
248     fn id(&self) -> PciCapabilityId;
249 }
250 
251 fn encode_32_bits_bar_size(bar_size: u32) -> Option<u32> {
252     if bar_size > 0 {
253         return Some(!(bar_size - 1));
254     }
255     None
256 }
257 
258 fn decode_32_bits_bar_size(bar_size: u32) -> Option<u32> {
259     if bar_size > 0 {
260         return Some(!bar_size + 1);
261     }
262     None
263 }
264 
265 fn encode_64_bits_bar_size(bar_size: u64) -> Option<(u32, u32)> {
266     if bar_size > 0 {
267         let result = !(bar_size - 1);
268         let result_hi = (result >> 32) as u32;
269         let result_lo = (result & 0xffff_ffff) as u32;
270         return Some((result_hi, result_lo));
271     }
272     None
273 }
274 
275 fn decode_64_bits_bar_size(bar_size_hi: u32, bar_size_lo: u32) -> Option<u64> {
276     let bar_size: u64 = ((bar_size_hi as u64) << 32) | (bar_size_lo as u64);
277     if bar_size > 0 {
278         return Some(!bar_size + 1);
279     }
280     None
281 }
282 
283 #[derive(Default, Clone, Copy, Versionize)]
284 struct PciBar {
285     addr: u32,
286     size: u32,
287     used: bool,
288     r#type: Option<PciBarRegionType>,
289 }
290 
291 #[derive(Versionize)]
292 struct PciConfigurationState {
293     registers: Vec<u32>,
294     writable_bits: Vec<u32>,
295     bars: Vec<PciBar>,
296     rom_bar_addr: u32,
297     rom_bar_size: u32,
298     rom_bar_used: bool,
299     last_capability: Option<(usize, usize)>,
300     msix_cap_reg_idx: Option<usize>,
301 }
302 
303 impl VersionMapped for PciConfigurationState {}
304 
305 /// Contains the configuration space of a PCI node.
306 /// See the [specification](https://en.wikipedia.org/wiki/PCI_configuration_space).
307 /// The configuration space is accessed with DWORD reads and writes from the guest.
308 pub struct PciConfiguration {
309     registers: [u32; NUM_CONFIGURATION_REGISTERS],
310     writable_bits: [u32; NUM_CONFIGURATION_REGISTERS], // writable bits for each register.
311     bars: [PciBar; NUM_BAR_REGS],
312     rom_bar_addr: u32,
313     rom_bar_size: u32,
314     rom_bar_used: bool,
315     // Contains the byte offset and size of the last capability.
316     last_capability: Option<(usize, usize)>,
317     msix_cap_reg_idx: Option<usize>,
318     msix_config: Option<Arc<Mutex<MsixConfig>>>,
319 }
320 
321 /// See pci_regs.h in kernel
322 #[derive(Copy, Clone, PartialEq, Versionize, Debug)]
323 pub enum PciBarRegionType {
324     Memory32BitRegion = 0,
325     IoRegion = 0x01,
326     Memory64BitRegion = 0x04,
327 }
328 
329 #[derive(Copy, Clone)]
330 pub enum PciBarPrefetchable {
331     NotPrefetchable = 0,
332     Prefetchable = 0x08,
333 }
334 
335 #[derive(Copy, Clone)]
336 pub struct PciBarConfiguration {
337     addr: u64,
338     size: u64,
339     reg_idx: usize,
340     region_type: PciBarRegionType,
341     prefetchable: PciBarPrefetchable,
342 }
343 
344 #[derive(Debug)]
345 pub enum Error {
346     BarAddressInvalid(u64, u64),
347     BarInUse(usize),
348     BarInUse64(usize),
349     BarInvalid(usize),
350     BarInvalid64(usize),
351     BarSizeInvalid(u64),
352     CapabilityEmpty,
353     CapabilityLengthInvalid(usize),
354     CapabilitySpaceFull(usize),
355     Decode32BarSize,
356     Decode64BarSize,
357     Encode32BarSize,
358     Encode64BarSize,
359     RomBarAddressInvalid(u64, u64),
360     RomBarInUse(usize),
361     RomBarInvalid(usize),
362     RomBarSizeInvalid(u64),
363 }
364 pub type Result<T> = std::result::Result<T, Error>;
365 
366 impl std::error::Error for Error {}
367 
368 impl Display for Error {
369     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
370         use self::Error::*;
371         match self {
372             BarAddressInvalid(a, s) => write!(f, "address {} size {} too big", a, s),
373             BarInUse(b) => write!(f, "bar {} already used", b),
374             BarInUse64(b) => write!(f, "64bit bar {} already used(requires two regs)", b),
375             BarInvalid(b) => write!(f, "bar {} invalid, max {}", b, NUM_BAR_REGS - 1),
376             BarInvalid64(b) => write!(
377                 f,
378                 "64bitbar {} invalid, requires two regs, max {}",
379                 b,
380                 NUM_BAR_REGS - 1
381             ),
382             BarSizeInvalid(s) => write!(f, "bar address {} not a power of two", s),
383             CapabilityEmpty => write!(f, "empty capabilities are invalid"),
384             CapabilityLengthInvalid(l) => write!(f, "Invalid capability length {}", l),
385             CapabilitySpaceFull(s) => write!(f, "capability of size {} doesn't fit", s),
386             Decode32BarSize => write!(f, "failed to decode 32 bits BAR size"),
387             Decode64BarSize => write!(f, "failed to decode 64 bits BAR size"),
388             Encode32BarSize => write!(f, "failed to encode 32 bits BAR size"),
389             Encode64BarSize => write!(f, "failed to encode 64 bits BAR size"),
390             RomBarAddressInvalid(a, s) => write!(f, "address {} size {} too big", a, s),
391             RomBarInUse(b) => write!(f, "rom bar {} already used", b),
392             RomBarInvalid(b) => write!(f, "rom bar {} invalid, max {}", b, NUM_BAR_REGS - 1),
393             RomBarSizeInvalid(s) => write!(f, "rom bar address {} not a power of two", s),
394         }
395     }
396 }
397 
398 impl PciConfiguration {
399     #[allow(clippy::too_many_arguments)]
400     pub fn new(
401         vendor_id: u16,
402         device_id: u16,
403         revision_id: u8,
404         class_code: PciClassCode,
405         subclass: &dyn PciSubclass,
406         programming_interface: Option<&dyn PciProgrammingInterface>,
407         header_type: PciHeaderType,
408         subsystem_vendor_id: u16,
409         subsystem_id: u16,
410         msix_config: Option<Arc<Mutex<MsixConfig>>>,
411     ) -> Self {
412         let mut registers = [0u32; NUM_CONFIGURATION_REGISTERS];
413         let mut writable_bits = [0u32; NUM_CONFIGURATION_REGISTERS];
414         registers[0] = u32::from(device_id) << 16 | u32::from(vendor_id);
415         // TODO(dverkamp): Status should be write-1-to-clear
416         writable_bits[1] = 0x0000_ffff; // Status (r/o), command (r/w)
417         let pi = if let Some(pi) = programming_interface {
418             pi.get_register_value()
419         } else {
420             0
421         };
422         registers[2] = u32::from(class_code.get_register_value()) << 24
423             | u32::from(subclass.get_register_value()) << 16
424             | u32::from(pi) << 8
425             | u32::from(revision_id);
426         writable_bits[3] = 0x0000_00ff; // Cacheline size (r/w)
427         match header_type {
428             PciHeaderType::Device => {
429                 registers[3] = 0x0000_0000; // Header type 0 (device)
430                 writable_bits[15] = 0x0000_00ff; // Interrupt line (r/w)
431             }
432             PciHeaderType::Bridge => {
433                 registers[3] = 0x0001_0000; // Header type 1 (bridge)
434                 writable_bits[9] = 0xfff0_fff0; // Memory base and limit
435                 writable_bits[15] = 0xffff_00ff; // Bridge control (r/w), interrupt line (r/w)
436             }
437         };
438         registers[11] = u32::from(subsystem_id) << 16 | u32::from(subsystem_vendor_id);
439 
440         let bars = [PciBar::default(); NUM_BAR_REGS];
441 
442         PciConfiguration {
443             registers,
444             writable_bits,
445             bars,
446             rom_bar_addr: 0,
447             rom_bar_size: 0,
448             rom_bar_used: false,
449             last_capability: None,
450             msix_cap_reg_idx: None,
451             msix_config,
452         }
453     }
454 
455     fn state(&self) -> PciConfigurationState {
456         PciConfigurationState {
457             registers: self.registers.to_vec(),
458             writable_bits: self.writable_bits.to_vec(),
459             bars: self.bars.to_vec(),
460             rom_bar_addr: self.rom_bar_addr,
461             rom_bar_size: self.rom_bar_size,
462             rom_bar_used: self.rom_bar_used,
463             last_capability: self.last_capability,
464             msix_cap_reg_idx: self.msix_cap_reg_idx,
465         }
466     }
467 
468     fn set_state(&mut self, state: &PciConfigurationState) {
469         self.registers.clone_from_slice(state.registers.as_slice());
470         self.writable_bits
471             .clone_from_slice(state.writable_bits.as_slice());
472         self.bars.clone_from_slice(state.bars.as_slice());
473         self.rom_bar_addr = state.rom_bar_addr;
474         self.rom_bar_size = state.rom_bar_size;
475         self.rom_bar_used = state.rom_bar_used;
476         self.last_capability = state.last_capability;
477         self.msix_cap_reg_idx = state.msix_cap_reg_idx;
478     }
479 
480     /// Reads a 32bit register from `reg_idx` in the register map.
481     pub fn read_reg(&self, reg_idx: usize) -> u32 {
482         *(self.registers.get(reg_idx).unwrap_or(&0xffff_ffff))
483     }
484 
485     /// Writes a 32bit register to `reg_idx` in the register map.
486     pub fn write_reg(&mut self, reg_idx: usize, value: u32) {
487         let mut mask = self.writable_bits[reg_idx];
488 
489         if (BAR0_REG..BAR0_REG + NUM_BAR_REGS).contains(&reg_idx) {
490             // Handle very specific case where the BAR is being written with
491             // all 1's to retrieve the BAR size during next BAR reading.
492             if value == 0xffff_ffff {
493                 mask &= self.bars[reg_idx - 4].size;
494             }
495         } else if reg_idx == ROM_BAR_REG {
496             // Handle very specific case where the BAR is being written with
497             // all 1's on bits 31-11 to retrieve the BAR size during next BAR
498             // reading.
499             if value & ROM_BAR_ADDR_MASK == ROM_BAR_ADDR_MASK {
500                 mask &= self.rom_bar_size;
501             }
502         }
503 
504         if let Some(r) = self.registers.get_mut(reg_idx) {
505             *r = (*r & !self.writable_bits[reg_idx]) | (value & mask);
506         } else {
507             warn!("bad PCI register write {}", reg_idx);
508         }
509     }
510 
511     /// Writes a 16bit word to `offset`. `offset` must be 16bit aligned.
512     pub fn write_word(&mut self, offset: usize, value: u16) {
513         let shift = match offset % 4 {
514             0 => 0,
515             2 => 16,
516             _ => {
517                 warn!("bad PCI config write offset {}", offset);
518                 return;
519             }
520         };
521         let reg_idx = offset / 4;
522 
523         if let Some(r) = self.registers.get_mut(reg_idx) {
524             let writable_mask = self.writable_bits[reg_idx];
525             let mask = (0xffffu32 << shift) & writable_mask;
526             let shifted_value = (u32::from(value) << shift) & writable_mask;
527             *r = *r & !mask | shifted_value;
528         } else {
529             warn!("bad PCI config write offset {}", offset);
530         }
531     }
532 
533     /// Writes a byte to `offset`.
534     pub fn write_byte(&mut self, offset: usize, value: u8) {
535         self.write_byte_internal(offset, value, true);
536     }
537 
538     /// Writes a byte to `offset`, optionally enforcing read-only bits.
539     fn write_byte_internal(&mut self, offset: usize, value: u8, apply_writable_mask: bool) {
540         let shift = (offset % 4) * 8;
541         let reg_idx = offset / 4;
542 
543         if let Some(r) = self.registers.get_mut(reg_idx) {
544             let writable_mask = if apply_writable_mask {
545                 self.writable_bits[reg_idx]
546             } else {
547                 0xffff_ffff
548             };
549             let mask = (0xffu32 << shift) & writable_mask;
550             let shifted_value = (u32::from(value) << shift) & writable_mask;
551             *r = *r & !mask | shifted_value;
552         } else {
553             warn!("bad PCI config write offset {}", offset);
554         }
555     }
556 
557     /// Adds a region specified by `config`.  Configures the specified BAR(s) to
558     /// report this region and size to the guest kernel.  Enforces a few constraints
559     /// (i.e, region size must be power of two, register not already used). Returns 'None' on
560     /// failure all, `Some(BarIndex)` on success.
561     pub fn add_pci_bar(&mut self, config: &PciBarConfiguration) -> Result<usize> {
562         if self.bars[config.reg_idx].used {
563             return Err(Error::BarInUse(config.reg_idx));
564         }
565 
566         if config.size.count_ones() != 1 {
567             return Err(Error::BarSizeInvalid(config.size));
568         }
569 
570         if config.reg_idx >= NUM_BAR_REGS {
571             return Err(Error::BarInvalid(config.reg_idx));
572         }
573 
574         let bar_idx = BAR0_REG + config.reg_idx;
575         let end_addr = config
576             .addr
577             .checked_add(config.size - 1)
578             .ok_or(Error::BarAddressInvalid(config.addr, config.size))?;
579         match config.region_type {
580             PciBarRegionType::Memory32BitRegion | PciBarRegionType::IoRegion => {
581                 if end_addr > u64::from(u32::max_value()) {
582                     return Err(Error::BarAddressInvalid(config.addr, config.size));
583                 }
584 
585                 // Encode the BAR size as expected by the software running in
586                 // the guest.
587                 self.bars[config.reg_idx].size =
588                     encode_32_bits_bar_size(config.size as u32).ok_or(Error::Encode32BarSize)?;
589             }
590             PciBarRegionType::Memory64BitRegion => {
591                 if config.reg_idx + 1 >= NUM_BAR_REGS {
592                     return Err(Error::BarInvalid64(config.reg_idx));
593                 }
594 
595                 if end_addr > u64::max_value() {
596                     return Err(Error::BarAddressInvalid(config.addr, config.size));
597                 }
598 
599                 if self.bars[config.reg_idx + 1].used {
600                     return Err(Error::BarInUse64(config.reg_idx));
601                 }
602 
603                 // Encode the BAR size as expected by the software running in
604                 // the guest.
605                 let (bar_size_hi, bar_size_lo) =
606                     encode_64_bits_bar_size(config.size).ok_or(Error::Encode64BarSize)?;
607 
608                 self.registers[bar_idx + 1] = (config.addr >> 32) as u32;
609                 self.writable_bits[bar_idx + 1] = 0xffff_ffff;
610                 self.bars[config.reg_idx + 1].addr = self.registers[bar_idx + 1];
611                 self.bars[config.reg_idx].size = bar_size_lo;
612                 self.bars[config.reg_idx + 1].size = bar_size_hi;
613                 self.bars[config.reg_idx + 1].used = true;
614             }
615         }
616 
617         let (mask, lower_bits) = match config.region_type {
618             PciBarRegionType::Memory32BitRegion | PciBarRegionType::Memory64BitRegion => (
619                 BAR_MEM_ADDR_MASK,
620                 config.prefetchable as u32 | config.region_type as u32,
621             ),
622             PciBarRegionType::IoRegion => (BAR_IO_ADDR_MASK, config.region_type as u32),
623         };
624 
625         self.registers[bar_idx] = ((config.addr as u32) & mask) | lower_bits;
626         self.writable_bits[bar_idx] = mask;
627         self.bars[config.reg_idx].addr = self.registers[bar_idx];
628         self.bars[config.reg_idx].used = true;
629         self.bars[config.reg_idx].r#type = Some(config.region_type);
630         Ok(config.reg_idx)
631     }
632 
633     /// Adds rom expansion BAR.
634     pub fn add_pci_rom_bar(&mut self, config: &PciBarConfiguration, active: u32) -> Result<usize> {
635         if self.rom_bar_used {
636             return Err(Error::RomBarInUse(config.reg_idx));
637         }
638 
639         if config.size.count_ones() != 1 {
640             return Err(Error::RomBarSizeInvalid(config.size));
641         }
642 
643         if config.reg_idx != ROM_BAR_REG {
644             return Err(Error::RomBarInvalid(config.reg_idx));
645         }
646 
647         let end_addr = config
648             .addr
649             .checked_add(config.size - 1)
650             .ok_or(Error::RomBarAddressInvalid(config.addr, config.size))?;
651 
652         if end_addr > u64::from(u32::max_value()) {
653             return Err(Error::RomBarAddressInvalid(config.addr, config.size));
654         }
655 
656         self.registers[config.reg_idx] = (config.addr as u32) | active;
657         self.writable_bits[config.reg_idx] = ROM_BAR_ADDR_MASK;
658         self.rom_bar_addr = self.registers[config.reg_idx];
659         self.rom_bar_size =
660             encode_32_bits_bar_size(config.size as u32).ok_or(Error::Encode32BarSize)?;
661         self.rom_bar_used = true;
662         Ok(config.reg_idx)
663     }
664 
665     /// Returns the address of the given BAR region.
666     pub fn get_bar_addr(&self, bar_num: usize) -> u64 {
667         let bar_idx = BAR0_REG + bar_num;
668 
669         let mut addr = u64::from(self.bars[bar_num].addr & self.writable_bits[bar_idx]);
670 
671         if let Some(bar_type) = self.bars[bar_num].r#type {
672             if bar_type == PciBarRegionType::Memory64BitRegion {
673                 addr |= u64::from(self.bars[bar_num + 1].addr) << 32;
674             }
675         }
676 
677         addr
678     }
679 
680     /// Configures the IRQ line and pin used by this device.
681     pub fn set_irq(&mut self, line: u8, pin: PciInterruptPin) {
682         // `pin` is 1-based in the pci config space.
683         let pin_idx = (pin as u32) + 1;
684         self.registers[INTERRUPT_LINE_PIN_REG] = (self.registers[INTERRUPT_LINE_PIN_REG]
685             & 0xffff_0000)
686             | (pin_idx << 8)
687             | u32::from(line);
688     }
689 
690     /// Adds the capability `cap_data` to the list of capabilities.
691     /// `cap_data` should include the two-byte PCI capability header (type, next),
692     /// but not populate it. Correct values will be generated automatically based
693     /// on `cap_data.id()`.
694     pub fn add_capability(&mut self, cap_data: &dyn PciCapability) -> Result<usize> {
695         let total_len = cap_data.bytes().len();
696         // Check that the length is valid.
697         if cap_data.bytes().is_empty() {
698             return Err(Error::CapabilityEmpty);
699         }
700         let (cap_offset, tail_offset) = match self.last_capability {
701             Some((offset, len)) => (Self::next_dword(offset, len), offset + 1),
702             None => (FIRST_CAPABILITY_OFFSET, CAPABILITY_LIST_HEAD_OFFSET),
703         };
704         let end_offset = cap_offset
705             .checked_add(total_len)
706             .ok_or(Error::CapabilitySpaceFull(total_len))?;
707         if end_offset > CAPABILITY_MAX_OFFSET {
708             return Err(Error::CapabilitySpaceFull(total_len));
709         }
710         self.registers[STATUS_REG] |= STATUS_REG_CAPABILITIES_USED_MASK;
711         self.write_byte_internal(tail_offset, cap_offset as u8, false);
712         self.write_byte_internal(cap_offset, cap_data.id() as u8, false);
713         self.write_byte_internal(cap_offset + 1, 0, false); // Next pointer.
714         for (i, byte) in cap_data.bytes().iter().enumerate() {
715             self.write_byte_internal(cap_offset + i + 2, *byte, false);
716         }
717         self.last_capability = Some((cap_offset, total_len));
718 
719         match cap_data.id() {
720             PciCapabilityId::MessageSignalledInterrupts => {
721                 self.writable_bits[cap_offset / 4] = MSI_CAPABILITY_REGISTER_MASK;
722             }
723             PciCapabilityId::MsiX => {
724                 self.msix_cap_reg_idx = Some(cap_offset / 4);
725                 self.writable_bits[self.msix_cap_reg_idx.unwrap()] = MSIX_CAPABILITY_REGISTER_MASK;
726             }
727             _ => {}
728         }
729 
730         Ok(cap_offset)
731     }
732 
733     // Find the next aligned offset after the one given.
734     fn next_dword(offset: usize, len: usize) -> usize {
735         let next = offset + len;
736         (next + 3) & !3
737     }
738 
739     pub fn write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8]) {
740         if offset as usize + data.len() > 4 {
741             return;
742         }
743 
744         // Handle potential write to MSI-X message control register
745         if let Some(msix_cap_reg_idx) = self.msix_cap_reg_idx {
746             if let Some(msix_config) = &self.msix_config {
747                 if msix_cap_reg_idx == reg_idx && offset == 2 && data.len() == 2 {
748                     msix_config
749                         .lock()
750                         .unwrap()
751                         .set_msg_ctl(LittleEndian::read_u16(data));
752                 } else if msix_cap_reg_idx == reg_idx && offset == 0 && data.len() == 4 {
753                     msix_config
754                         .lock()
755                         .unwrap()
756                         .set_msg_ctl((LittleEndian::read_u32(data) >> 16) as u16);
757                 }
758             }
759         }
760 
761         match data.len() {
762             1 => self.write_byte(reg_idx * 4 + offset as usize, data[0]),
763             2 => self.write_word(
764                 reg_idx * 4 + offset as usize,
765                 u16::from(data[0]) | u16::from(data[1]) << 8,
766             ),
767             4 => self.write_reg(reg_idx, LittleEndian::read_u32(data)),
768             _ => (),
769         }
770     }
771 
772     pub fn read_config_register(&self, reg_idx: usize) -> u32 {
773         self.read_reg(reg_idx)
774     }
775 
776     pub fn detect_bar_reprogramming(
777         &mut self,
778         reg_idx: usize,
779         data: &[u8],
780     ) -> Option<BarReprogrammingParams> {
781         if data.len() != 4 {
782             return None;
783         }
784 
785         let value = LittleEndian::read_u32(data);
786 
787         let mask = self.writable_bits[reg_idx];
788         if (BAR0_REG..BAR0_REG + NUM_BAR_REGS).contains(&reg_idx) {
789             // Ignore the case where the BAR size is being asked for.
790             if value == 0xffff_ffff {
791                 return None;
792             }
793 
794             let bar_idx = reg_idx - 4;
795             // Handle special case where the address being written is
796             // different from the address initially provided. This is a
797             // BAR reprogramming case which needs to be properly caught.
798             if let Some(bar_type) = self.bars[bar_idx].r#type {
799                 // In case of 64 bits memory BAR, we don't do anything until
800                 // the upper BAR is modified, otherwise we would be moving the
801                 // BAR to a wrong location in memory.
802                 if bar_type == PciBarRegionType::Memory64BitRegion {
803                     return None;
804                 }
805 
806                 // Ignore the case where the value is unchanged.
807                 if (value & mask) == (self.bars[bar_idx].addr & mask) {
808                     return None;
809                 }
810 
811                 info!(
812                     "Detected BAR reprogramming: (BAR {}) 0x{:x}->0x{:x}",
813                     reg_idx, self.registers[reg_idx], value
814                 );
815                 let old_base = u64::from(self.bars[bar_idx].addr & mask);
816                 let new_base = u64::from(value & mask);
817                 let len = u64::from(
818                     decode_32_bits_bar_size(self.bars[bar_idx].size)
819                         .ok_or(Error::Decode32BarSize)
820                         .unwrap(),
821                 );
822                 let region_type = bar_type;
823 
824                 self.bars[bar_idx].addr = value;
825 
826                 return Some(BarReprogrammingParams {
827                     old_base,
828                     new_base,
829                     len,
830                     region_type,
831                 });
832             } else if (reg_idx > BAR0_REG)
833                 && ((self.registers[reg_idx - 1] & self.writable_bits[reg_idx - 1])
834                     != (self.bars[bar_idx - 1].addr & self.writable_bits[reg_idx - 1])
835                     || (value & mask) != (self.bars[bar_idx].addr & mask))
836             {
837                 info!(
838                     "Detected BAR reprogramming: (BAR {}) 0x{:x}->0x{:x}",
839                     reg_idx, self.registers[reg_idx], value
840                 );
841                 let old_base = u64::from(self.bars[bar_idx].addr & mask) << 32
842                     | u64::from(self.bars[bar_idx - 1].addr & self.writable_bits[reg_idx - 1]);
843                 let new_base = u64::from(value & mask) << 32
844                     | u64::from(self.registers[reg_idx - 1] & self.writable_bits[reg_idx - 1]);
845                 let len =
846                     decode_64_bits_bar_size(self.bars[bar_idx].size, self.bars[bar_idx - 1].size)
847                         .ok_or(Error::Decode64BarSize)
848                         .unwrap();
849                 let region_type = PciBarRegionType::Memory64BitRegion;
850 
851                 self.bars[bar_idx].addr = value;
852                 self.bars[bar_idx - 1].addr = self.registers[reg_idx - 1];
853 
854                 return Some(BarReprogrammingParams {
855                     old_base,
856                     new_base,
857                     len,
858                     region_type,
859                 });
860             }
861         } else if reg_idx == ROM_BAR_REG && (value & mask) != (self.rom_bar_addr & mask) {
862             // Ignore the case where the BAR size is being asked for.
863             if value & ROM_BAR_ADDR_MASK == ROM_BAR_ADDR_MASK {
864                 return None;
865             }
866 
867             info!(
868                 "Detected ROM BAR reprogramming: (BAR {}) 0x{:x}->0x{:x}",
869                 reg_idx, self.registers[reg_idx], value
870             );
871             let old_base = u64::from(self.rom_bar_addr & mask);
872             let new_base = u64::from(value & mask);
873             let len = u64::from(
874                 decode_32_bits_bar_size(self.rom_bar_size)
875                     .ok_or(Error::Decode32BarSize)
876                     .unwrap(),
877             );
878             let region_type = PciBarRegionType::Memory32BitRegion;
879 
880             self.rom_bar_addr = value;
881 
882             return Some(BarReprogrammingParams {
883                 old_base,
884                 new_base,
885                 len,
886                 region_type,
887             });
888         }
889 
890         None
891     }
892 }
893 
894 impl Pausable for PciConfiguration {}
895 
896 impl Snapshottable for PciConfiguration {
897     fn id(&self) -> String {
898         String::from("pci_configuration")
899     }
900 
901     fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
902         Snapshot::new_from_versioned_state(&self.id(), &self.state())
903     }
904 
905     fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
906         self.set_state(&snapshot.to_versioned_state(&self.id())?);
907         Ok(())
908     }
909 }
910 
911 impl Default for PciBarConfiguration {
912     fn default() -> Self {
913         PciBarConfiguration {
914             reg_idx: 0,
915             addr: 0,
916             size: 0,
917             region_type: PciBarRegionType::Memory64BitRegion,
918             prefetchable: PciBarPrefetchable::NotPrefetchable,
919         }
920     }
921 }
922 
923 impl PciBarConfiguration {
924     pub fn new(
925         reg_idx: usize,
926         size: u64,
927         region_type: PciBarRegionType,
928         prefetchable: PciBarPrefetchable,
929     ) -> Self {
930         PciBarConfiguration {
931             reg_idx,
932             addr: 0,
933             size,
934             region_type,
935             prefetchable,
936         }
937     }
938 
939     #[must_use]
940     pub fn set_register_index(mut self, reg_idx: usize) -> Self {
941         self.reg_idx = reg_idx;
942         self
943     }
944 
945     #[must_use]
946     pub fn set_address(mut self, addr: u64) -> Self {
947         self.addr = addr;
948         self
949     }
950 
951     #[must_use]
952     pub fn set_size(mut self, size: u64) -> Self {
953         self.size = size;
954         self
955     }
956 
957     pub fn get_size(&self) -> u64 {
958         self.size
959     }
960 
961     #[must_use]
962     pub fn set_region_type(mut self, region_type: PciBarRegionType) -> Self {
963         self.region_type = region_type;
964         self
965     }
966 }
967 
968 #[cfg(test)]
969 mod tests {
970     use vm_memory::ByteValued;
971 
972     use super::*;
973 
974     #[repr(packed)]
975     #[derive(Clone, Copy, Default)]
976     #[allow(dead_code)]
977     struct TestCap {
978         len: u8,
979         foo: u8,
980     }
981 
982     // SAFETY: All members are simple numbers and any value is valid.
983     unsafe impl ByteValued for TestCap {}
984 
985     impl PciCapability for TestCap {
986         fn bytes(&self) -> &[u8] {
987             self.as_slice()
988         }
989 
990         fn id(&self) -> PciCapabilityId {
991             PciCapabilityId::VendorSpecific
992         }
993     }
994 
995     #[test]
996     fn add_capability() {
997         let mut cfg = PciConfiguration::new(
998             0x1234,
999             0x5678,
1000             0x1,
1001             PciClassCode::MultimediaController,
1002             &PciMultimediaSubclass::AudioController,
1003             None,
1004             PciHeaderType::Device,
1005             0xABCD,
1006             0x2468,
1007             None,
1008         );
1009 
1010         // Add two capabilities with different contents.
1011         let cap1 = TestCap { len: 4, foo: 0xAA };
1012         let cap1_offset = cfg.add_capability(&cap1).unwrap();
1013         assert_eq!(cap1_offset % 4, 0);
1014 
1015         let cap2 = TestCap {
1016             len: 0x04,
1017             foo: 0x55,
1018         };
1019         let cap2_offset = cfg.add_capability(&cap2).unwrap();
1020         assert_eq!(cap2_offset % 4, 0);
1021 
1022         // The capability list head should be pointing to cap1.
1023         let cap_ptr = cfg.read_reg(CAPABILITY_LIST_HEAD_OFFSET / 4) & 0xFF;
1024         assert_eq!(cap1_offset, cap_ptr as usize);
1025 
1026         // Verify the contents of the capabilities.
1027         let cap1_data = cfg.read_reg(cap1_offset / 4);
1028         assert_eq!(cap1_data & 0xFF, 0x09); // capability ID
1029         assert_eq!((cap1_data >> 8) & 0xFF, cap2_offset as u32); // next capability pointer
1030         assert_eq!((cap1_data >> 16) & 0xFF, 0x04); // cap1.len
1031         assert_eq!((cap1_data >> 24) & 0xFF, 0xAA); // cap1.foo
1032 
1033         let cap2_data = cfg.read_reg(cap2_offset / 4);
1034         assert_eq!(cap2_data & 0xFF, 0x09); // capability ID
1035         assert_eq!((cap2_data >> 8) & 0xFF, 0x00); // next capability pointer
1036         assert_eq!((cap2_data >> 16) & 0xFF, 0x04); // cap2.len
1037         assert_eq!((cap2_data >> 24) & 0xFF, 0x55); // cap2.foo
1038     }
1039 
1040     #[derive(Copy, Clone)]
1041     enum TestPi {
1042         Test = 0x5a,
1043     }
1044 
1045     impl PciProgrammingInterface for TestPi {
1046         fn get_register_value(&self) -> u8 {
1047             *self as u8
1048         }
1049     }
1050 
1051     #[test]
1052     fn class_code() {
1053         let cfg = PciConfiguration::new(
1054             0x1234,
1055             0x5678,
1056             0x1,
1057             PciClassCode::MultimediaController,
1058             &PciMultimediaSubclass::AudioController,
1059             Some(&TestPi::Test),
1060             PciHeaderType::Device,
1061             0xABCD,
1062             0x2468,
1063             None,
1064         );
1065 
1066         let class_reg = cfg.read_reg(2);
1067         let class_code = (class_reg >> 24) & 0xFF;
1068         let subclass = (class_reg >> 16) & 0xFF;
1069         let prog_if = (class_reg >> 8) & 0xFF;
1070         assert_eq!(class_code, 0x04);
1071         assert_eq!(subclass, 0x01);
1072         assert_eq!(prog_if, 0x5a);
1073     }
1074 }
1075