From a69310a03c86f885327e3a1f0247c9e211a2d53d Mon Sep 17 00:00:00 2001 From: Matheus Date: Sat, 6 Aug 2022 21:34:52 -0300 Subject: [PATCH] PCI enumeration --- src/arch/x86_64/include/arch/acpi.h | 15 ++++ src/arch/x86_64/include/arch/io.h | 14 ++- src/arch/x86_64/include/arch/pci.h | 56 ++++++++++++ src/arch/x86_64/main.c | 2 + src/arch/x86_64/pci.c | 134 ++++++++++++++++++++++++++++ 5 files changed, 219 insertions(+), 2 deletions(-) create mode 100644 src/arch/x86_64/include/arch/pci.h create mode 100644 src/arch/x86_64/pci.c diff --git a/src/arch/x86_64/include/arch/acpi.h b/src/arch/x86_64/include/arch/acpi.h index 92152343..d5c00b45 100644 --- a/src/arch/x86_64/include/arch/acpi.h +++ b/src/arch/x86_64/include/arch/acpi.h @@ -45,6 +45,21 @@ typedef struct { uint32_t flags; } __attribute__((packed)) madt_t; +typedef struct { + uint64_t address; + uint16_t segmentgroup; + uint8_t startbus; + uint8_t endbus; + uint32_t reserved; + +} __attribute__((packed)) mcfgentry; + +typedef struct { + sdt_t header; + uint64_t reserved; + mcfgentry entries[]; +} __attribute__((packed)) mcfg_t; + void* acpi_gettable(char* sig, size_t n); void acpi_init(); bool acpi_checksumok(sdt_t* table); diff --git a/src/arch/x86_64/include/arch/io.h b/src/arch/x86_64/include/arch/io.h index 762a8bb0..a419216f 100644 --- a/src/arch/x86_64/include/arch/io.h +++ b/src/arch/x86_64/include/arch/io.h @@ -1,13 +1,23 @@ #ifndef _IO_H_INCLUDE #define _IO_H_INCLUDE +static inline void outd(uint16_t port, uint32_t data){ + asm volatile("out %%eax, %%dx" : : "a"(data), "d"(port)); +} + +static inline uint32_t ind(uint16_t port){ + uint32_t ret; + asm volatile("in %%dx, %%eax" : "=a"(ret) : "d"(port)); + return ret; +} + static inline void outb(uint16_t port, uint8_t data){ - asm("out %%al, %%dx" : : "a"(data), "d"(port)); + asm volatile("out %%al, %%dx" : : "a"(data), "d"(port)); } static inline uint8_t inb(uint16_t port){ uint8_t ret; - asm("in %%dx, %%al" : "=a"(ret) : "d"(port)); + asm volatile ("in %%dx, %%al" : "=a"(ret) : "d"(port)); return ret; } diff --git a/src/arch/x86_64/include/arch/pci.h b/src/arch/x86_64/include/arch/pci.h new file mode 100644 index 00000000..9d26017b --- /dev/null +++ b/src/arch/x86_64/include/arch/pci.h @@ -0,0 +1,56 @@ +#ifndef _PCI_H_INCLUDE +#define _PCI_H_INCLUDE + +#include +#include + +#define PCI_DEV_HEADER 0 +#define PCI_BRIDGE_HEADER 1 +#define PCI_CARDBUS_HEADER 2 + +#define PCI_CARDBUS_HEADERSIZE 0x48 +#define PCI_OTHER_HEADERSIZE 0x40 + +typedef struct{ + uint16_t vendor; + uint16_t device; + uint16_t command; + uint16_t status; + uint8_t revision; + uint8_t progif; + uint8_t subclass; + uint8_t class; + uint8_t cachesize; + uint8_t latencytimer; + uint8_t type; + uint8_t bist; +} __attribute__((packed)) pci_common; + +typedef struct{ + pci_common common; + uint32_t BAR[6]; + uint32_t cardbuscis; + uint16_t subsystemvendor; + uint16_t subsystem; + uint32_t rombase; + uint8_t capabilities; + uint8_t r[3]; + uint32_t reserved; + uint8_t interruptline; + uint8_t interruptpin; + uint8_t mingrant; + uint8_t maxgrant; +} __attribute__((packed)) pci_deviceheader; + +typedef struct _pci_enumeration{ + struct pci_enumeration* next; + uint8_t bus; + uint8_t device; + uint8_t function; + pci_common* header; +} pci_enumeration; + + +void pci_enumerate(); + +#endif diff --git a/src/arch/x86_64/main.c b/src/arch/x86_64/main.c index 94fcf15e..aaf89b05 100644 --- a/src/arch/x86_64/main.c +++ b/src/arch/x86_64/main.c @@ -65,6 +65,8 @@ void kmain(){ apic_init(); apic_lapicinit(); + + pci_enumerate(); smp_init(); diff --git a/src/arch/x86_64/pci.c b/src/arch/x86_64/pci.c new file mode 100644 index 00000000..fe6d695d --- /dev/null +++ b/src/arch/x86_64/pci.c @@ -0,0 +1,134 @@ +#include +#include +#include +#include +#include + +pci_enumeration* enumerations; + +#define CONFIG_ADDRESS 0xCF8 +#define CONFIG_DATA 0xCFC + +uint32_t legacy_readdata(int bus, int device, int func, int reg){ + + uint32_t address = reg << 2; + address |= (func & 0b111) << 8; + address |= (device & 0b11111) << 11; + address |= (bus & 0xFF) << 16; + address |= 1 << 31; + + outd(CONFIG_ADDRESS, address); + + return ind(CONFIG_DATA); + +} + +static inline bool legacy_exists(int bus, int device, int func){ + return legacy_readdata(bus, device, func, 0) != 0xFFFFFFFF; +} + +static pci_enumeration* allocnewenum(){ + + pci_enumeration* enumeration; + + if(!enumerations){ + enumeration = alloc(sizeof(pci_enumeration)); + } + else{ + while(enumeration->next != NULL) + enumeration = enumeration->next; + + enumeration->next = alloc(sizeof(pci_enumeration)); + enumeration = enumeration->next; + } + + return enumeration; +} + +static void legacy_copyheader(pci_enumeration* dev, size_t size){ + size_t count = size / 4; + uint32_t* where = (uint32_t*)dev->header; + + for(size_t i = 0; i < count; ++i) + *where++ = legacy_readdata(dev->bus, dev->device, dev->function, i); + +} + + + +static size_t legacy_getcapabilityoffset(size_t id, pci_enumeration* enumeration){ + + // does this device have a capability list + + if(enumeration->header->status & (1 << 4) == 0) return 0; + + size_t offset = ((pci_deviceheader*)enumeration->header)->capabilities>> 2; + + while(offset){ + uint32_t word = legacy_readdata(enumeration->bus, enumeration->device, enumeration->function, offset); + + size_t targetid = word & 0xFF; + + if(targetid == id) + return offset; + + offset = (word >> 8) & 0xFF; + offset >>= 2; + + } + + return 0; + +} + +static void legacy_enumeratedevice(int bus, int device){ + + // if the device is multifunction, scan and enumerate all 8. else, only one + + size_t functioncount = ((legacy_readdata(bus, device, 0, 3) >> 16) & 0xFF) != 0 ? 8 : 1; + + for(size_t function = 0; function < functioncount; ++function){ + if(!legacy_exists(bus, device, function)) + continue; + + pci_enumeration* enumeration = allocnewenum(); + + enumeration->bus = bus; + enumeration->device = device; + enumeration->function = function; + + // type with multifunction masked off + size_t type = (legacy_readdata(bus, device, function, 3) >> 16) & 0x7F; + + size_t headersize = type == PCI_CARDBUS_HEADER ? PCI_CARDBUS_HEADERSIZE : PCI_OTHER_HEADERSIZE; + + enumeration->header = alloc(headersize); + + legacy_copyheader(enumeration, headersize); + + printf("PCI: %02x:%02x.%x %02x%02x: %04x:%04x (rev %2x) \n", bus, device, function, enumeration->header->class, enumeration->header->subclass, enumeration->header->vendor, enumeration->header->device, enumeration->header->revision); + } + +} + +static void legacy_enumeration(){ + + for(size_t bus = 0; bus < 1; ++bus){ + for(size_t device = 0; device < 32; ++device){ + if(legacy_exists(bus, device, 0)) + legacy_enumeratedevice(bus, device); + } + } + +} + + + +void pci_enumerate(){ + + // TODO PCIe enumeration + + legacy_enumeration(); + + +}