mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-19 04:26:39 +00:00
Add documentation to bus
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
0970adb37b
commit
d43fbd88ba
@ -9,7 +9,7 @@ use log::warn;
|
||||
use ostd::{
|
||||
bus::mmio::{
|
||||
bus::MmioDevice,
|
||||
device::{MmioCommonDevice, VirtioMmioVersion},
|
||||
common_device::{MmioCommonDevice, VirtioMmioVersion},
|
||||
},
|
||||
io_mem::IoMem,
|
||||
mm::{DmaCoherent, PAGE_SIZE},
|
||||
@ -34,7 +34,7 @@ pub struct VirtioMmioDevice {
|
||||
pub struct VirtioMmioTransport {
|
||||
layout: SafePtr<VirtioMmioLayout, IoMem>,
|
||||
device: Arc<VirtioMmioDevice>,
|
||||
common_device: ostd::bus::mmio::device::MmioCommonDevice,
|
||||
common_device: ostd::bus::mmio::common_device::MmioCommonDevice,
|
||||
multiplex: Arc<RwLock<MultiplexIrq>>,
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@ use ostd::{
|
||||
bus::{
|
||||
mmio::{
|
||||
bus::{MmioDevice, MmioDriver},
|
||||
device::MmioCommonDevice,
|
||||
common_device::MmioCommonDevice,
|
||||
},
|
||||
BusProbeError,
|
||||
},
|
||||
|
@ -3,9 +3,6 @@
|
||||
//! Device-related APIs.
|
||||
//! 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 io_port;
|
||||
pub mod serial;
|
||||
|
@ -1,15 +1,19 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
//! MMIO bus.
|
||||
|
||||
#![allow(unused_variables)]
|
||||
|
||||
use alloc::{collections::VecDeque, fmt::Debug, sync::Arc, vec::Vec};
|
||||
|
||||
use log::{debug, error};
|
||||
|
||||
use super::device::MmioCommonDevice;
|
||||
use super::common_device::MmioCommonDevice;
|
||||
use crate::bus::BusProbeError;
|
||||
|
||||
/// MMIO device trait
|
||||
pub trait MmioDevice: Sync + Send + Debug {
|
||||
/// Device ID
|
||||
fn device_id(&self) -> u32;
|
||||
}
|
||||
|
||||
@ -37,6 +41,7 @@ pub struct MmioBus {
|
||||
}
|
||||
|
||||
impl MmioBus {
|
||||
/// Registers a MMIO driver to the MMIO bus.
|
||||
pub fn register_driver(&mut self, driver: Arc<dyn MmioDriver>) {
|
||||
debug!("Register driver:{:#x?}", driver);
|
||||
let length = self.common_devices.len();
|
||||
|
85
ostd/src/bus/mmio/common_device.rs
Normal file
85
ostd/src/bus/mmio/common_device.rs
Normal 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,
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
//! MMIO device common definitions or functions.
|
||||
|
||||
use int_to_c_enum::TryFromInt;
|
||||
use log::info;
|
||||
|
||||
@ -40,34 +42,45 @@ impl MmioCommonDevice {
|
||||
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.
|
||||
///
|
||||
/// FIXME: This function can only used in Virtio-mmio devices.
|
||||
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,
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
//! Virtio over MMIO
|
||||
|
||||
pub mod bus;
|
||||
pub mod device;
|
||||
pub mod common_device;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use core::ops::Range;
|
||||
@ -18,16 +18,17 @@ use self::bus::MmioBus;
|
||||
#[cfg(feature = "intel_tdx")]
|
||||
use crate::arch::tdx_guest;
|
||||
use crate::{
|
||||
arch::kernel::IO_APIC, bus::mmio::device::MmioCommonDevice, mm::paddr_to_vaddr, sync::SpinLock,
|
||||
trap::IrqLine,
|
||||
arch::kernel::IO_APIC, bus::mmio::common_device::MmioCommonDevice, mm::paddr_to_vaddr,
|
||||
sync::SpinLock, trap::IrqLine,
|
||||
};
|
||||
|
||||
const VIRTIO_MMIO_MAGIC: u32 = 0x74726976;
|
||||
|
||||
/// MMIO bus instance
|
||||
pub static MMIO_BUS: SpinLock<MmioBus> = SpinLock::new(MmioBus::new());
|
||||
static IRQS: SpinLock<Vec<IrqLine>> = SpinLock::new(Vec::new());
|
||||
|
||||
pub fn init() {
|
||||
pub(crate) fn init() {
|
||||
#[cfg(feature = "intel_tdx")]
|
||||
// SAFETY:
|
||||
// This is safe because we are ensuring that the address range 0xFEB0_0000 to 0xFEB0_4000 is valid before this operation.
|
||||
|
@ -2,9 +2,6 @@
|
||||
|
||||
//! Bus operations
|
||||
|
||||
// FIXME: remove this lint when the docs of the whole bus module are added.
|
||||
#![allow(missing_docs)]
|
||||
|
||||
pub mod mmio;
|
||||
pub mod pci;
|
||||
|
||||
@ -18,7 +15,7 @@ pub enum BusProbeError {
|
||||
}
|
||||
|
||||
/// Initializes the bus
|
||||
pub fn init() {
|
||||
pub(crate) fn init() {
|
||||
pci::init();
|
||||
mmio::init();
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
//! PCI bus
|
||||
|
||||
#![allow(unused_variables)]
|
||||
|
||||
use alloc::{collections::VecDeque, sync::Arc, vec::Vec};
|
||||
@ -10,7 +12,9 @@ use log::{debug, error};
|
||||
use super::{device_info::PciDeviceId, PciCommonDevice};
|
||||
use crate::bus::BusProbeError;
|
||||
|
||||
/// PciDevice trait.
|
||||
pub trait PciDevice: Sync + Send + Debug {
|
||||
/// Gets device id.
|
||||
fn device_id(&self) -> PciDeviceId;
|
||||
}
|
||||
|
||||
@ -42,6 +46,7 @@ pub struct PciBus {
|
||||
}
|
||||
|
||||
impl PciBus {
|
||||
/// Registers a PCI driver to the PCI bus.
|
||||
pub fn register_driver(&mut self, driver: Arc<dyn PciDriver>) {
|
||||
debug!("Register driver:{:#x?}", driver);
|
||||
let length = self.common_devices.len();
|
||||
|
@ -1,5 +1,7 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
//! PCI device capabilities.
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
use alloc::vec::Vec;
|
||||
@ -14,6 +16,7 @@ use super::{
|
||||
pub mod msix;
|
||||
pub mod vendor;
|
||||
|
||||
/// PCI Capability
|
||||
#[derive(Debug)]
|
||||
pub struct Capability {
|
||||
id: u8,
|
||||
@ -26,6 +29,7 @@ pub struct Capability {
|
||||
cap_data: CapabilityData,
|
||||
}
|
||||
|
||||
/// PCI Capability data.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum CapabilityData {
|
||||
/// Id:0x01, Power Management
|
||||
@ -76,11 +80,12 @@ impl Capability {
|
||||
/// 0xFC, the top of the capability position.
|
||||
const CAPABILITY_TOP: u16 = 0xFC;
|
||||
|
||||
/// Gets the capability data
|
||||
pub fn capability_data(&self) -> &CapabilityData {
|
||||
&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> {
|
||||
if !dev.status().contains(Status::CAPABILITIES_LIST) {
|
||||
return Vec::new();
|
||||
|
@ -1,5 +1,7 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
//! MSI-X capability support.
|
||||
|
||||
#![allow(dead_code)]
|
||||
#![allow(unused_variables)]
|
||||
|
||||
@ -150,11 +152,13 @@ impl CapabilityMsixData {
|
||||
}
|
||||
}
|
||||
|
||||
/// MSI-X Table size
|
||||
pub fn table_size(&self) -> u16 {
|
||||
// bit 10:0 table size
|
||||
(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) {
|
||||
if index >= self.table_size {
|
||||
return;
|
||||
@ -174,6 +178,7 @@ impl CapabilityMsixData {
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
/// Gets mutable IrqLine. User can register callbacks by using this function.
|
||||
pub fn irq_mut(&mut self, index: usize) -> Option<&mut IrqLine> {
|
||||
self.irqs[index].as_mut()
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
//! Vendor-specific capability support.
|
||||
|
||||
use crate::{
|
||||
bus::pci::{common_device::PciCommonDevice, device_info::PciDeviceLocation},
|
||||
Error, Result,
|
||||
@ -23,41 +25,45 @@ impl CapabilityVndrData {
|
||||
}
|
||||
}
|
||||
|
||||
/// The length of this capability
|
||||
#[allow(clippy::len_without_is_empty)]
|
||||
pub fn len(&self) -> u16 {
|
||||
self.length
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.length == 0
|
||||
}
|
||||
|
||||
/// Reads u8 from the capability.
|
||||
pub fn read8(&self, offset: u16) -> Result<u8> {
|
||||
self.check_range(offset)?;
|
||||
Ok(self.location.read8(self.cap_ptr + offset))
|
||||
}
|
||||
|
||||
/// Writes u8 to the capability.
|
||||
pub fn write8(&self, offset: u16, value: u8) -> Result<()> {
|
||||
self.check_range(offset)?;
|
||||
self.location.write8(self.cap_ptr + offset, value);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Reads u16 from the capability.
|
||||
pub fn read16(&self, offset: u16) -> Result<u16> {
|
||||
self.check_range(offset)?;
|
||||
Ok(self.location.read16(self.cap_ptr + offset))
|
||||
}
|
||||
|
||||
/// Writes u16 to the capability.
|
||||
pub fn write16(&self, offset: u16, value: u16) -> Result<()> {
|
||||
self.check_range(offset)?;
|
||||
self.location.write16(self.cap_ptr + offset, value);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Reads u32 from the capability.
|
||||
pub fn read32(&self, offset: u16) -> Result<u32> {
|
||||
self.check_range(offset)?;
|
||||
Ok(self.location.read32(self.cap_ptr + offset))
|
||||
}
|
||||
|
||||
/// Writes u32 to the capability.
|
||||
pub fn write32(&self, offset: u16, value: u32) -> Result<()> {
|
||||
self.check_range(offset)?;
|
||||
self.location.write32(self.cap_ptr + offset, value);
|
||||
|
@ -1,5 +1,9 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
//! The PCI configuration space.
|
||||
//!
|
||||
//! Reference: <https://wiki.osdev.org/PCI>
|
||||
|
||||
use alloc::sync::Arc;
|
||||
use core::mem::size_of;
|
||||
|
||||
@ -12,48 +16,87 @@ use crate::{
|
||||
Error, Result,
|
||||
};
|
||||
|
||||
/// Offset in PCI device's common configuration space(Not the PCI bridge).
|
||||
#[repr(u16)]
|
||||
pub enum PciDeviceCommonCfgOffset {
|
||||
/// Vendor ID
|
||||
VendorId = 0x00,
|
||||
/// Device ID
|
||||
DeviceId = 0x02,
|
||||
/// PCI Command
|
||||
Command = 0x04,
|
||||
/// PCI Status
|
||||
Status = 0x06,
|
||||
/// Revision ID
|
||||
RevisionId = 0x08,
|
||||
/// Class code
|
||||
ClassCode = 0x09,
|
||||
/// Cache Line Size
|
||||
CacheLineSize = 0x0C,
|
||||
/// Latency Timer
|
||||
LatencyTimer = 0x0D,
|
||||
/// Header Type: Identifies the layout of the header.
|
||||
HeaderType = 0x0E,
|
||||
/// BIST: Represents the status and allows control of a devices BIST(built-in self test).
|
||||
Bist = 0x0F,
|
||||
/// Base Address Register #0
|
||||
Bar0 = 0x10,
|
||||
/// Base Address Register #1
|
||||
Bar1 = 0x14,
|
||||
/// Base Address Register #2
|
||||
Bar2 = 0x18,
|
||||
/// Base Address Register #3
|
||||
Bar3 = 0x1C,
|
||||
/// Base Address Register #4
|
||||
Bar4 = 0x20,
|
||||
/// Base Address Register #5
|
||||
Bar5 = 0x24,
|
||||
/// Cardbus CIS Pointer
|
||||
CardbusCisPtr = 0x28,
|
||||
/// Subsystem Vendor ID
|
||||
SubsystemVendorId = 0x2C,
|
||||
/// Subsystem ID
|
||||
SubsystemId = 0x2E,
|
||||
/// Expansion ROM base address
|
||||
XromBar = 0x30,
|
||||
/// Capabilities pointer
|
||||
CapabilitiesPointer = 0x34,
|
||||
/// Interrupt Line
|
||||
InterruptLine = 0x3C,
|
||||
/// INterrupt PIN
|
||||
InterruptPin = 0x3D,
|
||||
/// Min Grant
|
||||
MinGrant = 0x3E,
|
||||
/// Max latency
|
||||
MaxLatency = 0x3F,
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
/// PCI device common config space command register.
|
||||
pub struct Command: u16 {
|
||||
/// Sets to 1 if the device can respond to I/O Space accesses.
|
||||
const IO_SPACE = 1 << 0;
|
||||
/// Sets to 1 if the device can respond to Memory SPace accesses.
|
||||
const MEMORY_SPACE = 1 << 1;
|
||||
/// Sets to 1 if the device can behave as a bus master.
|
||||
const BUS_MASTER = 1 << 2;
|
||||
/// Sets to 1 if the device can monitor Special Cycle operations.
|
||||
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;
|
||||
/// Sets to 1 if the device does not respond to palette register writes
|
||||
/// and will snoop the data.
|
||||
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 STEPPING_CONTROL = 1 << 7;
|
||||
/// Sets to 1 if the SERR# driver is enabled.
|
||||
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;
|
||||
/// Sets to 1 if the assertion of the devices INTx# signal is disabled.
|
||||
const INTERRUPT_DISABLE = 1 << 10;
|
||||
}
|
||||
}
|
||||
@ -61,17 +104,45 @@ bitflags! {
|
||||
bitflags! {
|
||||
/// PCI device common config space status register.
|
||||
pub struct Status: u16 {
|
||||
/// The status of the device's INTx# signal.
|
||||
const INTERRUPT_STATUS = 1 << 3;
|
||||
/// Sets to 1 if the device support capabilities.
|
||||
const CAPABILITIES_LIST = 1 << 4;
|
||||
/// Sets to 1 if the device is capable of running at 66 MHz.
|
||||
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;
|
||||
/// 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;
|
||||
/// 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;
|
||||
/// Check `DEVSEL_MEDIUM_TIMING`
|
||||
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;
|
||||
/// Sets to 1 by a master device when its transaction is terminated with
|
||||
/// Target-Abort
|
||||
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;
|
||||
/// Sets to 1 when the device asserts SERR#
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -79,7 +150,9 @@ bitflags! {
|
||||
/// BAR space in PCI common config space.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Bar {
|
||||
/// Memory BAR
|
||||
Memory(Arc<MemoryBar>),
|
||||
/// I/O BAR
|
||||
Io(Arc<IoBar>),
|
||||
}
|
||||
|
||||
@ -103,12 +176,11 @@ impl Bar {
|
||||
}
|
||||
}
|
||||
|
||||
/// Memory BAR
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MemoryBar {
|
||||
base: u64,
|
||||
size: u32,
|
||||
/// Whether this bar is prefetchable, allowing the CPU to get the data
|
||||
/// in advance.
|
||||
prefetchable: bool,
|
||||
address_length: AddrLen,
|
||||
io_memory: IoMem,
|
||||
@ -120,23 +192,28 @@ impl MemoryBar {
|
||||
self.address_length
|
||||
}
|
||||
|
||||
/// Whether this bar is prefetchable, allowing the CPU to get the data
|
||||
/// in advance.
|
||||
pub fn prefetchable(&self) -> bool {
|
||||
self.prefetchable
|
||||
}
|
||||
|
||||
/// Base address
|
||||
pub fn base(&self) -> u64 {
|
||||
self.base
|
||||
}
|
||||
|
||||
/// Size of the memory
|
||||
pub fn size(&self) -> u32 {
|
||||
self.size
|
||||
}
|
||||
|
||||
/// Grants I/O memory access
|
||||
pub fn io_mem(&self) -> &IoMem {
|
||||
&self.io_memory
|
||||
}
|
||||
|
||||
/// Create a memory BAR structure.
|
||||
/// Creates a memory BAR structure.
|
||||
fn new(location: &PciDeviceLocation, index: u8) -> Result<Self> {
|
||||
// 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;
|
||||
@ -175,10 +252,13 @@ impl MemoryBar {
|
||||
/// Whether this BAR is 64bit address or 32bit address
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub enum AddrLen {
|
||||
/// 32 bits
|
||||
Bits32,
|
||||
/// 64 bits
|
||||
Bits64,
|
||||
}
|
||||
|
||||
/// I/O port BAR.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct IoBar {
|
||||
base: u32,
|
||||
@ -186,14 +266,17 @@ pub struct IoBar {
|
||||
}
|
||||
|
||||
impl IoBar {
|
||||
/// Base port
|
||||
pub fn base(&self) -> u32 {
|
||||
self.base
|
||||
}
|
||||
|
||||
/// Size of the port
|
||||
pub fn size(&self) -> u32 {
|
||||
self.size
|
||||
}
|
||||
|
||||
/// Reads from port
|
||||
pub fn read<T: PortRead>(&self, offset: u32) -> Result<T> {
|
||||
// Check alignment
|
||||
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)) }
|
||||
}
|
||||
|
||||
/// Writes to port
|
||||
pub fn write<T: PortWrite>(&self, offset: u32, value: T) -> Result<()> {
|
||||
// Check alignment
|
||||
if (self.base + offset) % size_of::<T>() as u32 != 0 {
|
||||
|
@ -1,5 +1,7 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
//! PCI device common definitions or functions.
|
||||
|
||||
#![allow(dead_code)]
|
||||
#![allow(unused_variables)]
|
||||
|
||||
@ -21,22 +23,27 @@ pub struct PciCommonDevice {
|
||||
}
|
||||
|
||||
impl PciCommonDevice {
|
||||
/// PCI device ID
|
||||
pub fn device_id(&self) -> &PciDeviceId {
|
||||
&self.device_id
|
||||
}
|
||||
|
||||
/// PCI device location
|
||||
pub fn location(&self) -> &PciDeviceLocation {
|
||||
&self.location
|
||||
}
|
||||
|
||||
/// PCI Base Address Register (BAR) manager
|
||||
pub fn bar_manager(&self) -> &BarManager {
|
||||
&self.bar_manager
|
||||
}
|
||||
|
||||
/// PCI capabilities
|
||||
pub fn capabilities(&self) -> &Vec<Capability> {
|
||||
&self.capabilities
|
||||
}
|
||||
|
||||
/// Gets the PCI Command
|
||||
pub fn command(&self) -> Command {
|
||||
Command::from_bits_truncate(
|
||||
self.location
|
||||
@ -44,11 +51,13 @@ impl PciCommonDevice {
|
||||
)
|
||||
}
|
||||
|
||||
/// Sets the PCI Command
|
||||
pub fn set_command(&self, command: Command) {
|
||||
self.location
|
||||
.write16(PciDeviceCommonCfgOffset::Command as u16, command.bits())
|
||||
}
|
||||
|
||||
/// Gets the PCI status
|
||||
pub fn status(&self) -> Status {
|
||||
Status::from_bits_truncate(
|
||||
self.location
|
||||
@ -84,6 +93,7 @@ impl PciCommonDevice {
|
||||
}
|
||||
}
|
||||
|
||||
/// Base Address Registers manager.
|
||||
#[derive(Debug)]
|
||||
pub struct BarManager {
|
||||
/// BARs, the bool indicate whether this bar should exposed to unprivileged part.
|
||||
|
@ -1,19 +1,30 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
//! PCI device Information
|
||||
|
||||
use core::iter;
|
||||
|
||||
use super::cfg_space::PciDeviceCommonCfgOffset;
|
||||
use crate::arch::pci::{PCI_ADDRESS_PORT, PCI_DATA_PORT};
|
||||
|
||||
/// PCI device ID
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub struct PciDeviceId {
|
||||
/// Vendor ID
|
||||
pub vendor_id: u16,
|
||||
/// Device ID
|
||||
pub device_id: u16,
|
||||
/// Revision ID
|
||||
pub revision_id: u8,
|
||||
/// Programming Interface Byte
|
||||
pub prog_if: u8,
|
||||
/// Specifies the specific function the device performs.
|
||||
pub subclass: u8,
|
||||
/// Specifies the type of function the device performs.
|
||||
pub class: u8,
|
||||
/// Subsystem Vendor ID
|
||||
pub subsystem_vendor_id: u16,
|
||||
/// Subsystem ID
|
||||
pub subsystem_id: u16,
|
||||
}
|
||||
|
||||
@ -41,22 +52,24 @@ impl PciDeviceId {
|
||||
}
|
||||
}
|
||||
|
||||
/// PCI device Location
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct PciDeviceLocation {
|
||||
/// Bus number
|
||||
pub bus: u8,
|
||||
/// Max 31
|
||||
/// Device number with max 31
|
||||
pub device: u8,
|
||||
/// Max 7
|
||||
/// Deivce number with max 7
|
||||
pub function: u8,
|
||||
}
|
||||
|
||||
impl PciDeviceLocation {
|
||||
pub const MIN_BUS: u8 = 0;
|
||||
pub const MAX_BUS: u8 = 255;
|
||||
pub const MIN_DEVICE: u8 = 0;
|
||||
pub const MAX_DEVICE: u8 = 31;
|
||||
pub const MIN_FUNCTION: u8 = 0;
|
||||
pub const MAX_FUNCTION: u8 = 7;
|
||||
const MIN_BUS: u8 = 0;
|
||||
const MAX_BUS: u8 = 255;
|
||||
const MIN_DEVICE: u8 = 0;
|
||||
const MAX_DEVICE: u8 = 31;
|
||||
const MIN_FUNCTION: u8 = 0;
|
||||
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.
|
||||
#[inline(always)]
|
||||
pub fn encode_as_x86_address_value(self) -> u32 {
|
||||
|
@ -61,6 +61,7 @@ pub use device_info::{PciDeviceId, PciDeviceLocation};
|
||||
use self::{bus::PciBus, common_device::PciCommonDevice};
|
||||
use crate::sync::Mutex;
|
||||
|
||||
/// PCI bus instance
|
||||
pub static PCI_BUS: Mutex<PciBus> = Mutex::new(PciBus::new());
|
||||
|
||||
pub(crate) fn init() {
|
||||
|
Reference in New Issue
Block a user