Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allocate PCI BARs where needed #230

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/bootinfo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,20 @@ pub trait Info {
fn kernel_load_addr(&self) -> u64;
// Reference to memory layout
fn memory_layout(&self) -> &'static [MemoryDescriptor];
// MMIO address space that can be used for PCI BARs if needed
fn pci_bar_memory(&self) -> Option<MemoryEntry> {
None
}
}

#[derive(Clone, Copy)]
pub struct MemoryEntry {
pub addr: u64,
pub size: u64,
pub entry_type: EntryType,
}

#[derive(PartialEq)]
#[derive(Clone, Copy, PartialEq)]
pub enum EntryType {
Ram,
Reserved,
Expand Down
7 changes: 7 additions & 0 deletions src/fdt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub struct StartInfo<'a> {
fdt: Fdt<'a>,
kernel_load_addr: u64,
memory_layout: &'static [MemoryDescriptor],
pci_bar_memory: Option<MemoryEntry>,
}

impl StartInfo<'_> {
Expand All @@ -22,6 +23,7 @@ impl StartInfo<'_> {
acpi_rsdp_addr: Option<u64>,
kernel_load_addr: u64,
memory_layout: &'static [MemoryDescriptor],
pci_bar_memory: Option<MemoryEntry>,
) -> Self {
let fdt = unsafe {
match Fdt::from_ptr(ptr) {
Expand All @@ -38,6 +40,7 @@ impl StartInfo<'_> {
acpi_rsdp_addr,
kernel_load_addr,
memory_layout,
pci_bar_memory,
}
}

Expand Down Expand Up @@ -94,4 +97,8 @@ impl Info for StartInfo<'_> {
fn memory_layout(&self) -> &'static [MemoryDescriptor] {
self.memory_layout
}

fn pci_bar_memory(&self) -> Option<MemoryEntry> {
self.pci_bar_memory
}
}
13 changes: 12 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ pub extern "C" fn rust64_start(x0: *const u8) -> ! {
Some(arch::aarch64::layout::map::dram::ACPI_START as u64),
arch::aarch64::layout::map::dram::KERNEL_START as u64,
&crate::arch::aarch64::layout::MEM_LAYOUT[..],
None,
);

if let Some((base, length)) = info.find_compatible_region(&["pci-host-ecam-generic"]) {
Expand All @@ -187,10 +188,20 @@ fn main(info: &dyn bootinfo::Info) -> ! {

pci::print_bus();

let mut next_address = info.pci_bar_memory().map(|m| m.addr);
let max_address = info.pci_bar_memory().map(|m| m.addr + m.size);

pci::with_devices(
VIRTIO_PCI_VENDOR_ID,
VIRTIO_PCI_BLOCK_DEVICE_ID,
|pci_device| {
|mut pci_device| {
pci_device.init();

next_address = pci_device.allocate_bars(next_address);
if next_address > max_address {
panic!("PCI BAR allocation space exceeded")
}

let mut pci_transport = pci::VirtioPciTransport::new(pci_device);
let mut device = block::VirtioBlockDevice::new(&mut pci_transport);
boot_from_device(&mut device, info)
Expand Down
72 changes: 65 additions & 7 deletions src/pci.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,9 +153,9 @@ pub fn print_bus() {
}
}

pub fn with_devices<F>(target_vendor_id: u16, target_device_id: u16, per_device: F)
pub fn with_devices<F>(target_vendor_id: u16, target_device_id: u16, mut per_device: F)
where
F: Fn(PciDevice) -> bool,
F: FnMut(PciDevice) -> bool,
{
for device in 0..MAX_DEVICES {
let (vendor_id, device_id) = get_device_details(0, device, 0);
Expand All @@ -168,6 +168,10 @@ where
}
}

fn naturally_align(address: u64, size: u64) -> u64 {
((address + size - 1) / size) * size
}

#[derive(Default)]
pub struct PciDevice {
bus: u8,
Expand All @@ -178,7 +182,7 @@ pub struct PciDevice {
device_id: u16,
}

#[derive(Debug, Default)]
#[derive(Debug, Default, Clone, Copy)]
enum PciBarType {
#[default]
Unused,
Expand All @@ -187,7 +191,7 @@ enum PciBarType {
IoSpace,
}

#[derive(Default)]
#[derive(Default, Clone, Copy)]
struct PciBar {
bar_type: PciBarType,
address: u64,
Expand Down Expand Up @@ -233,7 +237,7 @@ impl PciDevice {
.write(self.bus, self.device, self.func, offset, value)
}

fn init(&mut self) {
pub fn init(&mut self) {
let (vendor_id, device_id) = get_device_details(self.bus, self.device, self.func);

self.vendor_id = vendor_id;
Expand All @@ -248,6 +252,9 @@ impl PciDevice {
self.device_id
);

// Enable responses in memory space
self.write_u32(0x4, self.read_u32(0x4) | 0x2);

let mut current_bar_offset = 0x10;
let mut current_bar = 0;

Expand Down Expand Up @@ -319,6 +326,59 @@ impl PciDevice {
);
}
}

pub fn allocate_bars(&mut self, start_address: Option<u64>) -> Option<u64> {
let mut next_address = start_address;

let mut current_bar_offset = 0x10;
let mut current_bar = 0;

//0x24 offset is last bar
while current_bar_offset <= 0x24 {
let bar = self.bars[current_bar];
if bar.size != 0 && bar.address == 0 {
if let Some(next_address) = next_address.as_mut() {
match bar.bar_type {
PciBarType::IoSpace | PciBarType::Unused => {}
PciBarType::MemorySpace32 => {
let address = naturally_align(*next_address, bar.size);
self.write_u32(current_bar_offset, (address).try_into().unwrap());
self.bars[current_bar].address = address;
*next_address = address + bar.size;
}
PciBarType::MemorySpace64 => {
let address = naturally_align(*next_address, bar.size);
self.write_u32(
current_bar_offset,
(address & 0xffff_ffff).try_into().unwrap(),
);
current_bar_offset += 4;
self.write_u32(current_bar_offset, (address >> 32).try_into().unwrap());
self.bars[current_bar].address = address;
*next_address = address + bar.size;
}
}
} else {
panic!("Zero BAR address and no allocation available to allocate from")
}
}

current_bar += 1;
current_bar_offset += 4;
}

#[allow(clippy::disallowed_names)]
for bar in &self.bars {
log!(
"Updated BARs: type={:?} address={:x} size={:x}",
bar.bar_type,
bar.address,
bar.size
);
}

next_address
}
}

#[allow(clippy::enum_variant_names)]
Expand Down Expand Up @@ -370,8 +430,6 @@ impl VirtioPciTransport {

impl VirtioTransport for VirtioPciTransport {
fn init(&mut self, _device_type: u32) -> Result<(), VirtioError> {
self.device.init();

// Read status register
let status = self.device.read_u16(0x06);

Expand Down