#include /************************ *** Team Kitty, 2020 *** *** Chroma *** ***********************/ /* This file contains functions for accessing the PCI bus, * and devices contained wherein. * * It allows you to query the bus, as well as communicate with individual devices. * */ pci_device_t** pci_root_devices = NULL; pci_entry_t* pci_map = NULL; //static uint32_t PCIReadConfig(uint8_t bus, uint8_t slot, uint8_t function, uint8_t offset); //static const char* PCIGetDeviceName_Subclass(uint8_t DeviceClass, uint8_t Subclass, uint8_t ProgrammableInterface); //static const char* PCIGetClassName(uint8_t DeviceClass); void PCIEnumerate() { uint8_t bus = 0, device = 0, function = 0; uint32_t registerData; uint16_t DeviceID, VendorID; uint8_t ClassCode, subclass_code; SerialPrintf("[ PCI] Started PCI Enumeration."); SerialPrintf("\n[ PCI] PCI Scan result:\n[ PCI]"); do { for (device = 0; device <= 31; device++) { for(function = 0; function <= 7; function++) { registerData = PCIReadConfig(bus, device, 0, 0xC); // Read BIST/Header/Latency/Cache Line register uint8_t header = (uint8_t) ((registerData & 0x00FF0000) >> 24); // Header is lower byte of upper word, so mask it off and shift it down uint8_t multifunction_bit = header & 0x80; // The multifunction bit is the highest bit of the header registerData = PCIReadConfig(bus, device, function, 0); // Read the Vendor/Device ID register VendorID = (uint16_t) (registerData & 0x0000FFFF); // Vendor ID is bottom word DeviceID = (uint16_t) (registerData >> 16); // Device ID is top word registerData = PCIReadConfig(bus, device, function, 8); // Read the Device Info register ClassCode = (uint16_t)( registerData >> 24); // Device class is top byte, so shift them down subclass_code = (uint16_t) ((registerData >> 16) & 0x00FF); // Device subclass is same as header - lower byte of higher word. Shift down and mask just like before. uint8_t device_progif = (uint16_t) ((registerData & 0x0000FF00) >> 8); // Device Programming Interface is higher byte of lower word, so mask and shift uint8_t device_revision = (uint16_t) (registerData & 0x000000FF); // Device revision is lower byte of whole double word. Just mask it. /* 0xFFFF is not a valid Vendor ID. This serves as a sanity check. * If this check is true, then nothing is logged and we continue for the next loop. */ if(VendorID != 0xFFFF) { SerialPrintf("[ PCI]\n[ PCI]\t%x:%x:\n[ PCI]\t\tVendor: %x\n[ PCI]\t\tDevice: %x", bus, device, VendorID, DeviceID); SerialPrintf("\n[ PCI]\t\tClass: %s\n[ PCI]\t\tDevice Type: %s\n[ PCI]\t\tRevision: %d\n", PCIGetClassName(ClassCode), PCIGetDeviceName_Subclass(ClassCode, subclass_code, device_progif), device_revision); } /* If the PCI Device header tells us that this is not a multifunction device, * and we've already scanned function 0, then there is nothing else to see. * Therefore, stop this loop and move onto device++ */ if (multifunction_bit == 0) break; } } } while (++bus); } uint32_t PCIReadConfig(uint8_t bus, uint8_t slot, uint8_t function, uint8_t offset) { uint32_t address; uint32_t busLong = (uint32_t) bus; uint32_t slotLong = (uint32_t) slot; uint32_t functionLong = (uint32_t) function; /* --------------------------------------------------------------- * | 31 | 30 ... 24 | 23 ... 16 | 15 ... 11 | 10 ... 8 | 7 ... 0 | * --------------------------------------------------------------- * | EN | RESERVED | BUS NUM | DEVICE NO | FUNC NO | REG OFF | * --------------------------------------------------------------- * * NOTE: REG OFF *must* have 0 last two bits (ie. & 0xFC) */ address = (uint32_t) (( busLong << 16 ) | ( slotLong << 11 ) | ( functionLong << 8 ) | ( offset & 0xFC) | ((uint32_t)0x80000000)); WritePort(0xCF8, address, 4); return ReadPort(0xCFC, 4); } const char* PCIGetDeviceName_Subclass(uint8_t DeviceClass, uint8_t Subclass, uint8_t ProgrammableInterface) { switch(DeviceClass) { case 0x00: { switch(Subclass) { case 0x00: return "Non-VGA-Compatible device"; case 0x01: return "VGA-Compatible device"; default: return "Unknown Unclassified"; } } case 0x01: { switch(Subclass) { case 0x00: return "SCSI Bus Controller"; case 0x01: { switch(ProgrammableInterface) { case 0x00: return "ISA Compatibility Mode-only IDE Controller"; case 0x05: return "PCI Native Mode-only IDE Controller"; case 0x0A: return "ISA Compatibility Mode IDE Controller (supports PCI Native Mode)"; case 0x0F: return "PCI Native Mode IDE Controller (supports ISA Compatibility Mode)"; case 0x80: return "ISA Compatibilty Mode-only IDE Controller (supports Bus Mastering)"; case 0x85: return "PCI Native Mode-only IDE Controller (supports Bus Mastering)"; case 0x8A: return "ISA Compatibility Mode IDE Controller (supports PCI Native Mode & Bus Mastering)"; case 0x8F: return "PCI Native Mode IDE Controller (supports ISA Compatibiliy Mode & Bus Mastering)"; default: return "IDE Controller"; } } case 0x02: return "Floppy Disk Controller"; case 0x03: return "IPI Bus Controller"; case 0x04: return "RAID Controller"; case 0x05: { switch(ProgrammableInterface) { case 0x20: return "Single-DMA ATA Controller"; case 0x30: return "Chained-DMA ATA Controller"; default: return "ATA Controller"; } } case 0x06: { switch(ProgrammableInterface) { case 0x00: return "Vendor-Specific Interface SATA Controller"; case 0x01: return "AHCI 1.0 SATA Controller"; case 0x02: return "Serial Storage Bus SATA Controller"; default: return "Serial ATA Controller"; } } case 0x07: return "Serial Attached SCSI (SAS)"; case 0x08:{ switch(ProgrammableInterface) { case 0x01: return "NVMHCI Memory Controller"; case 0x02: return "NVMe Memory Controller"; default: return "Non-Volatile Memory Controller"; } } case 0x80: return "Other"; default: return "Unknown Mass Storage Controller"; } } case 0x02: { switch(Subclass) { case 0x00: return "Ethernet Controller"; case 0x01: return "Token Ring Controller"; case 0x02: return "FDDI Controller"; case 0x03: return "ATM Controller"; case 0x04: return "ISDN Controller"; case 0x05: return "WorldFip Controller"; case 0x06: return "PICMG 2.14 Multi Computing"; case 0x07: return "Infiniband Controller"; case 0x08: return "Fabric Controller"; case 0x80: return "Other"; default: return "Unknown Network Controller"; } } case 0x03: { switch(Subclass) { case 0x00: { switch(ProgrammableInterface) { case 0x00: return "VGA Controller"; case 0x01: return "8514 VGA Controller"; default: return "VGA Compatible Controller"; } } case 0x01: return "XGA Controller"; case 0x02: return "3D Controller (Not VGA-Compatible)"; case 0x80: return "Other"; default: return "Unknown Display Controller"; } } case 0x04: { switch(Subclass) { case 0x00: return "Multimedia Video Controller"; case 0x01: return "Multimedia Audio Controller"; case 0x02: return "Computer Telephony Device"; case 0x03: return "Audio Device"; case 0x80: return "Other"; default: return "Unknown Multimedia Controller"; } } case 0x05: { switch(Subclass) { case 0x00: return "RAM Controller"; case 0x01: return "Flash Controller"; case 0x80: return "Other"; default: return "Unknown Memory Controller"; } } case 0x06: { switch(Subclass) { case 0x00: return "Host Bridge"; case 0x01: return "ISA Bridge"; case 0x02: return "EISA Bridge"; case 0x03: return "MCA Bridge"; case 0x04: case 0x09: return "PCI-to-PCI Bridge"; case 0x05: return "PCMCIA Bridge"; case 0x06: return "NuBus Bridge"; case 0x07: return "CardBus Bridge"; case 0x08: return "RACEway Bridge"; case 0x0A: return "InfiniBand-to-PCI Host Bridge"; case 0x80: return "Other"; default: return "Unknown Bridge Device"; } } case 0x07: { switch(Subclass) { case 0x00: { switch(ProgrammableInterface) { case 0x00: return "Serial Controller <8250>"; case 0x01: return "Serial controller <16450>"; case 0x02: return "Serial controller <16550>"; case 0x03: return "Serial controller <16650>"; case 0x04: return "Serial controller <16750>"; case 0x05: return "Serial controller <16850>"; case 0x06: return "Serial controller <16950>"; default: return "Serial Controller"; } } case 0x01: { switch(ProgrammableInterface) { case 0x00: return "Standard Parallel Port"; case 0x01: return "Bi-Directional Parallel Port"; case 0x02: return "ECP 1.X Compliant Parallel Port"; case 0x03: return "IEEE 1284 Parallel Controller"; case 0x04: return "IEE 1284 Parallel Target"; default: return "Parallel Controller"; } } case 0x02: return "Multiport Serial Controller"; case 0x03: { switch(ProgrammableInterface) { case 0x00: return "Generic Modem"; case 0x01: return "Hayes 16450 Compatible Modem"; case 0x02: return "Hayes 16550 Compatible Modem"; case 0x03: return "Hayes 16650 Compatible Modem"; case 0x04: return "Hayes 16750 Compatible Modem"; default: return "Modem"; } } case 0x04: return "IEEE 488.1/2 (GPIB) Controller"; case 0x05: return "Smart Card"; case 0x80: return "Other"; default: return "Unknown Simple Comms Controller"; } } case 0x08: { switch(Subclass) { case 0x00: { switch(ProgrammableInterface) { case 0x00: return "Generic 8259-Compatible PIC"; case 0x01: return "ISA-Compatible PIC"; case 0x02: return "EISA-Compatible PIC"; case 0x03: return "I/O APIC Interrupt Controller"; case 0x04: return "I/O(x) APIC Interrupt Controller"; default: return "PIC"; } } case 0x01: { switch(ProgrammableInterface) { case 0x00: return "Generic 8237-Compatible DMA Controller"; case 0x01: return "ISA-Compatible DMA Controller"; case 0x02: return "EISA-Compatible DMA Controller"; default: return "DMA Controller"; } } case 0x02: { switch(ProgrammableInterface) { case 0x00: return "Generic 8254-Compatible Timer"; case 0x01: return "ISA-Compatible Timer"; case 0x02: return "EISA-Compatible Timer"; case 0x03: return "HPET Timer"; default: return "Timer"; } } case 0x03: { switch(ProgrammableInterface) { case 0x00: return "Generic RTC Controller"; case 0x01: return "ISA-Compatible RTC Controller"; default: return "RTC Controller"; } } case 0x04: return "PCI Hot-Plug Controller"; case 0x05: return "SD Host Controller"; case 0x06: return "IOMMU"; case 0x80: return "Other"; default: return "Unknown Base System Peripheral"; } } case 0x09: { switch(Subclass) { case 0x00: return "Keyboard Controller"; case 0x01: return "Digitiser Pen"; case 0x02: return "Mouse Controller"; case 0x03: return "Scanner Controller"; case 0x04: { switch(ProgrammableInterface) { case 0x00: return "Generic Gameport Controller"; case 0x10: return "Extended Gameport Controller"; default: return "Gameport Controller"; } } case 0x80: return "Other"; default: return "Unknown Input Device Controller"; } } case 0x0A: { switch(Subclass) { case 0x00: return "Generic Docking Station"; case 0x80: return "Other"; default: return "Unknown Docking Station"; } } case 0x0B: { switch(Subclass) { case 0x00: return "386 Processor"; case 0x01: return "486 Processor"; case 0x02: return "Pentium Processor"; case 0x03: return "Pentium Pro Processor"; case 0x10: return "Alpha Processor"; case 0x20: return "PowerPC Processor"; case 0x30: return "MIPS Processor"; case 0x40: return "Co-Processor"; case 0x80: return "Other"; default: return "Unknown Processor"; } } case 0x0C: { switch(Subclass) { case 0x00: { switch(ProgrammableInterface) { case 0x00: return "Generic Firewire Controller"; case 0x10: return "OHCI Firewire Controller"; default: return "FireWire (IEEE 1394) Controller"; } } case 0x01: return "ACCESS Bus"; case 0x02: return "SSA"; case 0x03: { switch(ProgrammableInterface) { case 0x00: return "UHCI USB Controller"; case 0x10: return "OHCI USB Controller"; case 0x20: return "EHCI USB (2.0) Controller"; case 0x30: return "XHCI USB (3.0) Controller"; case 0x80: return "Unspecified USB Controller"; case 0xFE: return "USB Device (NOT a Controller)"; default: return "USB Controller"; } } case 0x04: return "Fibre Channel"; case 0x05: return "SMBus"; case 0x06: return "InfiniBand"; case 0x07: { switch(ProgrammableInterface) { case 0x00: return "SMIC IPMI Interface"; case 0x01: return "Keyboard Controller-Style IPMI Interface"; case 0x02: return "Block Transfer IPMI Interface"; default: return "IPMI Interface"; } } case 0x08: return "SERCOS Interface (IEC 61491)"; case 0x09: return "CANbus"; case 0x80: return "Other"; default: return "Unknown Serial Bus Controller"; } } case 0x0D: { switch(Subclass) { case 0x00: return "IRDA Compatible Controller"; case 0x01: return "Consumer IR Controller"; case 0x10: return "RF Controller"; case 0x11: return "Bluetooth Controller"; case 0x12: return "Broadband Controller"; case 0x20: return "Ethernet Controller (802.1a)"; case 0x21: return "Ethernet Controller (802.1b)"; case 0x80: return "Other"; default: return "Unknown Wireless Controller"; } } case 0x0E: { switch(Subclass) { case 0x00: return "I20"; default: return "Unknown Intelligent Controller"; } } case 0x0F: { switch(Subclass) { case 0x01: return "Satellite TV Controller"; case 0x02: return "Satellite Audio Controller"; case 0x03: return "Satellite Voice Controller"; case 0x04: return "Satellite Data Controller"; default: return "Unknown Satelllite Comms Controller"; } } case 0x10: { switch(Subclass) { case 0x00: return "Network & Computing Codec"; case 0x10: return "Entertainment Codec"; case 0x80: return "Other Codec"; default: return "Unknown Encryption Controller"; } } case 0x11: { switch(Subclass) { case 0x00: return "DPIO Modules"; case 0x01: return "Performance Counters"; case 0x10: return "Communication Synchronizer"; case 0x20: return "Signal Processing Management"; case 0x80: return "Other"; default: return "Unknown Signal Processing Controller"; } } case 0x12: return "Processing Accelerator"; case 0x13: return "Non-Essential Instrumentation"; case 0x14: case 0x41: return "Reserved"; case 0x40: return "Co-Processor"; case 0xFF: return "Unassigned Class"; } return "Invalid Device!"; } const char* PCIGetClassName(uint8_t DeviceClass) { switch(DeviceClass) { case 0x00: return "Unclassified"; case 0x01: return "Mass Storage Controller"; case 0x02: return "Network Controller"; case 0x03: return "Display Controller"; case 0x04: return "Multimedia Controller"; case 0x05: return "Memory Controller"; case 0x06: return "Bridge Device"; case 0x07: return "Simple Communication Controller"; case 0x08: return "Base System Peripheral"; case 0x09: return "Input Device Controller"; case 0x0A: return "Docking Station"; case 0x0B: return "Processor"; case 0x0C: return "Serial Bus Controller"; case 0x0D: return "Wireless Controller"; case 0x0E: return "Intelligent Controller"; case 0x0F: return "Satellite Communication Controller"; case 0x10: return "Encryption Controller"; case 0x11: return "Signal Processing Controller"; case 0x12: return "Processing Accelerator"; case 0x13: return "Non-Essential Instrumentation"; case 0x14: return "Reserved"; case 0x40: return "Co-Processor"; case 0x41: return "Reserved"; case 0xFF: return "Unassigned Class"; default: return "Unknown Category"; } return "Invalid device!"; }