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