Skip to content

Commit aeb1b24

Browse files
committed
Provide method for accessing BARs on endpoint headers
1 parent d9cd580 commit aeb1b24

1 file changed

Lines changed: 59 additions & 0 deletions

File tree

src/lib.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,4 +184,63 @@ impl EndpointHeader {
184184
pub fn header(&self) -> PciHeader {
185185
PciHeader(self.0)
186186
}
187+
188+
/// Get the contents of a BAR in a given slot. Empty bars will return `None`.
189+
///
190+
/// ### Note
191+
/// 64-bit memory BARs use two slots, so if one is decoded in e.g. slot #0, this method should not be called
192+
/// for slot #1
193+
pub fn bar(&self, slot: u8, access: &impl ConfigRegionAccess) -> Option<Bar> {
194+
let offset = 0x10 + (slot as u16) * 4;
195+
let bar = unsafe { access.read(self.0, offset) };
196+
197+
/*
198+
* If bit 0 is `0`, the BAR is in memory. If it's `1`, it's in I/O.
199+
*/
200+
if bar.get_bit(0) == false {
201+
let prefetchable = bar.get_bit(3);
202+
let address = bar.get_bits(4..32) << 4;
203+
204+
// TODO: if the bar is 64-bits, do we need to do this on both BARs?
205+
let size = unsafe {
206+
access.write(self.0, offset, 0xffffffff);
207+
let mut readback = access.read(self.0, offset);
208+
access.write(self.0, offset, address);
209+
210+
/*
211+
* If the entire readback value is zero, the BAR is not implemented, so we return `None`.
212+
*/
213+
if readback == 0x0 {
214+
return None;
215+
}
216+
217+
readback.set_bits(0..4, 0);
218+
1 << readback.trailing_zeros()
219+
};
220+
221+
match bar.get_bits(1..3) {
222+
0b00 => Some(Bar::Memory32 { address, size, prefetchable }),
223+
0b10 => {
224+
let address = {
225+
let mut address = address as u64;
226+
// TODO: do we need to mask off the lower bits on this?
227+
address.set_bits(32..64, unsafe { access.read(self.0, offset + 4) } as u64);
228+
address
229+
};
230+
Some(Bar::Memory64 { address, size: size as u64, prefetchable })
231+
}
232+
// TODO: should we bother to return an error here?
233+
_ => panic!("BAR Memory type is reserved!"),
234+
}
235+
} else {
236+
Some(Bar::Io { port: bar.get_bits(2..32) })
237+
}
238+
}
239+
}
240+
241+
#[derive(Clone, Copy, Debug)]
242+
pub enum Bar {
243+
Memory32 { address: u32, size: u32, prefetchable: bool },
244+
Memory64 { address: u64, size: u64, prefetchable: bool },
245+
Io { port: u32 },
187246
}

0 commit comments

Comments
 (0)