Skip to content
Open
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
24 changes: 10 additions & 14 deletions src/drivers/net/rtl8139.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use core::mem::ManuallyDrop;
use core::ptr::NonNull;

use endian_num::{le16, le32, le64};
use pci_types::{Bar, CommandRegister, MAX_BARS};
use pci_types::CommandRegister;
use smoltcp::phy::DeviceCapabilities;
use thiserror::Error;
use volatile::access::{NoAccess, ReadOnly, ReadWrite};
Expand Down Expand Up @@ -746,19 +746,15 @@ pub(crate) fn init_device(
handlers: &mut InterruptHandlerMap,
) -> Result<RTL8139Driver, DriverError> {
let irq = device.get_irq().unwrap();
let mut regs = None;

for i in 0..MAX_BARS {
let Some(Bar::Memory32 { .. }) = device.get_bar(i.try_into().unwrap()) else {
continue;
};

let (addr, _size) = device.memory_map_bar(i.try_into().unwrap(), true).unwrap();

regs = Some(unsafe { VolatileRef::new(NonNull::new(addr.as_mut_ptr()).unwrap()) });
}

let mut regs = regs.ok_or(DriverError::InitRTL8139DevFail(RTL8139Error::Unknown))?;
let mut regs = device
.memory_map_bars(true)
.into_iter()
.find_map(|bar| {
bar.map(|(addr, _size)| unsafe {
VolatileRef::new(NonNull::new(addr.as_mut_ptr()).unwrap())

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The behaviour is slightly different:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From what I can see, QEMU's RTL8139 only implements 32-bit memory BARs:

[    0.015647][0][INFO  rtl8139   ] found a bar Some(Io { port: 1056899072 })
[    0.016225][0][INFO  rtl8139   ] found a bar Some(Memory32 { address: 268435456, size: 256, prefetchable: false })
[    0.017355][0][INFO  rtl8139   ] found a bar None

so in practice this is probably fine (as you can see from the passing tests, we do test RTL8139 on AArch64). From what I can tell, Linux doesn't care whether they are 32-bit or 64-bit either.

})
})
.ok_or(DriverError::InitRTL8139DevFail(RTL8139Error::Unknown))?;

debug!("Found RTL8139 at IO {regs:?} (irq {irq})");

Expand Down
88 changes: 50 additions & 38 deletions src/drivers/pci.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,53 +111,65 @@ impl<T: ConfigRegionAccess> PciDevice<T> {
}
}

/// Memory maps pci bar with specified index to identical location in virtual memory.
/// Memory maps pci BARs to identical location in virtual memory.
/// no_cache determines if we set the `Cache Disable` flag in the page-table-entry.
/// Returns (virtual-pointer, size) if successful, else None (if bar non-existent or IOSpace)
pub fn memory_map_bar(&self, index: u8, no_cache: bool) -> Option<(VirtAddr, usize)> {
let (address, size, prefetchable, _width) = match self.get_bar(index) {
Some(Bar::Io { .. }) => {
warn!("Cannot map IOBar!");
/// Element at index is [Some] if the mapping of the BAR at the same index is successful, else [None] (if bar non-existent or IOSpace)
pub fn memory_map_bars(&self, no_cache: bool) -> [Option<(VirtAddr, usize)>; MAX_BARS] {
let mut should_skip = false;
core::array::from_fn(|index| {
if should_skip {
should_skip = false;
return None;
}
Some(Bar::Memory32 {
address,
size,
prefetchable,
}) => (
u64::from(address),
usize::try_from(size).unwrap(),
prefetchable,
32,
),
Some(Bar::Memory64 {
address,
size,
prefetchable,
}) => (address, usize::try_from(size).unwrap(), prefetchable, 64),
_ => {

let index = u8::try_from(index).unwrap();
let (address, size, prefetchable, _width) = match self.get_bar(index) {
Some(Bar::Io { .. }) => {
warn!("Cannot map IOBar!");
return None;
}
Some(Bar::Memory32 {
address,
size,
prefetchable,
}) => (
u64::from(address),
usize::try_from(size).unwrap(),
prefetchable,
32,
),
Some(Bar::Memory64 {
address,
size,
prefetchable,
}) => {
should_skip = true;
(address, usize::try_from(size).unwrap(), prefetchable, 64)
}
_ => {
return None;
}
};

if address == 0 {
return None;
}
};

if address == 0 {
return None;
}

debug!("Mapping bar {index} at {address:#x} with length {size:#x}");
debug!("Mapping bar {index} at {address:#x} with length {size:#x}");

if !prefetchable {
warn!("Currently only mapping of prefetchable bars is supported!");
}
if !prefetchable {
warn!("Currently only mapping of prefetchable bars is supported!");
}

// Since the bios/bootloader manages the physical address space, the address got from the bar is unique and not overlapping.
// We therefore do not need to reserve any additional memory in our kernel.
// Map bar into RW^X virtual memory
let physical_address = address;
let virtual_address =
crate::mm::map(PhysAddr::new(physical_address), size, true, true, no_cache);
// Since the bios/bootloader manages the physical address space, the address got from the bar is unique and not overlapping.
// We therefore do not need to reserve any additional memory in our kernel.
// Map bar into RW^X virtual memory
let physical_address = address;
let virtual_address =
crate::mm::map(PhysAddr::new(physical_address), size, true, true, no_cache);

Some((virtual_address, size))
Some((virtual_address, size))
})
}

pub fn get_irq(&self) -> Option<InterruptLine> {
Expand Down
13 changes: 9 additions & 4 deletions src/drivers/virtio/transport/pci.rs
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,8 @@ pub(crate) fn map_caps(
#[cfg(target_arch = "x86_64")]
let mut msix_table = None;

let bar_mappings = device.memory_map_bars(true);

// Reads all PCI capabilities, starting at the capabilities list pointer from the
// PCI device.
//
Expand All @@ -594,7 +596,7 @@ pub(crate) fn map_caps(
continue;
}
let slot = cap.bar;
let Some((addr, size)) = device.memory_map_bar(slot, true) else {
let Some((addr, size)) = bar_mappings[usize::from(slot)] else {
continue;
};
let Some(pci_cap) = PciCap::new(
Expand Down Expand Up @@ -661,9 +663,12 @@ pub(crate) fn map_caps(
#[cfg(target_arch = "x86_64")]
PciCapability::MsiX(mut msix_capability) => {
msix_capability.set_enabled(true, device.access());
let (base_addr, _) = device
.memory_map_bar(msix_capability.table_bar(), true)
.unwrap();

// the capability should provide a valid BAR ID and "[t]he BAR [...] must map
// Memory Space" (PCIe spec. 6.0 sec. 7.7.2) for the MSI-X capability
let (base_addr, _) =
bar_mappings[usize::from(msix_capability.table_bar())].unwrap();

let table_ptr = NonNull::slice_from_raw_parts(
NonNull::with_exposed_provenance(
core::num::NonZero::new(
Expand Down
Loading