os-k/kaleid/kernel/io/pci.c

176 lines
6.3 KiB
C

//----------------------------------------------------------------------------//
// GNU GPL OS/K //
// //
// 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 <https://www.gnu.org/licenses/>. //
//----------------------------------------------------------------------------//
#include <io/pci.h>
#include <io/acpi.h>
#include <mm/paging.h>
void* pciConfigBaseAddress = NULL;
static inline void* pciGetConfigAddr(uchar bus, uchar device,
uchar function, ushort offset)
{
if(device > 32) {
KernLog("pciGetConfigAddr(): bad device ID\n");
return 0;
}
if(function > 8) {
KernLog("pciGetConfigAddr(): bad function ID\n");
return 0;
}
if(offset > 4096) {
KernLog("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) {
KernLog("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(vendor == 0xffff) continue;
DebugLog("PCI device found ! vendor: %x, device: %x\n",
vendor,
pciReadConfigWord((uchar)bus, device, function, PCI_REG_DEVICE)
);
}
}
}
}
PciDev_t *IoPciGetDevice(ushort vendorID, ushort deviceID)
{
if(pciConfigBaseAddress == NULL) {
KernLog("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)) {
PciDev_t *pciDevicePtr = (PciDev_t *)malloc(sizeof(PciDev_t));
pciDevicePtr->vendorID = vendorID;
pciDevicePtr->deviceID = deviceID;
pciDevicePtr->configAddr = pciGetConfigAddr((uchar)bus, device, function, 0);
return pciDevicePtr;
}
}
}
}
return NULL;
}
void IoInitPCI()
{
struct MCFG_t *MCFG_table = (struct MCFG_t*)IoGetAcpiTable(SDT_MCFG);
if(MCFG_table == NULL) {
KernLog("Unable to access PCI configuration : MCFG table not reachable\n");
}
pciConfigBaseAddress = MCFG_table->pciConfigBaseAddress;
DebugLog("PCI Config Base address = 0x%p\n", pciConfigBaseAddress);
IoPciEnumerate();
// Give R/W access to the configuration space
for(int i=0; i < 65536; i++) // 65536 = 256 * 32 * 8
{
// 4096 for page size TODO: use of KPAGESIZE
MmMapPage((void *)((ulong)pciConfigBaseAddress + i * 4096),
(void *)((ulong)pciConfigBaseAddress + i * 4096), PRESENT | READWRITE);
}
}