//----------------------------------------------------------------------------// // OS on Kaleid // // // // Desc: PCI driver // // // // // // Copyright © 2018-2020 The OS/K Team // // // // This file is part of OS/K. // // // // OS/K is free software: you can redistribute it and/or modify // // it under the terms of the GNU General Public License as published by // // the Free Software Foundation, either version 3 of the License, or // // any later version. // // // // OS/K is distributed in the hope that it will be useful, // // but WITHOUT ANY WARRANTY//without even the implied warranty of // // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // // GNU General Public License for more details. // // // // You should have received a copy of the GNU General Public License // // along with OS/K. If not, see . // //----------------------------------------------------------------------------// #include #include #include static void *pciConfigBaseAddress = NULL; static MCFG_t *MCFG_table = NULL; // -------------------------------------------------------------------------- // static inline void* pciGetConfigAddr(uchar bus, uchar device, uchar function, ushort offset) { if(device > 32) { DebugLog("pciGetConfigAddr(): bad device ID\n"); return 0; } if(function > 8) { DebugLog("pciGetConfigAddr(): bad function ID\n"); return 0; } if(offset > 4096) { DebugLog("pciGetConfigAddr(): bad register offset\n"); return 0; } return (void*)(bus*32*8*4096 + device*8*4096 + function*4096 + offset + (ulong)pciConfigBaseAddress); } static inline uchar pciReadConfigByte(uchar bus, uchar device, uchar function, ushort offset) { return *((uchar*)(pciGetConfigAddr(bus, device, function, offset))); } static inline ushort pciReadConfigWord(uchar bus, uchar device, uchar function, ushort offset) { return *((ushort*)(pciGetConfigAddr(bus, device, function, offset))); } static inline uint pciReadConfigDWord(uchar bus, uchar device, uchar function, ushort offset) { return *((uint*)(pciGetConfigAddr(bus, device, function, offset))); } //----------------------------------------------------------------------------// uchar IoPciReadConfigByte(PciDev_t *device, ushort offset) { return *((uchar *)((ulong)device->configAddr + offset)); } ushort IoPciReadConfigWord(PciDev_t *device, ushort offset) { return *((ushort *)((ulong)device->configAddr + offset)); } uint IoPciReadConfigDWord(PciDev_t *device, ushort offset) { return *((uint *)((ulong)device->configAddr + offset)); } void IoPciWriteConfigByte(PciDev_t *device, ushort offset, uchar data) { memmove((void *)((ulong)device->configAddr + offset), &data, 1); } void IoPciWriteConfigWord(PciDev_t *device, ushort offset, ushort data) { memmove((void *)((ulong)device->configAddr + offset), &data, 2); } void IoPciWriteConfigDWord(PciDev_t *device, ushort offset, uint data) { memmove((void *)((ulong)device->configAddr + offset), &data, 4); } void IoPciEnumerate() { if(pciConfigBaseAddress == NULL) { KeStartPanic("Unable to access PCI configuration : MCFG table not reachable\n"); return; } for(ushort bus = 0; bus < 256; bus++) { for(uchar device = 0; device < 32; device++) { for(uchar function = 0; function < 8; function++) { ushort vendor = pciReadConfigWord((uchar)bus, device, function, PCI_REG_VENDOR); if(bus * device * function > MCFG_table->length) break; if(vendor == 0xffff) continue; DebugLog("PCI device class: %x, subclass: %x, vendor: %x, device: %x\n", pciReadConfigByte((uchar)bus, device, function, PCI_REG_CLASS), pciReadConfigByte((uchar)bus, device, function, PCI_REG_SUBCLASS), vendor, pciReadConfigWord((uchar)bus, device, function, PCI_REG_DEVICE) ); } } } } PciDev_t *IoPciGetDevice(ushort vendorID, ushort deviceID) { if(pciConfigBaseAddress == NULL) { KeStartPanic("Unable to access PCI configuration : MCFG table not reachable\n"); return NULL; } for(ushort bus = 0; bus < 256; bus++) { for(uchar device = 0; device < 32; device++) { for(uchar function = 0; function < 8; function++) { if(vendorID == pciReadConfigWord((uchar)bus, device, function, PCI_REG_VENDOR) && deviceID == pciReadConfigWord((uchar)bus, device, function, PCI_REG_DEVICE)) { if(bus * device * function > MCFG_table->length) break; PciDev_t *pciDevicePtr = (PciDev_t *)malloc(sizeof(PciDev_t)); pciDevicePtr->vendorID = vendorID; pciDevicePtr->deviceID = deviceID; pciDevicePtr->classID = pciReadConfigByte((uchar)bus, device, function, PCI_REG_CLASS); pciDevicePtr->subclassID = pciReadConfigByte((uchar)bus, device, function, PCI_REG_SUBCLASS); pciDevicePtr->configAddr = pciGetConfigAddr((uchar)bus, device, function, 0); return pciDevicePtr; } } } } return NULL; } PciDev_t *IoPciGetDeviceByClass(uchar classID, uchar subclassID) { if(pciConfigBaseAddress == NULL) { KeStartPanic("Unable to access PCI configuration : MCFG table not reachable\n"); return NULL; } for(ushort bus = 0; bus < 256; bus++) { for(uchar device = 0; device < 32; device++) { for(uchar function = 0; function < 8; function++) { if(classID == pciReadConfigByte((uchar)bus, device, function, PCI_REG_CLASS) && subclassID == pciReadConfigByte((uchar)bus, device, function, PCI_REG_SUBCLASS)) { PciDev_t *pciDevicePtr = (PciDev_t *)malloc(sizeof(PciDev_t)); pciDevicePtr->vendorID = pciReadConfigWord((uchar)bus, device, function, PCI_REG_VENDOR); pciDevicePtr->deviceID = pciReadConfigWord((uchar)bus, device, function, PCI_REG_DEVICE); pciDevicePtr->classID = classID; pciDevicePtr->subclassID = subclassID; pciDevicePtr->configAddr = pciGetConfigAddr((uchar)bus, device, function, 0); return pciDevicePtr; } } } } return NULL; } void IoInitPCI() { MCFG_table = (MCFG_t*)IoGetAcpiTable(SDT_MCFG); if(MCFG_table == NULL) { KeStartPanic("Unable to access PCI configuration : MCFG table not reachable\n"); } pciConfigBaseAddress = MCFG_table->pciConfigBaseAddress; DebugLog("PCI Config Base address = 0x%p\n", pciConfigBaseAddress); // Give R/W access to the configuration space int maxI = (MCFG_table->length) / KPAGESIZE; // More secure, for(int i=0; i < maxI; i++) { // XXX verify that page is marked busy MmMapPage((void *)((ulong)pciConfigBaseAddress + i * KPAGESIZE), (void *)((ulong)pciConfigBaseAddress + i * KPAGESIZE), PRESENT | READWRITE); } IoPciEnumerate(); }