#![allow(dead_code)]
use alloc::vec::Vec;
use alloc::{boxed::Box, collections::LinkedList};
use bitflags::bitflags;
use core::{
convert::TryFrom,
fmt::{self, Display, Formatter},
};
use log::*;
use spin::{Lazy, RwLock, RwLockReadGuard, RwLockWriteGuard};
use x86_64::structures::paging::{Page, PageTableFlags, PhysFrame};
use x86_64::PhysAddr;
use crate::arch::{PciArch, TraitPciArch};
use crate::memory::{convert_physical_to_virtual, KERNEL_PAGE_TABLE};
pub static PCI_DEVICE_LINKEDLIST: Lazy<PciDeviceLinkedList> =
Lazy::new(|| PciDeviceLinkedList::new());
pub static PCI_ROOT_0: Lazy<Option<PciRoot>> = Lazy::new(|| match PciRoot::new(0) {
Ok(root) => Some(root),
Err(err) => {
error!("Pci_root init failed because of error: {}", err);
None
}
});
pub struct PciDeviceLinkedList {
list: RwLock<LinkedList<Box<dyn PciDeviceStructure>>>,
}
impl PciDeviceLinkedList {
fn new() -> Self {
PciDeviceLinkedList {
list: RwLock::new(LinkedList::new()),
}
}
pub fn read(&self) -> RwLockReadGuard<LinkedList<Box<dyn PciDeviceStructure>>> {
self.list.read()
}
pub fn write(&self) -> RwLockWriteGuard<LinkedList<Box<dyn PciDeviceStructure>>> {
self.list.write()
}
pub fn len(&self) -> usize {
let list = self.list.read();
list.len()
}
pub fn push_back(&self, device: Box<dyn PciDeviceStructure>) {
let mut list = self.list.write();
list.push_back(device);
}
}
pub fn get_pci_device_structure_mut<'a>(
list: &'a mut RwLockWriteGuard<'_, LinkedList<Box<dyn PciDeviceStructure>>>,
class_code: u8,
subclass: u8,
) -> Vec<&'a mut Box<(dyn PciDeviceStructure)>> {
let mut result = Vec::new();
for box_pci_device_structure in list.iter_mut() {
let common_header = (*box_pci_device_structure).common_header();
if (common_header.class_code == class_code) && (common_header.subclass == subclass) {
result.push(box_pci_device_structure);
}
}
result
}
pub fn get_pci_device_structure<'a>(
list: &'a mut RwLockReadGuard<'_, LinkedList<Box<dyn PciDeviceStructure>>>,
class_code: u8,
subclass: u8,
) -> Vec<&'a Box<(dyn PciDeviceStructure)>> {
let mut result = Vec::new();
for box_pci_device_structure in list.iter() {
let common_header = (*box_pci_device_structure).common_header();
if (common_header.class_code == class_code) && (common_header.subclass == subclass) {
result.push(box_pci_device_structure);
}
}
result
}
const BAR0_OFFSET: u8 = 0x10;
const STATUS_COMMAND_OFFSET: u8 = 0x04;
pub const PCI_CAP_ID_VNDR: u8 = 0x09;
pub const PORT_PCI_CONFIG_ADDRESS: u16 = 0xcf8;
pub const PORT_PCI_CONFIG_DATA: u16 = 0xcfc;
pub type SegmentGroupNumber = u16;
bitflags! {
pub struct Status: u16 {
const INTERRUPT_STATUS = 1 << 3;
const CAPABILITIES_LIST = 1 << 4;
const MHZ_66_CAPABLE = 1 << 5;
const FAST_BACK_TO_BACK_CAPABLE = 1 << 7;
const MASTER_DATA_PARITY_ERROR = 1 << 8;
const SIGNALED_TARGET_ABORT = 1 << 11;
const RECEIVED_TARGET_ABORT = 1 << 12;
const RECEIVED_MASTER_ABORT = 1 << 13;
const SIGNALED_SYSTEM_ERROR = 1 << 14;
const DETECTED_PARITY_ERROR = 1 << 15;
}
}
bitflags! {
pub struct Command: u16 {
const IO_SPACE = 1 << 0;
const MEMORY_SPACE = 1 << 1;
const BUS_MASTER = 1 << 2;
const SPECIAL_CYCLES = 1 << 3;
const MEMORY_WRITE_AND_INVALIDATE_ENABLE = 1 << 4;
const VGA_PALETTE_SNOOP = 1 << 5;
const PARITY_ERROR_RESPONSE = 1 << 6;
const SERR_ENABLE = 1 << 8;
const FAST_BACK_TO_BACK_ENABLE = 1 << 9;
const INTERRUPT_DISABLE = 1 << 10;
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum HeaderType {
Standard,
PciPciBridge,
PciCardbusBridge,
Unrecognised(u8),
}
impl From<u8> for HeaderType {
fn from(value: u8) -> Self {
match value {
0x00 => Self::Standard,
0x01 => Self::PciPciBridge,
0x02 => Self::PciCardbusBridge,
_ => Self::Unrecognised(value),
}
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum PciError {
InvalidBarType,
CreateMmioError,
InvalidBusDeviceFunction,
SegmentNotFound,
GetWrongHeader,
UnrecognisedHeaderType,
PciDeviceStructureTransformError,
}
impl Display for PciError {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
Self::InvalidBarType => write!(f, "Invalid PCI BAR type."),
Self::CreateMmioError => write!(f, "Error occurred while creating mmio."),
Self::InvalidBusDeviceFunction => write!(f, "Found invalid BusDeviceFunction."),
Self::SegmentNotFound => write!(f, "Target segment not found"),
Self::GetWrongHeader => write!(f, "GetWrongHeader with vendor id 0xffff"),
Self::UnrecognisedHeaderType => write!(f, "Found device with unrecognised header type"),
Self::PciDeviceStructureTransformError => {
write!(f, "Found None When transform Pci device structure")
}
}
}
}
pub trait PciDeviceStructure: Send + Sync {
fn header_type(&self) -> HeaderType;
fn as_standard_device(&self) -> Option<&PciDeviceStructureGeneralDevice> {
None
}
fn as_pci_to_pci_bridge_device(&self) -> Option<&PciDeviceStructurePciToPciBridge> {
None
}
fn as_pci_to_carbus_bridge_device(&self) -> Option<&PciDeviceStructurePciToCardbusBridge> {
None
}
fn common_header(&self) -> &PciDeviceStructureHeader;
fn as_standard_device_mut(&mut self) -> Option<&mut PciDeviceStructureGeneralDevice> {
None
}
fn as_pci_to_pci_bridge_device_mut(&mut self) -> Option<&mut PciDeviceStructurePciToPciBridge> {
None
}
fn as_pci_to_carbus_bridge_device_mut(
&mut self,
) -> Option<&mut PciDeviceStructurePciToCardbusBridge> {
None
}
fn capabilities(&self) -> Option<CapabilityIterator> {
None
}
fn status_command(&self) -> (Status, Command) {
let common_header = self.common_header();
let status = Status::from_bits_truncate(common_header.status);
let command = Command::from_bits_truncate(common_header.command);
(status, command)
}
fn set_command(&mut self, command: Command) {
let common_header = self.common_header_mut();
let command = command.bits();
common_header.command = command;
PciArch::write_config(
&common_header.bus_device_function,
STATUS_COMMAND_OFFSET,
command as u32,
);
}
fn common_header_mut(&mut self) -> &mut PciDeviceStructureHeader;
fn bar_init(&mut self) -> Option<Result<u8, PciError>> {
None
}
fn msix_init(&mut self) -> Option<Result<u8, PciError>> {
None
}
fn enable_master(&mut self) {
self.set_command(Command::IO_SPACE | Command::MEMORY_SPACE | Command::BUS_MASTER);
}
}
#[derive(Clone, Debug)]
pub struct PciDeviceStructureHeader {
pub msix_mmio_vaddr: u64,
pub msix_mmio_size: u64, pub msix_offset: u32, pub msix_table_size: u16, pub bus_device_function: BusDeviceFunction,
pub vendor_id: u16, pub device_id: u16, pub command: u16, pub status: u16, pub revision_id: u8, pub prog_if: u8, pub subclass: u8, pub class_code: u8, pub cache_line_size: u8, pub latency_timer: u8, pub header_type: u8, pub bist: u8, }
#[derive(Clone, Debug)]
pub struct PciDeviceStructureGeneralDevice {
pub common_header: PciDeviceStructureHeader,
pub standard_device_bar: PciStandardDeviceBar,
pub cardbus_cis_pointer: u32, pub subsystem_vendor_id: u16,
pub subsystem_id: u16,
pub expansion_rom_base_address: u32,
pub capabilities_pointer: u8,
pub reserved0: u8,
pub reserved1: u16,
pub reserved2: u32,
pub interrupt_line: u8, pub interrupt_pin: u8, pub min_grant: u8, pub max_latency: u8, }
impl PciDeviceStructure for PciDeviceStructureGeneralDevice {
fn header_type(&self) -> HeaderType {
HeaderType::Standard
}
fn as_standard_device(&self) -> Option<&PciDeviceStructureGeneralDevice> {
Some(self)
}
fn as_standard_device_mut(&mut self) -> Option<&mut PciDeviceStructureGeneralDevice> {
Some(self)
}
fn common_header(&self) -> &PciDeviceStructureHeader {
&self.common_header
}
fn common_header_mut(&mut self) -> &mut PciDeviceStructureHeader {
&mut self.common_header
}
fn capabilities(&self) -> Option<CapabilityIterator> {
Some(CapabilityIterator {
bus_device_function: self.common_header.bus_device_function,
next_capability_offset: Some(self.capabilities_pointer),
})
}
fn bar_init(&mut self) -> Option<Result<u8, PciError>> {
let common_header = &self.common_header;
match pci_bar_init(common_header.bus_device_function) {
Ok(bar) => {
self.standard_device_bar = bar;
Some(Ok(0))
}
Err(e) => Some(Err(e)),
}
}
}
#[derive(Clone, Debug)]
pub struct PciDeviceStructurePciToPciBridge {
pub common_header: PciDeviceStructureHeader,
pub bar0: u32,
pub bar1: u32,
pub primary_bus_number: u8,
pub secondary_bus_number: u8,
pub subordinate_bus_number: u8,
pub secondary_latency_timer: u8,
pub io_base: u8,
pub io_limit: u8,
pub secondary_status: u16,
pub memory_base: u16,
pub memory_limit: u16,
pub prefetchable_memory_base: u16,
pub prefetchable_memory_limit: u16,
pub prefetchable_base_upper_32_bits: u32,
pub prefetchable_limit_upper_32_bits: u32,
pub io_base_upper_16_bits: u16,
pub io_limit_upper_16_bits: u16,
pub capability_pointer: u8,
pub reserved0: u8,
pub reserved1: u16,
pub expansion_rom_base_address: u32,
pub interrupt_line: u8,
pub interrupt_pin: u8,
pub bridge_control: u16,
}
impl PciDeviceStructure for PciDeviceStructurePciToPciBridge {
fn header_type(&self) -> HeaderType {
HeaderType::PciPciBridge
}
fn as_pci_to_pci_bridge_device(&self) -> Option<&PciDeviceStructurePciToPciBridge> {
Some(self)
}
fn as_pci_to_pci_bridge_device_mut(&mut self) -> Option<&mut PciDeviceStructurePciToPciBridge> {
Some(self)
}
fn common_header(&self) -> &PciDeviceStructureHeader {
&self.common_header
}
fn common_header_mut(&mut self) -> &mut PciDeviceStructureHeader {
&mut self.common_header
}
}
#[derive(Clone, Debug)]
pub struct PciDeviceStructurePciToCardbusBridge {
pub common_header: PciDeviceStructureHeader,
pub cardbus_socket_ex_ca_base_address: u32,
pub offset_of_capabilities_list: u8,
pub reserved: u8,
pub secondary_status: u16,
pub pci_bus_number: u8,
pub card_bus_bus_number: u8,
pub subordinate_bus_number: u8,
pub card_bus_latency_timer: u8,
pub memory_base_address0: u32,
pub memory_limit0: u32,
pub memory_base_address1: u32,
pub memory_limit1: u32,
pub io_base_address0: u32,
pub io_limit0: u32,
pub io_base_address1: u32,
pub io_limit1: u32,
pub interrupt_line: u8,
pub interrupt_pin: u8,
pub bridge_control: u16,
pub subsystem_device_id: u16,
pub subsystem_vendor_id: u16,
pub pc_card_legacy_mode_base_address_16_bit: u32,
}
impl PciDeviceStructure for PciDeviceStructurePciToCardbusBridge {
fn header_type(&self) -> HeaderType {
HeaderType::PciCardbusBridge
}
fn as_pci_to_carbus_bridge_device(&self) -> Option<&PciDeviceStructurePciToCardbusBridge> {
Some(&self)
}
fn as_pci_to_carbus_bridge_device_mut(
&mut self,
) -> Option<&mut PciDeviceStructurePciToCardbusBridge> {
Some(self)
}
fn common_header(&self) -> &PciDeviceStructureHeader {
&self.common_header
}
fn common_header_mut(&mut self) -> &mut PciDeviceStructureHeader {
&mut self.common_header
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct PciRoot {
pub physical_address_base: u64, pub mmio_base: Option<*mut u32>, pub segement_group_number: SegmentGroupNumber, pub bus_begin: u8, pub bus_end: u8, }
unsafe impl Send for PciRoot {}
unsafe impl Sync for PciRoot {}
impl Display for PciRoot {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(
f,
"PCI Root with segement:{}, bus begin at {}, bus end at {}, physical address at {},mapped at {:#x}",
self.segement_group_number, self.bus_begin, self.bus_end, self.physical_address_base, self.mmio_base.unwrap() as usize
)
}
}
impl PciRoot {
pub fn new(segment_group_number: SegmentGroupNumber) -> Result<Self, PciError> {
let mut pci_root = PciArch::ecam_root(segment_group_number)?;
pci_root.map()?;
Ok(pci_root)
}
fn map(&mut self) -> Result<u8, PciError> {
let bus_number = self.bus_end - self.bus_begin + 1;
let bus_number_double = (bus_number + 1) / 2;
let paddr = PhysAddr::new(self.physical_address_base);
let vaddr = convert_physical_to_virtual(paddr);
for i in 0..bus_number_double {
let mut kernel_page_table = KERNEL_PAGE_TABLE.lock();
unsafe {
kernel_page_table.map_to_with_table_flags_general(
Page::containing_address(vaddr + i as u64 * 4096),
PhysFrame::containing_address(paddr + i as u64 * 4096),
PageTableFlags::PRESENT | PageTableFlags::WRITABLE,
PageTableFlags::PRESENT | PageTableFlags::WRITABLE,
)
};
}
self.mmio_base = Some(vaddr.as_u64() as *mut u32);
Ok(0)
}
fn cam_offset(&self, bus_device_function: BusDeviceFunction, register_offset: u16) -> u32 {
assert!(bus_device_function.valid());
let bdf = ((bus_device_function.bus - self.bus_begin) as u32) << 8
| (bus_device_function.device as u32) << 3
| bus_device_function.function as u32;
let address = bdf << 12 | register_offset as u32;
assert!(address & 0x3 == 0);
address
}
pub fn read_config(&self, bus_device_function: BusDeviceFunction, register_offset: u16) -> u32 {
let address = self.cam_offset(bus_device_function, register_offset);
unsafe {
(self.mmio_base.unwrap().add((address >> 2) as usize)).read_volatile()
}
}
pub fn write_config(
&mut self,
bus_device_function: BusDeviceFunction,
register_offset: u16,
data: u32,
) {
let address = self.cam_offset(bus_device_function, register_offset);
unsafe {
(self.mmio_base.unwrap().add((address >> 2) as usize)).write_volatile(data)
}
}
pub fn external_capabilities(
&self,
bus_device_function: BusDeviceFunction,
) -> ExternalCapabilityIterator {
ExternalCapabilityIterator {
root: self,
bus_device_function,
next_capability_offset: Some(0x100),
}
}
}
pub fn capabilities_offset(bus_device_function: BusDeviceFunction) -> Option<u8> {
let result = PciArch::read_config(&bus_device_function, STATUS_COMMAND_OFFSET);
let status: Status = Status::from_bits_truncate((result >> 16) as u16);
if status.contains(Status::CAPABILITIES_LIST) {
let cap_pointer = PciArch::read_config(&bus_device_function, 0x34) as u8 & 0xFC;
Some(cap_pointer)
} else {
None
}
}
fn pci_read_header(
bus_device_function: BusDeviceFunction,
add_to_list: bool,
) -> Result<Box<dyn PciDeviceStructure>, PciError> {
let result = PciArch::read_config(&bus_device_function, 0x00);
let vendor_id = result as u16;
let device_id = (result >> 16) as u16;
let result = PciArch::read_config(&bus_device_function, 0x04);
let command = result as u16;
let status = (result >> 16) as u16;
let result = PciArch::read_config(&bus_device_function, 0x08);
let revision_id = result as u8;
let prog_if = (result >> 8) as u8;
let subclass = (result >> 16) as u8;
let class_code = (result >> 24) as u8;
let result = PciArch::read_config(&bus_device_function, 0x0c);
let cache_line_size = result as u8;
let latency_timer = (result >> 8) as u8;
let header_type = (result >> 16) as u8;
let bist = (result >> 24) as u8;
if vendor_id == 0xffff {
return Err(PciError::GetWrongHeader);
}
let header = PciDeviceStructureHeader {
msix_mmio_vaddr: 0,
msix_mmio_size: 0,
msix_offset: 0,
msix_table_size: 0,
bus_device_function,
vendor_id,
device_id,
command,
status,
revision_id,
prog_if,
subclass,
class_code,
cache_line_size,
latency_timer,
header_type,
bist,
};
match HeaderType::from(header_type & 0x7f) {
HeaderType::Standard => {
let general_device = pci_read_general_device_header(header, &bus_device_function);
let box_general_device = Box::new(general_device);
let box_general_device_clone = box_general_device.clone();
if add_to_list {
PCI_DEVICE_LINKEDLIST.push_back(box_general_device);
}
Ok(box_general_device_clone)
}
HeaderType::PciPciBridge => {
let pci_to_pci_bridge = pci_read_pci_to_pci_bridge_header(header, &bus_device_function);
let box_pci_to_pci_bridge = Box::new(pci_to_pci_bridge);
let box_pci_to_pci_bridge_clone = box_pci_to_pci_bridge.clone();
if add_to_list {
PCI_DEVICE_LINKEDLIST.push_back(box_pci_to_pci_bridge);
}
Ok(box_pci_to_pci_bridge_clone)
}
HeaderType::PciCardbusBridge => {
let pci_cardbus_bridge =
pci_read_pci_to_cardbus_bridge_header(header, &bus_device_function);
let box_pci_cardbus_bridge = Box::new(pci_cardbus_bridge);
let box_pci_cardbus_bridge_clone = box_pci_cardbus_bridge.clone();
if add_to_list {
PCI_DEVICE_LINKEDLIST.push_back(box_pci_cardbus_bridge);
}
Ok(box_pci_cardbus_bridge_clone)
}
HeaderType::Unrecognised(_) => Err(PciError::UnrecognisedHeaderType),
}
}
fn pci_read_general_device_header(
common_header: PciDeviceStructureHeader,
bus_device_function: &BusDeviceFunction,
) -> PciDeviceStructureGeneralDevice {
let standard_device_bar = PciStandardDeviceBar::default();
let cardbus_cis_pointer = PciArch::read_config(bus_device_function, 0x28);
let result = PciArch::read_config(bus_device_function, 0x2c);
let subsystem_vendor_id = result as u16;
let subsystem_id = (result >> 16) as u16;
let expansion_rom_base_address = PciArch::read_config(bus_device_function, 0x30);
let result = PciArch::read_config(bus_device_function, 0x34);
let capabilities_pointer = result as u8;
let reserved0 = (result >> 8) as u8;
let reserved1 = (result >> 16) as u16;
let reserved2 = PciArch::read_config(bus_device_function, 0x38);
let result = PciArch::read_config(bus_device_function, 0x3c);
let interrupt_line = result as u8;
let interrupt_pin = (result >> 8) as u8;
let min_grant = (result >> 16) as u8;
let max_latency = (result >> 24) as u8;
PciDeviceStructureGeneralDevice {
common_header,
standard_device_bar,
cardbus_cis_pointer,
subsystem_vendor_id,
subsystem_id,
expansion_rom_base_address,
capabilities_pointer,
reserved0,
reserved1,
reserved2,
interrupt_line,
interrupt_pin,
min_grant,
max_latency,
}
}
fn pci_read_pci_to_pci_bridge_header(
common_header: PciDeviceStructureHeader,
bus_device_function: &BusDeviceFunction,
) -> PciDeviceStructurePciToPciBridge {
let bar0 = PciArch::read_config(bus_device_function, 0x10);
let bar1 = PciArch::read_config(bus_device_function, 0x14);
let result = PciArch::read_config(bus_device_function, 0x18);
let primary_bus_number = result as u8;
let secondary_bus_number = (result >> 8) as u8;
let subordinate_bus_number = (result >> 16) as u8;
let secondary_latency_timer = (result >> 24) as u8;
let result = PciArch::read_config(bus_device_function, 0x1c);
let io_base = result as u8;
let io_limit = (result >> 8) as u8;
let secondary_status = (result >> 16) as u16;
let result = PciArch::read_config(bus_device_function, 0x20);
let memory_base = result as u16;
let memory_limit = (result >> 16) as u16;
let result = PciArch::read_config(bus_device_function, 0x24);
let prefetchable_memory_base = result as u16;
let prefetchable_memory_limit = (result >> 16) as u16;
let prefetchable_base_upper_32_bits = PciArch::read_config(bus_device_function, 0x28);
let prefetchable_limit_upper_32_bits = PciArch::read_config(bus_device_function, 0x2c);
let result = PciArch::read_config(bus_device_function, 0x30);
let io_base_upper_16_bits = result as u16;
let io_limit_upper_16_bits = (result >> 16) as u16;
let result = PciArch::read_config(bus_device_function, 0x34);
let capability_pointer = result as u8;
let reserved0 = (result >> 8) as u8;
let reserved1 = (result >> 16) as u16;
let expansion_rom_base_address = PciArch::read_config(bus_device_function, 0x38);
let result = PciArch::read_config(bus_device_function, 0x3c);
let interrupt_line = result as u8;
let interrupt_pin = (result >> 8) as u8;
let bridge_control = (result >> 16) as u16;
PciDeviceStructurePciToPciBridge {
common_header,
bar0,
bar1,
primary_bus_number,
secondary_bus_number,
subordinate_bus_number,
secondary_latency_timer,
io_base,
io_limit,
secondary_status,
memory_base,
memory_limit,
prefetchable_memory_base,
prefetchable_memory_limit,
prefetchable_base_upper_32_bits,
prefetchable_limit_upper_32_bits,
io_base_upper_16_bits,
io_limit_upper_16_bits,
capability_pointer,
reserved0,
reserved1,
expansion_rom_base_address,
interrupt_line,
interrupt_pin,
bridge_control,
}
}
fn pci_read_pci_to_cardbus_bridge_header(
common_header: PciDeviceStructureHeader,
busdevicefunction: &BusDeviceFunction,
) -> PciDeviceStructurePciToCardbusBridge {
let cardbus_socket_ex_ca_base_address = PciArch::read_config(busdevicefunction, 0x10);
let result = PciArch::read_config(busdevicefunction, 0x14);
let offset_of_capabilities_list = result as u8;
let reserved = (result >> 8) as u8;
let secondary_status = (result >> 16) as u16;
let result = PciArch::read_config(busdevicefunction, 0x18);
let pci_bus_number = result as u8;
let card_bus_bus_number = (result >> 8) as u8;
let subordinate_bus_number = (result >> 16) as u8;
let card_bus_latency_timer = (result >> 24) as u8;
let memory_base_address0 = PciArch::read_config(busdevicefunction, 0x1c);
let memory_limit0 = PciArch::read_config(busdevicefunction, 0x20);
let memory_base_address1 = PciArch::read_config(busdevicefunction, 0x24);
let memory_limit1 = PciArch::read_config(busdevicefunction, 0x28);
let io_base_address0 = PciArch::read_config(busdevicefunction, 0x2c);
let io_limit0 = PciArch::read_config(busdevicefunction, 0x30);
let io_base_address1 = PciArch::read_config(busdevicefunction, 0x34);
let io_limit1 = PciArch::read_config(busdevicefunction, 0x38);
let result = PciArch::read_config(busdevicefunction, 0x3c);
let interrupt_line = result as u8;
let interrupt_pin = (result >> 8) as u8;
let bridge_control = (result >> 16) as u16;
let result = PciArch::read_config(busdevicefunction, 0x40);
let subsystem_device_id = result as u16;
let subsystem_vendor_id = (result >> 16) as u16;
let pc_card_legacy_mode_base_address_16_bit = PciArch::read_config(busdevicefunction, 0x44);
PciDeviceStructurePciToCardbusBridge {
common_header,
cardbus_socket_ex_ca_base_address,
offset_of_capabilities_list,
reserved,
secondary_status,
pci_bus_number,
card_bus_bus_number,
subordinate_bus_number,
card_bus_latency_timer,
memory_base_address0,
memory_limit0,
memory_base_address1,
memory_limit1,
io_base_address0,
io_limit0,
io_base_address1,
io_limit1,
interrupt_line,
interrupt_pin,
bridge_control,
subsystem_device_id,
subsystem_vendor_id,
pc_card_legacy_mode_base_address_16_bit,
}
}
fn pci_check_all_buses() -> Result<u8, PciError> {
info!("Checking all devices in PCI bus...");
let busdevicefunction = BusDeviceFunction {
bus: 0,
device: 0,
function: 0,
};
let header = pci_read_header(busdevicefunction, false)?;
let common_header = header.common_header();
pci_check_bus(0)?;
if common_header.header_type & 0x80 != 0 {
for function in 1..8 {
pci_check_bus(function)?;
}
}
Ok(0)
}
fn pci_check_function(busdevicefunction: BusDeviceFunction) -> Result<u8, PciError> {
let header = match pci_read_header(busdevicefunction, true) {
Ok(header) => header,
Err(PciError::GetWrongHeader) => {
return Ok(255);
}
Err(e) => {
return Err(e);
}
};
let common_header = header.common_header();
if (common_header.class_code == 0x06)
&& (common_header.subclass == 0x04 || common_header.subclass == 0x09)
{
let pci_to_pci_bridge = header
.as_pci_to_pci_bridge_device()
.ok_or(PciError::PciDeviceStructureTransformError)?;
let secondary_bus = pci_to_pci_bridge.secondary_bus_number;
pci_check_bus(secondary_bus)?;
}
Ok(0)
}
fn pci_check_device(bus: u8, device: u8) -> Result<u8, PciError> {
let busdevicefunction = BusDeviceFunction {
bus,
device,
function: 0,
};
let header = match pci_read_header(busdevicefunction, false) {
Ok(header) => header,
Err(PciError::GetWrongHeader) => {
return Ok(255);
}
Err(e) => {
return Err(e);
}
};
pci_check_function(busdevicefunction)?;
let common_header = header.common_header();
if common_header.header_type & 0x80 != 0 {
debug!(
"Detected multi func device in bus{},device{}",
busdevicefunction.bus, busdevicefunction.device
);
for function in 1..8 {
let busdevicefunction = BusDeviceFunction {
bus,
device,
function,
};
pci_check_function(busdevicefunction)?;
}
}
Ok(0)
}
fn pci_check_bus(bus: u8) -> Result<u8, PciError> {
for device in 0..32 {
pci_check_device(bus, device)?;
}
Ok(0)
}
pub fn init() {
info!("Initializing PCI bus...");
if let Err(e) = pci_check_all_buses() {
error!("pci init failed when checking bus because of error: {}", e);
return;
}
info!(
"Total pci device and function num = {}",
PCI_DEVICE_LINKEDLIST.len()
);
let list = PCI_DEVICE_LINKEDLIST.read();
for box_pci_device in list.iter() {
let common_header = box_pci_device.common_header();
match box_pci_device.header_type() {
HeaderType::Standard if common_header.status & 0x10 != 0 => {
info!("Found pci standard device with class code ={} subclass={} status={:#x} cap_pointer={:#x} vendor={:#x}, device id={:#x}", common_header.class_code, common_header.subclass, common_header.status, box_pci_device.as_standard_device().unwrap().capabilities_pointer,common_header.vendor_id, common_header.device_id);
}
HeaderType::Standard => {
info!(
"Found pci standard device with class code ={} subclass={} status={:#x} ",
common_header.class_code, common_header.subclass, common_header.status
);
}
HeaderType::PciPciBridge => {
info!(
"Found pci-to-pci bridge device with class code ={} subclass={} status={:#x} ",
common_header.class_code, common_header.subclass, common_header.status
);
}
HeaderType::PciCardbusBridge => {
info!(
"Found pcicardbus bridge device with class code ={} subclass={} status={:#x} ",
common_header.class_code, common_header.subclass, common_header.status
);
}
HeaderType::Unrecognised(_) => {}
}
}
info!("PCI bus initialized.");
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct BusDeviceFunction {
pub bus: u8,
pub device: u8,
pub function: u8,
}
impl BusDeviceFunction {
#[allow(dead_code)]
pub fn valid(&self) -> bool {
self.device < 32 && self.function < 8
}
}
impl Display for BusDeviceFunction {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{:02x}:{:02x}.{}", self.bus, self.device, self.function)
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum MemoryBarType {
Width32,
Below1MiB,
Width64,
}
impl From<MemoryBarType> for u8 {
fn from(bar_type: MemoryBarType) -> Self {
match bar_type {
MemoryBarType::Width32 => 0,
MemoryBarType::Below1MiB => 1,
MemoryBarType::Width64 => 2,
}
}
}
impl TryFrom<u8> for MemoryBarType {
type Error = PciError;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0 => Ok(Self::Width32),
1 => Ok(Self::Below1MiB),
2 => Ok(Self::Width64),
_ => Err(PciError::InvalidBarType),
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum BarInfo {
Memory {
address_type: MemoryBarType,
prefetchable: bool,
address: u64,
size: u32,
virtaddress: u64,
},
IO {
address: u32,
size: u32,
},
Unused,
}
impl BarInfo {
pub fn memory_address_size(&self) -> Option<(u64, u32)> {
if let Self::Memory { address, size, .. } = self {
Some((*address, *size))
} else {
None
}
}
pub fn virtual_address(&self) -> Option<u64> {
if let Self::Memory { virtaddress, .. } = self {
Some(*virtaddress)
} else {
None
}
}
}
impl Display for BarInfo {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Self::Memory {
address_type,
prefetchable,
address,
size,
virtaddress,
} => write!(
f,
"Memory space at {:#010x}, size {}, type {:?}, prefetchable {},mapped at {:#x}",
address, size, address_type, prefetchable, virtaddress
),
Self::IO { address, size } => {
write!(f, "I/O space at {:#010x}, size {}", address, size)
}
Self::Unused => {
write!(f, "Unused bar")
}
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PciStandardDeviceBar {
bar0: BarInfo,
bar1: BarInfo,
bar2: BarInfo,
bar3: BarInfo,
bar4: BarInfo,
bar5: BarInfo,
}
impl PciStandardDeviceBar {
pub fn get_bar(&self, bar_index: u8) -> Result<&BarInfo, PciError> {
match bar_index {
0 => Ok(&self.bar0),
1 => Ok(&self.bar1),
2 => Ok(&self.bar2),
3 => Ok(&self.bar3),
4 => Ok(&self.bar4),
5 => Ok(&self.bar5),
_ => Err(PciError::InvalidBarType),
}
}
}
impl Display for PciStandardDeviceBar {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(
f,
"\r\nBar0:{}\r\n Bar1:{}\r\n Bar2:{}\r\n Bar3:{}\r\nBar4:{}\r\nBar5:{}",
self.bar0, self.bar1, self.bar2, self.bar3, self.bar4, self.bar5
)
}
}
impl Default for PciStandardDeviceBar {
fn default() -> Self {
PciStandardDeviceBar {
bar0: BarInfo::Unused,
bar1: BarInfo::Unused,
bar2: BarInfo::Unused,
bar3: BarInfo::Unused,
bar4: BarInfo::Unused,
bar5: BarInfo::Unused,
}
}
}
pub fn pci_bar_init(
bus_device_function: BusDeviceFunction,
) -> Result<PciStandardDeviceBar, PciError> {
let mut device_bar: PciStandardDeviceBar = PciStandardDeviceBar::default();
let mut bar_index_ignore: u8 = 255;
for bar_index in 0..6 {
if bar_index == bar_index_ignore {
continue;
}
let bar_info;
let bar_orig = PciArch::read_config(&bus_device_function, BAR0_OFFSET + 4 * bar_index);
PciArch::write_config(
&bus_device_function,
BAR0_OFFSET + 4 * bar_index,
0xffffffff,
);
let size_mask = PciArch::read_config(&bus_device_function, BAR0_OFFSET + 4 * bar_index);
let size = (!(size_mask & 0xfffffff0)).wrapping_add(1);
PciArch::write_config(&bus_device_function, BAR0_OFFSET + 4 * bar_index, bar_orig);
if size == 0 {
continue;
}
if bar_orig & 0x00000001 == 0x00000001 {
let address = bar_orig & 0xfffffffc;
bar_info = BarInfo::IO { address, size };
} else {
let mut address = u64::from(bar_orig & 0xfffffff0);
let prefetchable = bar_orig & 0x00000008 != 0;
let address_type = MemoryBarType::try_from(((bar_orig & 0x00000006) >> 1) as u8)?;
if address_type == MemoryBarType::Width64 {
if bar_index >= 5 {
return Err(PciError::InvalidBarType);
}
let address_top =
PciArch::read_config(&bus_device_function, BAR0_OFFSET + 4 * (bar_index + 1));
address |= u64::from(address_top) << 32;
bar_index_ignore = bar_index + 1; }
let paddr = PhysAddr::new(address);
let vaddr = convert_physical_to_virtual(paddr);
for i in 0..(size / 4096) {
let mut kernel_page_table = KERNEL_PAGE_TABLE.lock();
unsafe {
kernel_page_table.map_to_with_table_flags_general(
Page::containing_address(vaddr + i as u64 * 4096),
PhysFrame::containing_address(paddr + i as u64 * 4096),
PageTableFlags::PRESENT | PageTableFlags::WRITABLE,
PageTableFlags::PRESENT | PageTableFlags::WRITABLE,
)
};
}
bar_info = BarInfo::Memory {
address_type,
prefetchable,
address,
size,
virtaddress: vaddr.as_u64(),
};
}
match bar_index {
0 => {
device_bar.bar0 = bar_info;
}
1 => {
device_bar.bar1 = bar_info;
}
2 => {
device_bar.bar2 = bar_info;
}
3 => {
device_bar.bar3 = bar_info;
}
4 => {
device_bar.bar4 = bar_info;
}
5 => {
device_bar.bar5 = bar_info;
}
_ => {}
}
}
debug!("pci_device_bar:{}", device_bar);
return Ok(device_bar);
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct CapabilityInfo {
pub offset: u8,
pub id: u8,
pub private_header: u16,
}
#[derive(Debug)]
pub struct CapabilityIterator {
pub bus_device_function: BusDeviceFunction,
pub next_capability_offset: Option<u8>,
}
impl Iterator for CapabilityIterator {
type Item = CapabilityInfo;
fn next(&mut self) -> Option<Self::Item> {
let offset = self.next_capability_offset?;
let capability_header = PciArch::read_config(&self.bus_device_function, offset);
let id = capability_header as u8;
let next_offset = (capability_header >> 8) as u8;
let private_header = (capability_header >> 16) as u16;
self.next_capability_offset = if next_offset == 0 {
None
} else if next_offset < 64 || next_offset & 0x3 != 0 {
warn!("Invalid next capability offset {:#04x}", next_offset);
None
} else {
Some(next_offset)
};
Some(CapabilityInfo {
offset,
id,
private_header,
})
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct ExternalCapabilityInfo {
pub offset: u16,
pub id: u16,
pub capability_version: u8,
}
#[derive(Debug)]
pub struct ExternalCapabilityIterator<'a> {
pub root: &'a PciRoot,
pub bus_device_function: BusDeviceFunction,
pub next_capability_offset: Option<u16>,
}
impl<'a> Iterator for ExternalCapabilityIterator<'a> {
type Item = ExternalCapabilityInfo;
fn next(&mut self) -> Option<Self::Item> {
let offset = self.next_capability_offset?;
let capability_header = self.root.read_config(self.bus_device_function, offset);
let id = capability_header as u16;
let next_offset = (capability_header >> 20) as u16;
let capability_version = ((capability_header >> 16) & 0xf) as u8;
self.next_capability_offset = if next_offset == 0 {
None
} else if next_offset < 0x100 || next_offset & 0x3 != 0 {
warn!("Invalid next capability offset {:#04x}", next_offset);
None
} else {
Some(next_offset)
};
Some(ExternalCapabilityInfo {
offset,
id,
capability_version,
})
}
}