From 4f7c5ebdd3422cc828047d1e76b4205d0d1fa778 Mon Sep 17 00:00:00 2001 From: Jonas 'Sortie' Termansen Date: Fri, 16 Jan 2015 01:19:05 +0100 Subject: [PATCH] Fix PCI code. --- kernel/Makefile | 1 + kernel/include/sortix/kernel/pci.h | 73 ++++++++++++++++++++++++--- kernel/pci.cpp | 53 ++++++++++++++------ kernel/x86-family/ioport.cpp | 80 ++++++++++++++++++++++++++++++ 4 files changed, 184 insertions(+), 23 deletions(-) create mode 100644 kernel/x86-family/ioport.cpp diff --git a/kernel/Makefile b/kernel/Makefile index e7d09076..03d771c7 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -45,6 +45,7 @@ ifdef X86FAMILY x86-family/memorymanagement.o \ $(CPU)/interrupt.o \ x86-family/interrupt.o \ + x86-family/ioport.o \ x86-family/pic.o \ x86-family/gdt.o \ x86-family/idt.o \ diff --git a/kernel/include/sortix/kernel/pci.h b/kernel/include/sortix/kernel/pci.h index f4a4a770..5dd37482 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, 2013, 2014. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014, 2015. This file is part of Sortix. @@ -55,10 +55,10 @@ 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; +static const uint8_t PCIBAR_TYPE_IOSPACE = 0x0 << 1 | 0x1 << 0; +static const uint8_t PCIBAR_TYPE_16BIT = 0x1 << 1 | 0x0 << 0; +static const uint8_t PCIBAR_TYPE_32BIT = 0x0 << 1 | 0x0 << 0; +static const uint8_t PCIBAR_TYPE_64BIT = 0x2 << 1 | 0x0 << 0; typedef struct { @@ -67,9 +67,12 @@ public: uint64_t size_raw; public: - uint64_t addr() const { return addr_raw & 0xFFFFFFFFFFFFFFF0; } + uint64_t addr() const { return is_iospace() ? + addr_raw & 0xFFFFFFFFFFFFFFFC : + addr_raw & 0xFFFFFFFFFFFFFFF0; } uint64_t size() const { return size_raw & 0xFFFFFFFFFFFFFFFF; } - uint8_t type() const { return addr_raw & 0x7; } + uint8_t type() const { return (addr_raw & 3) == PCIBAR_TYPE_IOSPACE ? + (addr_raw & 3) : (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; } @@ -79,6 +82,60 @@ public: bool is_mmio() const { return is_16bit() || is_32bit() || is_64bit(); } } pcibar_t; +static const uint8_t PCIFIELD_VENDOR_ID = 0x00; +static const uint8_t PCIFIELD_DEVICE_ID = 0x02; +static const uint8_t PCIFIELD_COMMAND = 0x04; +static const uint8_t PCIFIELD_STATUS = 0x06; +static const uint8_t PCIFIELD_REVISION_ID = 0x08; +static const uint8_t PCIFIELD_PROG_IF = 0x09; +static const uint8_t PCIFIELD_SUBCLASS = 0x0A; +static const uint8_t PCIFIELD_CLASS = 0x0B; +static const uint8_t PCIFIELD_CACHE_LINE_SIZE = 0x0C; +static const uint8_t PCIFIELD_LATENCY_TIMER = 0x0D; +static const uint8_t PCIFIELD_HEADER_TYPE = 0x0E; +static const uint8_t PCIFIELD_BIST = 0x0F; +static const uint8_t PCIFIELD_RAW_BAR0 = 0x10; +static const uint8_t PCIFIELD_RAW_BAR1 = 0x14; +static const uint8_t PCIFIELD_RAW_BAR2 = 0x18; +static const uint8_t PCIFIELD_PRIMARY_BUS_NUMBER = 0x18; +static const uint8_t PCIFIELD_SECONDARY_BUS_NUMBER = 0x19; +static const uint8_t PCIFIELD_SUBORDINATE_BUS_NUMBER = 0x1A; +static const uint8_t PCIFIELD_SECONDARY_LATENCY_TIMER = 0x1B; +static const uint8_t PCIFIELD_RAW_BAR3 = 0x1C; +static const uint8_t PCIFIELD_IO_BASE = 0x1C; +static const uint8_t PCIFIELD_IO_LIMIT = 0x1D; +static const uint8_t PCIFIELD_SECONDARY_STATUS = 0x1E; +static const uint8_t PCIFIELD_RAW_BAR4 = 0x20; +static const uint8_t PCIFIELD_MEMORY_BASE = 0x20; +static const uint8_t PCIFIELD_MEMORY_LIMIT = 0x22; +static const uint8_t PCIFIELD_RAW_BAR5 = 0x24; +static const uint8_t PCIFIELD_PREFETCHABLE_MEMORY_BASE = 0x24; +static const uint8_t PCIFIELD_PREFETCHABLE_MEMORY_LIMIT = 0x26; +static const uint8_t PCIFIELD_CARDBUS_CIS_POINTER = 0x28; +static const uint8_t PCIFIELD_PREFETCHABLE_BASE_UPPER_BITS = 0x28; +static const uint8_t PCIFIELD_SUBSYSTEM_VENDOR_ID = 0x2C; +static const uint8_t PCIFIELD_PREFETCHABLE_LIMIT_UPPER_BITS = 0x2C; +static const uint8_t PCIFIELD_SUBSYSTEM_ID = 0x2E; +static const uint8_t PCIFIELD_EXPANSION_ROM_BASE_ADDRESS = 0x30; +static const uint8_t PCIFIELD_CAPABILITIES = 0x34; +static const uint8_t PCIFIELD_EXPANSION_ROM_BASE_ADDRESS_PCI_BRIDGE = 0x38; +static const uint8_t PCIFIELD_INTERRUPT_LINE = 0x3C; +static const uint8_t PCIFIELD_INTERRUPT_PIN = 0x3D; +static const uint8_t PCIFIELD_MIN_GRANT = 0x3E; +static const uint8_t PCIFIELD_MAX_LATENCY = 0x3F; +static const uint8_t PCIFIELD_BRIDGE_CONTROL = 0x3E; + +static const uint16_t PCIFIELD_COMMAND_IO_SPACE = 1 << 0; +static const uint16_t PCIFIELD_COMMAND_MEMORY_SPACE = 1 << 1; +static const uint16_t PCIFIELD_COMMAND_BUS_MASTER = 1 << 2; +static const uint16_t PCIFIELD_COMMAND_SPECIAL_CYCLES = 1 << 3; +static const uint16_t PCIFIELD_COMMAND_MEMORY_WRITE_AND_INVALIDATE = 1 << 4; +static const uint16_t PCIFIELD_COMMAND_VGA_PALETTE_SNOOP = 1 << 5; +static const uint16_t PCIFIELD_COMMAND_PARITY_ERROR_RESPONSE = 1 << 6; +static const uint16_t PCIFIELD_COMMAND_SERR = 1 << 8; +static const uint16_t PCIFIELD_COMMAND_FAST_BACK_TO_BACK = 1 << 9; +static const uint16_t PCIFIELD_COMMAND_INTERRUPT_DISABLE = 1 << 10; + namespace PCI { void Init(); @@ -88,6 +145,8 @@ uint8_t Read8(uint32_t devaddr, uint8_t off); // Host endian uint16_t Read16(uint32_t devaddr, uint8_t off); // Host endian uint32_t Read32(uint32_t devaddr, uint8_t off); // Host endian uint32_t ReadRaw32(uint32_t devaddr, uint8_t off); // PCI endian +void Write8(uint32_t devaddr, uint8_t off, uint8_t val); // Host endian +void Write16(uint32_t devaddr, uint8_t off, uint16_t val); // Host endian void Write32(uint32_t devaddr, uint8_t off, uint32_t val); // Host endian void WriteRaw32(uint32_t devaddr, uint8_t off, uint32_t val); // PCI endian pciid_t GetDeviceId(uint32_t devaddr); diff --git a/kernel/pci.cpp b/kernel/pci.cpp index cb0dcc48..c18a643f 100644 --- a/kernel/pci.cpp +++ b/kernel/pci.cpp @@ -56,12 +56,14 @@ void SplitDevAddr(uint32_t devaddr, uint8_t* vals /* bus, slot, func */) uint32_t ReadRaw32(uint32_t devaddr, uint8_t off) { + assert((off & 0x3) == 0); outport32(CONFIG_ADDRESS, devaddr + off); return inport32(CONFIG_DATA); } void WriteRaw32(uint32_t devaddr, uint8_t off, uint32_t val) { + assert((off & 0x3) == 0); outport32(CONFIG_ADDRESS, devaddr + off); outport32(CONFIG_DATA, val); } @@ -76,23 +78,42 @@ void Write32(uint32_t devaddr, uint8_t off, uint32_t val) WriteRaw32(devaddr, off, htole32(val)); } +void Write16(uint32_t devaddr, uint8_t off, uint16_t val) +{ + assert((off & 0x1) == 0); + uint8_t alignedoff = off & ~0x3; + union { uint8_t val8[4]; uint32_t val32; }; + val32 = ReadRaw32(devaddr, alignedoff); + val8[(off & 0x3) + 0] = val >> 0 & 0xFF; + val8[(off & 0x3) + 1] = val >> 8 & 0xFF; + WriteRaw32(devaddr, alignedoff, val32); +} + uint16_t Read16(uint32_t devaddr, uint8_t off) { assert((off & 0x1) == 0); uint8_t alignedoff = off & ~0x3; - union { uint16_t val16[2]; uint32_t val32; }; + union { uint8_t val8[4]; uint32_t val32; }; val32 = ReadRaw32(devaddr, alignedoff); - uint16_t ret = off & 0x2 ? val16[0] : val16[1]; - return le16toh(ret); + return (uint16_t) val8[(off & 0x3) + 0] << 0 | + (uint16_t) val8[(off & 0x3) + 1] << 8; +} + +void Write8(uint32_t devaddr, uint8_t off, uint8_t val) +{ + uint8_t alignedoff = off & ~0x3; + union { uint8_t val8[4]; uint32_t val32; }; + val32 = ReadRaw32(devaddr, alignedoff); + val8[(off & 0x3)] = val; + WriteRaw32(devaddr, alignedoff, val32); } uint8_t Read8(uint32_t devaddr, uint8_t off) { - uint8_t alignedoff = off & ~0x1; - union { uint8_t val8[2]; uint32_t val16; }; - val16 = htole16(Read16(devaddr, alignedoff)); - uint8_t ret = off & 0x1 ? val8[0] : val8[1]; - return ret; + uint8_t alignedoff = off & ~0x3; + union { uint8_t val8[4]; uint32_t val32; }; + val32 = ReadRaw32(devaddr, alignedoff); + return val8[(off & 0x3)]; } uint32_t CheckDevice(uint8_t bus, uint8_t slot, uint8_t func) @@ -103,18 +124,18 @@ uint32_t CheckDevice(uint8_t bus, uint8_t slot, uint8_t func) pciid_t GetDeviceId(uint32_t devaddr) { pciid_t ret; - ret.deviceid = Read16(devaddr, 0x00); - ret.vendorid = Read16(devaddr, 0x02); + ret.deviceid = Read16(devaddr, PCIFIELD_DEVICE_ID); + ret.vendorid = Read16(devaddr, PCIFIELD_VENDOR_ID); return ret; } pcitype_t GetDeviceType(uint32_t devaddr) { pcitype_t ret; - ret.classid = Read8(devaddr, 0x08); - ret.subclassid = Read8(devaddr, 0x09); - ret.progif = Read8(devaddr, 0x0A); - ret.revid = Read8(devaddr, 0x0B); + ret.classid = Read8(devaddr, PCIFIELD_CLASS); + ret.subclassid = Read8(devaddr, PCIFIELD_SUBCLASS); + ret.progif = Read8(devaddr, PCIFIELD_PROG_IF); + ret.revid = Read8(devaddr, PCIFIELD_REVISION_ID); return ret; } @@ -155,12 +176,12 @@ static uint32_t SearchForDevicesOnBus(uint8_t bus, pcifind_t pcifind, uint32_t l (!found_any_device || devaddr < next_device) && MatchesSearchCriteria(devaddr, pcifind) ) next_device = devaddr, found_any_device = true; - uint8_t header = Read8(devaddr, 0x0D); // Secondary Bus Number. + uint8_t header = Read8(devaddr, PCIFIELD_HEADER_TYPE); if ( header & 0x80 ) // Multi function device. num_functions = 8; if ( (header & 0x7F) == 0x01 ) // PCI to PCI bus. { - uint8_t subbusid = Read8(devaddr, 0x1A); + uint8_t subbusid = Read8(devaddr, PCIFIELD_SECONDARY_BUS_NUMBER); uint32_t recret = SearchForDevicesOnBus(subbusid, pcifind, last); if ( last < recret && (!found_any_device || recret < next_device) ) diff --git a/kernel/x86-family/ioport.cpp b/kernel/x86-family/ioport.cpp new file mode 100644 index 00000000..62c286aa --- /dev/null +++ b/kernel/x86-family/ioport.cpp @@ -0,0 +1,80 @@ +/******************************************************************************* + + Copyright(C) Jonas 'Sortie' Termansen 2014, 2015. + + This file is part of Sortix. + + Sortix 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 (at your option) any later + version. + + Sortix 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 + Sortix. If not, see . + + x86-family/ioport.cpp + IO ports. + +*******************************************************************************/ + +#include +#include + +#include + +#include +#include +#include + +namespace Sortix { + +bool wait_inport8_clear(uint16_t ioport, uint8_t bits, bool any, unsigned int msecs) +{ + struct timespec timeout = timespec_make(msecs / 1000, (msecs % 1000) * 1000000L); + Clock* clock = Time::GetClock(CLOCK_BOOT); + struct timespec begun; + clock->Get(&begun, NULL); + while ( true ) + { + struct timespec now; + clock->Get(&now, NULL); + uint8_t reg_snapshop = inport8(ioport); + if ( !any && (reg_snapshop & bits) == 0 ) + return true; + if ( any && (reg_snapshop & bits) != bits ) + return true; + struct timespec elapsed = timespec_sub(now, begun); + if ( timespec_le(timeout, elapsed) ) + return errno = ETIMEDOUT, false; + kthread_yield(); + } +} + +bool wait_inport8_set(uint16_t ioport, uint8_t bits, bool any, unsigned int msecs) +{ + struct timespec timeout = timespec_make(msecs / 1000, (msecs % 1000) * 1000000L); + Clock* clock = Time::GetClock(CLOCK_BOOT); + struct timespec begun; + clock->Get(&begun, NULL); + while ( true ) + { + struct timespec now; + clock->Get(&now, NULL); + uint8_t reg_snapshop = inport8(ioport); + if ( !any && (reg_snapshop & bits) == bits ) + return true; + if ( any && (reg_snapshop & bits) != 0 ) + return true; + struct timespec elapsed = timespec_sub(now, begun); + if ( timespec_le(timeout, elapsed) ) + return errno = ETIMEDOUT, false; + kthread_yield(); + } +} + +} // namespace Sortix