use bitfield_struct::bitfield; use mammoth::{mem::MemoryRegion, zion::ZError}; #[bitfield(u16)] pub struct PciCommand { io_space_enable: bool, memory_space_enable: bool, bus_master_enable: bool, #[bits(access=RO)] special_cycles_enable: bool, #[bits(access=RO)] memory_write_and_invalidate_enable: bool, #[bits(access=RO)] vga_pallette_snoop_enable: bool, parity_error_response_enable: bool, #[bits(access=RO)] wait_cycle_enable: bool, serr_enable: bool, fast_back_to_back_enable: bool, /// Parity is reversed here, set to true to disable. /// Does not affect MSI. pub interrupt_disable: bool, #[bits(5)] __: u8, } #[bitfield(u16)] pub struct PciStatus { #[bits(3)] __: u8, #[bits(access=RO)] pub interrupt_status: bool, #[bits(access=RO)] pub capability_list: bool, #[bits(access=RO)] pub capable_of_66mhz: bool, ___: bool, #[bits(access=RO)] pub fast_back_to_back_capabale: bool, /// Write 1 to clear pub master_data_parity_error: bool, #[bits(2, access=RO)] pub devsel_timing: u8, /// Write 1 to clear pub signaled_target_abort: bool, /// Write 1 to clear pub received_target_abort: bool, /// Write 1 to clear pub received_master_abort: bool, /// Write 1 to clear pub signaled_system_erro: bool, /// Write 1 to clear pub detected_parity_error: bool, } /// Header definitions from https://wiki.osdev.org/PCI #[repr(C, packed)] #[derive(Debug)] pub struct HeaderShared { pub vendor_id: u16, pub device_id: u16, pub command: PciCommand, pub status: PciStatus, 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, bist: u8, } const _: () = assert!(size_of::() == 16); #[repr(C, packed)] #[derive(Debug)] pub struct PciDeviceHeader { pub vendor_id: u16, pub device_id: u16, pub command: PciCommand, pub status: PciStatus, 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, bist: u8, pub bars: [u32; 6], pub cardbus_cis_ptr: u32, pub subsystem_vendor_id: u16, pub subsystem_id: u16, pub expansion_rom_address: u32, pub capability_ptr: u8, __: [u8; 7], pub interrupt_line: u8, pub interrupt_pin: u8, pub min_grant: u8, pub max_latency: u8, } const _: () = assert!(size_of::() == 0x40); #[repr(C, packed)] #[derive(Debug)] pub struct PciCapabilityPointer { pub cap_id: u8, pub next_cap_offset: u8, } #[bitfield(u16)] pub struct PciMsiControl { pub msi_enable: bool, #[bits(3, access=RO)] pub multi_message_capable: u8, #[bits(3)] pub multi_message_enable: u8, #[bits(access=RO)] pub capable_address_64: bool, #[bits(access=RO)] pub per_vector_masking: bool, #[bits(7)] __: u8, } #[repr(C, packed)] #[derive(Debug)] pub struct PciMsiCapability { pub cap_id: u8, pub next_cap_offset: u8, pub msi_control: PciMsiControl, pub msi_addr_lower: u32, pub msi_addr_upper_or_data: u32, pub msi_data_if_64: u32, pub mask: u32, pub pending: u32, } #[derive(Debug)] pub enum PciHeaderType { Device, PciBridge, CardBusBridge, } pub fn get_header_type(memory_region: &MemoryRegion) -> Result { let shared: &HeaderShared = memory_region.as_ref(); // The only reference I can find to the high bit here is at // https://www.khoury.northeastern.edu/~pjd/cs7680/homework/pci-enumeration.html // > Header Type: bit 7 (0x80) indicates whether it is a multi-function device, match shared.header_type & (!0x80) { 0x0 => Ok(PciHeaderType::Device), 0x1 => Ok(PciHeaderType::PciBridge), 0x2 => Ok(PciHeaderType::CardBusBridge), _ => { mammoth::debug!("Unknown pci header type: {:#x}", shared.header_type); Err(ZError::INVALID_ARGUMENT) } } }