x86-64: add PCIe enumeration and general PCI support
This commit is contained in:
parent
3b89f444ff
commit
309c5c3e9f
@ -42,6 +42,8 @@ yboot-proto = { git = "https://git.alnyan.me/yggdrasil/yboot-proto.git" }
|
|||||||
aml = { git = "https://github.com/alnyan/acpi.git", version = "0.16.4" }
|
aml = { git = "https://github.com/alnyan/acpi.git", version = "0.16.4" }
|
||||||
acpi_lib = { git = "https://github.com/alnyan/acpi.git", version = "4.1.1", package = "acpi" }
|
acpi_lib = { git = "https://github.com/alnyan/acpi.git", version = "4.1.1", package = "acpi" }
|
||||||
acpi-system = { git = "https://github.com/alnyan/acpi-system.git", version = "0.1.0" }
|
acpi-system = { git = "https://github.com/alnyan/acpi-system.git", version = "0.1.0" }
|
||||||
|
# TODO currently only supported here
|
||||||
|
xhci_lib = { git = "https://github.com/rust-osdev/xhci.git", package = "xhci" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
use core::{ptr::NonNull, sync::atomic::Ordering};
|
use core::{ptr::NonNull, sync::atomic::Ordering};
|
||||||
|
|
||||||
use abi::error::Error;
|
use abi::error::Error;
|
||||||
use acpi_lib::{AcpiHandler, AcpiTables, HpetInfo, InterruptModel, PhysicalMapping};
|
use acpi_lib::{mcfg::Mcfg, AcpiHandler, AcpiTables, HpetInfo, InterruptModel, PhysicalMapping};
|
||||||
use alloc::boxed::Box;
|
use alloc::boxed::Box;
|
||||||
use cpu::Cpu;
|
use cpu::Cpu;
|
||||||
use device_api::{
|
use device_api::{
|
||||||
@ -24,6 +24,7 @@ use crate::{
|
|||||||
debug::{self, LogLevel},
|
debug::{self, LogLevel},
|
||||||
device::{
|
device::{
|
||||||
self,
|
self,
|
||||||
|
bus::pci::PciBusManager,
|
||||||
display::{console, fb_console::FramebufferConsole, linear_fb::LinearFramebuffer},
|
display::{console, fb_console::FramebufferConsole, linear_fb::LinearFramebuffer},
|
||||||
tty::combined::CombinedTerminal,
|
tty::combined::CombinedTerminal,
|
||||||
},
|
},
|
||||||
@ -392,6 +393,14 @@ impl X86_64 {
|
|||||||
self.timer.init(Hpet::from_acpi(&hpet).unwrap());
|
self.timer.init(Hpet::from_acpi(&hpet).unwrap());
|
||||||
|
|
||||||
acpi::init_acpi(acpi).unwrap();
|
acpi::init_acpi(acpi).unwrap();
|
||||||
|
|
||||||
|
// Enumerate PCIe root devices
|
||||||
|
// TODO can there be multiple MCFGs?
|
||||||
|
if let Ok(mcfg) = acpi.find_table::<Mcfg>() {
|
||||||
|
for entry in mcfg.entries() {
|
||||||
|
PciBusManager::add_segment_from_mcfg(entry).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn init_framebuffer(&'static self) {
|
unsafe fn init_framebuffer(&'static self) {
|
||||||
@ -469,6 +478,9 @@ impl X86_64 {
|
|||||||
device::register_device(self.timer.get());
|
device::register_device(self.timer.get());
|
||||||
device::register_device(ps2);
|
device::register_device(ps2);
|
||||||
|
|
||||||
|
// Initialize devices from PCI bus
|
||||||
|
PciBusManager::setup_bus_devices().unwrap();
|
||||||
|
|
||||||
infoln!("Device list:");
|
infoln!("Device list:");
|
||||||
for device in device::manager_lock().devices() {
|
for device in device::manager_lock().devices() {
|
||||||
infoln!("* {}", device.display_name());
|
infoln!("* {}", device.display_name());
|
||||||
|
@ -72,6 +72,28 @@ impl FixedTables {
|
|||||||
Ok(virt)
|
Ok(virt)
|
||||||
} else {
|
} else {
|
||||||
// 4KiB mappings
|
// 4KiB mappings
|
||||||
|
// Check if a mapping to that address already exists
|
||||||
|
if self.device_l3i >= count {
|
||||||
|
for i in 0..self.device_l3i {
|
||||||
|
let mut matches = true;
|
||||||
|
|
||||||
|
for j in 0..count {
|
||||||
|
let page = phys + j * 0x1000;
|
||||||
|
let existing = self.device_l3[i].as_page().unwrap();
|
||||||
|
|
||||||
|
if page != existing {
|
||||||
|
matches = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if matches {
|
||||||
|
let virt = DEVICE_VIRT_OFFSET + (i << 12);
|
||||||
|
return Ok(virt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if self.device_l3i + count > 512 {
|
if self.device_l3i + count > 512 {
|
||||||
return Err(Error::OutOfMemory);
|
return Err(Error::OutOfMemory);
|
||||||
}
|
}
|
||||||
|
@ -2,3 +2,5 @@
|
|||||||
|
|
||||||
#[cfg(feature = "device-tree")]
|
#[cfg(feature = "device-tree")]
|
||||||
pub mod simple_bus;
|
pub mod simple_bus;
|
||||||
|
|
||||||
|
pub mod pci;
|
||||||
|
238
src/device/bus/pci/mod.rs
Normal file
238
src/device/bus/pci/mod.rs
Normal file
@ -0,0 +1,238 @@
|
|||||||
|
use core::fmt;
|
||||||
|
|
||||||
|
use acpi_lib::mcfg::McfgEntry;
|
||||||
|
use alloc::{rc::Rc, vec::Vec};
|
||||||
|
use device_api::Device;
|
||||||
|
use yggdrasil_abi::error::Error;
|
||||||
|
|
||||||
|
mod space;
|
||||||
|
|
||||||
|
pub use space::{
|
||||||
|
ecam::PciEcam, PciConfigSpace, PciConfigurationSpace, PciLegacyConfigurationSpace,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::sync::IrqSafeSpinlock;
|
||||||
|
|
||||||
|
pub const PCI_COMMAND_IO: u16 = 1 << 0;
|
||||||
|
pub const PCI_COMMAND_MEMORY: u16 = 1 << 1;
|
||||||
|
pub const PCI_COMMAND_BUS_MASTER: u16 = 1 << 2;
|
||||||
|
pub const PCI_COMMAND_INTERRUPT_DISABLE: u16 = 1 << 10;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
||||||
|
pub struct PciAddress {
|
||||||
|
pub segment: u8,
|
||||||
|
pub bus: u8,
|
||||||
|
pub device: u8,
|
||||||
|
pub function: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO other attributes
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum PciBaseAddress {
|
||||||
|
Memory(usize),
|
||||||
|
Io(u16),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct PciDeviceInfo {
|
||||||
|
pub address: PciAddress,
|
||||||
|
pub config_space: PciConfigSpace,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait FromPciBus: Sized {
|
||||||
|
fn from_pci_bus(info: &PciDeviceInfo) -> Result<Self, Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PciBusDevice {
|
||||||
|
info: PciDeviceInfo,
|
||||||
|
driver: Option<Rc<dyn Device>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PciBusSegment {
|
||||||
|
segment_number: u8,
|
||||||
|
bus_number_start: u8,
|
||||||
|
bus_number_end: u8,
|
||||||
|
ecam_phys_base: Option<usize>,
|
||||||
|
|
||||||
|
devices: Vec<PciBusDevice>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PciBusManager {
|
||||||
|
segments: Vec<PciBusSegment>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PciBusSegment {
|
||||||
|
fn probe_config_space(&self, address: PciAddress) -> Result<Option<PciConfigSpace>, Error> {
|
||||||
|
match self.ecam_phys_base {
|
||||||
|
Some(ecam_phys_base) => Ok(unsafe {
|
||||||
|
PciEcam::probe_raw_parts(ecam_phys_base, self.bus_number_start, address)?
|
||||||
|
}
|
||||||
|
.map(PciConfigSpace::Ecam)),
|
||||||
|
None => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enumerate_function(
|
||||||
|
&mut self,
|
||||||
|
parent: &mut PciBusManager,
|
||||||
|
address: PciAddress,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let Some(config) = self.probe_config_space(address)? else {
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
|
||||||
|
let header_type = config.header_type();
|
||||||
|
|
||||||
|
// Enumerate multi-function devices
|
||||||
|
if address.function == 0 && header_type & 0x80 != 0 {
|
||||||
|
for function in 1..8 {
|
||||||
|
self.enumerate_function(parent, address.with_function(function))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PCI-to-PCI bridge
|
||||||
|
// if config.class_code() == 0x06 && config.subclass() == 0x04 {
|
||||||
|
// let secondary_bus = config.secondary_bus();
|
||||||
|
// // TODO
|
||||||
|
// }
|
||||||
|
|
||||||
|
let info = PciDeviceInfo {
|
||||||
|
address,
|
||||||
|
config_space: config,
|
||||||
|
};
|
||||||
|
self.devices.push(PciBusDevice { info, driver: None });
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enumerate_bus(&mut self, parent: &mut PciBusManager, bus: u8) -> Result<(), Error> {
|
||||||
|
let address = PciAddress::for_bus(self.segment_number, bus);
|
||||||
|
|
||||||
|
for i in 0..32 {
|
||||||
|
let device_address = address.with_device(i);
|
||||||
|
|
||||||
|
self.enumerate_function(parent, device_address)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enumerate(&mut self, parent: &mut PciBusManager) -> Result<(), Error> {
|
||||||
|
for bus in self.bus_number_start..self.bus_number_end {
|
||||||
|
self.enumerate_bus(parent, bus)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PciBusManager {
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
segments: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setup_bus_devices() -> Result<(), Error> {
|
||||||
|
Self::walk_bus_devices(|device| {
|
||||||
|
setup_bus_device(device)?;
|
||||||
|
Ok(true)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn walk_bus_devices<F: FnMut(&mut PciBusDevice) -> Result<bool, Error>>(
|
||||||
|
mut f: F,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let mut this = PCI_MANAGER.lock();
|
||||||
|
|
||||||
|
for segment in this.segments.iter_mut() {
|
||||||
|
for device in segment.devices.iter_mut() {
|
||||||
|
if !f(device)? {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_segment_from_mcfg(entry: &McfgEntry) -> Result<(), Error> {
|
||||||
|
let mut bus_segment = PciBusSegment {
|
||||||
|
segment_number: entry.pci_segment_group as u8,
|
||||||
|
bus_number_start: entry.bus_number_start,
|
||||||
|
bus_number_end: entry.bus_number_end,
|
||||||
|
ecam_phys_base: Some(entry.base_address as usize),
|
||||||
|
|
||||||
|
devices: Vec::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut this = PCI_MANAGER.lock();
|
||||||
|
bus_segment.enumerate(&mut *this)?;
|
||||||
|
this.segments.push(bus_segment);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for PciAddress {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{}:{}:{}", self.bus, self.device, self.function)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PciAddress {
|
||||||
|
pub const fn for_bus(segment: u8, bus: u8) -> Self {
|
||||||
|
Self {
|
||||||
|
segment,
|
||||||
|
bus,
|
||||||
|
device: 0,
|
||||||
|
function: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn with_device(self, device: u8) -> Self {
|
||||||
|
Self {
|
||||||
|
device,
|
||||||
|
function: 0,
|
||||||
|
..self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn with_function(self, function: u8) -> Self {
|
||||||
|
Self { function, ..self }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PciConfigurationSpace for PciConfigSpace {
|
||||||
|
fn read_u32(&self, offset: usize) -> u32 {
|
||||||
|
match self {
|
||||||
|
Self::Ecam(ecam) => ecam.read_u32(offset),
|
||||||
|
_ => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_bus_device(device: &mut PciBusDevice) -> Result<(), Error> {
|
||||||
|
if device.driver.is_some() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let config = &device.info.config_space;
|
||||||
|
|
||||||
|
debugln!(
|
||||||
|
"{}: {:04x}:{:04x}",
|
||||||
|
device.info.address,
|
||||||
|
config.vendor_id(),
|
||||||
|
config.device_id()
|
||||||
|
);
|
||||||
|
|
||||||
|
// Match by class
|
||||||
|
match (config.class_code(), config.subclass(), config.prog_if()) {
|
||||||
|
_ => {
|
||||||
|
debugln!(" -> No driver");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
static PCI_MANAGER: IrqSafeSpinlock<PciBusManager> = IrqSafeSpinlock::new(PciBusManager::new());
|
79
src/device/bus/pci/space/ecam.rs
Normal file
79
src/device/bus/pci/space/ecam.rs
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
use yggdrasil_abi::error::Error;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
device::bus::pci::{PciConfigSpace, PciDeviceInfo},
|
||||||
|
mem::{device::DeviceMemory, ConvertAddress},
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::{PciAddress, PciConfigurationSpace};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct PciEcam {
|
||||||
|
mapping: DeviceMemory,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only used for probing
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
struct PciRawEcam {
|
||||||
|
virt_addr: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PciConfigurationSpace for PciRawEcam {
|
||||||
|
fn read_u32(&self, offset: usize) -> u32 {
|
||||||
|
assert_eq!(offset & 3, 0);
|
||||||
|
unsafe { ((self.virt_addr + offset) as *const u32).read_volatile() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PciConfigurationSpace for PciEcam {
|
||||||
|
fn read_u32(&self, offset: usize) -> u32 {
|
||||||
|
assert_eq!(offset & 3, 0);
|
||||||
|
unsafe { ((self.mapping.base() + offset) as *const u32).read_volatile() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PciEcam {
|
||||||
|
pub unsafe fn map(phys_addr: usize) -> Result<Self, Error> {
|
||||||
|
// TODO check align
|
||||||
|
let mapping = DeviceMemory::map("pcie-ecam", phys_addr, 0x1000)?;
|
||||||
|
|
||||||
|
Ok(PciEcam { mapping })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn from_raw_parts(
|
||||||
|
segment_phys_addr: usize,
|
||||||
|
bus_offset: u8,
|
||||||
|
address: PciAddress,
|
||||||
|
) -> Result<Self, Error> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn probe_raw_parts(
|
||||||
|
segment_phys_addr: usize,
|
||||||
|
bus_offset: u8,
|
||||||
|
address: PciAddress,
|
||||||
|
) -> Result<Option<Self>, Error> {
|
||||||
|
let phys_addr = segment_phys_addr
|
||||||
|
+ ((address.bus - bus_offset) as usize * 256
|
||||||
|
+ address.device as usize * 8
|
||||||
|
+ address.function as usize)
|
||||||
|
* 0x1000;
|
||||||
|
|
||||||
|
if phys_addr + 0xFFF < 0x100000000 {
|
||||||
|
// Probe without allocating a mapping
|
||||||
|
let raw = PciRawEcam {
|
||||||
|
virt_addr: phys_addr.virtualize(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if !raw.is_valid() {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
Self::map(phys_addr).map(Some)
|
||||||
|
} else {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
131
src/device/bus/pci/space/mod.rs
Normal file
131
src/device/bus/pci/space/mod.rs
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
use super::{PciAddress, PciBaseAddress, PciEcam};
|
||||||
|
|
||||||
|
pub(super) mod ecam;
|
||||||
|
|
||||||
|
macro_rules! pci_config_field_getter {
|
||||||
|
(u32, $name:ident, $offset:expr) => {
|
||||||
|
fn $name(&self) -> u32 {
|
||||||
|
self.read_u32($offset)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
(u16, $name:ident, $offset:expr) => {
|
||||||
|
fn $name(&self) -> u16 {
|
||||||
|
self.read_u16($offset)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
(u8, $name:ident, $offset:expr) => {
|
||||||
|
fn $name(&self) -> u8 {
|
||||||
|
self.read_u8($offset)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! pci_config_field {
|
||||||
|
($offset:expr => $ty:ident, $getter:ident $(, $setter:ident)?) => {
|
||||||
|
pci_config_field_getter!($ty, $getter, $offset);
|
||||||
|
|
||||||
|
$(
|
||||||
|
fn $setter(&self, value: $ty) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
)?
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct PciLegacyConfigurationSpace {
|
||||||
|
address: PciAddress,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum PciConfigSpace {
|
||||||
|
Legacy(PciAddress),
|
||||||
|
Ecam(PciEcam),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait PciConfigurationSpace {
|
||||||
|
fn read_u32(&self, offset: usize) -> u32;
|
||||||
|
|
||||||
|
fn read_u16(&self, offset: usize) -> u16 {
|
||||||
|
assert_eq!(offset & 1, 0);
|
||||||
|
let value = self.read_u32(offset & !3);
|
||||||
|
(value >> ((offset & 3) * 8)) as u16
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_u8(&self, offset: usize) -> u8 {
|
||||||
|
let value = self.read_u32(offset & !3);
|
||||||
|
(value >> ((offset & 3) * 8)) as u8
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_valid(&self) -> bool {
|
||||||
|
self.vendor_id() != 0xFFFF && self.device_id() != 0xFFFF
|
||||||
|
}
|
||||||
|
|
||||||
|
pci_config_field!(0x00 => u16, vendor_id);
|
||||||
|
pci_config_field!(0x02 => u16, device_id);
|
||||||
|
pci_config_field!(0x04 => u16, command, set_command);
|
||||||
|
pci_config_field!(0x06 => u16, status);
|
||||||
|
|
||||||
|
pci_config_field!(0x08 => u8, rev_id);
|
||||||
|
pci_config_field!(0x09 => u8, prog_if);
|
||||||
|
pci_config_field!(0x0A => u8, subclass);
|
||||||
|
pci_config_field!(0x0B => u8, class_code);
|
||||||
|
|
||||||
|
// ...
|
||||||
|
pci_config_field!(0x0E => u8, header_type);
|
||||||
|
// Header Type 1 only
|
||||||
|
pci_config_field!(0x19 => u8, secondary_bus);
|
||||||
|
|
||||||
|
// Header Type 0 only
|
||||||
|
fn bar(&self, index: usize) -> Option<PciBaseAddress> {
|
||||||
|
assert!(index < 6);
|
||||||
|
|
||||||
|
if index % 2 == 0 {
|
||||||
|
let w0 = self.read_u32(0x10 + index * 4);
|
||||||
|
|
||||||
|
match w0 & 0 {
|
||||||
|
0 => match (w0 >> 1) & 3 {
|
||||||
|
0 => {
|
||||||
|
// 32-bit memory BAR
|
||||||
|
Some(PciBaseAddress::Memory((w0 as usize) & !0xF))
|
||||||
|
}
|
||||||
|
2 => {
|
||||||
|
// 64-bit memory BAR
|
||||||
|
let w1 = self.read_u32(0x10 + (index + 1) * 4);
|
||||||
|
Some(PciBaseAddress::Memory(
|
||||||
|
((w1 as usize) << 32) | ((w0 as usize) & !0xF),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
_ => unimplemented!(),
|
||||||
|
},
|
||||||
|
1 => todo!(),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let prev_w0 = self.read_u32(0x10 + (index - 1) * 4);
|
||||||
|
if prev_w0 & 0x7 == 0x4 {
|
||||||
|
// Previous BAR is 64-bit memory and this one is its continuation
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let w0 = self.read_u32(0x10 + index * 4);
|
||||||
|
|
||||||
|
match w0 & 0 {
|
||||||
|
0 => match (w0 >> 1) & 3 {
|
||||||
|
0 => {
|
||||||
|
// 32-bit memory BAR
|
||||||
|
Some(PciBaseAddress::Memory((w0 as usize) & !0xF))
|
||||||
|
}
|
||||||
|
// TODO can 64-bit BARs not be on a 64-bit boundary?
|
||||||
|
2 => todo!(),
|
||||||
|
_ => unimplemented!(),
|
||||||
|
},
|
||||||
|
1 => todo!(),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
//! osdev-x kernel crate
|
//! osdev-x kernel crate
|
||||||
#![feature(
|
#![feature(
|
||||||
|
decl_macro,
|
||||||
naked_functions,
|
naked_functions,
|
||||||
asm_const,
|
asm_const,
|
||||||
panic_info_message,
|
panic_info_message,
|
||||||
|
@ -6,7 +6,7 @@ use abi::error::Error;
|
|||||||
use crate::arch::{Architecture, ARCHITECTURE};
|
use crate::arch::{Architecture, ARCHITECTURE};
|
||||||
|
|
||||||
/// Generic MMIO access mapping
|
/// Generic MMIO access mapping
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Debug)]
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub struct DeviceMemory {
|
pub struct DeviceMemory {
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user