Chroma/chroma/system/pci.c

523 lines
21 KiB
C

#include <kernel/chroma.h>
/************************
*** 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_dev_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 devclass, uint8_t subclass, uint8_t progif);
//static const char* PCIGetClassName(uint8_t devclass);
void PCIEnumerate() {
uint8_t bus = 0, device = 0, function = 0;
uint32_t registerData;
uint16_t device_id, vendor_id;
uint8_t class_code, subclass_code;
SerialPrintf("Started PCI Enumeration.");
SerialPrintf("\nPCI Scan result:\n");
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
vendor_id = (uint16_t) (registerData & 0x0000FFFF); // Vendor ID is bottom word
device_id = (uint16_t) (registerData >> 16); // Device ID is top word
registerData = PCIReadConfig(bus, device, function, 8); // Read the Device Info register
class_code = (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(vendor_id != 0xFFFF) {
SerialPrintf("\n\t%x:%x:\n\t\tVendor: %x\n\t\tDevice: %x", bus, device, vendor_id, device_id);
SerialPrintf("\n\t\tClass: %s\n\t\tDevice Type: %s\n\t\tRevision: %d\n", PCIGetClassName(class_code), PCIGetDeviceName_Subclass(class_code, 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 devclass, uint8_t subclass, uint8_t progif) {
switch(devclass) {
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(progif) {
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(progif) {
case 0x20: return "Single-DMA ATA Controller";
case 0x30: return "Chained-DMA ATA Controller";
default: return "ATA Controller";
}
}
case 0x06: {
switch(progif) {
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(progif) {
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(progif) {
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(progif) {
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(progif) {
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(progif) {
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(progif) {
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(progif) {
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(progif) {
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(progif) {
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(progif) {
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(progif) {
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(progif) {
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(progif) {
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 devclass) {
switch(devclass) {
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!";
}