mycelium_pci/device/
bar.rs

1//! PCI Base Address Registers
2use crate::error::{self, UnexpectedValue};
3use mycelium_bitfield::{pack::Pack32, FromBits};
4/// A PCI Base Address Register (BAR).
5///
6/// Base Address Registers (or BARs) can be used to hold memory addresses used
7/// by the device, or offsets for port addresses. Typically, memory address BARs
8/// need to be located in physical RAM, while I/O space BARs can reside at any
9/// memory address (even beyond physical memory).
10#[derive(Copy, Clone, Debug, Eq, PartialEq)]
11pub enum BaseAddress {
12    Memory32 { prefetchable: bool, addr: u32 },
13    Memory64 { prefetchable: bool, addr: u64 },
14    Io(u32),
15}
16
17impl BaseAddress {
18    const BAR_KIND: Pack32 = Pack32::least_significant(1);
19    const MEM_TYPE: Pack32<MemoryBarType> = Self::BAR_KIND.then();
20    const MEM_PREFETCHABLE: Pack32<bool> = Self::MEM_TYPE.then();
21    const MEM_ADDR: Pack32 = Self::MEM_PREFETCHABLE.remaining();
22    const MEM_MASK: u32 = Self::MEM_ADDR.raw_mask();
23
24    // mask out the two low bits of an IO BAR to determine the address.
25    const IO_MASK: u32 = !0b11;
26
27    pub(crate) fn decode_bars<const BARS: usize>(
28        bars: &[u32; BARS],
29    ) -> Result<[Option<Self>; BARS], UnexpectedValue<u32>> {
30        let mut decoded = [None; BARS];
31        let mut curr_64_bit = None;
32        for (i, &bits) in bars.iter().enumerate() {
33            // if we have decoded half of a 64-bit BAR, this word is the upper
34            // half.
35            if let Some((prefetchable, low_bits)) = curr_64_bit.take() {
36                let addr = ((bits as u64) << 32) | (low_bits as u64);
37                // the previous index is a 64-bit BAR.
38                decoded[i - 1] = Some(Self::Memory64 { prefetchable, addr });
39                // this index is the upper half of the 64-bit BAR, so set it to
40                // `None` in the output array.
41                decoded[i] = None;
42                continue;
43            }
44
45            // if the first bit is set, this is an IO BAR.
46            if Self::BAR_KIND.unpack(bits) == 1 {
47                decoded[i] = Some(Self::Io(bits & Self::IO_MASK));
48                continue;
49            }
50
51            // okay, it's a memory BAR.
52            let prefetchable = Self::MEM_PREFETCHABLE.unpack(bits);
53            match Self::MEM_TYPE.try_unpack(bits)? {
54                // this BAR has a 32-bit base address. decode it and continue.
55                MemoryBarType::Base32 => {
56                    decoded[i] = Some(Self::Memory32 {
57                        prefetchable,
58                        addr: bits & Self::MEM_MASK,
59                    });
60                }
61                // this BAR has a 64-bit base address, so we'll use the next
62                // 32-bit word as the high part of its address.
63                MemoryBarType::Base64 => curr_64_bit = Some((prefetchable, bits & Self::MEM_MASK)),
64
65                // 16-bit base addresses are not supported in PCI v3.0
66                MemoryBarType::Legacy16 => {
67                    return Err(
68                        error::unexpected(bits).named("unsupported legacy 16-bit memory BAR")
69                    );
70                }
71            }
72        }
73
74        Ok(decoded)
75    }
76}
77
78#[derive(Copy, Clone, Debug, PartialEq, Eq)]
79#[repr(u8)]
80enum MemoryBarType {
81    /// 32-bit base address
82    Base32 = 0x0,
83    /// This is reserved in PCI v3.0. In earlier versions it indicated a 16-bit
84    Legacy16 = 0x1,
85    /// 64-bit base address
86    Base64 = 0x2,
87}
88
89// === impl MemoryBarType ===
90
91impl FromBits<u32> for MemoryBarType {
92    type Error = UnexpectedValue<u32>;
93    const BITS: u32 = 2;
94    fn try_from_bits(bits: u32) -> Result<Self, Self::Error> {
95        match bits as u8 {
96            bits if bits == Self::Base32 as u8 => Ok(Self::Base32),
97            bits if bits == Self::Base64 as u8 => Ok(Self::Base64),
98            bits if bits == Self::Legacy16 as u8 => Ok(Self::Legacy16),
99            _ => Err(crate::error::unexpected(bits).named("MemoryBarType")),
100        }
101    }
102
103    fn into_bits(self) -> u32 {
104        self as u8 as u32
105    }
106}