• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 file.
4 
5 use std::convert::TryInto;
6 use std::fmt::{self, Display};
7 
8 use crate::pci::PciInterruptPin;
9 use base::warn;
10 
11 // The number of 32bit registers in the config space, 256 bytes.
12 const NUM_CONFIGURATION_REGISTERS: usize = 64;
13 
14 pub const COMMAND_REG: usize = 1;
15 pub const COMMAND_REG_IO_SPACE_MASK: u32 = 0x0000_0001;
16 pub const COMMAND_REG_MEMORY_SPACE_MASK: u32 = 0x0000_0002;
17 const STATUS_REG: usize = 1;
18 const STATUS_REG_CAPABILITIES_USED_MASK: u32 = 0x0010_0000;
19 const BAR0_REG: usize = 4;
20 const BAR_IO_ADDR_MASK: u32 = 0xffff_fffc;
21 const BAR_IO_MIN_SIZE: u64 = 4;
22 const BAR_MEM_ADDR_MASK: u32 = 0xffff_fff0;
23 const BAR_MEM_MIN_SIZE: u64 = 16;
24 const NUM_BAR_REGS: usize = 6;
25 const CAPABILITY_LIST_HEAD_OFFSET: usize = 0x34;
26 const FIRST_CAPABILITY_OFFSET: usize = 0x40;
27 const CAPABILITY_MAX_OFFSET: usize = 255;
28 
29 const INTERRUPT_LINE_PIN_REG: usize = 15;
30 
31 /// Represents the types of PCI headers allowed in the configuration registers.
32 #[allow(dead_code)]
33 #[derive(Copy, Clone)]
34 pub enum PciHeaderType {
35     Device,
36     Bridge,
37 }
38 
39 /// Classes of PCI nodes.
40 #[allow(dead_code)]
41 #[derive(Copy, Clone)]
42 pub enum PciClassCode {
43     TooOld,
44     MassStorage,
45     NetworkController,
46     DisplayController,
47     MultimediaController,
48     MemoryController,
49     BridgeDevice,
50     SimpleCommunicationController,
51     BaseSystemPeripheral,
52     InputDevice,
53     DockingStation,
54     Processor,
55     SerialBusController,
56     WirelessController,
57     IntelligentIoController,
58     EncryptionController,
59     DataAcquisitionSignalProcessing,
60     Other = 0xff,
61 }
62 
63 impl PciClassCode {
get_register_value(&self) -> u864     pub fn get_register_value(&self) -> u8 {
65         *self as u8
66     }
67 }
68 
69 /// A PCI sublcass. Each class in `PciClassCode` can specify a unique set of subclasses. This trait
70 /// is implemented by each subclass. It allows use of a trait object to generate configurations.
71 pub trait PciSubclass {
72     /// Convert this subclass to the value used in the PCI specification.
get_register_value(&self) -> u873     fn get_register_value(&self) -> u8;
74 }
75 
76 /// Subclasses of the DisplayController class.
77 #[allow(dead_code)]
78 #[derive(Copy, Clone)]
79 pub enum PciDisplaySubclass {
80     VgaCompatibleController = 0x00,
81     XgaCompatibleController = 0x01,
82     ThreeDController = 0x02,
83     Other = 0x80,
84 }
85 
86 impl PciSubclass for PciDisplaySubclass {
get_register_value(&self) -> u887     fn get_register_value(&self) -> u8 {
88         *self as u8
89     }
90 }
91 
92 /// Subclasses of the MultimediaController class.
93 #[allow(dead_code)]
94 #[derive(Copy, Clone)]
95 pub enum PciMultimediaSubclass {
96     VideoController = 0x00,
97     AudioController = 0x01,
98     TelephonyDevice = 0x02,
99     AudioDevice = 0x03,
100     Other = 0x80,
101 }
102 
103 impl PciSubclass for PciMultimediaSubclass {
get_register_value(&self) -> u8104     fn get_register_value(&self) -> u8 {
105         *self as u8
106     }
107 }
108 
109 /// Subclasses of the BridgeDevice
110 #[allow(dead_code)]
111 #[derive(Copy, Clone)]
112 pub enum PciBridgeSubclass {
113     HostBridge = 0x00,
114     IsaBridge = 0x01,
115     EisaBridge = 0x02,
116     McaBridge = 0x03,
117     PciToPciBridge = 0x04,
118     PcmciaBridge = 0x05,
119     NuBusBridge = 0x06,
120     CardBusBridge = 0x07,
121     RACEwayBridge = 0x08,
122     PciToPciSemiTransparentBridge = 0x09,
123     InfiniBrandToPciHostBridge = 0x0a,
124     OtherBridgeDevice = 0x80,
125 }
126 
127 impl PciSubclass for PciBridgeSubclass {
get_register_value(&self) -> u8128     fn get_register_value(&self) -> u8 {
129         *self as u8
130     }
131 }
132 
133 /// Subclass of the SerialBus
134 #[allow(dead_code)]
135 #[derive(Copy, Clone)]
136 pub enum PciSerialBusSubClass {
137     Firewire = 0x00,
138     ACCESSbus = 0x01,
139     SSA = 0x02,
140     USB = 0x03,
141 }
142 
143 impl PciSubclass for PciSerialBusSubClass {
get_register_value(&self) -> u8144     fn get_register_value(&self) -> u8 {
145         *self as u8
146     }
147 }
148 
149 /// A PCI class programming interface. Each combination of `PciClassCode` and
150 /// `PciSubclass` can specify a set of register-level programming interfaces.
151 /// This trait is implemented by each programming interface.
152 /// It allows use of a trait object to generate configurations.
153 pub trait PciProgrammingInterface {
154     /// Convert this programming interface to the value used in the PCI specification.
get_register_value(&self) -> u8155     fn get_register_value(&self) -> u8;
156 }
157 
158 /// Types of PCI capabilities.
159 pub enum PciCapabilityID {
160     ListID = 0,
161     PowerManagement = 0x01,
162     AcceleratedGraphicsPort = 0x02,
163     VitalProductData = 0x03,
164     SlotIdentification = 0x04,
165     MessageSignalledInterrupts = 0x05,
166     CompactPCIHotSwap = 0x06,
167     PCIX = 0x07,
168     HyperTransport = 0x08,
169     VendorSpecific = 0x09,
170     Debugport = 0x0A,
171     CompactPCICentralResourceControl = 0x0B,
172     PCIStandardHotPlugController = 0x0C,
173     BridgeSubsystemVendorDeviceID = 0x0D,
174     AGPTargetPCIPCIbridge = 0x0E,
175     SecureDevice = 0x0F,
176     PCIExpress = 0x10,
177     MSIX = 0x11,
178     SATADataIndexConf = 0x12,
179     PCIAdvancedFeatures = 0x13,
180     PCIEnhancedAllocation = 0x14,
181 }
182 
183 /// A PCI capability list. Devices can optionally specify capabilities in their configuration space.
184 pub trait PciCapability {
bytes(&self) -> &[u8]185     fn bytes(&self) -> &[u8];
id(&self) -> PciCapabilityID186     fn id(&self) -> PciCapabilityID;
187 }
188 
189 /// Contains the configuration space of a PCI node.
190 /// See the [specification](https://en.wikipedia.org/wiki/PCI_configuration_space).
191 /// The configuration space is accessed with DWORD reads and writes from the guest.
192 pub struct PciConfiguration {
193     registers: [u32; NUM_CONFIGURATION_REGISTERS],
194     writable_bits: [u32; NUM_CONFIGURATION_REGISTERS], // writable bits for each register.
195     bar_used: [bool; NUM_BAR_REGS],
196     bar_configs: [Option<PciBarConfiguration>; NUM_BAR_REGS],
197     // Contains the byte offset and size of the last capability.
198     last_capability: Option<(usize, usize)>,
199 }
200 
201 /// See pci_regs.h in kernel
202 #[derive(Copy, Clone, Debug, PartialEq)]
203 pub enum PciBarRegionType {
204     Memory32BitRegion = 0,
205     IORegion = 0x01,
206     Memory64BitRegion = 0x04,
207 }
208 
209 #[derive(Copy, Clone, Debug, PartialEq)]
210 pub enum PciBarPrefetchable {
211     NotPrefetchable = 0,
212     Prefetchable = 0x08,
213 }
214 
215 #[derive(Copy, Clone, Debug, PartialEq)]
216 pub struct PciBarConfiguration {
217     addr: u64,
218     size: u64,
219     reg_idx: usize,
220     region_type: PciBarRegionType,
221     prefetchable: PciBarPrefetchable,
222 }
223 
224 pub struct PciBarIter<'a> {
225     config: &'a PciConfiguration,
226     bar_num: usize,
227 }
228 
229 impl<'a> Iterator for PciBarIter<'a> {
230     type Item = PciBarConfiguration;
231 
next(&mut self) -> Option<Self::Item>232     fn next(&mut self) -> Option<Self::Item> {
233         while self.bar_num < NUM_BAR_REGS {
234             let bar_config = self.config.get_bar_configuration(self.bar_num);
235             self.bar_num += 1;
236             if let Some(bar_config) = bar_config {
237                 return Some(bar_config);
238             }
239         }
240 
241         None
242     }
243 }
244 
245 #[derive(Debug, PartialEq)]
246 pub enum Error {
247     BarAddressInvalid(u64, u64),
248     BarAlignmentInvalid(u64, u64),
249     BarInUse(usize),
250     BarInUse64(usize),
251     BarInvalid(usize),
252     BarInvalid64(usize),
253     BarSizeInvalid(u64),
254     CapabilityEmpty,
255     CapabilityLengthInvalid(usize),
256     CapabilitySpaceFull(usize),
257 }
258 pub type Result<T> = std::result::Result<T, Error>;
259 
260 impl std::error::Error for Error {}
261 
262 impl Display for Error {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result263     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
264         use self::Error::*;
265         match self {
266             BarAddressInvalid(a, s) => write!(f, "address {} size {} too big", a, s),
267             BarAlignmentInvalid(a, s) => write!(f, "address {} is not aligned to size {}", a, s),
268             BarInUse(b) => write!(f, "bar {} already used", b),
269             BarInUse64(b) => write!(f, "64bit bar {} already used(requires two regs)", b),
270             BarInvalid(b) => write!(f, "bar {} invalid, max {}", b, NUM_BAR_REGS - 1),
271             BarInvalid64(b) => write!(
272                 f,
273                 "64bitbar {} invalid, requires two regs, max {}",
274                 b,
275                 NUM_BAR_REGS - 1
276             ),
277             BarSizeInvalid(s) => write!(f, "bar address {} not a power of two", s),
278             CapabilityEmpty => write!(f, "empty capabilities are invalid"),
279             CapabilityLengthInvalid(l) => write!(f, "Invalid capability length {}", l),
280             CapabilitySpaceFull(s) => write!(f, "capability of size {} doesn't fit", s),
281         }
282     }
283 }
284 
285 impl PciConfiguration {
new( vendor_id: u16, device_id: u16, class_code: PciClassCode, subclass: &dyn PciSubclass, programming_interface: Option<&dyn PciProgrammingInterface>, header_type: PciHeaderType, subsystem_vendor_id: u16, subsystem_id: u16, revision_id: u8, ) -> Self286     pub fn new(
287         vendor_id: u16,
288         device_id: u16,
289         class_code: PciClassCode,
290         subclass: &dyn PciSubclass,
291         programming_interface: Option<&dyn PciProgrammingInterface>,
292         header_type: PciHeaderType,
293         subsystem_vendor_id: u16,
294         subsystem_id: u16,
295         revision_id: u8,
296     ) -> Self {
297         let mut registers = [0u32; NUM_CONFIGURATION_REGISTERS];
298         let mut writable_bits = [0u32; NUM_CONFIGURATION_REGISTERS];
299         registers[0] = u32::from(device_id) << 16 | u32::from(vendor_id);
300         // TODO(dverkamp): Status should be write-1-to-clear
301         writable_bits[1] = 0x0000_ffff; // Status (r/o), command (r/w)
302         let pi = if let Some(pi) = programming_interface {
303             pi.get_register_value()
304         } else {
305             0
306         };
307         registers[2] = u32::from(class_code.get_register_value()) << 24
308             | u32::from(subclass.get_register_value()) << 16
309             | u32::from(pi) << 8
310             | u32::from(revision_id);
311         writable_bits[3] = 0x0000_00ff; // Cacheline size (r/w)
312         match header_type {
313             PciHeaderType::Device => {
314                 registers[3] = 0x0000_0000; // Header type 0 (device)
315                 writable_bits[15] = 0x0000_00ff; // Interrupt line (r/w)
316             }
317             PciHeaderType::Bridge => {
318                 registers[3] = 0x0001_0000; // Header type 1 (bridge)
319                 writable_bits[9] = 0xfff0_fff0; // Memory base and limit
320                 writable_bits[15] = 0xffff_00ff; // Bridge control (r/w), interrupt line (r/w)
321             }
322         };
323         registers[11] = u32::from(subsystem_id) << 16 | u32::from(subsystem_vendor_id);
324 
325         PciConfiguration {
326             registers,
327             writable_bits,
328             bar_used: [false; NUM_BAR_REGS],
329             bar_configs: [None; NUM_BAR_REGS],
330             last_capability: None,
331         }
332     }
333 
334     /// Reads a 32bit register from `reg_idx` in the register map.
read_reg(&self, reg_idx: usize) -> u32335     pub fn read_reg(&self, reg_idx: usize) -> u32 {
336         *(self.registers.get(reg_idx).unwrap_or(&0xffff_ffff))
337     }
338 
339     /// Writes data to PciConfiguration.registers.
340     /// `reg_idx` - index into PciConfiguration.registers.
341     /// `offset`  - PciConfiguration.registers is in unit of DWord, offset define byte
342     ///             offset in the DWrod.
343     /// `data`    - The data to write.
write_reg(&mut self, reg_idx: usize, offset: u64, data: &[u8])344     pub fn write_reg(&mut self, reg_idx: usize, offset: u64, data: &[u8]) {
345         let reg_offset = reg_idx * 4 + offset as usize;
346         match data.len() {
347             1 => self.write_byte(reg_offset, data[0]),
348             2 => self.write_word(reg_offset, u16::from_le_bytes(data.try_into().unwrap())),
349             4 => self.write_dword(reg_offset, u32::from_le_bytes(data.try_into().unwrap())),
350             _ => (),
351         }
352     }
353 
354     /// Writes a 32bit dword to `offset`. `offset` must be 32bit aligned.
write_dword(&mut self, offset: usize, value: u32)355     fn write_dword(&mut self, offset: usize, value: u32) {
356         if offset % 4 != 0 {
357             warn!("bad PCI config dword write offset {}", offset);
358             return;
359         }
360         let reg_idx = offset / 4;
361         if let Some(r) = self.registers.get_mut(reg_idx) {
362             *r = (*r & !self.writable_bits[reg_idx]) | (value & self.writable_bits[reg_idx]);
363         } else {
364             warn!("bad PCI dword write {}", offset);
365         }
366     }
367 
368     /// Writes a 16bit word to `offset`. `offset` must be 16bit aligned.
write_word(&mut self, offset: usize, value: u16)369     fn write_word(&mut self, offset: usize, value: u16) {
370         let shift = match offset % 4 {
371             0 => 0,
372             2 => 16,
373             _ => {
374                 warn!("bad PCI config word write offset {}", offset);
375                 return;
376             }
377         };
378         let reg_idx = offset / 4;
379 
380         if let Some(r) = self.registers.get_mut(reg_idx) {
381             let writable_mask = self.writable_bits[reg_idx];
382             let mask = (0xffffu32 << shift) & writable_mask;
383             let shifted_value = (u32::from(value) << shift) & writable_mask;
384             *r = *r & !mask | shifted_value;
385         } else {
386             warn!("bad PCI config word write offset {}", offset);
387         }
388     }
389 
390     /// Writes a byte to `offset`.
write_byte(&mut self, offset: usize, value: u8)391     fn write_byte(&mut self, offset: usize, value: u8) {
392         self.write_byte_internal(offset, value, true);
393     }
394 
395     /// Writes a byte to `offset`, optionally enforcing read-only bits.
write_byte_internal(&mut self, offset: usize, value: u8, apply_writable_mask: bool)396     fn write_byte_internal(&mut self, offset: usize, value: u8, apply_writable_mask: bool) {
397         let shift = (offset % 4) * 8;
398         let reg_idx = offset / 4;
399 
400         if let Some(r) = self.registers.get_mut(reg_idx) {
401             let writable_mask = if apply_writable_mask {
402                 self.writable_bits[reg_idx]
403             } else {
404                 0xffff_ffff
405             };
406             let mask = (0xffu32 << shift) & writable_mask;
407             let shifted_value = (u32::from(value) << shift) & writable_mask;
408             *r = *r & !mask | shifted_value;
409         } else {
410             warn!("bad PCI config byte write offset {}", offset);
411         }
412     }
413 
414     /// Adds a region specified by `config`.  Configures the specified BAR(s) to
415     /// report this region and size to the guest kernel.  Enforces a few constraints
416     /// (i.e, region size must be power of two, register not already used). Returns 'None' on
417     /// failure all, `Some(BarIndex)` on success.
add_pci_bar(&mut self, config: PciBarConfiguration) -> Result<usize>418     pub fn add_pci_bar(&mut self, config: PciBarConfiguration) -> Result<usize> {
419         if config.reg_idx >= NUM_BAR_REGS {
420             return Err(Error::BarInvalid(config.reg_idx));
421         }
422 
423         if self.bar_used[config.reg_idx] {
424             return Err(Error::BarInUse(config.reg_idx));
425         }
426 
427         if config.size.count_ones() != 1 {
428             return Err(Error::BarSizeInvalid(config.size));
429         }
430 
431         let min_size = if config.region_type == PciBarRegionType::IORegion {
432             BAR_IO_MIN_SIZE
433         } else {
434             BAR_MEM_MIN_SIZE
435         };
436 
437         if config.size < min_size {
438             return Err(Error::BarSizeInvalid(config.size));
439         }
440 
441         if config.addr % config.size != 0 {
442             return Err(Error::BarAlignmentInvalid(config.addr, config.size));
443         }
444 
445         let bar_idx = BAR0_REG + config.reg_idx;
446         let end_addr = config
447             .addr
448             .checked_add(config.size)
449             .ok_or(Error::BarAddressInvalid(config.addr, config.size))?;
450         match config.region_type {
451             PciBarRegionType::Memory32BitRegion | PciBarRegionType::IORegion => {
452                 if end_addr > u64::from(u32::max_value()) {
453                     return Err(Error::BarAddressInvalid(config.addr, config.size));
454                 }
455             }
456             PciBarRegionType::Memory64BitRegion => {
457                 if config.reg_idx + 1 >= NUM_BAR_REGS {
458                     return Err(Error::BarInvalid64(config.reg_idx));
459                 }
460 
461                 if end_addr > u64::max_value() {
462                     return Err(Error::BarAddressInvalid(config.addr, config.size));
463                 }
464 
465                 if self.bar_used[config.reg_idx + 1] {
466                     return Err(Error::BarInUse64(config.reg_idx));
467                 }
468 
469                 self.registers[bar_idx + 1] = (config.addr >> 32) as u32;
470                 self.writable_bits[bar_idx + 1] = !((config.size - 1) >> 32) as u32;
471                 self.bar_used[config.reg_idx + 1] = true;
472             }
473         }
474 
475         let (mask, lower_bits) = match config.region_type {
476             PciBarRegionType::Memory32BitRegion | PciBarRegionType::Memory64BitRegion => {
477                 self.registers[COMMAND_REG] |= COMMAND_REG_MEMORY_SPACE_MASK;
478                 (
479                     BAR_MEM_ADDR_MASK,
480                     config.prefetchable as u32 | config.region_type as u32,
481                 )
482             }
483             PciBarRegionType::IORegion => {
484                 self.registers[COMMAND_REG] |= COMMAND_REG_IO_SPACE_MASK;
485                 (BAR_IO_ADDR_MASK, config.region_type as u32)
486             }
487         };
488 
489         self.registers[bar_idx] = ((config.addr as u32) & mask) | lower_bits;
490         self.writable_bits[bar_idx] = !(config.size - 1) as u32;
491         self.bar_used[config.reg_idx] = true;
492         self.bar_configs[config.reg_idx] = Some(config);
493         Ok(config.reg_idx)
494     }
495 
496     /// Returns an iterator of the currently configured base address registers.
497     #[allow(dead_code)] // TODO(dverkamp): remove this once used
get_bars(&self) -> PciBarIter498     pub fn get_bars(&self) -> PciBarIter {
499         PciBarIter {
500             config: &self,
501             bar_num: 0,
502         }
503     }
504 
get_bar_configuration(&self, bar_num: usize) -> Option<PciBarConfiguration>505     fn get_bar_configuration(&self, bar_num: usize) -> Option<PciBarConfiguration> {
506         let config = self.bar_configs.get(bar_num)?;
507 
508         if let Some(mut config) = config {
509             // The address may have been modified by the guest, so the value in bar_configs
510             // may be outdated. Replace it with the current value.
511             config.addr = self.get_bar_addr(bar_num);
512             Some(config)
513         } else {
514             None
515         }
516     }
517 
518     /// Returns the type of the given BAR region.
get_bar_type(&self, bar_num: usize) -> Option<PciBarRegionType>519     pub fn get_bar_type(&self, bar_num: usize) -> Option<PciBarRegionType> {
520         self.bar_configs.get(bar_num)?.map(|c| c.region_type)
521     }
522 
523     /// Returns the address of the given BAR region.
get_bar_addr(&self, bar_num: usize) -> u64524     pub fn get_bar_addr(&self, bar_num: usize) -> u64 {
525         let bar_idx = BAR0_REG + bar_num;
526 
527         let bar_type = match self.get_bar_type(bar_num) {
528             Some(t) => t,
529             None => return 0,
530         };
531 
532         match bar_type {
533             PciBarRegionType::IORegion => u64::from(self.registers[bar_idx] & BAR_IO_ADDR_MASK),
534             PciBarRegionType::Memory32BitRegion => {
535                 u64::from(self.registers[bar_idx] & BAR_MEM_ADDR_MASK)
536             }
537             PciBarRegionType::Memory64BitRegion => {
538                 u64::from(self.registers[bar_idx] & BAR_MEM_ADDR_MASK)
539                     | u64::from(self.registers[bar_idx + 1]) << 32
540             }
541         }
542     }
543 
544     /// Configures the IRQ line and pin used by this device.
set_irq(&mut self, line: u8, pin: PciInterruptPin)545     pub fn set_irq(&mut self, line: u8, pin: PciInterruptPin) {
546         // `pin` is 1-based in the pci config space.
547         let pin_idx = (pin as u32) + 1;
548         self.registers[INTERRUPT_LINE_PIN_REG] = (self.registers[INTERRUPT_LINE_PIN_REG]
549             & 0xffff_0000)
550             | (pin_idx << 8)
551             | u32::from(line);
552     }
553 
554     /// Adds the capability `cap_data` to the list of capabilities.
555     /// `cap_data` should include the two-byte PCI capability header (type, next),
556     /// but not populate it. Correct values will be generated automatically based
557     /// on `cap_data.id()`.
add_capability(&mut self, cap_data: &dyn PciCapability) -> Result<usize>558     pub fn add_capability(&mut self, cap_data: &dyn PciCapability) -> Result<usize> {
559         let total_len = cap_data.bytes().len();
560         // Check that the length is valid.
561         if cap_data.bytes().is_empty() {
562             return Err(Error::CapabilityEmpty);
563         }
564         let (cap_offset, tail_offset) = match self.last_capability {
565             Some((offset, len)) => (Self::next_dword(offset, len), offset + 1),
566             None => (FIRST_CAPABILITY_OFFSET, CAPABILITY_LIST_HEAD_OFFSET),
567         };
568         let end_offset = cap_offset
569             .checked_add(total_len)
570             .ok_or(Error::CapabilitySpaceFull(total_len))?;
571         if end_offset > CAPABILITY_MAX_OFFSET {
572             return Err(Error::CapabilitySpaceFull(total_len));
573         }
574         self.registers[STATUS_REG] |= STATUS_REG_CAPABILITIES_USED_MASK;
575         self.write_byte_internal(tail_offset, cap_offset as u8, false);
576         self.write_byte_internal(cap_offset, cap_data.id() as u8, false);
577         self.write_byte_internal(cap_offset + 1, 0, false); // Next pointer.
578         for (i, byte) in cap_data.bytes().iter().enumerate().skip(2) {
579             self.write_byte_internal(cap_offset + i, *byte, false);
580         }
581         self.last_capability = Some((cap_offset, total_len));
582         Ok(cap_offset)
583     }
584 
585     // Find the next aligned offset after the one given.
next_dword(offset: usize, len: usize) -> usize586     fn next_dword(offset: usize, len: usize) -> usize {
587         let next = offset + len;
588         (next + 3) & !3
589     }
590 }
591 
592 impl Default for PciBarConfiguration {
default() -> Self593     fn default() -> Self {
594         PciBarConfiguration {
595             reg_idx: 0,
596             addr: 0,
597             size: 0,
598             region_type: PciBarRegionType::Memory32BitRegion,
599             prefetchable: PciBarPrefetchable::NotPrefetchable,
600         }
601     }
602 }
603 
604 impl PciBarConfiguration {
new( reg_idx: usize, size: u64, region_type: PciBarRegionType, prefetchable: PciBarPrefetchable, ) -> Self605     pub fn new(
606         reg_idx: usize,
607         size: u64,
608         region_type: PciBarRegionType,
609         prefetchable: PciBarPrefetchable,
610     ) -> Self {
611         PciBarConfiguration {
612             reg_idx,
613             addr: 0,
614             size,
615             region_type,
616             prefetchable,
617         }
618     }
619 
set_register_index(mut self, reg_idx: usize) -> Self620     pub fn set_register_index(mut self, reg_idx: usize) -> Self {
621         self.reg_idx = reg_idx;
622         self
623     }
624 
get_register_index(&self) -> usize625     pub fn get_register_index(&self) -> usize {
626         self.reg_idx
627     }
628 
set_address(mut self, addr: u64) -> Self629     pub fn set_address(mut self, addr: u64) -> Self {
630         self.addr = addr;
631         self
632     }
633 
set_size(mut self, size: u64) -> Self634     pub fn set_size(mut self, size: u64) -> Self {
635         self.size = size;
636         self
637     }
638 
get_size(&self) -> u64639     pub fn get_size(&self) -> u64 {
640         self.size
641     }
642 }
643 
644 #[cfg(test)]
645 mod tests {
646     use data_model::DataInit;
647 
648     use super::*;
649 
650     #[repr(packed)]
651     #[derive(Clone, Copy)]
652     #[allow(dead_code)]
653     struct TestCap {
654         _vndr: u8,
655         _next: u8,
656         len: u8,
657         foo: u8,
658     }
659 
660     // It is safe to implement DataInit; all members are simple numbers and any value is valid.
661     unsafe impl DataInit for TestCap {}
662 
663     impl PciCapability for TestCap {
bytes(&self) -> &[u8]664         fn bytes(&self) -> &[u8] {
665             self.as_slice()
666         }
667 
id(&self) -> PciCapabilityID668         fn id(&self) -> PciCapabilityID {
669             PciCapabilityID::VendorSpecific
670         }
671     }
672 
673     #[test]
add_capability()674     fn add_capability() {
675         let mut cfg = PciConfiguration::new(
676             0x1234,
677             0x5678,
678             PciClassCode::MultimediaController,
679             &PciMultimediaSubclass::AudioController,
680             None,
681             PciHeaderType::Device,
682             0xABCD,
683             0x2468,
684             0,
685         );
686 
687         // Add two capabilities with different contents.
688         let cap1 = TestCap {
689             _vndr: 0,
690             _next: 0,
691             len: 4,
692             foo: 0xAA,
693         };
694         let cap1_offset = cfg.add_capability(&cap1).unwrap();
695         assert_eq!(cap1_offset % 4, 0);
696 
697         let cap2 = TestCap {
698             _vndr: 0,
699             _next: 0,
700             len: 0x04,
701             foo: 0x55,
702         };
703         let cap2_offset = cfg.add_capability(&cap2).unwrap();
704         assert_eq!(cap2_offset % 4, 0);
705 
706         // The capability list head should be pointing to cap1.
707         let cap_ptr = cfg.read_reg(CAPABILITY_LIST_HEAD_OFFSET / 4) & 0xFF;
708         assert_eq!(cap1_offset, cap_ptr as usize);
709 
710         // Verify the contents of the capabilities.
711         let cap1_data = cfg.read_reg(cap1_offset / 4);
712         assert_eq!(cap1_data & 0xFF, 0x09); // capability ID
713         assert_eq!((cap1_data >> 8) & 0xFF, cap2_offset as u32); // next capability pointer
714         assert_eq!((cap1_data >> 16) & 0xFF, 0x04); // cap1.len
715         assert_eq!((cap1_data >> 24) & 0xFF, 0xAA); // cap1.foo
716 
717         let cap2_data = cfg.read_reg(cap2_offset / 4);
718         assert_eq!(cap2_data & 0xFF, 0x09); // capability ID
719         assert_eq!((cap2_data >> 8) & 0xFF, 0x00); // next capability pointer
720         assert_eq!((cap2_data >> 16) & 0xFF, 0x04); // cap2.len
721         assert_eq!((cap2_data >> 24) & 0xFF, 0x55); // cap2.foo
722     }
723 
724     #[derive(Copy, Clone)]
725     enum TestPI {
726         Test = 0x5a,
727     }
728 
729     impl PciProgrammingInterface for TestPI {
get_register_value(&self) -> u8730         fn get_register_value(&self) -> u8 {
731             *self as u8
732         }
733     }
734 
735     #[test]
class_code()736     fn class_code() {
737         let cfg = PciConfiguration::new(
738             0x1234,
739             0x5678,
740             PciClassCode::MultimediaController,
741             &PciMultimediaSubclass::AudioController,
742             Some(&TestPI::Test),
743             PciHeaderType::Device,
744             0xABCD,
745             0x2468,
746             0,
747         );
748 
749         let class_reg = cfg.read_reg(2);
750         let class_code = (class_reg >> 24) & 0xFF;
751         let subclass = (class_reg >> 16) & 0xFF;
752         let prog_if = (class_reg >> 8) & 0xFF;
753         assert_eq!(class_code, 0x04);
754         assert_eq!(subclass, 0x01);
755         assert_eq!(prog_if, 0x5a);
756     }
757 
758     #[test]
read_only_bits()759     fn read_only_bits() {
760         let mut cfg = PciConfiguration::new(
761             0x1234,
762             0x5678,
763             PciClassCode::MultimediaController,
764             &PciMultimediaSubclass::AudioController,
765             Some(&TestPI::Test),
766             PciHeaderType::Device,
767             0xABCD,
768             0x2468,
769             0,
770         );
771 
772         // Attempt to overwrite vendor ID and device ID, which are read-only
773         cfg.write_reg(0, 0, &[0xBA, 0xAD, 0xF0, 0x0D]);
774         // The original vendor and device ID should remain.
775         assert_eq!(cfg.read_reg(0), 0x56781234);
776     }
777 
778     #[test]
query_unused_bar()779     fn query_unused_bar() {
780         let cfg = PciConfiguration::new(
781             0x1234,
782             0x5678,
783             PciClassCode::MultimediaController,
784             &PciMultimediaSubclass::AudioController,
785             Some(&TestPI::Test),
786             PciHeaderType::Device,
787             0xABCD,
788             0x2468,
789             0,
790         );
791 
792         // No BAR 0 has been configured, so these should return None or 0 as appropriate.
793         assert_eq!(cfg.get_bar_type(0), None);
794         assert_eq!(cfg.get_bar_addr(0), 0);
795 
796         let mut bar_iter = cfg.get_bars();
797         assert_eq!(bar_iter.next(), None);
798     }
799 
800     #[test]
add_pci_bar_mem_64bit()801     fn add_pci_bar_mem_64bit() {
802         let mut cfg = PciConfiguration::new(
803             0x1234,
804             0x5678,
805             PciClassCode::MultimediaController,
806             &PciMultimediaSubclass::AudioController,
807             Some(&TestPI::Test),
808             PciHeaderType::Device,
809             0xABCD,
810             0x2468,
811             0,
812         );
813 
814         cfg.add_pci_bar(
815             PciBarConfiguration::new(
816                 0,
817                 0x10,
818                 PciBarRegionType::Memory64BitRegion,
819                 PciBarPrefetchable::NotPrefetchable,
820             )
821             .set_address(0x01234567_89ABCDE0),
822         )
823         .expect("add_pci_bar failed");
824 
825         assert_eq!(
826             cfg.get_bar_type(0),
827             Some(PciBarRegionType::Memory64BitRegion)
828         );
829         assert_eq!(cfg.get_bar_addr(0), 0x01234567_89ABCDE0);
830         assert_eq!(cfg.writable_bits[BAR0_REG + 1], 0xFFFFFFFF);
831         assert_eq!(cfg.writable_bits[BAR0_REG + 0], 0xFFFFFFF0);
832 
833         let mut bar_iter = cfg.get_bars();
834         assert_eq!(
835             bar_iter.next(),
836             Some(PciBarConfiguration {
837                 addr: 0x01234567_89ABCDE0,
838                 size: 0x10,
839                 reg_idx: 0,
840                 region_type: PciBarRegionType::Memory64BitRegion,
841                 prefetchable: PciBarPrefetchable::NotPrefetchable
842             })
843         );
844         assert_eq!(bar_iter.next(), None);
845     }
846 
847     #[test]
add_pci_bar_mem_32bit()848     fn add_pci_bar_mem_32bit() {
849         let mut cfg = PciConfiguration::new(
850             0x1234,
851             0x5678,
852             PciClassCode::MultimediaController,
853             &PciMultimediaSubclass::AudioController,
854             Some(&TestPI::Test),
855             PciHeaderType::Device,
856             0xABCD,
857             0x2468,
858             0,
859         );
860 
861         cfg.add_pci_bar(
862             PciBarConfiguration::new(
863                 0,
864                 0x10,
865                 PciBarRegionType::Memory32BitRegion,
866                 PciBarPrefetchable::NotPrefetchable,
867             )
868             .set_address(0x12345670),
869         )
870         .expect("add_pci_bar failed");
871 
872         assert_eq!(
873             cfg.get_bar_type(0),
874             Some(PciBarRegionType::Memory32BitRegion)
875         );
876         assert_eq!(cfg.get_bar_addr(0), 0x12345670);
877         assert_eq!(cfg.writable_bits[BAR0_REG], 0xFFFFFFF0);
878 
879         let mut bar_iter = cfg.get_bars();
880         assert_eq!(
881             bar_iter.next(),
882             Some(PciBarConfiguration {
883                 addr: 0x12345670,
884                 size: 0x10,
885                 reg_idx: 0,
886                 region_type: PciBarRegionType::Memory32BitRegion,
887                 prefetchable: PciBarPrefetchable::NotPrefetchable
888             })
889         );
890         assert_eq!(bar_iter.next(), None);
891     }
892 
893     #[test]
add_pci_bar_io()894     fn add_pci_bar_io() {
895         let mut cfg = PciConfiguration::new(
896             0x1234,
897             0x5678,
898             PciClassCode::MultimediaController,
899             &PciMultimediaSubclass::AudioController,
900             Some(&TestPI::Test),
901             PciHeaderType::Device,
902             0xABCD,
903             0x2468,
904             0,
905         );
906 
907         cfg.add_pci_bar(
908             PciBarConfiguration::new(
909                 0,
910                 0x4,
911                 PciBarRegionType::IORegion,
912                 PciBarPrefetchable::NotPrefetchable,
913             )
914             .set_address(0x1230),
915         )
916         .expect("add_pci_bar failed");
917 
918         assert_eq!(cfg.get_bar_type(0), Some(PciBarRegionType::IORegion));
919         assert_eq!(cfg.get_bar_addr(0), 0x1230);
920         assert_eq!(cfg.writable_bits[BAR0_REG], 0xFFFFFFFC);
921 
922         let mut bar_iter = cfg.get_bars();
923         assert_eq!(
924             bar_iter.next(),
925             Some(PciBarConfiguration {
926                 addr: 0x1230,
927                 size: 0x4,
928                 reg_idx: 0,
929                 region_type: PciBarRegionType::IORegion,
930                 prefetchable: PciBarPrefetchable::NotPrefetchable
931             })
932         );
933         assert_eq!(bar_iter.next(), None);
934     }
935 
936     #[test]
add_pci_bar_multiple()937     fn add_pci_bar_multiple() {
938         let mut cfg = PciConfiguration::new(
939             0x1234,
940             0x5678,
941             PciClassCode::MultimediaController,
942             &PciMultimediaSubclass::AudioController,
943             Some(&TestPI::Test),
944             PciHeaderType::Device,
945             0xABCD,
946             0x2468,
947             0,
948         );
949 
950         // bar_num 0-1: 64-bit memory
951         cfg.add_pci_bar(
952             PciBarConfiguration::new(
953                 0,
954                 0x10,
955                 PciBarRegionType::Memory64BitRegion,
956                 PciBarPrefetchable::NotPrefetchable,
957             )
958             .set_address(0x01234567_89ABCDE0),
959         )
960         .expect("add_pci_bar failed");
961 
962         // bar 2: 32-bit memory
963         cfg.add_pci_bar(
964             PciBarConfiguration::new(
965                 2,
966                 0x10,
967                 PciBarRegionType::Memory32BitRegion,
968                 PciBarPrefetchable::NotPrefetchable,
969             )
970             .set_address(0x12345670),
971         )
972         .expect("add_pci_bar failed");
973 
974         // bar 3: I/O
975         cfg.add_pci_bar(
976             PciBarConfiguration::new(
977                 3,
978                 0x4,
979                 PciBarRegionType::IORegion,
980                 PciBarPrefetchable::NotPrefetchable,
981             )
982             .set_address(0x1230),
983         )
984         .expect("add_pci_bar failed");
985 
986         // Confirm default memory and I/O region configurations.
987         let mut bar_iter = cfg.get_bars();
988         assert_eq!(
989             bar_iter.next(),
990             Some(PciBarConfiguration {
991                 addr: 0x01234567_89ABCDE0,
992                 size: 0x10,
993                 reg_idx: 0,
994                 region_type: PciBarRegionType::Memory64BitRegion,
995                 prefetchable: PciBarPrefetchable::NotPrefetchable
996             })
997         );
998         assert_eq!(
999             bar_iter.next(),
1000             Some(PciBarConfiguration {
1001                 addr: 0x12345670,
1002                 size: 0x10,
1003                 reg_idx: 2,
1004                 region_type: PciBarRegionType::Memory32BitRegion,
1005                 prefetchable: PciBarPrefetchable::NotPrefetchable
1006             })
1007         );
1008         assert_eq!(
1009             bar_iter.next(),
1010             Some(PciBarConfiguration {
1011                 addr: 0x1230,
1012                 size: 0x4,
1013                 reg_idx: 3,
1014                 region_type: PciBarRegionType::IORegion,
1015                 prefetchable: PciBarPrefetchable::NotPrefetchable
1016             })
1017         );
1018         assert_eq!(bar_iter.next(), None);
1019 
1020         // Reassign the address for BAR 0 and verify that get_memory_regions() matches.
1021         cfg.write_reg(4 + 0, 0, &0xBBAA9980u32.to_le_bytes());
1022         cfg.write_reg(4 + 1, 0, &0xFFEEDDCCu32.to_le_bytes());
1023 
1024         let mut bar_iter = cfg.get_bars();
1025         assert_eq!(
1026             bar_iter.next(),
1027             Some(PciBarConfiguration {
1028                 addr: 0xFFEEDDCC_BBAA9980,
1029                 size: 0x10,
1030                 reg_idx: 0,
1031                 region_type: PciBarRegionType::Memory64BitRegion,
1032                 prefetchable: PciBarPrefetchable::NotPrefetchable
1033             })
1034         );
1035         assert_eq!(
1036             bar_iter.next(),
1037             Some(PciBarConfiguration {
1038                 addr: 0x12345670,
1039                 size: 0x10,
1040                 reg_idx: 2,
1041                 region_type: PciBarRegionType::Memory32BitRegion,
1042                 prefetchable: PciBarPrefetchable::NotPrefetchable
1043             })
1044         );
1045         assert_eq!(
1046             bar_iter.next(),
1047             Some(PciBarConfiguration {
1048                 addr: 0x1230,
1049                 size: 0x4,
1050                 reg_idx: 3,
1051                 region_type: PciBarRegionType::IORegion,
1052                 prefetchable: PciBarPrefetchable::NotPrefetchable
1053             })
1054         );
1055         assert_eq!(bar_iter.next(), None);
1056     }
1057 
1058     #[test]
add_pci_bar_invalid_size()1059     fn add_pci_bar_invalid_size() {
1060         let mut cfg = PciConfiguration::new(
1061             0x1234,
1062             0x5678,
1063             PciClassCode::MultimediaController,
1064             &PciMultimediaSubclass::AudioController,
1065             Some(&TestPI::Test),
1066             PciHeaderType::Device,
1067             0xABCD,
1068             0x2468,
1069             0,
1070         );
1071 
1072         // I/O BAR with size 2 (too small)
1073         assert_eq!(
1074             cfg.add_pci_bar(
1075                 PciBarConfiguration::new(
1076                     0,
1077                     0x2,
1078                     PciBarRegionType::IORegion,
1079                     PciBarPrefetchable::NotPrefetchable,
1080                 )
1081                 .set_address(0x1230),
1082             ),
1083             Err(Error::BarSizeInvalid(0x2))
1084         );
1085 
1086         // I/O BAR with size 3 (not a power of 2)
1087         assert_eq!(
1088             cfg.add_pci_bar(
1089                 PciBarConfiguration::new(
1090                     0,
1091                     0x3,
1092                     PciBarRegionType::IORegion,
1093                     PciBarPrefetchable::NotPrefetchable,
1094                 )
1095                 .set_address(0x1230),
1096             ),
1097             Err(Error::BarSizeInvalid(0x3))
1098         );
1099 
1100         // Memory BAR with size 8 (too small)
1101         assert_eq!(
1102             cfg.add_pci_bar(
1103                 PciBarConfiguration::new(
1104                     0,
1105                     0x8,
1106                     PciBarRegionType::Memory32BitRegion,
1107                     PciBarPrefetchable::NotPrefetchable,
1108                 )
1109                 .set_address(0x12345670),
1110             ),
1111             Err(Error::BarSizeInvalid(0x8))
1112         );
1113     }
1114 }
1115