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