Merge branch 'pci_use_pci_types' into 'master'
Start using the pci_types crate See merge request redox-os/drivers!135
This commit is contained in:
Generated
+17
-6
@@ -196,9 +196,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.4.0"
|
||||
version = "2.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
|
||||
checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
|
||||
|
||||
[[package]]
|
||||
name = "bitvec"
|
||||
@@ -527,7 +527,7 @@ version = "3.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8283e7331b8c93b9756e0cfdbcfb90312852f953c6faf9bf741e684cc3b6ad69"
|
||||
dependencies = [
|
||||
"bitflags 2.4.0",
|
||||
"bitflags 2.4.2",
|
||||
"crc",
|
||||
"log",
|
||||
"uuid",
|
||||
@@ -698,7 +698,7 @@ version = "0.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8"
|
||||
dependencies = [
|
||||
"bitflags 2.4.0",
|
||||
"bitflags 2.4.2",
|
||||
"libc",
|
||||
"redox_syscall 0.4.1",
|
||||
]
|
||||
@@ -956,6 +956,16 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pci_types"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "831e5bebf010674bc2e8070b892948120d4c453c71f37387e1ffea5636620dbe"
|
||||
dependencies = [
|
||||
"bit_field",
|
||||
"bitflags 2.4.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pcid"
|
||||
version = "0.1.0"
|
||||
@@ -968,6 +978,7 @@ dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"paw",
|
||||
"pci_types",
|
||||
"plain",
|
||||
"redox-log",
|
||||
"redox_syscall 0.4.1",
|
||||
@@ -1151,7 +1162,7 @@ version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "475e252d7add4825405d2248d530d33e22364ac5477eab816b56efbeec1e2712"
|
||||
dependencies = [
|
||||
"bitflags 2.4.0",
|
||||
"bitflags 2.4.2",
|
||||
"libredox",
|
||||
"redox_syscall 0.4.1",
|
||||
]
|
||||
@@ -1727,7 +1738,7 @@ dependencies = [
|
||||
name = "virtio-core"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bitflags 2.4.0",
|
||||
"bitflags 2.4.2",
|
||||
"common",
|
||||
"crossbeam-queue",
|
||||
"futures",
|
||||
|
||||
+2
-9
@@ -73,15 +73,8 @@ fn main() {
|
||||
let mut name = pci_config.func.name();
|
||||
name.push_str("_ac97");
|
||||
|
||||
let bar0 = match pci_config.func.bars[0] {
|
||||
PciBar::Port(port) => port,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let bar1 = match pci_config.func.bars[1] {
|
||||
PciBar::Port(port) => port,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let bar0 = pci_config.func.bars[0].expect_port();
|
||||
let bar1 = pci_config.func.bars[1].expect_port();
|
||||
|
||||
let irq = pci_config.func.legacy_interrupt_line;
|
||||
|
||||
|
||||
+3
-8
@@ -9,7 +9,7 @@ use std::io::{ErrorKind, Read, Write};
|
||||
use std::os::unix::io::{FromRawFd, RawFd};
|
||||
use std::usize;
|
||||
|
||||
use pcid_interface::{PciBar, PcidServerHandle};
|
||||
use pcid_interface::PcidServerHandle;
|
||||
use syscall::error::{Error, ENODEV};
|
||||
use syscall::data::{Event, Packet};
|
||||
use syscall::flag::EVENT_READ;
|
||||
@@ -81,12 +81,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! {
|
||||
let mut name = pci_config.func.name();
|
||||
name.push_str("_ahci");
|
||||
|
||||
let bar = match pci_config.func.bars[5] {
|
||||
PciBar::Memory32(addr) => addr as usize,
|
||||
PciBar::Memory64(addr) => addr as usize,
|
||||
PciBar::None | PciBar::Port(_) => unreachable!(),
|
||||
};
|
||||
let bar_size = pci_config.func.bar_sizes[5];
|
||||
let (bar, bar_size) = pci_config.func.bars[5].expect_mem();
|
||||
|
||||
let irq = pci_config.func.legacy_interrupt_line;
|
||||
|
||||
@@ -97,7 +92,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! {
|
||||
let address = unsafe {
|
||||
common::physmap(
|
||||
bar,
|
||||
bar_size as usize,
|
||||
bar_size,
|
||||
common::Prot { read: true, write: true },
|
||||
common::MemoryType::Uncacheable,
|
||||
).expect("ahcid: failed to map address")
|
||||
|
||||
+2
-7
@@ -10,7 +10,7 @@ use std::process;
|
||||
use std::sync::Arc;
|
||||
|
||||
use event::EventQueue;
|
||||
use pcid_interface::{PciBar, PcidServerHandle};
|
||||
use pcid_interface::PcidServerHandle;
|
||||
use syscall::{EventFlags, Packet, SchemeBlockMut};
|
||||
|
||||
pub mod device;
|
||||
@@ -68,12 +68,7 @@ fn main() {
|
||||
let mut name = pci_config.func.name();
|
||||
name.push_str("_e1000");
|
||||
|
||||
let bar = match pci_config.func.bars[0] {
|
||||
PciBar::Memory32(addr) => addr as usize,
|
||||
PciBar::Memory64(addr) => addr as usize,
|
||||
PciBar::None | PciBar::Port(_) => unreachable!(),
|
||||
};
|
||||
let bar_size = pci_config.func.bar_sizes[0] as usize;
|
||||
let (bar, bar_size) = pci_config.func.bars[0].expect_mem();
|
||||
|
||||
let irq = pci_config.func.legacy_interrupt_line;
|
||||
|
||||
|
||||
+1
-4
@@ -86,10 +86,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! {
|
||||
|
||||
info!("IDE PCI CONFIG: {:?}", pci_config);
|
||||
|
||||
let busmaster_base = match pci_config.func.bars[4] {
|
||||
PciBar::Port(port) => port,
|
||||
other => panic!("TODO: IDE busmaster BAR {:#x?}", other),
|
||||
};
|
||||
let busmaster_base = pci_config.func.bars[4].expect_port();
|
||||
let (primary, primary_irq) = if pci_config.func.full_device_id.interface & 1 != 0 {
|
||||
panic!("TODO: IDE primary channel is PCI native");
|
||||
} else {
|
||||
|
||||
+2
-14
@@ -160,24 +160,12 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! {
|
||||
let mut name = pci_config.func.name();
|
||||
name.push_str("_ihda");
|
||||
|
||||
let bar = pci_config.func.bars[0];
|
||||
let bar_size = pci_config.func.bar_sizes[0];
|
||||
let bar_ptr = match bar {
|
||||
pcid_interface::PciBar::Memory32(ptr) => match ptr {
|
||||
0 => panic!("BAR 0 is mapped to address 0"),
|
||||
_ => ptr as u64,
|
||||
},
|
||||
pcid_interface::PciBar::Memory64(ptr) => match ptr {
|
||||
0 => panic!("BAR 0 is mapped to address 0"),
|
||||
_ => ptr,
|
||||
},
|
||||
other => panic!("Expected memory bar, found {:?}", other),
|
||||
};
|
||||
let (bar_ptr, bar_size) = pci_config.func.bars[0].expect_mem();
|
||||
|
||||
log::info!(" + IHDA {} on: {:#X} size: {}", name, bar_ptr, bar_size);
|
||||
|
||||
let address = unsafe {
|
||||
common::physmap(bar_ptr as usize, bar_size as usize, common::Prot::RW, common::MemoryType::Uncacheable)
|
||||
common::physmap(bar_ptr, bar_size, common::Prot::RW, common::MemoryType::Uncacheable)
|
||||
.expect("ihdad: failed to map address") as usize
|
||||
};
|
||||
|
||||
|
||||
+2
-6
@@ -13,7 +13,7 @@ use std::sync::Arc;
|
||||
use std::thread;
|
||||
|
||||
use event::EventQueue;
|
||||
use pcid_interface::{PciBar, PcidServerHandle};
|
||||
use pcid_interface::PcidServerHandle;
|
||||
use std::time::Duration;
|
||||
use syscall::{EventFlags, Packet, SchemeBlockMut};
|
||||
|
||||
@@ -76,11 +76,7 @@ fn main() {
|
||||
let mut name = pci_config.func.name();
|
||||
name.push_str("_ixgbe");
|
||||
|
||||
let bar = match pci_config.func.bars[0] {
|
||||
PciBar::Memory32(addr) => addr as usize,
|
||||
PciBar::Memory64(addr) => addr as usize,
|
||||
PciBar::None | PciBar::Port(_) => unreachable!(),
|
||||
};
|
||||
let (bar, _) = pci_config.func.bars[0].expect_mem();
|
||||
|
||||
let irq = pci_config.func.legacy_interrupt_line;
|
||||
|
||||
|
||||
+8
-30
@@ -9,7 +9,7 @@ use std::ptr::NonNull;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::{slice, usize};
|
||||
|
||||
use pcid_interface::{PciBar, PciFeature, PciFeatureInfo, PciFunction, PcidServerHandle};
|
||||
use pcid_interface::{PciFeature, PciFeatureInfo, PciFunction, PcidServerHandle};
|
||||
use syscall::{
|
||||
Event, Mmio, Packet, Result, SchemeBlockMut,
|
||||
PAGE_SIZE,
|
||||
@@ -93,20 +93,9 @@ fn get_int_method(
|
||||
match &mut *bar_guard {
|
||||
&mut Some(ref bar) => Ok(bar.ptr),
|
||||
bar_to_set @ &mut None => {
|
||||
let bar = match function.bars[bir] {
|
||||
PciBar::Memory32(addr) => match addr {
|
||||
0 => panic!("BAR {} is mapped to address 0", bir),
|
||||
_ => addr as u64,
|
||||
},
|
||||
PciBar::Memory64(addr) => match addr {
|
||||
0 => panic!("BAR {} is mapped to address 0", bir),
|
||||
_ => addr,
|
||||
},
|
||||
other => panic!("Expected memory BAR, found {:?}", other),
|
||||
};
|
||||
let bar_size = function.bar_sizes[bir];
|
||||
let (bar, bar_size) = function.bars[bir].expect_mem();
|
||||
|
||||
let bar = Bar::allocate(bar as usize, bar_size as usize)?;
|
||||
let bar = Bar::allocate(bar, bar_size)?;
|
||||
*bar_to_set = Some(bar);
|
||||
Ok(bar_to_set.as_ref().unwrap().ptr)
|
||||
}
|
||||
@@ -303,18 +292,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! {
|
||||
|
||||
let _logger_ref = setup_logging(&scheme_name);
|
||||
|
||||
let bar = match pci_config.func.bars[0] {
|
||||
PciBar::Memory32(mem) => match mem {
|
||||
0 => panic!("BAR 0 is mapped to address 0"),
|
||||
_ => mem as u64,
|
||||
},
|
||||
PciBar::Memory64(mem) => match mem {
|
||||
0 => panic!("BAR 0 is mapped to address 0"),
|
||||
_ => mem,
|
||||
},
|
||||
other => panic!("received a non-memory BAR ({:?})", other),
|
||||
};
|
||||
let bar_size = pci_config.func.bar_sizes[0];
|
||||
let (bar, bar_size) = pci_config.func.bars[0].expect_mem();
|
||||
let irq = pci_config.func.legacy_interrupt_line;
|
||||
|
||||
log::debug!("NVME PCI CONFIG: {:?}", pci_config);
|
||||
@@ -323,16 +301,16 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! {
|
||||
|
||||
let address = unsafe {
|
||||
common::physmap(
|
||||
bar as usize,
|
||||
bar_size as usize,
|
||||
bar,
|
||||
bar_size,
|
||||
common::Prot { read: true, write: true },
|
||||
common::MemoryType::Uncacheable,
|
||||
)
|
||||
.expect("nvmed: failed to map address")
|
||||
} as usize;
|
||||
*allocated_bars.0[0].lock().unwrap() = Some(Bar {
|
||||
physical: bar as usize,
|
||||
bar_size: bar_size as usize,
|
||||
physical: bar,
|
||||
bar_size,
|
||||
ptr: NonNull::new(address as *mut u8).expect("Physmapping BAR gave nullptr"),
|
||||
});
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ byteorder = "1.2"
|
||||
libc = "0.2"
|
||||
log = "0.4"
|
||||
paw = "1.0"
|
||||
pci_types = "0.6.1"
|
||||
plain = "0.2"
|
||||
redox-log = "0.1"
|
||||
redox_syscall = "0.4"
|
||||
|
||||
@@ -6,8 +6,7 @@ use std::sync::Mutex;
|
||||
use syscall::io::{Io as _, Pio};
|
||||
|
||||
use log::info;
|
||||
|
||||
use crate::pci::{CfgAccess, PciAddress};
|
||||
use pci_types::{ConfigRegionAccess, PciAddress};
|
||||
|
||||
pub(crate) struct Pci {
|
||||
lock: Mutex<()>,
|
||||
@@ -58,7 +57,11 @@ impl Pci {
|
||||
}
|
||||
}
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
impl CfgAccess for Pci {
|
||||
impl ConfigRegionAccess for Pci {
|
||||
fn function_exists(&self, _address: PciAddress) -> bool {
|
||||
todo!();
|
||||
}
|
||||
|
||||
unsafe fn read(&self, address: PciAddress, offset: u16) -> u32 {
|
||||
let _guard = self.lock.lock().unwrap();
|
||||
|
||||
@@ -86,7 +89,11 @@ impl CfgAccess for Pci {
|
||||
}
|
||||
}
|
||||
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
|
||||
impl CfgAccess for Pci {
|
||||
impl ConfigRegionAccess for Pci {
|
||||
fn function_exists(&self, _address: PciAddress) -> bool {
|
||||
todo!();
|
||||
}
|
||||
|
||||
unsafe fn read(&self, addr: PciAddress, offset: u16) -> u32 {
|
||||
let _guard = self.lock.lock().unwrap();
|
||||
todo!("Pci::CfgAccess::read on this architecture")
|
||||
|
||||
@@ -2,8 +2,8 @@ use std::sync::Mutex;
|
||||
use std::{fmt, fs, io, mem, ptr, slice};
|
||||
|
||||
use log::info;
|
||||
use pci_types::{ConfigRegionAccess, PciAddress};
|
||||
|
||||
use crate::pci::{CfgAccess, PciAddress};
|
||||
use fallback::Pci;
|
||||
|
||||
mod fallback;
|
||||
@@ -221,7 +221,11 @@ impl Pcie {
|
||||
}
|
||||
}
|
||||
|
||||
impl CfgAccess for Pcie {
|
||||
impl ConfigRegionAccess for Pcie {
|
||||
fn function_exists(&self, _address: PciAddress) -> bool {
|
||||
todo!();
|
||||
}
|
||||
|
||||
unsafe fn read(&self, address: PciAddress, offset: u16) -> u32 {
|
||||
let _guard = self.lock.lock().unwrap();
|
||||
|
||||
|
||||
@@ -26,17 +26,34 @@ pub enum LegacyInterruptPin {
|
||||
IntD = 4,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(remote = "PciAddress")]
|
||||
struct PciAddressDef {
|
||||
#[serde(getter = "PciAddress::segment")]
|
||||
segment: u16,
|
||||
#[serde(getter = "PciAddress::bus")]
|
||||
bus: u8,
|
||||
#[serde(getter = "PciAddress::device")]
|
||||
device: u8,
|
||||
#[serde(getter = "PciAddress::function")]
|
||||
function: u8,
|
||||
}
|
||||
|
||||
impl From<PciAddressDef> for PciAddress {
|
||||
fn from(value: PciAddressDef) -> Self {
|
||||
PciAddress::new(value.segment, value.bus, value.device, value.function)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||||
pub struct PciFunction {
|
||||
/// Address of the PCI function.
|
||||
#[serde(with = "PciAddressDef")]
|
||||
pub addr: PciAddress,
|
||||
|
||||
/// PCI Base Address Registers
|
||||
pub bars: [PciBar; 6],
|
||||
|
||||
/// BAR sizes
|
||||
pub bar_sizes: [u32; 6],
|
||||
|
||||
/// Legacy IRQ line: It's the responsibility of pcid to make sure that it be mapped in either
|
||||
/// the I/O APIC or the 8259 PIC, so that the subdriver can map the interrupt vector directly.
|
||||
/// The vector to map is always this field, plus 32.
|
||||
@@ -262,6 +279,7 @@ impl PcidServerHandle {
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME turn into struct with bool fields
|
||||
pub fn fetch_all_features(&mut self) -> Result<Vec<(PciFeature, FeatureStatus)>> {
|
||||
self.send(&PcidClientRequest::RequestFeatures)?;
|
||||
match self.recv()? {
|
||||
|
||||
+38
-96
@@ -5,20 +5,24 @@ use std::process::Command;
|
||||
use std::thread;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use pci_types::device_type::DeviceType;
|
||||
use pci_types::{ConfigRegionAccess, PciAddress};
|
||||
use structopt::StructOpt;
|
||||
use log::{debug, error, info, warn, trace};
|
||||
use redox_log::{OutputBuilder, RedoxLogger};
|
||||
|
||||
use crate::cfg_access::Pcie;
|
||||
use crate::config::Config;
|
||||
use crate::pci::{CfgAccess, PciAddress, PciBar, PciClass, PciFunc, PciHeader, PciHeaderError, PciHeaderType};
|
||||
use crate::pci::{PciBar, PciFunc};
|
||||
use crate::pci::cap::Capability as PciCapability;
|
||||
use crate::pci::func::{ConfigReader, ConfigWriter};
|
||||
use crate::pci_header::{PciHeader, PciHeaderError};
|
||||
|
||||
mod cfg_access;
|
||||
mod config;
|
||||
mod driver_interface;
|
||||
mod pci;
|
||||
mod pci_header;
|
||||
|
||||
#[derive(StructOpt)]
|
||||
#[structopt(about)]
|
||||
@@ -38,7 +42,7 @@ pub struct DriverHandler {
|
||||
|
||||
state: Arc<State>,
|
||||
}
|
||||
fn with_pci_func_raw<T, F: FnOnce(&PciFunc) -> T>(pci: &dyn CfgAccess, addr: PciAddress, function: F) -> T {
|
||||
fn with_pci_func_raw<T, F: FnOnce(&PciFunc) -> T>(pci: &dyn ConfigRegionAccess, addr: PciAddress, function: F) -> T {
|
||||
let func = PciFunc {
|
||||
pci,
|
||||
addr,
|
||||
@@ -71,7 +75,7 @@ impl DriverHandler {
|
||||
None => return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(feature)),
|
||||
};
|
||||
unsafe {
|
||||
with_pci_func_raw(self.state.preferred_cfg_access(), self.addr, |func| {
|
||||
with_pci_func_raw(&self.state.pcie, self.addr, |func| {
|
||||
capability.set_enabled(true);
|
||||
capability.write_message_control(func, offset);
|
||||
});
|
||||
@@ -84,7 +88,7 @@ impl DriverHandler {
|
||||
None => return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(feature)),
|
||||
};
|
||||
unsafe {
|
||||
with_pci_func_raw(self.state.preferred_cfg_access(), self.addr, |func| {
|
||||
with_pci_func_raw(&self.state.pcie, self.addr, |func| {
|
||||
capability.set_msix_enabled(true);
|
||||
capability.write_a(func, offset);
|
||||
});
|
||||
@@ -144,7 +148,7 @@ impl DriverHandler {
|
||||
info.set_mask_bits(mask_bits);
|
||||
}
|
||||
unsafe {
|
||||
with_pci_func_raw(self.state.preferred_cfg_access(), self.addr, |func| {
|
||||
with_pci_func_raw(&self.state.pcie, self.addr, |func| {
|
||||
info.write_all(func, offset);
|
||||
});
|
||||
}
|
||||
@@ -156,7 +160,7 @@ impl DriverHandler {
|
||||
if let Some(mask) = function_mask {
|
||||
info.set_function_mask(mask);
|
||||
unsafe {
|
||||
with_pci_func_raw(self.state.preferred_cfg_access(), self.addr, |func| {
|
||||
with_pci_func_raw(&self.state.pcie, self.addr, |func| {
|
||||
info.write_a(func, offset);
|
||||
});
|
||||
}
|
||||
@@ -168,7 +172,7 @@ impl DriverHandler {
|
||||
}
|
||||
PcidClientRequest::ReadConfig(offset) => {
|
||||
let value = unsafe {
|
||||
with_pci_func_raw(self.state.preferred_cfg_access(), self.addr, |func| {
|
||||
with_pci_func_raw(&self.state.pcie, self.addr, |func| {
|
||||
func.read_u32(offset)
|
||||
})
|
||||
};
|
||||
@@ -176,7 +180,7 @@ impl DriverHandler {
|
||||
},
|
||||
PcidClientRequest::WriteConfig(offset, value) => {
|
||||
unsafe {
|
||||
with_pci_func_raw(self.state.preferred_cfg_access(), self.addr, |func| {
|
||||
with_pci_func_raw(&self.state.pcie, self.addr, |func| {
|
||||
func.write_u32(offset, value);
|
||||
});
|
||||
}
|
||||
@@ -201,58 +205,37 @@ pub struct State {
|
||||
threads: Mutex<Vec<thread::JoinHandle<()>>>,
|
||||
pcie: Pcie,
|
||||
}
|
||||
impl State {
|
||||
fn preferred_cfg_access(&self) -> &dyn CfgAccess {
|
||||
&self.pcie
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_parsed_header(state: Arc<State>, config: &Config, addr: PciAddress, header: PciHeader) {
|
||||
let pci = state.preferred_cfg_access();
|
||||
|
||||
let raw_class: u8 = header.class().into();
|
||||
let mut string = format!("PCI {} {:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X} {:?}",
|
||||
addr, header.vendor_id(), header.device_id(), raw_class,
|
||||
header.subclass(), header.interface(), header.revision(), header.class());
|
||||
match header.class() {
|
||||
PciClass::Legacy if header.subclass() == 1 => string.push_str(" VGA CTL"),
|
||||
PciClass::Storage => match header.subclass() {
|
||||
0x01 => {
|
||||
string.push_str(" IDE");
|
||||
},
|
||||
0x06 => if header.interface() == 0 {
|
||||
string.push_str(" SATA VND");
|
||||
} else if header.interface() == 1 {
|
||||
string.push_str(" SATA AHCI");
|
||||
},
|
||||
_ => ()
|
||||
let device_type = DeviceType::from((header.class(), header.subclass()));
|
||||
match device_type {
|
||||
DeviceType::LegacyVgaCompatible => string.push_str(" VGA CTL"),
|
||||
DeviceType::IdeController => string.push_str(" IDE"),
|
||||
DeviceType::SataController => match header.interface() {
|
||||
0 => string.push_str(" SATA VND"),
|
||||
1 => string.push_str(" SATA AHCI"),
|
||||
_ => (),
|
||||
},
|
||||
PciClass::SerialBus => match header.subclass() {
|
||||
0x03 => match header.interface() {
|
||||
0x00 => {
|
||||
string.push_str(" UHCI");
|
||||
},
|
||||
0x10 => {
|
||||
string.push_str(" OHCI");
|
||||
},
|
||||
0x20 => {
|
||||
string.push_str(" EHCI");
|
||||
},
|
||||
0x30 => {
|
||||
string.push_str(" XHCI");
|
||||
},
|
||||
_ => ()
|
||||
},
|
||||
_ => ()
|
||||
DeviceType::UsbController => match header.interface() {
|
||||
0x00 => string.push_str(" UHCI"),
|
||||
0x10 => string.push_str(" OHCI"),
|
||||
0x20 => string.push_str(" EHCI"),
|
||||
0x30 => string.push_str(" XHCI"),
|
||||
_ => (),
|
||||
},
|
||||
_ => ()
|
||||
_ => (),
|
||||
}
|
||||
|
||||
for (i, bar) in header.bars().iter().enumerate() {
|
||||
let bars = header.bars(&state.pcie);
|
||||
for (i, bar) in bars.iter().enumerate() {
|
||||
match bar {
|
||||
PciBar::None => {},
|
||||
PciBar::Memory32(addr) => string.push_str(&format!(" {i}={addr:08X}")),
|
||||
PciBar::Memory64(addr) => string.push_str(&format!(" {i}={addr:016X}")),
|
||||
PciBar::Memory32{addr,..} => string.push_str(&format!(" {i}={addr:08X}")),
|
||||
PciBar::Memory64{addr,..} => string.push_str(&format!(" {i}={addr:016X}")),
|
||||
PciBar::Port(port) => string.push_str(&format!(" {i}=P{port:04X}")),
|
||||
}
|
||||
}
|
||||
@@ -270,9 +253,9 @@ fn handle_parsed_header(state: Arc<State>, config: &Config, addr: PciAddress, he
|
||||
|
||||
// Enable bus mastering, memory space, and I/O space
|
||||
unsafe {
|
||||
let mut data = pci.read(addr, 0x04);
|
||||
let mut data = state.pcie.read(addr, 0x04);
|
||||
data |= 7;
|
||||
pci.write(addr, 0x04, data);
|
||||
state.pcie.write(addr, 0x04, data);
|
||||
}
|
||||
|
||||
// Set IRQ line to 9 if not set
|
||||
@@ -280,56 +263,19 @@ fn handle_parsed_header(state: Arc<State>, config: &Config, addr: PciAddress, he
|
||||
let interrupt_pin;
|
||||
|
||||
unsafe {
|
||||
let mut data = pci.read(addr, 0x3C);
|
||||
let mut data = state.pcie.read(addr, 0x3C);
|
||||
irq = (data & 0xFF) as u8;
|
||||
interrupt_pin = ((data & 0x0000_FF00) >> 8) as u8;
|
||||
if irq == 0xFF {
|
||||
irq = 9;
|
||||
}
|
||||
data = (data & 0xFFFFFF00) | irq as u32;
|
||||
pci.write(addr, 0x3C, data);
|
||||
state.pcie.write(addr, 0x3C, data);
|
||||
};
|
||||
|
||||
// Find BAR sizes
|
||||
//TODO: support 64-bit BAR sizes?
|
||||
let mut bars = [PciBar::None; 6];
|
||||
let mut bar_sizes = [0; 6];
|
||||
unsafe {
|
||||
let count = match header.header_type() {
|
||||
PciHeaderType::GENERAL => 6,
|
||||
PciHeaderType::PCITOPCI => 2,
|
||||
_ => 0,
|
||||
};
|
||||
|
||||
for i in 0..count {
|
||||
bars[i] = header.get_bar(i);
|
||||
|
||||
let offset = 0x10 + (i as u8) * 4;
|
||||
|
||||
let original = pci.read(addr, offset.into());
|
||||
pci.write(addr, offset.into(), 0xFFFFFFFF);
|
||||
|
||||
let new = pci.read(addr, offset.into());
|
||||
pci.write(addr, offset.into(), original);
|
||||
|
||||
let masked = if new & 1 == 1 {
|
||||
new & 0xFFFFFFFC
|
||||
} else {
|
||||
new & 0xFFFFFFF0
|
||||
};
|
||||
|
||||
let size = (!masked).wrapping_add(1);
|
||||
bar_sizes[i] = if size <= 1 {
|
||||
0
|
||||
} else {
|
||||
size
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
let capabilities = if header.status() & (1 << 4) != 0 {
|
||||
let func = PciFunc {
|
||||
pci: state.preferred_cfg_access(),
|
||||
pci: &state.pcie,
|
||||
addr
|
||||
};
|
||||
crate::pci::cap::CapabilitiesIter { inner: crate::pci::cap::CapabilityOffsetsIter::new(header.cap_pointer(), &func) }.collect::<Vec<_>>()
|
||||
@@ -355,7 +301,6 @@ fn handle_parsed_header(state: Arc<State>, config: &Config, addr: PciAddress, he
|
||||
|
||||
let func = driver_interface::PciFunction {
|
||||
bars,
|
||||
bar_sizes,
|
||||
addr,
|
||||
legacy_interrupt_line: irq,
|
||||
legacy_interrupt_pin,
|
||||
@@ -506,8 +451,6 @@ fn main(args: Args) {
|
||||
threads: Mutex::new(Vec::new()),
|
||||
});
|
||||
|
||||
let pci = state.preferred_cfg_access();
|
||||
|
||||
info!("PCI SG-BS:DV.F VEND:DEVI CL.SC.IN.RV");
|
||||
|
||||
// FIXME Use full ACPI for enumerating the host bridges. MCFG only describes the first
|
||||
@@ -522,8 +465,7 @@ fn main(args: Args) {
|
||||
'dev: for dev_num in 0..32 {
|
||||
for func_num in 0..8 {
|
||||
let func_addr = PciAddress::new(0, bus_num, dev_num, func_num);
|
||||
let func = PciFunc { pci, addr: func_addr };
|
||||
match PciHeader::from_reader(func) {
|
||||
match PciHeader::from_reader(&state.pcie, func_addr) {
|
||||
Ok(header) => {
|
||||
handle_parsed_header(Arc::clone(&state), &config, func_addr, header);
|
||||
if let PciHeader::PciToPci { secondary_bus_num, .. } = header {
|
||||
@@ -537,7 +479,7 @@ fn main(args: Args) {
|
||||
}
|
||||
},
|
||||
Err(PciHeaderError::UnknownHeaderType(id)) => {
|
||||
warn!("pcid: unknown header type: {}", id);
|
||||
warn!("pcid: unknown header type: {id:?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+26
-23
@@ -1,11 +1,13 @@
|
||||
use serde::{Serialize, Deserialize};
|
||||
use std::convert::TryInto;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum PciBar {
|
||||
None,
|
||||
Memory32(u32),
|
||||
Memory64(u64),
|
||||
Port(u16)
|
||||
Memory32 { addr: u32, size: u32 },
|
||||
Memory64 { addr: u64, size: u64 },
|
||||
Port(u16),
|
||||
}
|
||||
|
||||
impl PciBar {
|
||||
@@ -15,27 +17,28 @@ impl PciBar {
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u32> for PciBar {
|
||||
fn from(bar: u32) -> Self {
|
||||
if bar & 0xFFFFFFFC == 0 {
|
||||
PciBar::None
|
||||
} else if bar & 1 == 0 {
|
||||
match (bar >> 1) & 3 {
|
||||
0 => {
|
||||
PciBar::Memory32(bar & 0xFFFFFFF0)
|
||||
},
|
||||
2 => {
|
||||
PciBar::Memory64((bar & 0xFFFFFFF0) as u64)
|
||||
},
|
||||
other => {
|
||||
log::warn!("unsupported PCI memory type {}", other);
|
||||
PciBar::None
|
||||
},
|
||||
pub fn expect_port(&self) -> u16 {
|
||||
match *self {
|
||||
PciBar::Port(port) => port,
|
||||
PciBar::Memory32 { .. } | PciBar::Memory64 { .. } => {
|
||||
panic!("expected port BAR, found memory BAR");
|
||||
}
|
||||
} else {
|
||||
PciBar::Port((bar & 0xFFFC) as u16)
|
||||
PciBar::None => panic!("expected BAR to exist"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expect_mem(&self) -> (usize, usize) {
|
||||
match *self {
|
||||
PciBar::Memory32 { addr, size } => (addr as usize, size as usize),
|
||||
PciBar::Memory64 { addr, size } => (
|
||||
addr.try_into()
|
||||
.expect("conversion from 64bit BAR to usize failed"),
|
||||
size.try_into()
|
||||
.expect("conversion from 64bit BAR size to usize failed"),
|
||||
),
|
||||
PciBar::Port(_) => panic!("expected memory BAR, found port BAR"),
|
||||
PciBar::None => panic!("expected BAR to exist"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum PciClass {
|
||||
Legacy,
|
||||
Storage,
|
||||
Network,
|
||||
Display,
|
||||
Multimedia,
|
||||
Memory,
|
||||
Bridge,
|
||||
SimpleComms,
|
||||
Peripheral,
|
||||
Input,
|
||||
Docking,
|
||||
Processor,
|
||||
SerialBus,
|
||||
Wireless,
|
||||
IntelligentIo,
|
||||
SatelliteComms,
|
||||
Cryptography,
|
||||
SignalProc,
|
||||
Reserved(u8),
|
||||
Unknown
|
||||
}
|
||||
|
||||
impl From<u8> for PciClass {
|
||||
fn from(class: u8) -> PciClass {
|
||||
match class {
|
||||
0x00 => PciClass::Legacy,
|
||||
0x01 => PciClass::Storage,
|
||||
0x02 => PciClass::Network,
|
||||
0x03 => PciClass::Display,
|
||||
0x04 => PciClass::Multimedia,
|
||||
0x05 => PciClass::Memory,
|
||||
0x06 => PciClass::Bridge,
|
||||
0x07 => PciClass::SimpleComms,
|
||||
0x08 => PciClass::Peripheral,
|
||||
0x09 => PciClass::Input,
|
||||
0x0A => PciClass::Docking,
|
||||
0x0B => PciClass::Processor,
|
||||
0x0C => PciClass::SerialBus,
|
||||
0x0D => PciClass::Wireless,
|
||||
0x0E => PciClass::IntelligentIo,
|
||||
0x0F => PciClass::SatelliteComms,
|
||||
0x10 => PciClass::Cryptography,
|
||||
0x11 => PciClass::SignalProc,
|
||||
0xFF => PciClass::Unknown,
|
||||
reserved => PciClass::Reserved(reserved)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u8> for PciClass {
|
||||
fn into(self) -> u8 {
|
||||
match self {
|
||||
PciClass::Legacy => 0x00,
|
||||
PciClass::Storage => 0x01,
|
||||
PciClass::Network => 0x02,
|
||||
PciClass::Display => 0x03,
|
||||
PciClass::Multimedia => 0x04,
|
||||
PciClass::Memory => 0x05,
|
||||
PciClass::Bridge => 0x06,
|
||||
PciClass::SimpleComms => 0x07,
|
||||
PciClass::Peripheral => 0x08,
|
||||
PciClass::Input => 0x09,
|
||||
PciClass::Docking => 0x0A,
|
||||
PciClass::Processor => 0x0B,
|
||||
PciClass::SerialBus => 0x0C,
|
||||
PciClass::Wireless => 0x0D,
|
||||
PciClass::IntelligentIo => 0x0E,
|
||||
PciClass::SatelliteComms => 0x0F,
|
||||
PciClass::Cryptography => 0x10,
|
||||
PciClass::SignalProc => 0x11,
|
||||
PciClass::Unknown => 0xFF,
|
||||
PciClass::Reserved(reserved) => reserved
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
|
||||
use super::{CfgAccess, PciAddress};
|
||||
use pci_types::{ConfigRegionAccess, PciAddress};
|
||||
|
||||
pub trait ConfigReader {
|
||||
unsafe fn read_range(&self, offset: u16, len: u16) -> Vec<u8> {
|
||||
@@ -33,7 +32,7 @@ pub trait ConfigWriter {
|
||||
}
|
||||
|
||||
pub struct PciFunc<'pci> {
|
||||
pub pci: &'pci dyn CfgAccess,
|
||||
pub pci: &'pci dyn ConfigRegionAccess,
|
||||
pub addr: PciAddress,
|
||||
}
|
||||
|
||||
|
||||
@@ -1,379 +0,0 @@
|
||||
use bitflags::bitflags;
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::bar::PciBar;
|
||||
use super::class::PciClass;
|
||||
use super::func::ConfigReader;
|
||||
use super::id::FullDeviceId;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum PciHeaderError {
|
||||
NoDevice,
|
||||
UnknownHeaderType(u8),
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
/// Flags found in the status register of a PCI device
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct PciHeaderType: u8 {
|
||||
/// A general PCI device (Type 0x01).
|
||||
const GENERAL = 0b00000000;
|
||||
/// A PCI-to-PCI bridge device (Type 0x01).
|
||||
const PCITOPCI = 0b00000001;
|
||||
/// A PCI-to-PCI bridge device (Type 0x02).
|
||||
const CARDBUSBRIDGE = 0b00000010;
|
||||
/// A multifunction device.
|
||||
const MULTIFUNCTION = 0b01000000;
|
||||
/// Mask used for fetching the header type.
|
||||
const HEADER_TYPE = 0b00000011;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct SharedPciHeader {
|
||||
full_device_id: FullDeviceId,
|
||||
command: u16,
|
||||
status: u16,
|
||||
header_type: PciHeaderType,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum PciHeader {
|
||||
General {
|
||||
shared: SharedPciHeader,
|
||||
bars: [PciBar; 6],
|
||||
subsystem_vendor_id: u16,
|
||||
subsystem_id: u16,
|
||||
cap_pointer: u8,
|
||||
interrupt_line: u8,
|
||||
interrupt_pin: u8,
|
||||
},
|
||||
PciToPci {
|
||||
shared: SharedPciHeader,
|
||||
bars: [PciBar; 2],
|
||||
secondary_bus_num: u8,
|
||||
cap_pointer: u8,
|
||||
interrupt_line: u8,
|
||||
interrupt_pin: u8,
|
||||
bridge_control: u16,
|
||||
},
|
||||
}
|
||||
|
||||
impl PciHeader {
|
||||
fn get_bars(bytes: &[u8], bars: &mut [PciBar]) {
|
||||
let mut i = 0;
|
||||
while i < bars.len() {
|
||||
let offset = i * 4;
|
||||
let bar_bytes = match bytes.get(offset..offset + 4) {
|
||||
Some(some) => some,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
match PciBar::from(LittleEndian::read_u32(bar_bytes)) {
|
||||
PciBar::Memory64(mut addr) => {
|
||||
let high_bytes = match bytes.get(offset + 4..offset + 8) {
|
||||
Some(some) => some,
|
||||
None => continue,
|
||||
};
|
||||
addr |= (LittleEndian::read_u32(high_bytes) as u64) << 32;
|
||||
bars[i] = PciBar::Memory64(addr);
|
||||
i += 2;
|
||||
}
|
||||
bar => {
|
||||
bars[i] = bar;
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse the bytes found in the Configuration Space of the PCI device into
|
||||
/// a more usable PciHeader.
|
||||
pub fn from_reader<T: ConfigReader>(reader: T) -> Result<PciHeader, PciHeaderError> {
|
||||
if unsafe { reader.read_u32(0) } != 0xffffffff {
|
||||
// Read the initial 16 bytes and set variables used by all header types.
|
||||
let bytes = unsafe { reader.read_range(0, 16) };
|
||||
let vendor_id = LittleEndian::read_u16(&bytes[0..2]);
|
||||
let device_id = LittleEndian::read_u16(&bytes[2..4]);
|
||||
let command = LittleEndian::read_u16(&bytes[4..6]);
|
||||
let status = LittleEndian::read_u16(&bytes[6..8]);
|
||||
let revision = bytes[8];
|
||||
let interface = bytes[9];
|
||||
let subclass = bytes[10];
|
||||
let class = bytes[11];
|
||||
let header_type = PciHeaderType::from_bits_truncate(bytes[14]);
|
||||
let shared = SharedPciHeader {
|
||||
full_device_id: FullDeviceId {
|
||||
vendor_id,
|
||||
device_id,
|
||||
class,
|
||||
subclass,
|
||||
interface,
|
||||
revision,
|
||||
},
|
||||
command,
|
||||
status,
|
||||
header_type,
|
||||
};
|
||||
|
||||
match header_type & PciHeaderType::HEADER_TYPE {
|
||||
PciHeaderType::GENERAL => {
|
||||
let bytes = unsafe { reader.read_range(16, 48) };
|
||||
let mut bars = [PciBar::None; 6];
|
||||
Self::get_bars(&bytes, &mut bars);
|
||||
let subsystem_vendor_id = LittleEndian::read_u16(&bytes[28..30]);
|
||||
let subsystem_id = LittleEndian::read_u16(&bytes[30..32]);
|
||||
let cap_pointer = bytes[36];
|
||||
let interrupt_line = bytes[44];
|
||||
let interrupt_pin = bytes[45];
|
||||
Ok(PciHeader::General {
|
||||
shared,
|
||||
bars,
|
||||
subsystem_vendor_id,
|
||||
subsystem_id,
|
||||
cap_pointer,
|
||||
interrupt_line,
|
||||
interrupt_pin,
|
||||
})
|
||||
}
|
||||
PciHeaderType::PCITOPCI => {
|
||||
let bytes = unsafe { reader.read_range(16, 48) };
|
||||
let mut bars = [PciBar::None; 2];
|
||||
Self::get_bars(&bytes, &mut bars);
|
||||
let secondary_bus_num = bytes[9];
|
||||
let cap_pointer = bytes[36];
|
||||
let interrupt_line = bytes[44];
|
||||
let interrupt_pin = bytes[45];
|
||||
let bridge_control = LittleEndian::read_u16(&bytes[46..48]);
|
||||
Ok(PciHeader::PciToPci {
|
||||
shared,
|
||||
bars,
|
||||
secondary_bus_num,
|
||||
cap_pointer,
|
||||
interrupt_line,
|
||||
interrupt_pin,
|
||||
bridge_control,
|
||||
})
|
||||
}
|
||||
id => Err(PciHeaderError::UnknownHeaderType(id.bits())),
|
||||
}
|
||||
} else {
|
||||
Err(PciHeaderError::NoDevice)
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the Header Type.
|
||||
pub fn header_type(&self) -> PciHeaderType {
|
||||
match self {
|
||||
&PciHeader::General {
|
||||
shared: SharedPciHeader { header_type, .. },
|
||||
..
|
||||
}
|
||||
| &PciHeader::PciToPci {
|
||||
shared: SharedPciHeader { header_type, .. },
|
||||
..
|
||||
} => header_type,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return all identifying information of the PCI function.
|
||||
pub fn full_device_id(&self) -> &FullDeviceId {
|
||||
match self {
|
||||
PciHeader::General {
|
||||
shared:
|
||||
SharedPciHeader {
|
||||
full_device_id: device_id,
|
||||
..
|
||||
},
|
||||
..
|
||||
}
|
||||
| PciHeader::PciToPci {
|
||||
shared:
|
||||
SharedPciHeader {
|
||||
full_device_id: device_id,
|
||||
..
|
||||
},
|
||||
..
|
||||
} => device_id,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the Vendor ID field.
|
||||
pub fn vendor_id(&self) -> u16 {
|
||||
self.full_device_id().vendor_id
|
||||
}
|
||||
|
||||
/// Return the Device ID field.
|
||||
pub fn device_id(&self) -> u16 {
|
||||
self.full_device_id().device_id
|
||||
}
|
||||
|
||||
/// Return the Revision field.
|
||||
pub fn revision(&self) -> u8 {
|
||||
self.full_device_id().revision
|
||||
}
|
||||
|
||||
/// Return the Interface field.
|
||||
pub fn interface(&self) -> u8 {
|
||||
self.full_device_id().interface
|
||||
}
|
||||
|
||||
/// Return the Subclass field.
|
||||
pub fn subclass(&self) -> u8 {
|
||||
self.full_device_id().subclass
|
||||
}
|
||||
|
||||
/// Return the Class field.
|
||||
pub fn class(&self) -> PciClass {
|
||||
PciClass::from(self.full_device_id().class)
|
||||
}
|
||||
|
||||
/// Return the Headers BARs.
|
||||
pub fn bars(&self) -> &[PciBar] {
|
||||
match self {
|
||||
&PciHeader::General { ref bars, .. } => bars,
|
||||
&PciHeader::PciToPci { ref bars, .. } => bars,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the BAR at the given index.
|
||||
///
|
||||
/// # Panics
|
||||
/// This function panics if the requested BAR index is beyond the length of the header
|
||||
/// types BAR array.
|
||||
pub fn get_bar(&self, idx: usize) -> PciBar {
|
||||
match self {
|
||||
&PciHeader::General { bars, .. } => {
|
||||
assert!(idx < 6, "the general PCI device only has 6 BARs");
|
||||
bars[idx]
|
||||
}
|
||||
&PciHeader::PciToPci { bars, .. } => {
|
||||
assert!(idx < 2, "the general PCI device only has 2 BARs");
|
||||
bars[idx]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the Interrupt Line field.
|
||||
pub fn interrupt_line(&self) -> u8 {
|
||||
match self {
|
||||
&PciHeader::General { interrupt_line, .. }
|
||||
| &PciHeader::PciToPci { interrupt_line, .. } => interrupt_line,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn status(&self) -> u16 {
|
||||
match self {
|
||||
&PciHeader::General {
|
||||
shared: SharedPciHeader { status, .. },
|
||||
..
|
||||
}
|
||||
| &PciHeader::PciToPci {
|
||||
shared: SharedPciHeader { status, .. },
|
||||
..
|
||||
} => status,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cap_pointer(&self) -> u8 {
|
||||
match self {
|
||||
&PciHeader::General { cap_pointer, .. } | &PciHeader::PciToPci { cap_pointer, .. } => {
|
||||
cap_pointer
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl<'a> ConfigReader for &'a [u8] {
|
||||
unsafe fn read_u32(&self, offset: u16) -> u32 {
|
||||
let offset = offset as usize;
|
||||
assert!(offset < self.len());
|
||||
LittleEndian::read_u32(&self[offset..offset + 4])
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::{PciHeaderError, PciHeader, PciHeaderType};
|
||||
use super::super::func::ConfigReader;
|
||||
use super::super::class::PciClass;
|
||||
use super::super::bar::PciBar;
|
||||
|
||||
const IGB_DEV_BYTES: [u8; 256] = [
|
||||
0x86, 0x80, 0x33, 0x15, 0x07, 0x04, 0x10, 0x00, 0x03, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x50, 0xf7, 0x00, 0x00, 0x00, 0x00, 0x01, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x58, 0xf7,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd9, 0x15, 0x33, 0x15,
|
||||
0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00,
|
||||
0x01, 0x50, 0x23, 0xc8, 0x08, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x05, 0x70, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x11, 0xa0, 0x04, 0x80, 0x03, 0x00, 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
|
||||
0x10, 0x00, 0x02, 0x00, 0xc2, 0x8c, 0x00, 0x10, 0x0f, 0x28, 0x19, 0x00, 0x11, 0x5c, 0x42, 0x00,
|
||||
0x42, 0x00, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
];
|
||||
|
||||
#[test]
|
||||
fn tset_parse_igb_dev() {
|
||||
let header = PciHeader::from_reader(&IGB_DEV_BYTES[..]).unwrap();
|
||||
assert_eq!(header.header_type(), PciHeaderType::GENERAL);
|
||||
assert_eq!(header.device_id(), 0x1533);
|
||||
assert_eq!(header.vendor_id(), 0x8086);
|
||||
assert_eq!(header.revision(), 3);
|
||||
assert_eq!(header.interface(), 0);
|
||||
assert_eq!(header.class(), PciClass::Network);
|
||||
assert_eq!(header.subclass(), 0);
|
||||
assert_eq!(header.bars().len(), 6);
|
||||
assert_eq!(header.get_bar(0), PciBar::Memory32(0xf7500000));
|
||||
assert_eq!(header.get_bar(1), PciBar::None);
|
||||
assert_eq!(header.get_bar(2), PciBar::Port(0xb000));
|
||||
assert_eq!(header.get_bar(3), PciBar::Memory32(0xf7580000));
|
||||
assert_eq!(header.get_bar(4), PciBar::None);
|
||||
assert_eq!(header.get_bar(5), PciBar::None);
|
||||
assert_eq!(header.interrupt_line(), 10);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_nonexistent() {
|
||||
let bytes = [
|
||||
0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff
|
||||
];
|
||||
assert_eq!(PciHeader::from_reader(&bytes[..]), Err(PciHeaderError::NoDevice));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_range() {
|
||||
let res = unsafe { (&IGB_DEV_BYTES[..]).read_range(0, 4) };
|
||||
assert_eq!(res, &[0x86, 0x80, 0x33, 0x15][..]);
|
||||
|
||||
let res = unsafe { (&IGB_DEV_BYTES[..]).read_range(16, 32) };
|
||||
let expected = [
|
||||
0x00, 0x00, 0x50, 0xf7, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x58, 0xf7,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xd9, 0x15, 0x33, 0x15
|
||||
];
|
||||
assert_eq!(res, expected);
|
||||
}
|
||||
|
||||
macro_rules! read_range_should_panic {
|
||||
($name:ident, $len:expr) => {
|
||||
#[test]
|
||||
#[should_panic(expected = "invalid range length")]
|
||||
fn $name() {
|
||||
let _ = unsafe { (&IGB_DEV_BYTES[..]).read_range(0, $len) };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
read_range_should_panic!(test_short_len, 2);
|
||||
read_range_should_panic!(test_not_mod_4_len, 7);
|
||||
}
|
||||
+1
-75
@@ -1,84 +1,10 @@
|
||||
use std::fmt;
|
||||
|
||||
use bit_field::BitField;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub use self::bar::PciBar;
|
||||
pub use self::class::PciClass;
|
||||
pub use self::func::PciFunc;
|
||||
pub use self::header::{PciHeader, PciHeaderError, PciHeaderType};
|
||||
pub use self::id::FullDeviceId;
|
||||
pub use pci_types::PciAddress;
|
||||
|
||||
mod bar;
|
||||
pub mod cap;
|
||||
mod class;
|
||||
pub mod func;
|
||||
pub mod header;
|
||||
mod id;
|
||||
pub mod msi;
|
||||
|
||||
pub trait CfgAccess {
|
||||
unsafe fn read(&self, addr: PciAddress, offset: u16) -> u32;
|
||||
unsafe fn write(&self, addr: PciAddress, offset: u16, value: u32);
|
||||
}
|
||||
|
||||
// Copied from the pci_types crate, version 0.6.1. It has been modified to add serde support.
|
||||
// FIXME If we start using it in the future use the upstream version instead.
|
||||
/// The address of a PCIe function.
|
||||
///
|
||||
/// PCIe supports 65536 segments, each with 256 buses, each with 32 slots, each with 8 possible functions. We pack this into a `u32`:
|
||||
///
|
||||
/// ```ignore
|
||||
/// 32 16 8 3 0
|
||||
/// +-------------------------------+---------------+---------+------+
|
||||
/// | segment | bus | device | func |
|
||||
/// +-------------------------------+---------------+---------+------+
|
||||
/// ```
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default, Serialize, Deserialize)]
|
||||
pub struct PciAddress(u32);
|
||||
|
||||
impl PciAddress {
|
||||
pub fn new(segment: u16, bus: u8, device: u8, function: u8) -> PciAddress {
|
||||
let mut result = 0;
|
||||
result.set_bits(0..3, function as u32);
|
||||
result.set_bits(3..8, device as u32);
|
||||
result.set_bits(8..16, bus as u32);
|
||||
result.set_bits(16..32, segment as u32);
|
||||
PciAddress(result)
|
||||
}
|
||||
|
||||
pub fn segment(&self) -> u16 {
|
||||
self.0.get_bits(16..32) as u16
|
||||
}
|
||||
|
||||
pub fn bus(&self) -> u8 {
|
||||
self.0.get_bits(8..16) as u8
|
||||
}
|
||||
|
||||
pub fn device(&self) -> u8 {
|
||||
self.0.get_bits(3..8) as u8
|
||||
}
|
||||
|
||||
pub fn function(&self) -> u8 {
|
||||
self.0.get_bits(0..3) as u8
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for PciAddress {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{:02x}-{:02x}:{:02x}.{}",
|
||||
self.segment(),
|
||||
self.bus(),
|
||||
self.device(),
|
||||
self.function()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for PciAddress {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self)
|
||||
}
|
||||
}
|
||||
|
||||
+3
-33
@@ -219,13 +219,9 @@ impl MsixCapability {
|
||||
self.a &= 0x0000_FFFF;
|
||||
self.a |= u32::from(message_control) << 16;
|
||||
}
|
||||
/// Returns the MSI-X table size, subtracted by one.
|
||||
pub const fn table_size_raw(&self) -> u16 {
|
||||
self.message_control() & Self::MC_TABLE_SIZE_MASK
|
||||
}
|
||||
/// Returns the MSI-X table size.
|
||||
pub const fn table_size(&self) -> u16 {
|
||||
self.table_size_raw() + 1
|
||||
(self.message_control() & Self::MC_TABLE_SIZE_MASK) + 1
|
||||
}
|
||||
/// Returns the MSI-X enabled bit, which enables MSI-X if the MSI enable bit is also set in the
|
||||
/// MSI capability structure.
|
||||
@@ -289,20 +285,7 @@ impl MsixCapability {
|
||||
if self.table_bir() > 5 {
|
||||
panic!("MSI-X Table BIR contained a reserved enum value: {}", self.table_bir());
|
||||
}
|
||||
let base = bars[usize::from(self.table_bir())];
|
||||
|
||||
//TODO: ensure type conversions are safe
|
||||
match base {
|
||||
PciBar::Memory32(ptr) => {
|
||||
ptr as usize + self.table_offset() as usize
|
||||
},
|
||||
PciBar::Memory64(ptr) => {
|
||||
ptr as usize + self.table_offset() as usize
|
||||
},
|
||||
_ => {
|
||||
panic!("MSI-X Table BIR referenced a non-memory BAR: {:?}", base);
|
||||
}
|
||||
}
|
||||
bars[usize::from(self.table_bir())].expect_mem().0 + self.table_offset() as usize
|
||||
}
|
||||
pub fn table_pointer(&self, bars: [PciBar; 6], k: u16) -> usize {
|
||||
self.table_base_pointer(bars) + k as usize * 16
|
||||
@@ -312,20 +295,7 @@ impl MsixCapability {
|
||||
if self.pba_bir() > 5 {
|
||||
panic!("MSI-X PBA BIR contained a reserved enum value: {}", self.pba_bir());
|
||||
}
|
||||
let base = bars[usize::from(self.pba_bir())];
|
||||
|
||||
//TODO: ensure type conversions are safe
|
||||
match base {
|
||||
PciBar::Memory32(ptr) => {
|
||||
ptr as usize + self.pba_offset() as usize
|
||||
},
|
||||
PciBar::Memory64(ptr) => {
|
||||
ptr as usize + self.pba_offset() as usize
|
||||
},
|
||||
_ => {
|
||||
panic!("MSI-X PBA BIR referenced a non-memory BAR: {:?}", base);
|
||||
}
|
||||
}
|
||||
bars[usize::from(self.pba_bir())].expect_mem().0 + self.pba_offset() as usize
|
||||
}
|
||||
pub fn pba_pointer_dword(&self, bars: [PciBar; 6], k: u16) -> usize {
|
||||
self.pba_base_pointer(bars) + (k as usize / 32) * 4
|
||||
|
||||
@@ -0,0 +1,310 @@
|
||||
use std::convert::TryInto;
|
||||
|
||||
use pci_types::{
|
||||
Bar as TyBar, ConfigRegionAccess, EndpointHeader, HeaderType, PciAddress,
|
||||
PciHeader as TyPciHeader, PciPciBridgeHeader,
|
||||
};
|
||||
|
||||
use crate::pci::{FullDeviceId, PciBar};
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum PciHeaderError {
|
||||
NoDevice,
|
||||
UnknownHeaderType(HeaderType),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct SharedPciHeader {
|
||||
full_device_id: FullDeviceId,
|
||||
command: u16,
|
||||
status: u16,
|
||||
addr: PciAddress,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub enum PciHeader {
|
||||
General {
|
||||
shared: SharedPciHeader,
|
||||
subsystem_vendor_id: u16,
|
||||
subsystem_id: u16,
|
||||
cap_pointer: u8,
|
||||
},
|
||||
PciToPci {
|
||||
shared: SharedPciHeader,
|
||||
secondary_bus_num: u8,
|
||||
cap_pointer: u8,
|
||||
},
|
||||
}
|
||||
|
||||
impl PciHeader {
|
||||
/// Parse the bytes found in the Configuration Space of the PCI device into
|
||||
/// a more usable PciHeader.
|
||||
pub fn from_reader(
|
||||
access: &impl ConfigRegionAccess,
|
||||
addr: PciAddress,
|
||||
) -> Result<PciHeader, PciHeaderError> {
|
||||
if unsafe { access.read(addr, 0) } == 0xffffffff {
|
||||
return Err(PciHeaderError::NoDevice);
|
||||
}
|
||||
|
||||
let header = TyPciHeader::new(addr);
|
||||
let (vendor_id, device_id) = header.id(access);
|
||||
let command_and_status = unsafe { access.read(addr, 4) };
|
||||
let command = (command_and_status & 0xffff) as u16;
|
||||
let status = (command_and_status >> 16) as u16;
|
||||
let (revision, class, subclass, interface) = header.revision_and_class(access);
|
||||
let header_type = header.header_type(access);
|
||||
let shared = SharedPciHeader {
|
||||
full_device_id: FullDeviceId {
|
||||
vendor_id,
|
||||
device_id,
|
||||
class,
|
||||
subclass,
|
||||
interface,
|
||||
revision,
|
||||
},
|
||||
command,
|
||||
status,
|
||||
addr,
|
||||
};
|
||||
|
||||
match header_type {
|
||||
HeaderType::Endpoint => {
|
||||
let endpoint_header = EndpointHeader::from_header(header, access).unwrap();
|
||||
let (subsystem_id, subsystem_vendor_id) = endpoint_header.subsystem(access);
|
||||
let cap_pointer = (unsafe { access.read(addr, 0x34) } & 0xff) as u8;
|
||||
Ok(PciHeader::General {
|
||||
shared,
|
||||
subsystem_vendor_id,
|
||||
subsystem_id,
|
||||
cap_pointer,
|
||||
})
|
||||
}
|
||||
HeaderType::PciPciBridge => {
|
||||
let bridge_header = PciPciBridgeHeader::from_header(header, access).unwrap();
|
||||
let secondary_bus_num = bridge_header.secondary_bus_number(access);
|
||||
let cap_pointer = (unsafe { access.read(addr, 0x34) } & 0xff) as u8;
|
||||
Ok(PciHeader::PciToPci {
|
||||
shared,
|
||||
secondary_bus_num,
|
||||
cap_pointer,
|
||||
})
|
||||
}
|
||||
ty => Err(PciHeaderError::UnknownHeaderType(ty)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Return all identifying information of the PCI function.
|
||||
pub fn full_device_id(&self) -> &FullDeviceId {
|
||||
match self {
|
||||
PciHeader::General {
|
||||
shared:
|
||||
SharedPciHeader {
|
||||
full_device_id: device_id,
|
||||
..
|
||||
},
|
||||
..
|
||||
}
|
||||
| PciHeader::PciToPci {
|
||||
shared:
|
||||
SharedPciHeader {
|
||||
full_device_id: device_id,
|
||||
..
|
||||
},
|
||||
..
|
||||
} => device_id,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the Vendor ID field.
|
||||
pub fn vendor_id(&self) -> u16 {
|
||||
self.full_device_id().vendor_id
|
||||
}
|
||||
|
||||
/// Return the Device ID field.
|
||||
pub fn device_id(&self) -> u16 {
|
||||
self.full_device_id().device_id
|
||||
}
|
||||
|
||||
/// Return the Revision field.
|
||||
pub fn revision(&self) -> u8 {
|
||||
self.full_device_id().revision
|
||||
}
|
||||
|
||||
/// Return the Interface field.
|
||||
pub fn interface(&self) -> u8 {
|
||||
self.full_device_id().interface
|
||||
}
|
||||
|
||||
/// Return the Subclass field.
|
||||
pub fn subclass(&self) -> u8 {
|
||||
self.full_device_id().subclass
|
||||
}
|
||||
|
||||
/// Return the Class field.
|
||||
pub fn class(&self) -> u8 {
|
||||
self.full_device_id().class
|
||||
}
|
||||
|
||||
/// Return the Headers BARs.
|
||||
// FIXME use pci_types::Bar instead
|
||||
pub fn bars(&self, access: &impl ConfigRegionAccess) -> [PciBar; 6] {
|
||||
let endpoint_header = match *self {
|
||||
PciHeader::General {
|
||||
shared: SharedPciHeader { addr, .. },
|
||||
..
|
||||
} => EndpointHeader::from_header(TyPciHeader::new(addr), access).unwrap(),
|
||||
PciHeader::PciToPci { .. } => unreachable!(),
|
||||
};
|
||||
|
||||
let mut bars = [PciBar::None; 6];
|
||||
let mut skip = false;
|
||||
for i in 0..6 {
|
||||
if skip {
|
||||
skip = false;
|
||||
continue;
|
||||
}
|
||||
match endpoint_header.bar(i, access) {
|
||||
Some(TyBar::Io { port }) => {
|
||||
bars[i as usize] = PciBar::Port(port.try_into().unwrap())
|
||||
}
|
||||
Some(TyBar::Memory32 {
|
||||
address,
|
||||
size,
|
||||
prefetchable: _,
|
||||
}) => {
|
||||
bars[i as usize] = PciBar::Memory32 {
|
||||
addr: address,
|
||||
size,
|
||||
}
|
||||
}
|
||||
Some(TyBar::Memory64 {
|
||||
address,
|
||||
size,
|
||||
prefetchable: _,
|
||||
}) => {
|
||||
bars[i as usize] = PciBar::Memory64 {
|
||||
addr: address,
|
||||
size,
|
||||
};
|
||||
skip = true; // Each 64bit memory BAR occupies two slots
|
||||
}
|
||||
None => bars[i as usize] = PciBar::None,
|
||||
}
|
||||
}
|
||||
bars
|
||||
}
|
||||
|
||||
pub fn status(&self) -> u16 {
|
||||
match self {
|
||||
&PciHeader::General {
|
||||
shared: SharedPciHeader { status, .. },
|
||||
..
|
||||
}
|
||||
| &PciHeader::PciToPci {
|
||||
shared: SharedPciHeader { status, .. },
|
||||
..
|
||||
} => status,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cap_pointer(&self) -> u8 {
|
||||
match self {
|
||||
&PciHeader::General { cap_pointer, .. } | &PciHeader::PciToPci { cap_pointer, .. } => {
|
||||
cap_pointer
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::convert::TryInto;
|
||||
|
||||
use pci_types::device_type::DeviceType;
|
||||
use pci_types::{ConfigRegionAccess, PciAddress};
|
||||
|
||||
use super::{PciHeader, PciHeaderError};
|
||||
|
||||
struct TestCfgAccess<'a> {
|
||||
addr: PciAddress,
|
||||
bytes: &'a [u8],
|
||||
}
|
||||
|
||||
impl ConfigRegionAccess for TestCfgAccess<'_> {
|
||||
fn function_exists(&self, _address: PciAddress) -> bool {
|
||||
unreachable!();
|
||||
}
|
||||
|
||||
unsafe fn read(&self, addr: PciAddress, offset: u16) -> u32 {
|
||||
assert_eq!(addr, self.addr);
|
||||
let offset = offset as usize;
|
||||
assert!(offset < self.bytes.len());
|
||||
u32::from_le_bytes(self.bytes[offset..offset + 4].try_into().unwrap())
|
||||
}
|
||||
|
||||
unsafe fn write(&self, _addr: PciAddress, _offset: u16, _value: u32) {
|
||||
unreachable!("should not write during tests");
|
||||
}
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
const IGB_DEV_BYTES: [u8; 256] = [
|
||||
0x86, 0x80, 0x33, 0x15, 0x07, 0x04, 0x10, 0x00, 0x03, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x50, 0xf7, 0x00, 0x00, 0x00, 0x00, 0x01, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x58, 0xf7,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd9, 0x15, 0x33, 0x15,
|
||||
0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00,
|
||||
0x01, 0x50, 0x23, 0xc8, 0x08, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x05, 0x70, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x11, 0xa0, 0x04, 0x80, 0x03, 0x00, 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
|
||||
0x10, 0x00, 0x02, 0x00, 0xc2, 0x8c, 0x00, 0x10, 0x0f, 0x28, 0x19, 0x00, 0x11, 0x5c, 0x42, 0x00,
|
||||
0x42, 0x00, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
];
|
||||
|
||||
#[test]
|
||||
fn tset_parse_igb_dev() {
|
||||
let header = PciHeader::from_reader(
|
||||
&TestCfgAccess {
|
||||
addr: PciAddress::new(0, 2, 4, 0),
|
||||
bytes: &IGB_DEV_BYTES,
|
||||
},
|
||||
PciAddress::new(0, 2, 4, 0),
|
||||
)
|
||||
.unwrap();
|
||||
match header {
|
||||
PciHeader::General { .. } => {}
|
||||
_ => panic!("wrong header type"),
|
||||
}
|
||||
assert_eq!(header.device_id(), 0x1533);
|
||||
assert_eq!(header.vendor_id(), 0x8086);
|
||||
assert_eq!(header.revision(), 3);
|
||||
assert_eq!(header.interface(), 0);
|
||||
assert_eq!(
|
||||
DeviceType::from((header.class(), header.subclass())),
|
||||
DeviceType::EthernetController
|
||||
);
|
||||
assert_eq!(header.subclass(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_nonexistent() {
|
||||
let bytes = &[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff];
|
||||
assert_eq!(
|
||||
PciHeader::from_reader(
|
||||
&TestCfgAccess {
|
||||
addr: PciAddress::new(0, 2, 4, 0),
|
||||
bytes,
|
||||
},
|
||||
PciAddress::new(0, 2, 4, 0),
|
||||
),
|
||||
Err(PciHeaderError::NoDevice)
|
||||
);
|
||||
}
|
||||
}
|
||||
+14
-33
@@ -171,36 +171,23 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> Option<File> {
|
||||
let pba_base = capability.pba_base_pointer(pci_config.func.bars);
|
||||
|
||||
let bir = capability.table_bir() as usize;
|
||||
let bar = pci_config.func.bars[bir];
|
||||
let bar_size = pci_config.func.bar_sizes[bir] as u64;
|
||||
|
||||
let bar_ptr = match bar {
|
||||
pcid_interface::PciBar::Memory32(ptr) => match ptr {
|
||||
0 => panic!("BAR {} is mapped to address 0", bir),
|
||||
_ => ptr as u64,
|
||||
},
|
||||
pcid_interface::PciBar::Memory64(ptr) => match ptr {
|
||||
0 => panic!("BAR {} is mapped to address 0", bir),
|
||||
_ => ptr,
|
||||
},
|
||||
other => panic!("Expected memory bar, found {:?}", other),
|
||||
};
|
||||
let (bar_ptr, bar_size) = pci_config.func.bars[bir].expect_mem();
|
||||
|
||||
let address = unsafe {
|
||||
common::physmap(bar_ptr as usize, bar_size as usize, common::Prot::RW, common::MemoryType::Uncacheable)
|
||||
common::physmap(bar_ptr, bar_size, common::Prot::RW, common::MemoryType::Uncacheable)
|
||||
.expect("rtl8139d: failed to map address") as usize
|
||||
};
|
||||
|
||||
if !(bar_ptr..bar_ptr + bar_size).contains(&(table_base as u64 + table_min_length as u64)) {
|
||||
if !(bar_ptr as u64..bar_ptr as u64 + bar_size as u64).contains(&(table_base as u64 + table_min_length as u64)) {
|
||||
panic!("Table {:#x}{:#x} outside of BAR {:#x}:{:#x}", table_base, table_base + table_min_length as usize, bar_ptr, bar_ptr + bar_size);
|
||||
}
|
||||
|
||||
if !(bar_ptr..bar_ptr + bar_size).contains(&(pba_base as u64 + pba_min_length as u64)) {
|
||||
if !(bar_ptr as u64..bar_ptr as u64 + bar_size as u64).contains(&(pba_base as u64 + pba_min_length as u64)) {
|
||||
panic!("PBA {:#x}{:#x} outside of BAR {:#x}:{:#X}", pba_base, pba_base + pba_min_length as usize, bar_ptr, bar_ptr + bar_size);
|
||||
}
|
||||
|
||||
let virt_table_base = ((table_base - bar_ptr as usize) + address) as *mut MsixTableEntry;
|
||||
let virt_pba_base = ((pba_base - bar_ptr as usize) + address) as *mut u64;
|
||||
let virt_table_base = ((table_base - bar_ptr) + address) as *mut MsixTableEntry;
|
||||
let virt_pba_base = ((pba_base - bar_ptr) + address) as *mut u64;
|
||||
|
||||
let mut info = MsixInfo {
|
||||
virt_table_base: NonNull::new(virt_table_base).unwrap(),
|
||||
@@ -311,20 +298,14 @@ fn find_bar(pci_config: &SubdriverArguments) -> Option<(usize, usize)> {
|
||||
// RTL8139 uses BAR2, RTL8169 uses BAR1, search in that order
|
||||
for &barnum in &[2, 1] {
|
||||
match pci_config.func.bars[barnum] {
|
||||
pcid_interface::PciBar::Memory32(ptr) => match ptr {
|
||||
0 => log::warn!("BAR {} is mapped to address 0", barnum),
|
||||
_ => return Some((
|
||||
ptr.try_into().unwrap(),
|
||||
pci_config.func.bar_sizes[barnum].try_into().unwrap()
|
||||
)),
|
||||
},
|
||||
pcid_interface::PciBar::Memory64(ptr) => match ptr {
|
||||
0 => log::warn!("BAR {} is mapped to address 0", barnum),
|
||||
_ => return Some((
|
||||
ptr.try_into().unwrap(),
|
||||
pci_config.func.bar_sizes[barnum].try_into().unwrap()
|
||||
)),
|
||||
},
|
||||
pcid_interface::PciBar::Memory32 { addr, size } => return Some((
|
||||
addr.try_into().unwrap(),
|
||||
size.try_into().unwrap()
|
||||
)),
|
||||
pcid_interface::PciBar::Memory64 { addr, size } => return Some((
|
||||
addr.try_into().unwrap(),
|
||||
size.try_into().unwrap()
|
||||
)),
|
||||
other => log::warn!("BAR {} is {:?} instead of memory BAR", barnum, other),
|
||||
}
|
||||
}
|
||||
|
||||
+14
-33
@@ -169,36 +169,23 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> Option<File> {
|
||||
let pba_base = capability.pba_base_pointer(pci_config.func.bars);
|
||||
|
||||
let bir = capability.table_bir() as usize;
|
||||
let bar = pci_config.func.bars[bir];
|
||||
let bar_size = pci_config.func.bar_sizes[bir] as u64;
|
||||
|
||||
let bar_ptr = match bar {
|
||||
pcid_interface::PciBar::Memory32(ptr) => match ptr {
|
||||
0 => panic!("BAR {} is mapped to address 0", bir),
|
||||
_ => ptr as u64,
|
||||
},
|
||||
pcid_interface::PciBar::Memory64(ptr) => match ptr {
|
||||
0 => panic!("BAR {} is mapped to address 0", bir),
|
||||
_ => ptr,
|
||||
},
|
||||
other => panic!("Expected memory bar, found {:?}", other),
|
||||
};
|
||||
let (bar_ptr, bar_size) = pci_config.func.bars[bir].expect_mem();
|
||||
|
||||
let address = unsafe {
|
||||
common::physmap(bar_ptr as usize, bar_size as usize, common::Prot::RW, common::MemoryType::Uncacheable)
|
||||
common::physmap(bar_ptr, bar_size, common::Prot::RW, common::MemoryType::Uncacheable)
|
||||
.expect("rtl8168d: failed to map address") as usize
|
||||
};
|
||||
|
||||
if !(bar_ptr..bar_ptr + bar_size).contains(&(table_base as u64 + table_min_length as u64)) {
|
||||
if !(bar_ptr as u64..bar_ptr as u64 + bar_size as u64).contains(&(table_base as u64 + table_min_length as u64)) {
|
||||
panic!("Table {:#x}{:#x} outside of BAR {:#x}:{:#x}", table_base, table_base + table_min_length as usize, bar_ptr, bar_ptr + bar_size);
|
||||
}
|
||||
|
||||
if !(bar_ptr..bar_ptr + bar_size).contains(&(pba_base as u64 + pba_min_length as u64)) {
|
||||
if !(bar_ptr as u64..bar_ptr as u64 + bar_size as u64).contains(&(pba_base as u64 + pba_min_length as u64)) {
|
||||
panic!("PBA {:#x}{:#x} outside of BAR {:#x}:{:#X}", pba_base, pba_base + pba_min_length as usize, bar_ptr, bar_ptr + bar_size);
|
||||
}
|
||||
|
||||
let virt_table_base = ((table_base - bar_ptr as usize) + address) as *mut MsixTableEntry;
|
||||
let virt_pba_base = ((pba_base - bar_ptr as usize) + address) as *mut u64;
|
||||
let virt_table_base = ((table_base - bar_ptr) + address) as *mut MsixTableEntry;
|
||||
let virt_pba_base = ((pba_base - bar_ptr) + address) as *mut u64;
|
||||
|
||||
let mut info = MsixInfo {
|
||||
virt_table_base: NonNull::new(virt_table_base).unwrap(),
|
||||
@@ -309,20 +296,14 @@ fn find_bar(pci_config: &SubdriverArguments) -> Option<(usize, usize)> {
|
||||
// RTL8168 uses BAR2, RTL8169 uses BAR1, search in that order
|
||||
for &barnum in &[2, 1] {
|
||||
match pci_config.func.bars[barnum] {
|
||||
pcid_interface::PciBar::Memory32(ptr) => match ptr {
|
||||
0 => log::warn!("BAR {} is mapped to address 0", barnum),
|
||||
_ => return Some((
|
||||
ptr.try_into().unwrap(),
|
||||
pci_config.func.bar_sizes[barnum].try_into().unwrap()
|
||||
)),
|
||||
},
|
||||
pcid_interface::PciBar::Memory64(ptr) => match ptr {
|
||||
0 => log::warn!("BAR {} is mapped to address 0", barnum),
|
||||
_ => return Some((
|
||||
ptr.try_into().unwrap(),
|
||||
pci_config.func.bar_sizes[barnum].try_into().unwrap()
|
||||
)),
|
||||
},
|
||||
pcid_interface::PciBar::Memory32 { addr, size } => return Some((
|
||||
addr.try_into().unwrap(),
|
||||
size.try_into().unwrap()
|
||||
)),
|
||||
pcid_interface::PciBar::Memory64 { addr, size } => return Some((
|
||||
addr.try_into().unwrap(),
|
||||
size.try_into().unwrap()
|
||||
)),
|
||||
other => log::warn!("BAR {} is {:?} instead of memory BAR", barnum, other),
|
||||
}
|
||||
}
|
||||
|
||||
+2
-9
@@ -194,16 +194,9 @@ fn main() {
|
||||
let mut name = pci_config.func.name();
|
||||
name.push_str("_vbox");
|
||||
|
||||
let bar0 = match pci_config.func.bars[0] {
|
||||
PciBar::Port(port) => port,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let bar0 = pci_config.func.bars[0].expect_port();
|
||||
|
||||
let bar1 = match pci_config.func.bars[1] {
|
||||
PciBar::Memory32(addr) => addr as usize,
|
||||
PciBar::Memory64(addr) => addr as usize,
|
||||
PciBar::None | PciBar::Port(_) => unreachable!(),
|
||||
};
|
||||
let (bar1, _) = pci_config.func.bars[1].expect_mem();
|
||||
|
||||
let irq = pci_config.func.legacy_interrupt_line;
|
||||
|
||||
|
||||
+21
-23
@@ -11,33 +11,31 @@ pub fn probe_legacy_port_transport(
|
||||
pci_header: &PciHeader,
|
||||
pcid_handle: &mut PcidServerHandle,
|
||||
) -> Result<Device, Error> {
|
||||
if let PciBar::Port(port) = pci_header.get_bar(0) {
|
||||
unsafe { syscall::iopl(3).expect("virtio: failed to set I/O privilege level") };
|
||||
log::warn!("virtio: using legacy transport");
|
||||
let port = pci_header.get_bar(0).expect_port();
|
||||
|
||||
let transport = LegacyTransport::new(port);
|
||||
unsafe { syscall::iopl(3).expect("virtio: failed to set I/O privilege level") };
|
||||
log::warn!("virtio: using legacy transport");
|
||||
|
||||
// Setup interrupts.
|
||||
let all_pci_features = pcid_handle.fetch_all_features()?;
|
||||
let has_msix = all_pci_features
|
||||
.iter()
|
||||
.any(|(feature, _)| feature.is_msix());
|
||||
let transport = LegacyTransport::new(port);
|
||||
|
||||
// According to the virtio specification, the device REQUIRED to support MSI-X.
|
||||
assert!(has_msix, "virtio: device does not support MSI-X");
|
||||
let irq_handle = enable_msix(pcid_handle)?;
|
||||
// Setup interrupts.
|
||||
let all_pci_features = pcid_handle.fetch_all_features()?;
|
||||
let has_msix = all_pci_features
|
||||
.iter()
|
||||
.any(|(feature, _)| feature.is_msix());
|
||||
|
||||
let device = Device {
|
||||
transport,
|
||||
irq_handle,
|
||||
device_space: core::ptr::null_mut(),
|
||||
};
|
||||
// According to the virtio specification, the device REQUIRED to support MSI-X.
|
||||
assert!(has_msix, "virtio: device does not support MSI-X");
|
||||
let irq_handle = enable_msix(pcid_handle)?;
|
||||
|
||||
device.transport.reset();
|
||||
reinit(&device)?;
|
||||
let device = Device {
|
||||
transport,
|
||||
irq_handle,
|
||||
device_space: core::ptr::null_mut(),
|
||||
};
|
||||
|
||||
Ok(device)
|
||||
} else {
|
||||
unreachable!("virtio: legacy transport with non-port IO?")
|
||||
}
|
||||
device.transport.reset();
|
||||
reinit(&device)?;
|
||||
|
||||
Ok(device)
|
||||
}
|
||||
|
||||
@@ -27,19 +27,12 @@ pub fn enable_msix(pcid_handle: &mut PcidServerHandle) -> Result<File, Error> {
|
||||
let pba_base = capability.pba_base_pointer(pci_config.func.bars);
|
||||
|
||||
let bir = capability.table_bir() as usize;
|
||||
let bar = pci_config.func.bars[bir];
|
||||
let bar_size = pci_config.func.bar_sizes[bir] as u64;
|
||||
|
||||
let bar_ptr = match bar {
|
||||
PciBar::Memory32(ptr) => ptr.into(),
|
||||
PciBar::Memory64(ptr) => ptr,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let (bar_ptr, bar_size) = pci_config.func.bars[bir].expect_mem();
|
||||
|
||||
let address = unsafe {
|
||||
common::physmap(
|
||||
bar_ptr as usize,
|
||||
bar_size as usize,
|
||||
bar_ptr,
|
||||
bar_size,
|
||||
common::Prot::RW,
|
||||
common::MemoryType::Uncacheable,
|
||||
)? as usize
|
||||
@@ -47,7 +40,7 @@ pub fn enable_msix(pcid_handle: &mut PcidServerHandle) -> Result<File, Error> {
|
||||
|
||||
// Ensure that the table and PBA are be within the BAR.
|
||||
{
|
||||
let bar_range = bar_ptr..bar_ptr + bar_size;
|
||||
let bar_range = bar_ptr as u64..bar_ptr as u64 + bar_size as u64;
|
||||
assert!(bar_range.contains(&(table_base as u64 + table_min_length as u64)));
|
||||
assert!(bar_range.contains(&(pba_base as u64 + pba_min_length as u64)));
|
||||
}
|
||||
@@ -99,33 +92,31 @@ pub fn probe_legacy_port_transport(
|
||||
pci_config: &SubdriverArguments,
|
||||
pcid_handle: &mut PcidServerHandle,
|
||||
) -> Result<Device, Error> {
|
||||
if let PciBar::Port(port) = pci_config.func.bars[0] {
|
||||
unsafe { syscall::iopl(3).expect("virtio: failed to set I/O privilege level") };
|
||||
log::warn!("virtio: using legacy transport");
|
||||
let port = pci_config.func.bars[0].expect_port();
|
||||
|
||||
let transport = LegacyTransport::new(port);
|
||||
unsafe { syscall::iopl(3).expect("virtio: failed to set I/O privilege level") };
|
||||
log::warn!("virtio: using legacy transport");
|
||||
|
||||
// Setup interrupts.
|
||||
let all_pci_features = pcid_handle.fetch_all_features()?;
|
||||
let has_msix = all_pci_features
|
||||
.iter()
|
||||
.any(|(feature, _)| feature.is_msix());
|
||||
let transport = LegacyTransport::new(port);
|
||||
|
||||
// According to the virtio specification, the device REQUIRED to support MSI-X.
|
||||
assert!(has_msix, "virtio: device does not support MSI-X");
|
||||
let irq_handle = enable_msix(pcid_handle)?;
|
||||
// Setup interrupts.
|
||||
let all_pci_features = pcid_handle.fetch_all_features()?;
|
||||
let has_msix = all_pci_features
|
||||
.iter()
|
||||
.any(|(feature, _)| feature.is_msix());
|
||||
|
||||
let device = Device {
|
||||
transport,
|
||||
irq_handle,
|
||||
device_space: core::ptr::null_mut(),
|
||||
};
|
||||
// According to the virtio specification, the device REQUIRED to support MSI-X.
|
||||
assert!(has_msix, "virtio: device does not support MSI-X");
|
||||
let irq_handle = enable_msix(pcid_handle)?;
|
||||
|
||||
device.transport.reset();
|
||||
reinit(&device)?;
|
||||
let device = Device {
|
||||
transport,
|
||||
irq_handle,
|
||||
device_space: core::ptr::null_mut(),
|
||||
};
|
||||
|
||||
Ok(device)
|
||||
} else {
|
||||
unreachable!("virtio: legacy transport with non-port IO?")
|
||||
}
|
||||
device.transport.reset();
|
||||
reinit(&device)?;
|
||||
|
||||
Ok(device)
|
||||
}
|
||||
|
||||
@@ -90,13 +90,7 @@ pub fn probe_device(pcid_handle: &mut PcidServerHandle) -> Result<Device, Error>
|
||||
_ => continue,
|
||||
}
|
||||
|
||||
let bar = pci_config.func.bars[capability.bar as usize];
|
||||
let addr = match bar {
|
||||
PciBar::Memory32(addr) => addr as usize,
|
||||
PciBar::Memory64(addr) => addr as usize,
|
||||
|
||||
_ => unreachable!("virtio: unsupported bar type: {bar:?}"),
|
||||
};
|
||||
let (addr, _) = pci_config.func.bars[capability.bar as usize].expect_mem();
|
||||
|
||||
let address = unsafe {
|
||||
let addr = addr + capability.offset as usize;
|
||||
|
||||
+5
-31
@@ -85,22 +85,9 @@ fn setup_logging(name: &str) -> Option<&'static RedoxLogger> {
|
||||
fn get_int_method(pcid_handle: &mut PcidServerHandle, address: usize) -> (Option<File>, InterruptMethod) {
|
||||
let pci_config = pcid_handle.fetch_config().expect("xhcid: failed to fetch config");
|
||||
|
||||
let bar = pci_config.func.bars[0];
|
||||
let bar_size = pci_config.func.bar_sizes[0] as u64;
|
||||
let (bar_ptr, bar_size) = pci_config.func.bars[0].expect_mem();
|
||||
let irq = pci_config.func.legacy_interrupt_line;
|
||||
|
||||
let bar_ptr = match bar {
|
||||
pcid_interface::PciBar::Memory32(ptr) => match ptr {
|
||||
0 => panic!("BAR 0 is mapped to address 0"),
|
||||
_ => ptr as u64,
|
||||
},
|
||||
pcid_interface::PciBar::Memory64(ptr) => match ptr {
|
||||
0 => panic!("BAR 0 is mapped to address 0"),
|
||||
_ => ptr,
|
||||
},
|
||||
other => panic!("Expected memory bar, found {:?}", other),
|
||||
};
|
||||
|
||||
let all_pci_features = pcid_handle.fetch_all_features().expect("xhcid: failed to fetch pci features");
|
||||
log::debug!("XHCI PCI FEATURES: {:?}", all_pci_features);
|
||||
|
||||
@@ -158,11 +145,11 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle, address: usize) -> (Option
|
||||
|
||||
let pba_base = capability.pba_base_pointer(pci_config.func.bars);
|
||||
|
||||
if !(bar_ptr..bar_ptr + bar_size).contains(&(table_base as u64 + table_min_length as u64)) {
|
||||
if !(bar_ptr as u64..bar_ptr as u64 + bar_size as u64).contains(&(table_base as u64 + table_min_length as u64)) {
|
||||
panic!("Table {:#x}{:#x} outside of BAR {:#x}:{:#x}", table_base, table_base + table_min_length as usize, bar_ptr, bar_ptr + bar_size);
|
||||
}
|
||||
|
||||
if !(bar_ptr..bar_ptr + bar_size).contains(&(pba_base as u64 + pba_min_length as u64)) {
|
||||
if !(bar_ptr as u64..bar_ptr as u64 + bar_size as u64).contains(&(pba_base as u64 + pba_min_length as u64)) {
|
||||
panic!("PBA {:#x}{:#x} outside of BAR {:#x}:{:#X}", pba_base, pba_base + pba_min_length as usize, bar_ptr, bar_ptr + bar_size);
|
||||
}
|
||||
|
||||
@@ -247,24 +234,11 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! {
|
||||
let _logger_ref = setup_logging(&name);
|
||||
|
||||
log::debug!("XHCI PCI CONFIG: {:?}", pci_config);
|
||||
let bar = pci_config.func.bars[0];
|
||||
let bar_size = pci_config.func.bar_sizes[0];
|
||||
let (bar_ptr, bar_size) = pci_config.func.bars[0].expect_mem();
|
||||
let irq = pci_config.func.legacy_interrupt_line;
|
||||
|
||||
let bar_ptr = match bar {
|
||||
pcid_interface::PciBar::Memory32(ptr) => match ptr {
|
||||
0 => panic!("BAR 0 is mapped to address 0"),
|
||||
_ => ptr as u64,
|
||||
},
|
||||
pcid_interface::PciBar::Memory64(ptr) => match ptr {
|
||||
0 => panic!("BAR 0 is mapped to address 0"),
|
||||
_ => ptr,
|
||||
},
|
||||
other => panic!("Expected memory bar, found {:?}", other),
|
||||
};
|
||||
|
||||
let address = unsafe {
|
||||
common::physmap(bar_ptr as usize, bar_size as usize, common::Prot::RW, common::MemoryType::Uncacheable)
|
||||
common::physmap(bar_ptr, bar_size, common::Prot::RW, common::MemoryType::Uncacheable)
|
||||
.expect("xhcid: failed to map address") as usize
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user