• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Module for dealing with a PCI bus in general, without anything specific to VirtIO.
2 
3 use bitflags::bitflags;
4 use core::{
5     convert::TryFrom,
6     fmt::{self, Display, Formatter},
7 };
8 use log::warn;
9 
10 const INVALID_READ: u32 = 0xffffffff;
11 
12 /// The maximum number of devices on a bus.
13 const MAX_DEVICES: u8 = 32;
14 /// The maximum number of functions on a device.
15 const MAX_FUNCTIONS: u8 = 8;
16 
17 /// The offset in bytes to the status and command fields within PCI configuration space.
18 const STATUS_COMMAND_OFFSET: u8 = 0x04;
19 /// The offset in bytes to BAR0 within PCI configuration space.
20 const BAR0_OFFSET: u8 = 0x10;
21 
22 /// ID for vendor-specific PCI capabilities.
23 pub const PCI_CAP_ID_VNDR: u8 = 0x09;
24 
25 bitflags! {
26     /// The status register in PCI configuration space.
27     pub struct Status: u16 {
28         // Bits 0-2 are reserved.
29         /// The state of the device's INTx# signal.
30         const INTERRUPT_STATUS = 1 << 3;
31         /// The device has a linked list of capabilities.
32         const CAPABILITIES_LIST = 1 << 4;
33         /// The device is capabile of running at 66 MHz rather than 33 MHz.
34         const MHZ_66_CAPABLE = 1 << 5;
35         // Bit 6 is reserved.
36         /// The device can accept fast back-to-back transactions not from the same agent.
37         const FAST_BACK_TO_BACK_CAPABLE = 1 << 7;
38         /// The bus agent observed a parity error (if parity error handling is enabled).
39         const MASTER_DATA_PARITY_ERROR = 1 << 8;
40         // Bits 9-10 are DEVSEL timing.
41         /// A target device terminated a transaction with target-abort.
42         const SIGNALED_TARGET_ABORT = 1 << 11;
43         /// A master device transaction was terminated with target-abort.
44         const RECEIVED_TARGET_ABORT = 1 << 12;
45         /// A master device transaction was terminated with master-abort.
46         const RECEIVED_MASTER_ABORT = 1 << 13;
47         /// A device asserts SERR#.
48         const SIGNALED_SYSTEM_ERROR = 1 << 14;
49         /// The device detects a parity error, even if parity error handling is disabled.
50         const DETECTED_PARITY_ERROR = 1 << 15;
51     }
52 }
53 
54 bitflags! {
55     /// The command register in PCI configuration space.
56     pub struct Command: u16 {
57         /// The device can respond to I/O Space accesses.
58         const IO_SPACE = 1 << 0;
59         /// The device can respond to Memory Space accesses.
60         const MEMORY_SPACE = 1 << 1;
61         /// The device can behave as a bus master.
62         const BUS_MASTER = 1 << 2;
63         /// The device can monitor Special Cycle operations.
64         const SPECIAL_CYCLES = 1 << 3;
65         /// The device can generate the Memory Write and Invalidate command.
66         const MEMORY_WRITE_AND_INVALIDATE_ENABLE = 1 << 4;
67         /// The device will snoop palette register data.
68         const VGA_PALETTE_SNOOP = 1 << 5;
69         /// The device should take its normal action when a parity error is detected.
70         const PARITY_ERROR_RESPONSE = 1 << 6;
71         // Bit 7 is reserved.
72         /// The SERR# driver is enabled.
73         const SERR_ENABLE = 1 << 8;
74         /// The device is allowed to generate fast back-to-back transactions.
75         const FAST_BACK_TO_BACK_ENABLE = 1 << 9;
76         /// Assertion of the device's INTx# signal is disabled.
77         const INTERRUPT_DISABLE = 1 << 10;
78     }
79 }
80 
81 /// Errors accessing a PCI device.
82 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
83 pub enum PciError {
84     /// The device reported an invalid BAR type.
85     InvalidBarType,
86 }
87 
88 impl Display for PciError {
fmt(&self, f: &mut Formatter) -> fmt::Result89     fn fmt(&self, f: &mut Formatter) -> fmt::Result {
90         match self {
91             Self::InvalidBarType => write!(f, "Invalid PCI BAR type."),
92         }
93     }
94 }
95 
96 /// The root complex of a PCI bus.
97 #[derive(Debug)]
98 pub struct PciRoot {
99     mmio_base: *mut u32,
100     cam: Cam,
101 }
102 
103 /// A PCI Configuration Access Mechanism.
104 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
105 pub enum Cam {
106     /// The PCI memory-mapped Configuration Access Mechanism.
107     ///
108     /// This provides access to 256 bytes of configuration space per device function.
109     MmioCam,
110     /// The PCIe memory-mapped Enhanced Configuration Access Mechanism.
111     ///
112     /// This provides access to 4 KiB of configuration space per device function.
113     Ecam,
114 }
115 
116 impl Cam {
117     /// Returns the total size in bytes of the memory-mapped region.
size(self) -> u32118     pub const fn size(self) -> u32 {
119         match self {
120             Self::MmioCam => 0x1000000,
121             Self::Ecam => 0x10000000,
122         }
123     }
124 }
125 
126 impl PciRoot {
127     /// Wraps the PCI root complex with the given MMIO base address.
128     ///
129     /// Panics if the base address is not aligned to a 4-byte boundary.
130     ///
131     /// # Safety
132     ///
133     /// `mmio_base` must be a valid pointer to an appropriately-mapped MMIO region of at least
134     /// 16 MiB (if `cam == Cam::MmioCam`) or 256 MiB (if `cam == Cam::Ecam`). The pointer must be
135     /// valid for the entire lifetime of the program (i.e. `'static`), which implies that no Rust
136     /// references may be used to access any of the memory region at any point.
new(mmio_base: *mut u8, cam: Cam) -> Self137     pub unsafe fn new(mmio_base: *mut u8, cam: Cam) -> Self {
138         assert!(mmio_base as usize & 0x3 == 0);
139         Self {
140             mmio_base: mmio_base as *mut u32,
141             cam,
142         }
143     }
144 
145     /// Makes a clone of the `PciRoot`, pointing at the same MMIO region.
146     ///
147     /// # Safety
148     ///
149     /// This function allows concurrent mutable access to the PCI CAM. To avoid this causing
150     /// problems, the returned `PciRoot` instance must only be used to read read-only fields.
unsafe_clone(&self) -> Self151     unsafe fn unsafe_clone(&self) -> Self {
152         Self {
153             mmio_base: self.mmio_base,
154             cam: self.cam,
155         }
156     }
157 
cam_offset(&self, device_function: DeviceFunction, register_offset: u8) -> u32158     fn cam_offset(&self, device_function: DeviceFunction, register_offset: u8) -> u32 {
159         assert!(device_function.valid());
160 
161         let bdf = (device_function.bus as u32) << 8
162             | (device_function.device as u32) << 3
163             | device_function.function as u32;
164         let address =
165             bdf << match self.cam {
166                 Cam::MmioCam => 8,
167                 Cam::Ecam => 12,
168             } | register_offset as u32;
169         // Ensure that address is within range.
170         assert!(address < self.cam.size());
171         // Ensure that address is word-aligned.
172         assert!(address & 0x3 == 0);
173         address
174     }
175 
176     /// Reads 4 bytes from configuration space using the appropriate CAM.
config_read_word( &self, device_function: DeviceFunction, register_offset: u8, ) -> u32177     pub(crate) fn config_read_word(
178         &self,
179         device_function: DeviceFunction,
180         register_offset: u8,
181     ) -> u32 {
182         let address = self.cam_offset(device_function, register_offset);
183         // Safe because both the `mmio_base` and the address offset are properly aligned, and the
184         // resulting pointer is within the MMIO range of the CAM.
185         unsafe {
186             // Right shift to convert from byte offset to word offset.
187             (self.mmio_base.add((address >> 2) as usize)).read_volatile()
188         }
189     }
190 
191     /// Writes 4 bytes to configuration space using the appropriate CAM.
config_write_word( &mut self, device_function: DeviceFunction, register_offset: u8, data: u32, )192     pub(crate) fn config_write_word(
193         &mut self,
194         device_function: DeviceFunction,
195         register_offset: u8,
196         data: u32,
197     ) {
198         let address = self.cam_offset(device_function, register_offset);
199         // Safe because both the `mmio_base` and the address offset are properly aligned, and the
200         // resulting pointer is within the MMIO range of the CAM.
201         unsafe {
202             // Right shift to convert from byte offset to word offset.
203             (self.mmio_base.add((address >> 2) as usize)).write_volatile(data)
204         }
205     }
206 
207     /// Enumerates PCI devices on the given bus.
enumerate_bus(&self, bus: u8) -> BusDeviceIterator208     pub fn enumerate_bus(&self, bus: u8) -> BusDeviceIterator {
209         // Safe because the BusDeviceIterator only reads read-only fields.
210         let root = unsafe { self.unsafe_clone() };
211         BusDeviceIterator {
212             root,
213             next: DeviceFunction {
214                 bus,
215                 device: 0,
216                 function: 0,
217             },
218         }
219     }
220 
221     /// Reads the status and command registers of the given device function.
get_status_command(&self, device_function: DeviceFunction) -> (Status, Command)222     pub fn get_status_command(&self, device_function: DeviceFunction) -> (Status, Command) {
223         let status_command = self.config_read_word(device_function, STATUS_COMMAND_OFFSET);
224         let status = Status::from_bits_truncate((status_command >> 16) as u16);
225         let command = Command::from_bits_truncate(status_command as u16);
226         (status, command)
227     }
228 
229     /// Sets the command register of the given device function.
set_command(&mut self, device_function: DeviceFunction, command: Command)230     pub fn set_command(&mut self, device_function: DeviceFunction, command: Command) {
231         self.config_write_word(
232             device_function,
233             STATUS_COMMAND_OFFSET,
234             command.bits().into(),
235         );
236     }
237 
238     /// Gets an iterator over the capabilities of the given device function.
capabilities(&self, device_function: DeviceFunction) -> CapabilityIterator239     pub fn capabilities(&self, device_function: DeviceFunction) -> CapabilityIterator {
240         CapabilityIterator {
241             root: self,
242             device_function,
243             next_capability_offset: self.capabilities_offset(device_function),
244         }
245     }
246 
247     /// Gets information about the given BAR of the given device function.
bar_info( &mut self, device_function: DeviceFunction, bar_index: u8, ) -> Result<BarInfo, PciError>248     pub fn bar_info(
249         &mut self,
250         device_function: DeviceFunction,
251         bar_index: u8,
252     ) -> Result<BarInfo, PciError> {
253         let bar_orig = self.config_read_word(device_function, BAR0_OFFSET + 4 * bar_index);
254 
255         // Get the size of the BAR.
256         self.config_write_word(device_function, BAR0_OFFSET + 4 * bar_index, 0xffffffff);
257         let size_mask = self.config_read_word(device_function, BAR0_OFFSET + 4 * bar_index);
258         // A wrapping add is necessary to correctly handle the case of unused BARs, which read back
259         // as 0, and should be treated as size 0.
260         let size = (!(size_mask & 0xfffffff0)).wrapping_add(1);
261 
262         // Restore the original value.
263         self.config_write_word(device_function, BAR0_OFFSET + 4 * bar_index, bar_orig);
264 
265         if bar_orig & 0x00000001 == 0x00000001 {
266             // I/O space
267             let address = bar_orig & 0xfffffffc;
268             Ok(BarInfo::IO { address, size })
269         } else {
270             // Memory space
271             let mut address = u64::from(bar_orig & 0xfffffff0);
272             let prefetchable = bar_orig & 0x00000008 != 0;
273             let address_type = MemoryBarType::try_from(((bar_orig & 0x00000006) >> 1) as u8)?;
274             if address_type == MemoryBarType::Width64 {
275                 if bar_index >= 5 {
276                     return Err(PciError::InvalidBarType);
277                 }
278                 let address_top =
279                     self.config_read_word(device_function, BAR0_OFFSET + 4 * (bar_index + 1));
280                 address |= u64::from(address_top) << 32;
281             }
282             Ok(BarInfo::Memory {
283                 address_type,
284                 prefetchable,
285                 address,
286                 size,
287             })
288         }
289     }
290 
291     /// Sets the address of the given 32-bit memory or I/O BAR of the given device function.
set_bar_32(&mut self, device_function: DeviceFunction, bar_index: u8, address: u32)292     pub fn set_bar_32(&mut self, device_function: DeviceFunction, bar_index: u8, address: u32) {
293         self.config_write_word(device_function, BAR0_OFFSET + 4 * bar_index, address);
294     }
295 
296     /// Sets the address of the given 64-bit memory BAR of the given device function.
set_bar_64(&mut self, device_function: DeviceFunction, bar_index: u8, address: u64)297     pub fn set_bar_64(&mut self, device_function: DeviceFunction, bar_index: u8, address: u64) {
298         self.config_write_word(device_function, BAR0_OFFSET + 4 * bar_index, address as u32);
299         self.config_write_word(
300             device_function,
301             BAR0_OFFSET + 4 * (bar_index + 1),
302             (address >> 32) as u32,
303         );
304     }
305 
306     /// Gets the capabilities 'pointer' for the device function, if any.
capabilities_offset(&self, device_function: DeviceFunction) -> Option<u8>307     fn capabilities_offset(&self, device_function: DeviceFunction) -> Option<u8> {
308         let (status, _) = self.get_status_command(device_function);
309         if status.contains(Status::CAPABILITIES_LIST) {
310             Some((self.config_read_word(device_function, 0x34) & 0xFC) as u8)
311         } else {
312             None
313         }
314     }
315 }
316 
317 /// Information about a PCI Base Address Register.
318 #[derive(Clone, Debug, Eq, PartialEq)]
319 pub enum BarInfo {
320     /// The BAR is for a memory region.
321     Memory {
322         /// The size of the BAR address and where it can be located.
323         address_type: MemoryBarType,
324         /// If true, then reading from the region doesn't have side effects. The CPU may cache reads
325         /// and merge repeated stores.
326         prefetchable: bool,
327         /// The memory address, always 16-byte aligned.
328         address: u64,
329         /// The size of the BAR in bytes.
330         size: u32,
331     },
332     /// The BAR is for an I/O region.
333     IO {
334         /// The I/O address, always 4-byte aligned.
335         address: u32,
336         /// The size of the BAR in bytes.
337         size: u32,
338     },
339 }
340 
341 impl BarInfo {
342     /// Returns whether this BAR is a 64-bit memory region, and so takes two entries in the table in
343     /// configuration space.
takes_two_entries(&self) -> bool344     pub fn takes_two_entries(&self) -> bool {
345         matches!(
346             self,
347             BarInfo::Memory {
348                 address_type: MemoryBarType::Width64,
349                 ..
350             }
351         )
352     }
353 
354     /// Returns the address and size of this BAR if it is a memory bar, or `None` if it is an IO
355     /// BAR.
memory_address_size(&self) -> Option<(u64, u32)>356     pub fn memory_address_size(&self) -> Option<(u64, u32)> {
357         if let Self::Memory { address, size, .. } = self {
358             Some((*address, *size))
359         } else {
360             None
361         }
362     }
363 }
364 
365 impl Display for BarInfo {
fmt(&self, f: &mut Formatter<'_>) -> fmt::Result366     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
367         match self {
368             Self::Memory {
369                 address_type,
370                 prefetchable,
371                 address,
372                 size,
373             } => write!(
374                 f,
375                 "Memory space at {:#010x}, size {}, type {:?}, prefetchable {}",
376                 address, size, address_type, prefetchable
377             ),
378             Self::IO { address, size } => {
379                 write!(f, "I/O space at {:#010x}, size {}", address, size)
380             }
381         }
382     }
383 }
384 
385 /// The location allowed for a memory BAR.
386 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
387 pub enum MemoryBarType {
388     /// The BAR has a 32-bit address and can be mapped anywhere in 32-bit address space.
389     Width32,
390     /// The BAR must be mapped below 1MiB.
391     Below1MiB,
392     /// The BAR has a 64-bit address and can be mapped anywhere in 64-bit address space.
393     Width64,
394 }
395 
396 impl From<MemoryBarType> for u8 {
from(bar_type: MemoryBarType) -> Self397     fn from(bar_type: MemoryBarType) -> Self {
398         match bar_type {
399             MemoryBarType::Width32 => 0,
400             MemoryBarType::Below1MiB => 1,
401             MemoryBarType::Width64 => 2,
402         }
403     }
404 }
405 
406 impl TryFrom<u8> for MemoryBarType {
407     type Error = PciError;
408 
try_from(value: u8) -> Result<Self, Self::Error>409     fn try_from(value: u8) -> Result<Self, Self::Error> {
410         match value {
411             0 => Ok(Self::Width32),
412             1 => Ok(Self::Below1MiB),
413             2 => Ok(Self::Width64),
414             _ => Err(PciError::InvalidBarType),
415         }
416     }
417 }
418 
419 /// Iterator over capabilities for a device.
420 #[derive(Debug)]
421 pub struct CapabilityIterator<'a> {
422     root: &'a PciRoot,
423     device_function: DeviceFunction,
424     next_capability_offset: Option<u8>,
425 }
426 
427 impl<'a> Iterator for CapabilityIterator<'a> {
428     type Item = CapabilityInfo;
429 
next(&mut self) -> Option<Self::Item>430     fn next(&mut self) -> Option<Self::Item> {
431         let offset = self.next_capability_offset?;
432 
433         // Read the first 4 bytes of the capability.
434         let capability_header = self.root.config_read_word(self.device_function, offset);
435         let id = capability_header as u8;
436         let next_offset = (capability_header >> 8) as u8;
437         let private_header = (capability_header >> 16) as u16;
438 
439         self.next_capability_offset = if next_offset == 0 {
440             None
441         } else if next_offset < 64 || next_offset & 0x3 != 0 {
442             warn!("Invalid next capability offset {:#04x}", next_offset);
443             None
444         } else {
445             Some(next_offset)
446         };
447 
448         Some(CapabilityInfo {
449             offset,
450             id,
451             private_header,
452         })
453     }
454 }
455 
456 /// Information about a PCI device capability.
457 #[derive(Debug, Copy, Clone, Eq, PartialEq)]
458 pub struct CapabilityInfo {
459     /// The offset of the capability in the PCI configuration space of the device function.
460     pub offset: u8,
461     /// The ID of the capability.
462     pub id: u8,
463     /// The third and fourth bytes of the capability, to save reading them again.
464     pub private_header: u16,
465 }
466 
467 /// An iterator which enumerates PCI devices and functions on a given bus.
468 #[derive(Debug)]
469 pub struct BusDeviceIterator {
470     /// This must only be used to read read-only fields, and must not be exposed outside this
471     /// module, because it uses the same CAM as the main `PciRoot` instance.
472     root: PciRoot,
473     next: DeviceFunction,
474 }
475 
476 impl Iterator for BusDeviceIterator {
477     type Item = (DeviceFunction, DeviceFunctionInfo);
478 
next(&mut self) -> Option<Self::Item>479     fn next(&mut self) -> Option<Self::Item> {
480         while self.next.device < MAX_DEVICES {
481             // Read the header for the current device and function.
482             let current = self.next;
483             let device_vendor = self.root.config_read_word(current, 0);
484 
485             // Advance to the next device or function.
486             self.next.function += 1;
487             if self.next.function >= MAX_FUNCTIONS {
488                 self.next.function = 0;
489                 self.next.device += 1;
490             }
491 
492             if device_vendor != INVALID_READ {
493                 let class_revision = self.root.config_read_word(current, 8);
494                 let device_id = (device_vendor >> 16) as u16;
495                 let vendor_id = device_vendor as u16;
496                 let class = (class_revision >> 24) as u8;
497                 let subclass = (class_revision >> 16) as u8;
498                 let prog_if = (class_revision >> 8) as u8;
499                 let revision = class_revision as u8;
500                 let bist_type_latency_cache = self.root.config_read_word(current, 12);
501                 let header_type = HeaderType::from((bist_type_latency_cache >> 16) as u8 & 0x7f);
502                 return Some((
503                     current,
504                     DeviceFunctionInfo {
505                         vendor_id,
506                         device_id,
507                         class,
508                         subclass,
509                         prog_if,
510                         revision,
511                         header_type,
512                     },
513                 ));
514             }
515         }
516         None
517     }
518 }
519 
520 /// An identifier for a PCI bus, device and function.
521 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
522 pub struct DeviceFunction {
523     /// The PCI bus number, between 0 and 255.
524     pub bus: u8,
525     /// The device number on the bus, between 0 and 31.
526     pub device: u8,
527     /// The function number of the device, between 0 and 7.
528     pub function: u8,
529 }
530 
531 impl DeviceFunction {
532     /// Returns whether the device and function numbers are valid, i.e. the device is between 0 and
533     /// 31, and the function is between 0 and 7.
valid(&self) -> bool534     pub fn valid(&self) -> bool {
535         self.device < 32 && self.function < 8
536     }
537 }
538 
539 impl Display for DeviceFunction {
fmt(&self, f: &mut Formatter) -> fmt::Result540     fn fmt(&self, f: &mut Formatter) -> fmt::Result {
541         write!(f, "{:02x}:{:02x}.{}", self.bus, self.device, self.function)
542     }
543 }
544 
545 /// Information about a PCI device function.
546 #[derive(Clone, Debug, Eq, PartialEq)]
547 pub struct DeviceFunctionInfo {
548     /// The PCI vendor ID.
549     pub vendor_id: u16,
550     /// The PCI device ID.
551     pub device_id: u16,
552     /// The PCI class.
553     pub class: u8,
554     /// The PCI subclass.
555     pub subclass: u8,
556     /// The PCI programming interface byte.
557     pub prog_if: u8,
558     /// The PCI revision ID.
559     pub revision: u8,
560     /// The type of PCI device.
561     pub header_type: HeaderType,
562 }
563 
564 impl Display for DeviceFunctionInfo {
fmt(&self, f: &mut Formatter) -> fmt::Result565     fn fmt(&self, f: &mut Formatter) -> fmt::Result {
566         write!(
567             f,
568             "{:04x}:{:04x} (class {:02x}.{:02x}, rev {:02x}) {:?}",
569             self.vendor_id,
570             self.device_id,
571             self.class,
572             self.subclass,
573             self.revision,
574             self.header_type,
575         )
576     }
577 }
578 
579 /// The type of a PCI device function header.
580 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
581 pub enum HeaderType {
582     /// A normal PCI device.
583     Standard,
584     /// A PCI to PCI bridge.
585     PciPciBridge,
586     /// A PCI to CardBus bridge.
587     PciCardbusBridge,
588     /// Unrecognised header type.
589     Unrecognised(u8),
590 }
591 
592 impl From<u8> for HeaderType {
from(value: u8) -> Self593     fn from(value: u8) -> Self {
594         match value {
595             0x00 => Self::Standard,
596             0x01 => Self::PciPciBridge,
597             0x02 => Self::PciCardbusBridge,
598             _ => Self::Unrecognised(value),
599         }
600     }
601 }
602