diff --git a/kernel/bga.cpp b/kernel/bga.cpp index 2ae07eac..9a2c3f19 100644 --- a/kernel/bga.cpp +++ b/kernel/bga.cpp @@ -84,6 +84,12 @@ const uint16_t VBE_MAX_POS_VERSION = 0xB0CF; const size_t VBE_BANK_SIZE = 64UL * 1024UL; volatile uint8_t* const VBE_VIDEO_MEM = (volatile uint8_t*) 0xA0000; +static addr_t ParseDevBar0(uint32_t devaddr) +{ + pcibar_t bar = PCI::GetBAR(devaddr, 0); + return bar.addr(); +} + addr_t DetectBGAFramebuffer() { uint32_t devaddr; @@ -94,7 +100,7 @@ addr_t DetectBGAFramebuffer() pcifind.vendorid = 0x1234; pcifind.deviceid = 0x1111; if ( (devaddr = PCI::SearchForDevice(pcifind)) ) - return PCI::ParseDevBar0(devaddr); + return ParseDevBar0(devaddr); // Search for a generic VGA compatible device. memset(&pcifind, 255, sizeof(pcifind)); @@ -102,7 +108,7 @@ addr_t DetectBGAFramebuffer() pcifind.subclassid = 0x00; pcifind.progif = 0x00; if ( (devaddr = PCI::SearchForDevice(pcifind)) ) - return PCI::ParseDevBar0(devaddr); + return ParseDevBar0(devaddr); return 0; } diff --git a/kernel/include/sortix/kernel/pci.h b/kernel/include/sortix/kernel/pci.h index 154099ea..cd3d90ba 100644 --- a/kernel/include/sortix/kernel/pci.h +++ b/kernel/include/sortix/kernel/pci.h @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011, 2012. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014. This file is part of Sortix. @@ -25,6 +25,9 @@ #ifndef SORTIX_PCI_H #define SORTIX_PCI_H +#include +#include + namespace Sortix { typedef struct @@ -52,6 +55,30 @@ typedef struct uint8_t revid; } pcifind_t; +const uint8_t PCIBAR_TYPE_IOSPACE = 0x0 << 1 | 0x1 << 0; +const uint8_t PCIBAR_TYPE_16BIT = 0x1 << 1 | 0x0 << 0; +const uint8_t PCIBAR_TYPE_32BIT = 0x0 << 1 | 0x0 << 0; +const uint8_t PCIBAR_TYPE_64BIT = 0x2 << 1 | 0x0 << 0; + +typedef struct +{ +public: + uint64_t addr_raw; + uint64_t size_raw; + +public: + uint64_t addr() const { return addr_raw & 0xFFFFFFFFFFFFFFF0; } + uint64_t size() const { return size_raw & 0xFFFFFFFFFFFFFFFF; } + uint8_t type() const { return addr_raw & 0x7; } + uint32_t ioaddr() const { return addr_raw & 0xFFFFFFFC; }; + bool is_prefetchable() const { return addr_raw & 0x8; } + bool is_iospace() const { return type() == PCIBAR_TYPE_IOSPACE; } + bool is_16bit() const { return type() == PCIBAR_TYPE_16BIT; } + bool is_32bit() const { return type() == PCIBAR_TYPE_32BIT; } + bool is_64bit() const { return type() == PCIBAR_TYPE_64BIT; } + bool is_mmio() const { return is_16bit() || is_32bit() || is_64bit(); } +} pcibar_t; + namespace PCI { void Init(); @@ -66,10 +93,11 @@ void WriteRaw32(uint32_t devaddr, uint8_t off, uint32_t val); // PCI endian pciid_t GetDeviceId(uint32_t devaddr); pcitype_t GetDeviceType(uint32_t devaddr); uint32_t SearchForDevice(pcifind_t pcifind); -addr_t ParseDevBar0(uint32_t devaddr); -bool IsIOSpaceBar(uint32_t devaddr, uint8_t bar); -bool Is64BitBar(uint32_t devaddr, uint8_t bar); -uint64_t GetPCIBAR(uint32_t devaddr, uint8_t bar); +pcibar_t GetBAR(uint32_t devaddr, uint8_t bar); +pcibar_t GetExpansionROM(uint32_t devaddr); +void EnableExpansionROM(uint32_t devaddr); +void DisableExpansionROM(uint32_t devaddr); +bool IsExpansionROMEnabled(uint32_t devaddr); } // namespace PCI } // namespace Sortix diff --git a/kernel/pci.cpp b/kernel/pci.cpp index 68b655a3..e8cae90b 100644 --- a/kernel/pci.cpp +++ b/kernel/pci.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014. This file is part of Sortix. @@ -27,11 +27,14 @@ #include #include +#include #include namespace Sortix { namespace PCI { +static kthread_mutex_t pci_lock = KTHREAD_MUTEX_INITIALIZER; + const uint16_t CONFIG_ADDRESS = 0xCF8; const uint16_t CONFIG_DATA = 0xCFC; @@ -166,45 +169,85 @@ uint32_t SearchForDevice(pcifind_t pcifind) return SearchForDeviceOnBus(0, pcifind); } -// TODO: This is just a hack but will do for now. -addr_t ParseDevBar0(uint32_t devaddr) +pcibar_t GetBAR(uint32_t devaddr, uint8_t bar) { - uint32_t bar0 = Read32(devaddr, 0x10); - if ( bar0 & 0x1 ) // IO Space - return bar0 & ~0x7UL; - else // Memory Space + ScopedLock lock(&pci_lock); + + uint32_t low = PCI::Read32(devaddr, 0x10 + 4 * (bar+0)); + + pcibar_t result; + result.addr_raw = low; + result.size_raw = 0; + if ( result.is_64bit() ) { - //uint32_t type = bar0 >> 1 & 0x3; - //uint32_t prefetchable = bar0 >> 3 & 0x1; - //if ( type == 0x01 ) - // // TODO: Support 16-bit addresses here. - //if ( type == 0x02 ) - // // TODO: Support 64-bit addresses here. - return bar0 & ~0xFUL; + uint32_t high = PCI::Read32(devaddr, 0x10 + 4 * (bar+1)); + result.addr_raw |= (uint64_t) high << 32; + PCI::Write32(devaddr, 0x10 + 4 * (bar+0), 0xFFFFFFFF); + PCI::Write32(devaddr, 0x10 + 4 * (bar+1), 0xFFFFFFFF); + uint32_t size_low = PCI::Read32(devaddr, 0x10 + 4 * (bar+0)); + uint32_t size_high = PCI::Read32(devaddr, 0x10 + 4 * (bar+1)); + PCI::Write32(devaddr, 0x10 + 4 * (bar+0), low); + PCI::Write32(devaddr, 0x10 + 4 * (bar+1), high); + result.size_raw = (uint64_t) size_high << 32 | (uint64_t) size_low << 0; + result.size_raw = ~(result.size_raw & 0xFFFFFFFFFFFFFFF0) + 1; } + else if ( result.is_32bit() ) + { + PCI::Write32(devaddr, 0x10 + 4 * (bar+0), 0xFFFFFFFF); + uint32_t size_low = PCI::Read32(devaddr, 0x10 + 4 * (bar+0)); + PCI::Write32(devaddr, 0x10 + 4 * (bar+0), low); + result.size_raw = (uint64_t) size_low << 0; + result.size_raw = ~(result.size_raw & 0xFFFFFFF0) + 1; + } + else if ( result.is_iospace() ) + { + PCI::Write32(devaddr, 0x10 + 4 * (bar+0), 0xFFFFFFFF); + uint32_t size_low = PCI::Read32(devaddr, 0x10 + 4 * (bar+0)); + PCI::Write32(devaddr, 0x10 + 4 * (bar+0), low); + result.size_raw = (uint64_t) size_low << 0; + result.size_raw = ~(result.size_raw & 0xFFFFFFFC) + 1; + } + + return result; } -bool IsIOSpaceBar(uint32_t devaddr, uint8_t bar) +pcibar_t GetExpansionROM(uint32_t devaddr) { - uint32_t val = PCI::Read32(devaddr, 0x10 + 4 * bar); - return val & 0x1; + const uint32_t ROM_ADDRESS_MASK = ~UINT32_C(0x7FF); + + ScopedLock lock(&pci_lock); + + uint32_t low = PCI::Read32(devaddr, 0x30); + PCI::Write32(devaddr, 0x30, ROM_ADDRESS_MASK | low); + uint32_t size_low = PCI::Read32(devaddr, 0x30); + PCI::Write32(devaddr, 0x30, low); + + pcibar_t result; + result.addr_raw = (low & ROM_ADDRESS_MASK) | PCIBAR_TYPE_32BIT; + result.size_raw = ~(size_low & ROM_ADDRESS_MASK) + 1; + return result; } -bool Is64BitBar(uint32_t devaddr, uint8_t bar) +void EnableExpansionROM(uint32_t devaddr) { - uint32_t val = PCI::Read32(devaddr, 0x10 + 4 * bar); - return (val & 0x3 << 1) == 0x2 << 1; + ScopedLock lock(&pci_lock); + + PCI::Write32(devaddr, 0x30, PCI::Read32(devaddr, 0x30) | 0x1); } -uint64_t GetPCIBAR(uint32_t devaddr, uint8_t bar) +void DisableExpansionROM(uint32_t devaddr) { - uint64_t low = PCI::Read32(devaddr, 0x10 + 4 * (bar+0)); - if ( (low & (0x3 << 1)) != (0x2 << 1) ) - return low & 0xFFFFFFF0ULL; - uint64_t high = PCI::Read32(devaddr, 0x10 + 4 * (bar+1)); - return (low & 0xFFFFFFF0ULL) | high << 32ULL; + ScopedLock lock(&pci_lock); + + PCI::Write32(devaddr, 0x30, PCI::Read32(devaddr, 0x30) & ~UINT32_C(0x1)); } +bool IsExpansionROMEnabled(uint32_t devaddr) +{ + ScopedLock lock(&pci_lock); + + return PCI::Read32(devaddr, 0x30) & 0x1; +} void Init() {