Add documentation to bus

This commit is contained in:
Yuke Peng
2024-06-27 17:47:20 +08:00
committed by Tate, Hongliang Tian
parent 0970adb37b
commit d43fbd88ba
16 changed files with 259 additions and 32 deletions

View File

@ -9,7 +9,7 @@ use log::warn;
use ostd::{ use ostd::{
bus::mmio::{ bus::mmio::{
bus::MmioDevice, bus::MmioDevice,
device::{MmioCommonDevice, VirtioMmioVersion}, common_device::{MmioCommonDevice, VirtioMmioVersion},
}, },
io_mem::IoMem, io_mem::IoMem,
mm::{DmaCoherent, PAGE_SIZE}, mm::{DmaCoherent, PAGE_SIZE},
@ -34,7 +34,7 @@ pub struct VirtioMmioDevice {
pub struct VirtioMmioTransport { pub struct VirtioMmioTransport {
layout: SafePtr<VirtioMmioLayout, IoMem>, layout: SafePtr<VirtioMmioLayout, IoMem>,
device: Arc<VirtioMmioDevice>, device: Arc<VirtioMmioDevice>,
common_device: ostd::bus::mmio::device::MmioCommonDevice, common_device: ostd::bus::mmio::common_device::MmioCommonDevice,
multiplex: Arc<RwLock<MultiplexIrq>>, multiplex: Arc<RwLock<MultiplexIrq>>,
} }

View File

@ -6,7 +6,7 @@ use ostd::{
bus::{ bus::{
mmio::{ mmio::{
bus::{MmioDevice, MmioDriver}, bus::{MmioDevice, MmioDriver},
device::MmioCommonDevice, common_device::MmioCommonDevice,
}, },
BusProbeError, BusProbeError,
}, },

View File

@ -3,9 +3,6 @@
//! Device-related APIs. //! Device-related APIs.
//! This module mainly contains the APIs that should exposed to the device driver like PCI, RTC //! This module mainly contains the APIs that should exposed to the device driver like PCI, RTC
// FIXME: remove this lint when the documentation of this module is extensively added.
#![allow(missing_docs)]
pub mod cmos; pub mod cmos;
pub mod io_port; pub mod io_port;
pub mod serial; pub mod serial;

View File

@ -1,15 +1,19 @@
// SPDX-License-Identifier: MPL-2.0 // SPDX-License-Identifier: MPL-2.0
//! MMIO bus.
#![allow(unused_variables)] #![allow(unused_variables)]
use alloc::{collections::VecDeque, fmt::Debug, sync::Arc, vec::Vec}; use alloc::{collections::VecDeque, fmt::Debug, sync::Arc, vec::Vec};
use log::{debug, error}; use log::{debug, error};
use super::device::MmioCommonDevice; use super::common_device::MmioCommonDevice;
use crate::bus::BusProbeError; use crate::bus::BusProbeError;
/// MMIO device trait
pub trait MmioDevice: Sync + Send + Debug { pub trait MmioDevice: Sync + Send + Debug {
/// Device ID
fn device_id(&self) -> u32; fn device_id(&self) -> u32;
} }
@ -37,6 +41,7 @@ pub struct MmioBus {
} }
impl MmioBus { impl MmioBus {
/// Registers a MMIO driver to the MMIO bus.
pub fn register_driver(&mut self, driver: Arc<dyn MmioDriver>) { pub fn register_driver(&mut self, driver: Arc<dyn MmioDriver>) {
debug!("Register driver:{:#x?}", driver); debug!("Register driver:{:#x?}", driver);
let length = self.common_devices.len(); let length = self.common_devices.len();

View File

@ -0,0 +1,85 @@
// SPDX-License-Identifier: MPL-2.0
//! MMIO device common definitions or functions.
use int_to_c_enum::TryFromInt;
use log::info;
use super::VIRTIO_MMIO_MAGIC;
use crate::{
io_mem::IoMem,
mm::{paddr_to_vaddr, Paddr, VmIo},
trap::IrqLine,
};
/// MMIO Common device.
#[derive(Debug)]
pub struct MmioCommonDevice {
io_mem: IoMem,
irq: IrqLine,
}
impl MmioCommonDevice {
pub(super) fn new(paddr: Paddr, handle: IrqLine) -> Self {
// TODO: Implement universal access to MMIO devices since we are temporarily
// using specific virtio device as implementation of CommonDevice.
// Read magic value
// SAFETY: It only read the value and judge if the magic value fit 0x74726976
unsafe {
debug_assert_eq!(*(paddr_to_vaddr(paddr) as *const u32), VIRTIO_MMIO_MAGIC);
}
// SAFETY: This range is virtio-mmio device space.
let io_mem = unsafe { IoMem::new(paddr..paddr + 0x200) };
let res = Self {
io_mem,
irq: handle,
};
info!(
"[Virtio]: Found Virtio mmio device, device id:{:?}, irq number:{:?}",
res.device_id(),
res.irq.num()
);
res
}
/// Base address
pub fn address(&self) -> Paddr {
self.io_mem.paddr()
}
/// Grants access to the MMIO
pub fn io_mem(&self) -> &IoMem {
&self.io_mem
}
/// Device ID
pub fn device_id(&self) -> u32 {
self.io_mem.read_val::<u32>(8).unwrap()
}
/// Version of the MMIO device.
pub fn version(&self) -> VirtioMmioVersion {
VirtioMmioVersion::try_from(self.io_mem.read_val::<u32>(4).unwrap()).unwrap()
}
/// Interrupt line
pub fn irq(&self) -> &IrqLine {
&self.irq
}
/// Mutable Interrupt line
pub fn irq_mut(&mut self) -> &mut IrqLine {
&mut self.irq
}
}
/// Virtio MMIO version
#[derive(Debug, Clone, Copy, TryFromInt, PartialEq, Eq, PartialOrd, Ord)]
#[repr(u32)]
pub enum VirtioMmioVersion {
/// Legacy
Legacy = 1,
/// Modern
Modern = 2,
}

View File

@ -1,5 +1,7 @@
// SPDX-License-Identifier: MPL-2.0 // SPDX-License-Identifier: MPL-2.0
//! MMIO device common definitions or functions.
use int_to_c_enum::TryFromInt; use int_to_c_enum::TryFromInt;
use log::info; use log::info;
@ -40,34 +42,45 @@ impl MmioCommonDevice {
res res
} }
/// Base address
pub fn address(&self) -> Paddr { pub fn address(&self) -> Paddr {
self.io_mem.paddr() self.io_mem.paddr()
} }
/// Grants access to the MMIO
pub fn io_mem(&self) -> &IoMem { pub fn io_mem(&self) -> &IoMem {
&self.io_mem &self.io_mem
} }
/// Device ID
pub fn device_id(&self) -> u32 { pub fn device_id(&self) -> u32 {
self.io_mem.read_val::<u32>(8).unwrap() self.io_mem.read_val::<u32>(8).unwrap()
} }
/// Version of the MMIO device.
///
/// FIXME: This function can only used in Virtio-mmio devices.
pub fn version(&self) -> VirtioMmioVersion { pub fn version(&self) -> VirtioMmioVersion {
VirtioMmioVersion::try_from(self.io_mem.read_val::<u32>(4).unwrap()).unwrap() VirtioMmioVersion::try_from(self.io_mem.read_val::<u32>(4).unwrap()).unwrap()
} }
/// Interrupt line
pub fn irq(&self) -> &IrqLine { pub fn irq(&self) -> &IrqLine {
&self.irq &self.irq
} }
/// Mutable Interrupt line
pub fn irq_mut(&mut self) -> &mut IrqLine { pub fn irq_mut(&mut self) -> &mut IrqLine {
&mut self.irq &mut self.irq
} }
} }
/// Virtio MMIO version
#[derive(Debug, Clone, Copy, TryFromInt, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Clone, Copy, TryFromInt, PartialEq, Eq, PartialOrd, Ord)]
#[repr(u32)] #[repr(u32)]
pub enum VirtioMmioVersion { pub enum VirtioMmioVersion {
/// Legacy
Legacy = 1, Legacy = 1,
/// Modern
Modern = 2, Modern = 2,
} }

View File

@ -5,7 +5,7 @@
//! Virtio over MMIO //! Virtio over MMIO
pub mod bus; pub mod bus;
pub mod device; pub mod common_device;
use alloc::vec::Vec; use alloc::vec::Vec;
use core::ops::Range; use core::ops::Range;
@ -18,16 +18,17 @@ use self::bus::MmioBus;
#[cfg(feature = "intel_tdx")] #[cfg(feature = "intel_tdx")]
use crate::arch::tdx_guest; use crate::arch::tdx_guest;
use crate::{ use crate::{
arch::kernel::IO_APIC, bus::mmio::device::MmioCommonDevice, mm::paddr_to_vaddr, sync::SpinLock, arch::kernel::IO_APIC, bus::mmio::common_device::MmioCommonDevice, mm::paddr_to_vaddr,
trap::IrqLine, sync::SpinLock, trap::IrqLine,
}; };
const VIRTIO_MMIO_MAGIC: u32 = 0x74726976; const VIRTIO_MMIO_MAGIC: u32 = 0x74726976;
/// MMIO bus instance
pub static MMIO_BUS: SpinLock<MmioBus> = SpinLock::new(MmioBus::new()); pub static MMIO_BUS: SpinLock<MmioBus> = SpinLock::new(MmioBus::new());
static IRQS: SpinLock<Vec<IrqLine>> = SpinLock::new(Vec::new()); static IRQS: SpinLock<Vec<IrqLine>> = SpinLock::new(Vec::new());
pub fn init() { pub(crate) fn init() {
#[cfg(feature = "intel_tdx")] #[cfg(feature = "intel_tdx")]
// SAFETY: // SAFETY:
// This is safe because we are ensuring that the address range 0xFEB0_0000 to 0xFEB0_4000 is valid before this operation. // This is safe because we are ensuring that the address range 0xFEB0_0000 to 0xFEB0_4000 is valid before this operation.

View File

@ -2,9 +2,6 @@
//! Bus operations //! Bus operations
// FIXME: remove this lint when the docs of the whole bus module are added.
#![allow(missing_docs)]
pub mod mmio; pub mod mmio;
pub mod pci; pub mod pci;
@ -18,7 +15,7 @@ pub enum BusProbeError {
} }
/// Initializes the bus /// Initializes the bus
pub fn init() { pub(crate) fn init() {
pci::init(); pci::init();
mmio::init(); mmio::init();
} }

View File

@ -1,5 +1,7 @@
// SPDX-License-Identifier: MPL-2.0 // SPDX-License-Identifier: MPL-2.0
//! PCI bus
#![allow(unused_variables)] #![allow(unused_variables)]
use alloc::{collections::VecDeque, sync::Arc, vec::Vec}; use alloc::{collections::VecDeque, sync::Arc, vec::Vec};
@ -10,7 +12,9 @@ use log::{debug, error};
use super::{device_info::PciDeviceId, PciCommonDevice}; use super::{device_info::PciDeviceId, PciCommonDevice};
use crate::bus::BusProbeError; use crate::bus::BusProbeError;
/// PciDevice trait.
pub trait PciDevice: Sync + Send + Debug { pub trait PciDevice: Sync + Send + Debug {
/// Gets device id.
fn device_id(&self) -> PciDeviceId; fn device_id(&self) -> PciDeviceId;
} }
@ -42,6 +46,7 @@ pub struct PciBus {
} }
impl PciBus { impl PciBus {
/// Registers a PCI driver to the PCI bus.
pub fn register_driver(&mut self, driver: Arc<dyn PciDriver>) { pub fn register_driver(&mut self, driver: Arc<dyn PciDriver>) {
debug!("Register driver:{:#x?}", driver); debug!("Register driver:{:#x?}", driver);
let length = self.common_devices.len(); let length = self.common_devices.len();

View File

@ -1,5 +1,7 @@
// SPDX-License-Identifier: MPL-2.0 // SPDX-License-Identifier: MPL-2.0
//! PCI device capabilities.
#![allow(dead_code)] #![allow(dead_code)]
use alloc::vec::Vec; use alloc::vec::Vec;
@ -14,6 +16,7 @@ use super::{
pub mod msix; pub mod msix;
pub mod vendor; pub mod vendor;
/// PCI Capability
#[derive(Debug)] #[derive(Debug)]
pub struct Capability { pub struct Capability {
id: u8, id: u8,
@ -26,6 +29,7 @@ pub struct Capability {
cap_data: CapabilityData, cap_data: CapabilityData,
} }
/// PCI Capability data.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum CapabilityData { pub enum CapabilityData {
/// Id:0x01, Power Management /// Id:0x01, Power Management
@ -76,11 +80,12 @@ impl Capability {
/// 0xFC, the top of the capability position. /// 0xFC, the top of the capability position.
const CAPABILITY_TOP: u16 = 0xFC; const CAPABILITY_TOP: u16 = 0xFC;
/// Gets the capability data
pub fn capability_data(&self) -> &CapabilityData { pub fn capability_data(&self) -> &CapabilityData {
&self.cap_data &self.cap_data
} }
/// get the capabilities of one device /// Gets the capabilities of one device
pub(super) fn device_capabilities(dev: &mut PciCommonDevice) -> Vec<Self> { pub(super) fn device_capabilities(dev: &mut PciCommonDevice) -> Vec<Self> {
if !dev.status().contains(Status::CAPABILITIES_LIST) { if !dev.status().contains(Status::CAPABILITIES_LIST) {
return Vec::new(); return Vec::new();

View File

@ -1,5 +1,7 @@
// SPDX-License-Identifier: MPL-2.0 // SPDX-License-Identifier: MPL-2.0
//! MSI-X capability support.
#![allow(dead_code)] #![allow(dead_code)]
#![allow(unused_variables)] #![allow(unused_variables)]
@ -150,11 +152,13 @@ impl CapabilityMsixData {
} }
} }
/// MSI-X Table size
pub fn table_size(&self) -> u16 { pub fn table_size(&self) -> u16 {
// bit 10:0 table size // bit 10:0 table size
(self.loc.read16(self.ptr + 2) & 0b11_1111_1111) + 1 (self.loc.read16(self.ptr + 2) & 0b11_1111_1111) + 1
} }
/// Enables an interrupt line, it will replace the old handle with the new handle.
pub fn set_interrupt_vector(&mut self, handle: IrqLine, index: u16) { pub fn set_interrupt_vector(&mut self, handle: IrqLine, index: u16) {
if index >= self.table_size { if index >= self.table_size {
return; return;
@ -174,6 +178,7 @@ impl CapabilityMsixData {
.unwrap(); .unwrap();
} }
/// Gets mutable IrqLine. User can register callbacks by using this function.
pub fn irq_mut(&mut self, index: usize) -> Option<&mut IrqLine> { pub fn irq_mut(&mut self, index: usize) -> Option<&mut IrqLine> {
self.irqs[index].as_mut() self.irqs[index].as_mut()
} }

View File

@ -1,5 +1,7 @@
// SPDX-License-Identifier: MPL-2.0 // SPDX-License-Identifier: MPL-2.0
//! Vendor-specific capability support.
use crate::{ use crate::{
bus::pci::{common_device::PciCommonDevice, device_info::PciDeviceLocation}, bus::pci::{common_device::PciCommonDevice, device_info::PciDeviceLocation},
Error, Result, Error, Result,
@ -23,41 +25,45 @@ impl CapabilityVndrData {
} }
} }
/// The length of this capability
#[allow(clippy::len_without_is_empty)]
pub fn len(&self) -> u16 { pub fn len(&self) -> u16 {
self.length self.length
} }
pub fn is_empty(&self) -> bool { /// Reads u8 from the capability.
self.length == 0
}
pub fn read8(&self, offset: u16) -> Result<u8> { pub fn read8(&self, offset: u16) -> Result<u8> {
self.check_range(offset)?; self.check_range(offset)?;
Ok(self.location.read8(self.cap_ptr + offset)) Ok(self.location.read8(self.cap_ptr + offset))
} }
/// Writes u8 to the capability.
pub fn write8(&self, offset: u16, value: u8) -> Result<()> { pub fn write8(&self, offset: u16, value: u8) -> Result<()> {
self.check_range(offset)?; self.check_range(offset)?;
self.location.write8(self.cap_ptr + offset, value); self.location.write8(self.cap_ptr + offset, value);
Ok(()) Ok(())
} }
/// Reads u16 from the capability.
pub fn read16(&self, offset: u16) -> Result<u16> { pub fn read16(&self, offset: u16) -> Result<u16> {
self.check_range(offset)?; self.check_range(offset)?;
Ok(self.location.read16(self.cap_ptr + offset)) Ok(self.location.read16(self.cap_ptr + offset))
} }
/// Writes u16 to the capability.
pub fn write16(&self, offset: u16, value: u16) -> Result<()> { pub fn write16(&self, offset: u16, value: u16) -> Result<()> {
self.check_range(offset)?; self.check_range(offset)?;
self.location.write16(self.cap_ptr + offset, value); self.location.write16(self.cap_ptr + offset, value);
Ok(()) Ok(())
} }
/// Reads u32 from the capability.
pub fn read32(&self, offset: u16) -> Result<u32> { pub fn read32(&self, offset: u16) -> Result<u32> {
self.check_range(offset)?; self.check_range(offset)?;
Ok(self.location.read32(self.cap_ptr + offset)) Ok(self.location.read32(self.cap_ptr + offset))
} }
/// Writes u32 to the capability.
pub fn write32(&self, offset: u16, value: u32) -> Result<()> { pub fn write32(&self, offset: u16, value: u32) -> Result<()> {
self.check_range(offset)?; self.check_range(offset)?;
self.location.write32(self.cap_ptr + offset, value); self.location.write32(self.cap_ptr + offset, value);

View File

@ -1,5 +1,9 @@
// SPDX-License-Identifier: MPL-2.0 // SPDX-License-Identifier: MPL-2.0
//! The PCI configuration space.
//!
//! Reference: <https://wiki.osdev.org/PCI>
use alloc::sync::Arc; use alloc::sync::Arc;
use core::mem::size_of; use core::mem::size_of;
@ -12,48 +16,87 @@ use crate::{
Error, Result, Error, Result,
}; };
/// Offset in PCI device's common configuration space(Not the PCI bridge).
#[repr(u16)] #[repr(u16)]
pub enum PciDeviceCommonCfgOffset { pub enum PciDeviceCommonCfgOffset {
/// Vendor ID
VendorId = 0x00, VendorId = 0x00,
/// Device ID
DeviceId = 0x02, DeviceId = 0x02,
/// PCI Command
Command = 0x04, Command = 0x04,
/// PCI Status
Status = 0x06, Status = 0x06,
/// Revision ID
RevisionId = 0x08, RevisionId = 0x08,
/// Class code
ClassCode = 0x09, ClassCode = 0x09,
/// Cache Line Size
CacheLineSize = 0x0C, CacheLineSize = 0x0C,
/// Latency Timer
LatencyTimer = 0x0D, LatencyTimer = 0x0D,
/// Header Type: Identifies the layout of the header.
HeaderType = 0x0E, HeaderType = 0x0E,
/// BIST: Represents the status and allows control of a devices BIST(built-in self test).
Bist = 0x0F, Bist = 0x0F,
/// Base Address Register #0
Bar0 = 0x10, Bar0 = 0x10,
/// Base Address Register #1
Bar1 = 0x14, Bar1 = 0x14,
/// Base Address Register #2
Bar2 = 0x18, Bar2 = 0x18,
/// Base Address Register #3
Bar3 = 0x1C, Bar3 = 0x1C,
/// Base Address Register #4
Bar4 = 0x20, Bar4 = 0x20,
/// Base Address Register #5
Bar5 = 0x24, Bar5 = 0x24,
/// Cardbus CIS Pointer
CardbusCisPtr = 0x28, CardbusCisPtr = 0x28,
/// Subsystem Vendor ID
SubsystemVendorId = 0x2C, SubsystemVendorId = 0x2C,
/// Subsystem ID
SubsystemId = 0x2E, SubsystemId = 0x2E,
/// Expansion ROM base address
XromBar = 0x30, XromBar = 0x30,
/// Capabilities pointer
CapabilitiesPointer = 0x34, CapabilitiesPointer = 0x34,
/// Interrupt Line
InterruptLine = 0x3C, InterruptLine = 0x3C,
/// INterrupt PIN
InterruptPin = 0x3D, InterruptPin = 0x3D,
/// Min Grant
MinGrant = 0x3E, MinGrant = 0x3E,
/// Max latency
MaxLatency = 0x3F, MaxLatency = 0x3F,
} }
bitflags! { bitflags! {
/// PCI device common config space command register. /// PCI device common config space command register.
pub struct Command: u16 { pub struct Command: u16 {
/// Sets to 1 if the device can respond to I/O Space accesses.
const IO_SPACE = 1 << 0; const IO_SPACE = 1 << 0;
/// Sets to 1 if the device can respond to Memory SPace accesses.
const MEMORY_SPACE = 1 << 1; const MEMORY_SPACE = 1 << 1;
/// Sets to 1 if the device can behave as a bus master.
const BUS_MASTER = 1 << 2; const BUS_MASTER = 1 << 2;
/// Sets to 1 if the device can monitor Special Cycle operations.
const SPECIAL_CYCLES = 1 << 3; const SPECIAL_CYCLES = 1 << 3;
/// Memory Write and Invalidate Enable. Set to 1 if the device can
/// generate the Memory Write and Invalidate command.
const MWI_ENABLE = 1 << 4; const MWI_ENABLE = 1 << 4;
/// Sets to 1 if the device does not respond to palette register writes
/// and will snoop the data.
const VGA_PALETTE_SNOOP = 1 << 5; const VGA_PALETTE_SNOOP = 1 << 5;
/// Sets to 1 if the device will takes its normal action when a parity
/// error is detected.
const PARITY_ERROR_RESPONSE = 1 << 6; const PARITY_ERROR_RESPONSE = 1 << 6;
const STEPPING_CONTROL = 1 << 7; /// Sets to 1 if the SERR# driver is enabled.
const SERR_ENABLE = 1 << 8; const SERR_ENABLE = 1 << 8;
/// Sets to 1 if the device is allowed to generate fast back-to-back
/// transactions
const FAST_BACK_TO_BACK_ENABLE = 1 << 9; const FAST_BACK_TO_BACK_ENABLE = 1 << 9;
/// Sets to 1 if the assertion of the devices INTx# signal is disabled.
const INTERRUPT_DISABLE = 1 << 10; const INTERRUPT_DISABLE = 1 << 10;
} }
} }
@ -61,17 +104,45 @@ bitflags! {
bitflags! { bitflags! {
/// PCI device common config space status register. /// PCI device common config space status register.
pub struct Status: u16 { pub struct Status: u16 {
/// The status of the device's INTx# signal.
const INTERRUPT_STATUS = 1 << 3; const INTERRUPT_STATUS = 1 << 3;
/// Sets to 1 if the device support capabilities.
const CAPABILITIES_LIST = 1 << 4; const CAPABILITIES_LIST = 1 << 4;
/// Sets to 1 if the device is capable of running at 66 MHz.
const MHZ66_CAPABLE = 1 << 5; const MHZ66_CAPABLE = 1 << 5;
/// Sets to 1 if the device can accpet fast back-to-back transactions
/// that are not from the same agent.
const FAST_BACK_TO_BACK_CAPABLE = 1 << 7; const FAST_BACK_TO_BACK_CAPABLE = 1 << 7;
/// This bit is only set when the following conditions are met:
/// 1. The bus agent asserted PERR# on a read or observed an assertion
/// of PERR# on a write
/// 2. The agent setting the bit acted as the bus master for the
/// operation in which the error occurred
/// 3. Bit 6 of the Command register (Parity Error Response bit) is set
/// to 1.
const MASTER_DATA_PARITY_ERROR = 1 << 8; const MASTER_DATA_PARITY_ERROR = 1 << 8;
/// The read-only bit that represent the slowest time that a device will
/// assert DEVSEL# for any bus command except Configuration Space read
/// and writes.
///
/// If both `DEVSEL_MEDIUM_TIMING` and `DEVSEL_SLOW_TIMING` are not set,
/// then it represents fast timing
const DEVSEL_MEDIUM_TIMING = 1 << 9; const DEVSEL_MEDIUM_TIMING = 1 << 9;
/// Check `DEVSEL_MEDIUM_TIMING`
const DEVSEL_SLOW_TIMING = 1 << 10; const DEVSEL_SLOW_TIMING = 1 << 10;
/// Sets to 1 when a target device terminates a transaction with Target-
/// Abort.
const SIGNALED_TARGET_ABORT = 1 << 11; const SIGNALED_TARGET_ABORT = 1 << 11;
/// Sets to 1 by a master device when its transaction is terminated with
/// Target-Abort
const RECEIVED_TARGET_ABORT = 1 << 12; const RECEIVED_TARGET_ABORT = 1 << 12;
/// Sets to 1 by a master device when its transcation (except for Special
/// Cycle transactions) is terminated with Master-Abort.
const RECEIVED_MASTER_ABORT = 1 << 13; const RECEIVED_MASTER_ABORT = 1 << 13;
/// Sets to 1 when the device asserts SERR#
const SIGNALED_SYSTEM_ERROR = 1 << 14; const SIGNALED_SYSTEM_ERROR = 1 << 14;
/// Sets to 1 when the device detects a parity error, even if parity error
/// handling is disabled.
const DETECTED_PARITY_ERROR = 1 << 15; const DETECTED_PARITY_ERROR = 1 << 15;
} }
} }
@ -79,7 +150,9 @@ bitflags! {
/// BAR space in PCI common config space. /// BAR space in PCI common config space.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Bar { pub enum Bar {
/// Memory BAR
Memory(Arc<MemoryBar>), Memory(Arc<MemoryBar>),
/// I/O BAR
Io(Arc<IoBar>), Io(Arc<IoBar>),
} }
@ -103,12 +176,11 @@ impl Bar {
} }
} }
/// Memory BAR
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct MemoryBar { pub struct MemoryBar {
base: u64, base: u64,
size: u32, size: u32,
/// Whether this bar is prefetchable, allowing the CPU to get the data
/// in advance.
prefetchable: bool, prefetchable: bool,
address_length: AddrLen, address_length: AddrLen,
io_memory: IoMem, io_memory: IoMem,
@ -120,23 +192,28 @@ impl MemoryBar {
self.address_length self.address_length
} }
/// Whether this bar is prefetchable, allowing the CPU to get the data
/// in advance.
pub fn prefetchable(&self) -> bool { pub fn prefetchable(&self) -> bool {
self.prefetchable self.prefetchable
} }
/// Base address
pub fn base(&self) -> u64 { pub fn base(&self) -> u64 {
self.base self.base
} }
/// Size of the memory
pub fn size(&self) -> u32 { pub fn size(&self) -> u32 {
self.size self.size
} }
/// Grants I/O memory access
pub fn io_mem(&self) -> &IoMem { pub fn io_mem(&self) -> &IoMem {
&self.io_memory &self.io_memory
} }
/// Create a memory BAR structure. /// Creates a memory BAR structure.
fn new(location: &PciDeviceLocation, index: u8) -> Result<Self> { fn new(location: &PciDeviceLocation, index: u8) -> Result<Self> {
// Get the original value first, then write all 1 to the register to get the length // Get the original value first, then write all 1 to the register to get the length
let offset = index as u16 * 4 + PciDeviceCommonCfgOffset::Bar0 as u16; let offset = index as u16 * 4 + PciDeviceCommonCfgOffset::Bar0 as u16;
@ -175,10 +252,13 @@ impl MemoryBar {
/// Whether this BAR is 64bit address or 32bit address /// Whether this BAR is 64bit address or 32bit address
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum AddrLen { pub enum AddrLen {
/// 32 bits
Bits32, Bits32,
/// 64 bits
Bits64, Bits64,
} }
/// I/O port BAR.
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct IoBar { pub struct IoBar {
base: u32, base: u32,
@ -186,14 +266,17 @@ pub struct IoBar {
} }
impl IoBar { impl IoBar {
/// Base port
pub fn base(&self) -> u32 { pub fn base(&self) -> u32 {
self.base self.base
} }
/// Size of the port
pub fn size(&self) -> u32 { pub fn size(&self) -> u32 {
self.size self.size
} }
/// Reads from port
pub fn read<T: PortRead>(&self, offset: u32) -> Result<T> { pub fn read<T: PortRead>(&self, offset: u32) -> Result<T> {
// Check alignment // Check alignment
if (self.base + offset) % size_of::<T>() as u32 != 0 { if (self.base + offset) % size_of::<T>() as u32 != 0 {
@ -208,6 +291,7 @@ impl IoBar {
unsafe { Ok(T::read_from_port((self.base + offset) as u16)) } unsafe { Ok(T::read_from_port((self.base + offset) as u16)) }
} }
/// Writes to port
pub fn write<T: PortWrite>(&self, offset: u32, value: T) -> Result<()> { pub fn write<T: PortWrite>(&self, offset: u32, value: T) -> Result<()> {
// Check alignment // Check alignment
if (self.base + offset) % size_of::<T>() as u32 != 0 { if (self.base + offset) % size_of::<T>() as u32 != 0 {

View File

@ -1,5 +1,7 @@
// SPDX-License-Identifier: MPL-2.0 // SPDX-License-Identifier: MPL-2.0
//! PCI device common definitions or functions.
#![allow(dead_code)] #![allow(dead_code)]
#![allow(unused_variables)] #![allow(unused_variables)]
@ -21,22 +23,27 @@ pub struct PciCommonDevice {
} }
impl PciCommonDevice { impl PciCommonDevice {
/// PCI device ID
pub fn device_id(&self) -> &PciDeviceId { pub fn device_id(&self) -> &PciDeviceId {
&self.device_id &self.device_id
} }
/// PCI device location
pub fn location(&self) -> &PciDeviceLocation { pub fn location(&self) -> &PciDeviceLocation {
&self.location &self.location
} }
/// PCI Base Address Register (BAR) manager
pub fn bar_manager(&self) -> &BarManager { pub fn bar_manager(&self) -> &BarManager {
&self.bar_manager &self.bar_manager
} }
/// PCI capabilities
pub fn capabilities(&self) -> &Vec<Capability> { pub fn capabilities(&self) -> &Vec<Capability> {
&self.capabilities &self.capabilities
} }
/// Gets the PCI Command
pub fn command(&self) -> Command { pub fn command(&self) -> Command {
Command::from_bits_truncate( Command::from_bits_truncate(
self.location self.location
@ -44,11 +51,13 @@ impl PciCommonDevice {
) )
} }
/// Sets the PCI Command
pub fn set_command(&self, command: Command) { pub fn set_command(&self, command: Command) {
self.location self.location
.write16(PciDeviceCommonCfgOffset::Command as u16, command.bits()) .write16(PciDeviceCommonCfgOffset::Command as u16, command.bits())
} }
/// Gets the PCI status
pub fn status(&self) -> Status { pub fn status(&self) -> Status {
Status::from_bits_truncate( Status::from_bits_truncate(
self.location self.location
@ -84,6 +93,7 @@ impl PciCommonDevice {
} }
} }
/// Base Address Registers manager.
#[derive(Debug)] #[derive(Debug)]
pub struct BarManager { pub struct BarManager {
/// BARs, the bool indicate whether this bar should exposed to unprivileged part. /// BARs, the bool indicate whether this bar should exposed to unprivileged part.

View File

@ -1,19 +1,30 @@
// SPDX-License-Identifier: MPL-2.0 // SPDX-License-Identifier: MPL-2.0
//! PCI device Information
use core::iter; use core::iter;
use super::cfg_space::PciDeviceCommonCfgOffset; use super::cfg_space::PciDeviceCommonCfgOffset;
use crate::arch::pci::{PCI_ADDRESS_PORT, PCI_DATA_PORT}; use crate::arch::pci::{PCI_ADDRESS_PORT, PCI_DATA_PORT};
/// PCI device ID
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct PciDeviceId { pub struct PciDeviceId {
/// Vendor ID
pub vendor_id: u16, pub vendor_id: u16,
/// Device ID
pub device_id: u16, pub device_id: u16,
/// Revision ID
pub revision_id: u8, pub revision_id: u8,
/// Programming Interface Byte
pub prog_if: u8, pub prog_if: u8,
/// Specifies the specific function the device performs.
pub subclass: u8, pub subclass: u8,
/// Specifies the type of function the device performs.
pub class: u8, pub class: u8,
/// Subsystem Vendor ID
pub subsystem_vendor_id: u16, pub subsystem_vendor_id: u16,
/// Subsystem ID
pub subsystem_id: u16, pub subsystem_id: u16,
} }
@ -41,22 +52,24 @@ impl PciDeviceId {
} }
} }
/// PCI device Location
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct PciDeviceLocation { pub struct PciDeviceLocation {
/// Bus number
pub bus: u8, pub bus: u8,
/// Max 31 /// Device number with max 31
pub device: u8, pub device: u8,
/// Max 7 /// Deivce number with max 7
pub function: u8, pub function: u8,
} }
impl PciDeviceLocation { impl PciDeviceLocation {
pub const MIN_BUS: u8 = 0; const MIN_BUS: u8 = 0;
pub const MAX_BUS: u8 = 255; const MAX_BUS: u8 = 255;
pub const MIN_DEVICE: u8 = 0; const MIN_DEVICE: u8 = 0;
pub const MAX_DEVICE: u8 = 31; const MAX_DEVICE: u8 = 31;
pub const MIN_FUNCTION: u8 = 0; const MIN_FUNCTION: u8 = 0;
pub const MAX_FUNCTION: u8 = 7; const MAX_FUNCTION: u8 = 7;
/// By encoding bus, device, and function into u32, user can access a PCI device in x86 by passing in this value. /// By encoding bus, device, and function into u32, user can access a PCI device in x86 by passing in this value.
#[inline(always)] #[inline(always)]
pub fn encode_as_x86_address_value(self) -> u32 { pub fn encode_as_x86_address_value(self) -> u32 {

View File

@ -61,6 +61,7 @@ pub use device_info::{PciDeviceId, PciDeviceLocation};
use self::{bus::PciBus, common_device::PciCommonDevice}; use self::{bus::PciBus, common_device::PciCommonDevice};
use crate::sync::Mutex; use crate::sync::Mutex;
/// PCI bus instance
pub static PCI_BUS: Mutex<PciBus> = Mutex::new(PciBus::new()); pub static PCI_BUS: Mutex<PciBus> = Mutex::new(PciBus::new());
pub(crate) fn init() { pub(crate) fn init() {