diff --git a/drivers/bga.cpp b/drivers/bga.cpp
index a17579b..b490a1f 100644
--- a/drivers/bga.cpp
+++ b/drivers/bga.cpp
@@ -1,4 +1,5 @@
 #include <module.h>
+#include <kernel/x86_64.h>
 
 struct BGADisplay : KGraphicsTarget {
 };
@@ -38,8 +39,8 @@ void BGADeviceAttached(KDevice *_parent) {
 		return;
 	}
 
-	ProcessorOut16(0x01CE, 0 /* version */);
-	uint16_t version = ProcessorIn16(0x01CF);
+	ProcessorOut16(IO_BGA_INDEX, 0 /* version */);
+	uint16_t version = ProcessorIn16(IO_BGA_DATA);
 	KernelLog(LOG_INFO, "BGA", "version", "Detected version %X%X.\n", version >> 8, version);
 
 	if (version < 0xB0C0 || version > 0xB0C5) {
@@ -48,25 +49,25 @@ void BGADeviceAttached(KDevice *_parent) {
 	}
 
 	// Set the mode.
-	ProcessorOut16(0x01CE, 4 /* enable */);
-	ProcessorOut16(0x01CF, 0);
-	ProcessorOut16(0x01CE, 1 /* x resolution */);
-	ProcessorOut16(0x01CF, BGA_RESOLUTION_WIDTH);
-	ProcessorOut16(0x01CE, 2 /* y resolution */);
-	ProcessorOut16(0x01CF, BGA_RESOLUTION_HEIGHT);
-	ProcessorOut16(0x01CE, 3 /* bpp */);
-	ProcessorOut16(0x01CF, 32);
-	ProcessorOut16(0x01CE, 4 /* enable */);
-	ProcessorOut16(0x01CF, 0x41 /* linear frame-buffer */);
+	ProcessorOut16(IO_BGA_INDEX, 4 /* enable */);
+	ProcessorOut16(IO_BGA_DATA, 0);
+	ProcessorOut16(IO_BGA_INDEX, 1 /* x resolution */);
+	ProcessorOut16(IO_BGA_DATA, BGA_RESOLUTION_WIDTH);
+	ProcessorOut16(IO_BGA_INDEX, 2 /* y resolution */);
+	ProcessorOut16(IO_BGA_DATA, BGA_RESOLUTION_HEIGHT);
+	ProcessorOut16(IO_BGA_INDEX, 3 /* bpp */);
+	ProcessorOut16(IO_BGA_DATA, 32);
+	ProcessorOut16(IO_BGA_INDEX, 4 /* enable */);
+	ProcessorOut16(IO_BGA_DATA, 0x41 /* linear frame-buffer */);
 
 	// Setup the graphics target.
 	device->updateScreen = BGAUpdateScreen;
 	device->debugPutBlock = BGADebugPutBlock;
 	device->debugClearScreen = BGADebugClearScreen;
-	ProcessorOut16(0x01CE, 1 /* x resolution */);
-	device->screenWidth = ProcessorIn16(0x01CF);
-	ProcessorOut16(0x01CE, 2 /* y resolution */);
-	device->screenHeight = ProcessorIn16(0x01CF);
+	ProcessorOut16(IO_BGA_INDEX, 1 /* x resolution */);
+	device->screenWidth = ProcessorIn16(IO_BGA_DATA);
+	ProcessorOut16(IO_BGA_INDEX, 2 /* y resolution */);
+	device->screenHeight = ProcessorIn16(IO_BGA_DATA);
 
 	// Register the display.
 	KernelLog(LOG_INFO, "BGA", "register target", 
diff --git a/drivers/ide.cpp b/drivers/ide.cpp
index a441d2b..4de7b2e 100644
--- a/drivers/ide.cpp
+++ b/drivers/ide.cpp
@@ -2,6 +2,7 @@
 // TODO Inserting/removing ATAPI devices.
 
 #include <module.h>
+#include <kernel/x86_64.h>
 
 #define ATA_BUSES 2
 #define ATA_DRIVES (ATA_BUSES * 2)
@@ -9,7 +10,7 @@
 #define ATA_TIMEOUT (10000)
 #define ATAPI_SECTOR_SIZE (2048)
 
-#define ATA_REGISTER(_bus, _reg) (_reg != -1 ? ((_bus ? 0x170 : 0x1F0) + _reg) : (_bus ? 0x376 : 0x3F6))
+#define ATA_REGISTER(_bus, _reg) (_reg != -1 ? ((_bus ? IO_ATA_1 : IO_ATA_2) + _reg) : (_bus ? IO_ATA_3 : IO_ATA_4))
 #define ATA_IRQ(_bus) (_bus ? 15 : 14)
 #define ATA_DATA 0
 #define ATA_FEATURES 1
diff --git a/drivers/pci.cpp b/drivers/pci.cpp
index 6547907..4515e47 100644
--- a/drivers/pci.cpp
+++ b/drivers/pci.cpp
@@ -2,13 +2,7 @@
 
 #include <module.h>
 
-#define PCI_CONFIG	(0xCF8)
-#define PCI_DATA	(0xCFC)
-
 struct PCIController : KDevice {
-	inline uint32_t ReadConfig(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, int size = 32);
-	inline void WriteConfig(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, uint32_t value, int size = 32);
-
 #define PCI_BUS_DO_NOT_SCAN 0
 #define PCI_BUS_SCAN_NEXT 1
 #define PCI_BUS_SCANNED 2
@@ -174,65 +168,30 @@ void KPCIDevice::WriteBAR64(uintptr_t index, uintptr_t offset, uint64_t value) {
 	}
 }
 
-// Spinlock since some drivers need to access it in IRQs (e.g. ACPICA).
-// Also can't be part of PCIController since PCI is initialised after ACPICA.
-static KSpinlock configSpaceSpinlock; 
-
 static PCIController *pci;
 
-uint32_t KPCIReadConfig(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, int size) {
-	return pci->ReadConfig(bus, device, function, offset, size);
-}
-
-void KPCIWriteConfig(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, uint32_t value, int size) {
-	pci->WriteConfig(bus, device, function, offset, value, size);
-}
-
-uint32_t PCIController::ReadConfig(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, int size) {
-	KSpinlockAcquire(&configSpaceSpinlock);
-	EsDefer(KSpinlockRelease(&configSpaceSpinlock));
-	if (offset & 3) KernelPanic("PCIController::ReadConfig - offset is not 4-byte aligned.");
-	ProcessorOut32(PCI_CONFIG, (uint32_t) (0x80000000 | (bus << 16) | (device << 11) | (function << 8) | offset));
-	if (size == 8) return ProcessorIn8(PCI_DATA);
-	if (size == 16) return ProcessorIn16(PCI_DATA);
-	if (size == 32) return ProcessorIn32(PCI_DATA);
-	KernelPanic("PCIController::ReadConfig - Invalid size %d.\n", size);
-	return 0;
-}
-
-void PCIController::WriteConfig(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, uint32_t value, int size) {
-	KSpinlockAcquire(&configSpaceSpinlock);
-	EsDefer(KSpinlockRelease(&configSpaceSpinlock));
-	if (offset & 3) KernelPanic("PCIController::WriteConfig - offset is not 4-byte aligned.");
-	ProcessorOut32(PCI_CONFIG, (uint32_t) (0x80000000 | (bus << 16) | (device << 11) | (function << 8) | offset));
-	if (size == 8) ProcessorOut8(PCI_DATA, value);
-	else if (size == 16) ProcessorOut16(PCI_DATA, value);
-	else if (size == 32) ProcessorOut32(PCI_DATA, value);
-	else KernelPanic("PCIController::WriteConfig - Invalid size %d.\n", size);
-}
-
 void KPCIDevice::WriteConfig8(uintptr_t offset, uint8_t value) {
-	pci->WriteConfig(bus, slot, function, offset, value, 8);
+	KPCIWriteConfig(bus, slot, function, offset, value, 8);
 }
 
 uint8_t KPCIDevice::ReadConfig8(uintptr_t offset) {
-	return pci->ReadConfig(bus, slot, function, offset, 8);
+	return KPCIReadConfig(bus, slot, function, offset, 8);
 }
 
 void KPCIDevice::WriteConfig16(uintptr_t offset, uint16_t value) {
-	pci->WriteConfig(bus, slot, function, offset, value, 16);
+	KPCIWriteConfig(bus, slot, function, offset, value, 16);
 }
 
 uint16_t KPCIDevice::ReadConfig16(uintptr_t offset) {
-	return pci->ReadConfig(bus, slot, function, offset, 16);
+	return KPCIReadConfig(bus, slot, function, offset, 16);
 }
 
 void KPCIDevice::WriteConfig32(uintptr_t offset, uint32_t value) {
-	pci->WriteConfig(bus, slot, function, offset, value, 32);
+	KPCIWriteConfig(bus, slot, function, offset, value, 32);
 }
 
 uint32_t KPCIDevice::ReadConfig32(uintptr_t offset) {
-	return pci->ReadConfig(bus, slot, function, offset, 32);
+	return KPCIReadConfig(bus, slot, function, offset, 32);
 }
 
 bool KPCIDevice::EnableSingleInterrupt(KIRQHandler irqHandler, void *context, const char *cOwnerName) {
@@ -440,11 +399,11 @@ bool EnumeratePCIDrivers(KInstalledDriver *driver, KDevice *_device) {
 }
 
 void PCIController::EnumerateFunction(int bus, int device, int function, int *busesToScan) {
-	uint32_t deviceID = ReadConfig(bus, device, function, 0x00);
+	uint32_t deviceID = KPCIReadConfig(bus, device, function, 0x00);
 	if ((deviceID & 0xFFFF) == 0xFFFF) return;
 
-	uint32_t deviceClass = ReadConfig(bus, device, function, 0x08);
-	uint32_t interruptInformation = ReadConfig(bus, device, function, 0x3C);
+	uint32_t deviceClass = KPCIReadConfig(bus, device, function, 0x08);
+	uint32_t interruptInformation = KPCIReadConfig(bus, device, function, 0x3C);
 
 	KPCIDevice *pciDevice = (KPCIDevice *) KDeviceCreate("PCI function", this, sizeof(KPCIDevice));
 	if (!pciDevice) return;
@@ -460,8 +419,8 @@ void PCIController::EnumerateFunction(int bus, int device, int function, int *bu
 	pciDevice->interruptPin = (interruptInformation >> 8) & 0xFF;
 	pciDevice->interruptLine = (interruptInformation >> 0) & 0xFF;
 
-	pciDevice->deviceID = ReadConfig(bus, device, function, 0);
-	pciDevice->subsystemID = ReadConfig(bus, device, function, 0x2C);
+	pciDevice->deviceID = KPCIReadConfig(bus, device, function, 0);
+	pciDevice->subsystemID = KPCIReadConfig(bus, device, function, 0x2C);
 
 	for (int i = 0; i < 6; i++) {
 		pciDevice->baseAddresses[i] = pciDevice->ReadConfig32(0x10 + 4 * i);
@@ -485,7 +444,7 @@ void PCIController::EnumerateFunction(int bus, int device, int function, int *bu
 			pciDevice->interruptPin, pciDevice->interruptLine);
 
 	if (pciDevice->classCode == 0x06 && pciDevice->subclassCode == 0x04 /* PCI bridge */) {
-		uint8_t secondaryBus = (ReadConfig(bus, device, function, 0x18) >> 8) & 0xFF; 
+		uint8_t secondaryBus = (KPCIReadConfig(bus, device, function, 0x18) >> 8) & 0xFF; 
 
 		if (busScanStates[secondaryBus] == PCI_BUS_DO_NOT_SCAN) {
 			KernelLog(LOG_INFO, "PCI", "PCI bridge", "PCI bridge to bus %d.\n", secondaryBus);
@@ -504,13 +463,13 @@ void PCIController::EnumerateFunction(int bus, int device, int function, int *bu
 }
 
 void PCIController::Enumerate() {
-	uint32_t baseHeaderType = ReadConfig(0, 0, 0, 0x0C);
+	uint32_t baseHeaderType = KPCIReadConfig(0, 0, 0, 0x0C);
 	int baseBuses = (baseHeaderType & 0x80) ? 8 : 1;
 
 	int busesToScan = 0;
 
 	for (int baseBus = 0; baseBus < baseBuses; baseBus++) {
-		uint32_t deviceID = ReadConfig(0, 0, baseBus, 0x00);
+		uint32_t deviceID = KPCIReadConfig(0, 0, baseBus, 0x00);
 		if ((deviceID & 0xFFFF) == 0xFFFF) continue;
 		busScanStates[baseBus] = PCI_BUS_SCAN_NEXT;
 		busesToScan++;
@@ -530,10 +489,10 @@ void PCIController::Enumerate() {
 			busesToScan--;
 
 			for (int device = 0; device < 32; device++) {
-				uint32_t deviceID = ReadConfig(bus, device, 0, 0x00);
+				uint32_t deviceID = KPCIReadConfig(bus, device, 0, 0x00);
 				if ((deviceID & 0xFFFF) == 0xFFFF) continue;
 
-				uint32_t headerType = (ReadConfig(bus, device, 0, 0x0C) >> 16) & 0xFF;
+				uint32_t headerType = (KPCIReadConfig(bus, device, 0, 0x0C) >> 16) & 0xFF;
 				int functions = (headerType & 0x80) ? 8 : 1;
 
 				for (int function = 0; function < functions; function++) {
diff --git a/drivers/ps2.cpp b/drivers/ps2.cpp
index ff0561d..0248aaf 100644
--- a/drivers/ps2.cpp
+++ b/drivers/ps2.cpp
@@ -1,6 +1,7 @@
 // TODO Scrolling.
 
 #include <module.h>
+#include <kernel/x86_64.h>
 
 struct PS2Update {
 	union {
@@ -176,11 +177,6 @@ uint16_t scancodeConversionTable2[] = {
 #define PS2_FIRST_IRQ 		(1)
 #define PS2_SECOND_IRQ		(12)
 
-// Ports.
-#define PS2_PORT_DATA		(0x60)
-#define PS2_PORT_STATUS		(0x64)
-#define PS2_PORT_COMMAND	(0x64)
-
 // Keyboard commands.
 #define PS2_KEYBOARD_RESET	(0xFF)
 #define PS2_KEYBOARD_ENABLE	(0xF4)
@@ -217,16 +213,16 @@ void PS2KeyboardUpdated(EsGeneric _update) {
 }
 
 void PS2::WaitInputBuffer() {
-	while (ProcessorIn8(PS2_PORT_STATUS) & PS2_INPUT_FULL);
+	while (ProcessorIn8(IO_PS2_STATUS) & PS2_INPUT_FULL);
 }
 
 bool PS2::PollRead(uint8_t *value, bool forMouse) {
-	uint8_t status = ProcessorIn8(PS2_PORT_STATUS);
+	uint8_t status = ProcessorIn8(IO_PS2_STATUS);
 	if (status & PS2_MOUSE_BYTE && !forMouse) return false;
 	if (!(status & PS2_MOUSE_BYTE) && forMouse) return false;
 
 	if (status & PS2_OUTPUT_FULL) {
-		*value = ProcessorIn8(PS2_PORT_DATA);
+		*value = ProcessorIn8(IO_PS2_DATA);
 
 		if (*value == 0xE1 && !forMouse) {
 			KDebugKeyPressed();
@@ -382,60 +378,60 @@ bool PS2IRQHandler(uintptr_t interruptIndex, void *) {
 void PS2::DisableDevices(unsigned which) {
 	WaitInputBuffer();
 	// EsPrint("ps2 first write...\n");
-	if (which & 1) ProcessorOut8(PS2_PORT_COMMAND, PS2_DISABLE_FIRST);
+	if (which & 1) ProcessorOut8(IO_PS2_COMMAND, PS2_DISABLE_FIRST);
 	// EsPrint("ps2 first write end\n");
 	WaitInputBuffer();
-	if (which & 2) ProcessorOut8(PS2_PORT_COMMAND, PS2_DISABLE_SECOND);
+	if (which & 2) ProcessorOut8(IO_PS2_COMMAND, PS2_DISABLE_SECOND);
 }
 
 void PS2::EnableDevices(unsigned which) {
 	WaitInputBuffer();
-	if (which & 1) ProcessorOut8(PS2_PORT_COMMAND, PS2_ENABLE_FIRST);
+	if (which & 1) ProcessorOut8(IO_PS2_COMMAND, PS2_ENABLE_FIRST);
 	WaitInputBuffer();
-	if (which & 2) ProcessorOut8(PS2_PORT_COMMAND, PS2_ENABLE_SECOND);
+	if (which & 2) ProcessorOut8(IO_PS2_COMMAND, PS2_ENABLE_SECOND);
 }
 
 void PS2::FlushOutputBuffer() {
-	while (ProcessorIn8(PS2_PORT_STATUS) & PS2_OUTPUT_FULL) {
-		ProcessorIn8(PS2_PORT_DATA);
+	while (ProcessorIn8(IO_PS2_STATUS) & PS2_OUTPUT_FULL) {
+		ProcessorIn8(IO_PS2_DATA);
 	}
 }
 
 void PS2::SendCommand(uint8_t command) {
 	WaitInputBuffer();
-	ProcessorOut8(PS2_PORT_COMMAND, command);
+	ProcessorOut8(IO_PS2_COMMAND, command);
 }
 
 uint8_t PS2::ReadByte(KTimeout *timeout) {
-	while (!(ProcessorIn8(PS2_PORT_STATUS) & PS2_OUTPUT_FULL) && !timeout->Hit());
-	return ProcessorIn8(PS2_PORT_DATA);
+	while (!(ProcessorIn8(IO_PS2_STATUS) & PS2_OUTPUT_FULL) && !timeout->Hit());
+	return ProcessorIn8(IO_PS2_DATA);
 }
 
 void PS2::WriteByte(KTimeout *timeout, uint8_t value) {
-	while ((ProcessorIn8(PS2_PORT_STATUS) & PS2_INPUT_FULL) && !timeout->Hit());
+	while ((ProcessorIn8(IO_PS2_STATUS) & PS2_INPUT_FULL) && !timeout->Hit());
 	if (timeout->Hit()) return;
-	ProcessorOut8(PS2_PORT_DATA, value);
+	ProcessorOut8(IO_PS2_DATA, value);
 }
 
 bool PS2::SetupKeyboard(KTimeout *timeout) {
 	WaitInputBuffer();
-	ProcessorOut8(PS2_PORT_DATA, PS2_KEYBOARD_ENABLE);
+	ProcessorOut8(IO_PS2_DATA, PS2_KEYBOARD_ENABLE);
 	if (ReadByte(timeout) != 0xFA) return false;
 
 	WaitInputBuffer();
-	ProcessorOut8(PS2_PORT_DATA, PS2_KEYBOARD_SCANCODE_SET);
+	ProcessorOut8(IO_PS2_DATA, PS2_KEYBOARD_SCANCODE_SET);
 	if (ReadByte(timeout) != 0xFA) return false;
 	WaitInputBuffer();
-	ProcessorOut8(PS2_PORT_DATA, 0);
+	ProcessorOut8(IO_PS2_DATA, 0);
 	if (ReadByte(timeout) != 0xFA) return false;
 	scancodeSet = ReadByte(timeout) & 3;
 	KernelLog(LOG_INFO, "PS/2", "scancode set", "Keyboard reports it is using scancode set %d.\n", scancodeSet);
 
 	WaitInputBuffer();
-	ProcessorOut8(PS2_PORT_DATA, PS2_KEYBOARD_REPEAT);
+	ProcessorOut8(IO_PS2_DATA, PS2_KEYBOARD_REPEAT);
 	if (ReadByte(timeout) != 0xFA) return false;
 	WaitInputBuffer();
-	ProcessorOut8(PS2_PORT_DATA, 0);
+	ProcessorOut8(IO_PS2_DATA, 0);
 	if (ReadByte(timeout) != 0xFA) return false;
 
 	return true;
@@ -443,14 +439,14 @@ bool PS2::SetupKeyboard(KTimeout *timeout) {
 
 bool PS2::SetMouseRate(KTimeout *timeout, int rate) {
 	WaitInputBuffer();
-	ProcessorOut8(PS2_PORT_COMMAND, PS2_WRITE_SECOND);
+	ProcessorOut8(IO_PS2_COMMAND, PS2_WRITE_SECOND);
 	WaitInputBuffer();
-	ProcessorOut8(PS2_PORT_DATA, PS2_MOUSE_SAMPLE_RATE);
+	ProcessorOut8(IO_PS2_DATA, PS2_MOUSE_SAMPLE_RATE);
 	if (ReadByte(timeout) != 0xFA) return false;
 	WaitInputBuffer();
-	ProcessorOut8(PS2_PORT_COMMAND, PS2_WRITE_SECOND);
+	ProcessorOut8(IO_PS2_COMMAND, PS2_WRITE_SECOND);
 	WaitInputBuffer();
-	ProcessorOut8(PS2_PORT_DATA, rate);
+	ProcessorOut8(IO_PS2_DATA, rate);
 	if (ReadByte(timeout) != 0xFA) return false;
 	return true;
 }
@@ -459,9 +455,9 @@ bool PS2::SetupMouse(KTimeout *timeout) {
 	// TODO Mouse with scroll wheel detection.
 
 	WaitInputBuffer();
-	ProcessorOut8(PS2_PORT_COMMAND, PS2_WRITE_SECOND);
+	ProcessorOut8(IO_PS2_COMMAND, PS2_WRITE_SECOND);
 	WaitInputBuffer();
-	ProcessorOut8(PS2_PORT_DATA, PS2_MOUSE_RESET);
+	ProcessorOut8(IO_PS2_DATA, PS2_MOUSE_RESET);
 	if (ReadByte(timeout) != 0xFA) return false;
 	if (ReadByte(timeout) != 0xAA) return false;
 	if (ReadByte(timeout) != 0x00) return false;
@@ -469,26 +465,26 @@ bool PS2::SetupMouse(KTimeout *timeout) {
 	if (!SetMouseRate(timeout, 100)) return false;
 	if (!SetMouseRate(timeout, 80)) return false;
 	WaitInputBuffer();
-	ProcessorOut8(PS2_PORT_COMMAND, PS2_WRITE_SECOND);
+	ProcessorOut8(IO_PS2_COMMAND, PS2_WRITE_SECOND);
 	WaitInputBuffer();
-	ProcessorOut8(PS2_PORT_DATA, 0xF2);
+	ProcessorOut8(IO_PS2_DATA, 0xF2);
 	if (ReadByte(timeout) != 0xFA) return false;
 	mouseType = ReadByte(timeout);
 	if (!SetMouseRate(timeout, 100)) return false;
 	WaitInputBuffer();
-	ProcessorOut8(PS2_PORT_COMMAND, PS2_WRITE_SECOND);
+	ProcessorOut8(IO_PS2_COMMAND, PS2_WRITE_SECOND);
 	WaitInputBuffer();
-	ProcessorOut8(PS2_PORT_DATA, PS2_MOUSE_RESOLUTION);
+	ProcessorOut8(IO_PS2_DATA, PS2_MOUSE_RESOLUTION);
 	if (ReadByte(timeout) != 0xFA) return false;
 	WaitInputBuffer();
-	ProcessorOut8(PS2_PORT_COMMAND, PS2_WRITE_SECOND);
+	ProcessorOut8(IO_PS2_COMMAND, PS2_WRITE_SECOND);
 	WaitInputBuffer();
-	ProcessorOut8(PS2_PORT_DATA, 3);
+	ProcessorOut8(IO_PS2_DATA, 3);
 	if (ReadByte(timeout) != 0xFA) return false;
 	WaitInputBuffer();
-	ProcessorOut8(PS2_PORT_COMMAND, PS2_WRITE_SECOND);
+	ProcessorOut8(IO_PS2_COMMAND, PS2_WRITE_SECOND);
 	WaitInputBuffer();
-	ProcessorOut8(PS2_PORT_DATA, PS2_MOUSE_ENABLE);
+	ProcessorOut8(IO_PS2_DATA, PS2_MOUSE_ENABLE);
 	if (ReadByte(timeout) != 0xFA) return false;
 
 	return true;
@@ -515,10 +511,10 @@ void PS2::Initialise(KDevice *parentDevice) {
 	FlushOutputBuffer();
 
 	WaitInputBuffer();
-	ProcessorOut8(PS2_PORT_COMMAND, PS2_READ_CONFIG);
+	ProcessorOut8(IO_PS2_COMMAND, PS2_READ_CONFIG);
 	uint8_t configurationByte = ReadByte(&timeout);
 	WaitInputBuffer();
-	ProcessorOut8(PS2_PORT_COMMAND, PS2_WRITE_CONFIG);
+	ProcessorOut8(IO_PS2_COMMAND, PS2_WRITE_CONFIG);
 	WriteByte(&timeout, configurationByte & ~(PS2_FIRST_IRQ_MASK | PS2_SECOND_IRQ_MASK | PS2_TRANSLATION));
 	if (timeout.Hit()) return;
 
@@ -529,7 +525,7 @@ void PS2::Initialise(KDevice *parentDevice) {
 	if (configurationByte & PS2_SECOND_CLOCK) {
 		EnableDevices(2);
 		WaitInputBuffer();
-		ProcessorOut8(PS2_PORT_COMMAND, PS2_READ_CONFIG);
+		ProcessorOut8(IO_PS2_COMMAND, PS2_READ_CONFIG);
 		configurationByte = ReadByte(&timeout);
 		if (!(configurationByte & PS2_SECOND_CLOCK)) {
 			hasMouse = true;
@@ -539,7 +535,7 @@ void PS2::Initialise(KDevice *parentDevice) {
 
 	{
 		WaitInputBuffer();
-		ProcessorOut8(PS2_PORT_COMMAND, PS2_TEST_FIRST);
+		ProcessorOut8(IO_PS2_COMMAND, PS2_TEST_FIRST);
 		uint8_t b = ReadByte(&timeout);
 		if (b) return;
 		if (timeout.Hit()) return;
@@ -548,7 +544,7 @@ void PS2::Initialise(KDevice *parentDevice) {
 
 	if (hasMouse) {
 		WaitInputBuffer();
-		ProcessorOut8(PS2_PORT_COMMAND, PS2_TEST_SECOND);
+		ProcessorOut8(IO_PS2_COMMAND, PS2_TEST_SECOND);
 		if (!ReadByte(&timeout) && !timeout.Hit()) channels = 2;
 	}
 
@@ -565,10 +561,10 @@ void PS2::Initialise(KDevice *parentDevice) {
 
 	{
 		WaitInputBuffer();
-		ProcessorOut8(PS2_PORT_COMMAND, PS2_READ_CONFIG);
+		ProcessorOut8(IO_PS2_COMMAND, PS2_READ_CONFIG);
 		uint8_t configurationByte = ReadByte(&timeout);
 		WaitInputBuffer();
-		ProcessorOut8(PS2_PORT_COMMAND, PS2_WRITE_CONFIG);
+		ProcessorOut8(IO_PS2_COMMAND, PS2_WRITE_CONFIG);
 		WriteByte(&timeout, configurationByte | PS2_FIRST_IRQ_MASK | PS2_SECOND_IRQ_MASK);
 	}
 
diff --git a/drivers/rtc.cpp b/drivers/rtc.cpp
index 84fea09..193697a 100644
--- a/drivers/rtc.cpp
+++ b/drivers/rtc.cpp
@@ -11,10 +11,10 @@ uint8_t RTCRead(uint8_t index, bool convertFromBCD, bool convertFrom12Hour) {
 
 	for (uint8_t i = 0; i < 10; i++) {
 		// Write the index a few times to delay before reading.
-		ProcessorOut8(0x70, index);
+		ProcessorOut8(IO_RTC_INDEX, index);
 	}
 
-	uint8_t value = ProcessorIn8(0x71);
+	uint8_t value = ProcessorIn8(IO_RTC_DATA);
 
 	if (convertFromBCD) {
 		value = (value >> 4) * 10 + (value & 0xF);
diff --git a/drivers/svga.cpp b/drivers/svga.cpp
index 16ecbf7..7e0d39d 100644
--- a/drivers/svga.cpp
+++ b/drivers/svga.cpp
@@ -129,28 +129,6 @@ void InitialiseVBE(KDevice *parent) {
 
 #if 0
 
-#define VGA_AC_INDEX 0x3C0
-#define VGA_AC_WRITE 0x3C0
-#define VGA_AC_READ  0x3C1
-
-#define VGA_MISC_WRITE 0x3C2
-#define VGA_MISC_READ  0x3CC
-
-#define VGA_SEQ_INDEX 0x3C4
-#define VGA_SEQ_DATA  0x3C5
-
-#define VGA_DAC_READ_INDEX  0x3C7
-#define VGA_DAC_WRITE_INDEX 0x3C8
-#define VGA_DAC_DATA        0x3C9
-
-#define VGA_GC_INDEX 0x3CE
-#define VGA_GC_DATA  0x3CF
-
-#define VGA_CRTC_INDEX 0x3D4
-#define VGA_CRTC_DATA  0x3D5
-
-#define VGA_INSTAT_READ 0x3DA
-
 uint8_t vgaMode18[] = {
 	0xE3, 0x03, 0x01, 0x08, 0x00, 0x06, 0x5F, 0x4F,
 	0x50, 0x82, 0x54, 0x80, 0x0B, 0x3E, 0x00, 0x40,
@@ -182,8 +160,8 @@ void VGAUpdateScreen(uint8_t *_source, uint8_t *modifiedScanlineBitset, KModifie
 	for (int plane = 0; plane < 4; plane++) {
 		uint8_t *source = _source;
 
-		ProcessorOut8(VGA_SEQ_INDEX, 2);
-		ProcessorOut8(VGA_SEQ_DATA, 1 << plane);
+		ProcessorOut8(IO_VGA_SEQ_INDEX, 2);
+		ProcessorOut8(IO_VGA_SEQ_DATA, 1 << plane);
 
 		for (uintptr_t y_ = 0; y_ < VGA_SCREEN_HEIGHT / 8; y_++) {
 			if (modifiedScanlineBitset[y_] == 0) {
@@ -227,8 +205,8 @@ void VGAUpdateScreen(uint8_t *_source, uint8_t *modifiedScanlineBitset, KModifie
 
 void VGAPutBlock(uintptr_t x, uintptr_t y, bool toggle) {
 	for (int plane = 0; plane < 4; plane++) {
-		ProcessorOut8(VGA_SEQ_INDEX, 2);
-		ProcessorOut8(VGA_SEQ_DATA, 1 << plane);
+		ProcessorOut8(IO_VGA_SEQ_INDEX, 2);
+		ProcessorOut8(IO_VGA_SEQ_DATA, 1 << plane);
 		
 		if (toggle) {
 			vgaAddress[y * 80 + x / 8] ^= 1 << (7 - (x & 7));
@@ -240,8 +218,8 @@ void VGAPutBlock(uintptr_t x, uintptr_t y, bool toggle) {
 
 void VGAClearScreen() {
 	for (int plane = 0; plane < 4; plane++) {
-		ProcessorOut8(VGA_SEQ_INDEX, 2);
-		ProcessorOut8(VGA_SEQ_DATA, 1 << plane);
+		ProcessorOut8(IO_VGA_SEQ_INDEX, 2);
+		ProcessorOut8(IO_VGA_SEQ_DATA, 1 << plane);
 		EsMemoryZero((void *) vgaAddress, VGA_SCREEN_WIDTH / 8 * VGA_SCREEN_HEIGHT);
 	}
 }
@@ -253,19 +231,19 @@ void InitialiseVGA(KDevice *parent) {
 
 	vgaAddress = (uint8_t *) MMMapPhysical(MMGetKernelSpace(), 0xA0000, 0x10000, MM_REGION_WRITE_COMBINING);
 	uint8_t *registers = vgaMode18;
-	ProcessorOut8(VGA_MISC_WRITE, *registers++);
-	for (int i = 0; i < 5; i++) { ProcessorOut8(VGA_SEQ_INDEX, i); ProcessorOut8(VGA_SEQ_DATA, *registers++); }
-	ProcessorOut8(VGA_CRTC_INDEX, 0x03);
-	ProcessorOut8(VGA_CRTC_DATA, ProcessorIn8(VGA_CRTC_DATA) | 0x80);
-	ProcessorOut8(VGA_CRTC_INDEX, 0x11);
-	ProcessorOut8(VGA_CRTC_DATA, ProcessorIn8(VGA_CRTC_DATA) & ~0x80);
+	ProcessorOut8(IO_VGA_MISC_WRITE, *registers++);
+	for (int i = 0; i < 5; i++) { ProcessorOut8(IO_VGA_SEQ_INDEX, i); ProcessorOut8(IO_VGA_SEQ_DATA, *registers++); }
+	ProcessorOut8(IO_VGA_CRTC_INDEX, 0x03);
+	ProcessorOut8(IO_VGA_CRTC_DATA, ProcessorIn8(IO_VGA_CRTC_DATA) | 0x80);
+	ProcessorOut8(IO_VGA_CRTC_INDEX, 0x11);
+	ProcessorOut8(IO_VGA_CRTC_DATA, ProcessorIn8(IO_VGA_CRTC_DATA) & ~0x80);
 	registers[0x03] |= 0x80;
 	registers[0x11] &= ~0x80;
-	for (int i = 0; i < 25; i++) { ProcessorOut8(VGA_CRTC_INDEX, i); ProcessorOut8(VGA_CRTC_DATA, *registers++); }
-	for (int i = 0; i < 9; i++) { ProcessorOut8(VGA_GC_INDEX, i); ProcessorOut8(VGA_GC_DATA, *registers++); }
-	for (int i = 0; i < 21; i++) { ProcessorIn8(VGA_INSTAT_READ); ProcessorOut8(VGA_AC_INDEX, i); ProcessorOut8(VGA_AC_WRITE, *registers++); }
-	ProcessorIn8(VGA_INSTAT_READ);
-	ProcessorOut8(VGA_AC_INDEX, 0x20);
+	for (int i = 0; i < 25; i++) { ProcessorOut8(IO_VGA_CRTC_INDEX, i); ProcessorOut8(IO_VGA_CRTC_DATA, *registers++); }
+	for (int i = 0; i < 9; i++) { ProcessorOut8(IO_VGA_GC_INDEX, i); ProcessorOut8(IO_VGA_GC_DATA, *registers++); }
+	for (int i = 0; i < 21; i++) { ProcessorIn8(IO_VGA_INSTAT_READ); ProcessorOut8(IO_VGA_AC_INDEX, i); ProcessorOut8(IO_VGA_AC_WRITE, *registers++); }
+	ProcessorIn8(IO_VGA_INSTAT_READ);
+	ProcessorOut8(IO_VGA_AC_INDEX, 0x20);
 
 	KGraphicsTarget *target = (KGraphicsTarget *) KDeviceCreate("VGA", parent, sizeof(KGraphicsTarget));
 	target->screenWidth = VGA_SCREEN_WIDTH;
diff --git a/kernel/kernel.h b/kernel/kernel.h
index 6057596..007122c 100644
--- a/kernel/kernel.h
+++ b/kernel/kernel.h
@@ -153,13 +153,12 @@ KSpinlock ipiLock;
 #include "files.cpp"
 #include "windows.cpp"
 #include "networking.cpp"
+#include "terminal.cpp"
 
 #ifdef ENABLE_POSIX_SUBSYSTEM
 #include "posix.cpp"
 #endif
 
-#include "terminal.cpp"
-
 #ifdef IMPLEMENTATION
 
 //////////////////////////////////
diff --git a/kernel/x86_64.cpp b/kernel/x86_64.cpp
index 5332feb..29b0301 100644
--- a/kernel/x86_64.cpp
+++ b/kernel/x86_64.cpp
@@ -664,16 +664,16 @@ uint64_t ArchGetTimeFromPITMs() {
 	static uint64_t cumulative = 0, last = 0;
 
 	if (!started) {
-		ProcessorOut8(0x43, 0x30);
-		ProcessorOut8(0x40, 0xFF);
-		ProcessorOut8(0x40, 0xFF);
+		ProcessorOut8(IO_PIT_COMMAND, 0x30);
+		ProcessorOut8(IO_PIT_DATA, 0xFF);
+		ProcessorOut8(IO_PIT_DATA, 0xFF);
 		started = true;
 		last = 0xFFFF;
 		return 0;
 	} else {
-		ProcessorOut8(0x43, 0x00);
-		uint16_t x = ProcessorIn8(0x40);
-		x |= (ProcessorIn8(0x40)) << 8;
+		ProcessorOut8(IO_PIT_COMMAND, 0x00);
+		uint16_t x = ProcessorIn8(IO_PIT_DATA);
+		x |= (ProcessorIn8(IO_PIT_DATA)) << 8;
 		cumulative += last - x;
 		if (x > last) cumulative += 0x10000;
 		last = x;
@@ -682,14 +682,14 @@ uint64_t ArchGetTimeFromPITMs() {
 }
 
 void ArchDelay1Ms() {
-	ProcessorOut8(0x43, 0x30);
-	ProcessorOut8(0x40, 0xA9);
-	ProcessorOut8(0x40, 0x04);
+	ProcessorOut8(IO_PIT_COMMAND, 0x30);
+	ProcessorOut8(IO_PIT_DATA, 0xA9);
+	ProcessorOut8(IO_PIT_DATA, 0x04);
 
 	while (true) {
-		ProcessorOut8(0x43, 0xE2);
+		ProcessorOut8(IO_PIT_COMMAND, 0xE2);
 
-		if (ProcessorIn8(0x40) & (1 << 7)) {
+		if (ProcessorIn8(IO_PIT_DATA) & (1 << 7)) {
 			break;
 		}
 	}
@@ -1307,4 +1307,30 @@ uintptr_t GetBootloaderInformationOffset() {
 	return bootloaderInformationOffset;
 }
 
+// Spinlock since some drivers need to access it in IRQs (e.g. ACPICA).
+static KSpinlock pciConfigSpinlock; 
+
+uint32_t KPCIReadConfig(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, int size) {
+	KSpinlockAcquire(&pciConfigSpinlock);
+	EsDefer(KSpinlockRelease(&pciConfigSpinlock));
+	if (offset & 3) KernelPanic("KPCIReadConfig - offset is not 4-byte aligned.");
+	ProcessorOut32(IO_PCI_CONFIG, (uint32_t) (0x80000000 | (bus << 16) | (device << 11) | (function << 8) | offset));
+	if (size == 8) return ProcessorIn8(IO_PCI_DATA);
+	if (size == 16) return ProcessorIn16(IO_PCI_DATA);
+	if (size == 32) return ProcessorIn32(IO_PCI_DATA);
+	KernelPanic("PCIController::ReadConfig - Invalid size %d.\n", size);
+	return 0;
+}
+
+void KPCIWriteConfig(uint8_t bus, uint8_t device, uint8_t function, uint8_t offset, uint32_t value, int size) {
+	KSpinlockAcquire(&pciConfigSpinlock);
+	EsDefer(KSpinlockRelease(&pciConfigSpinlock));
+	if (offset & 3) KernelPanic("KPCIWriteConfig - offset is not 4-byte aligned.");
+	ProcessorOut32(IO_PCI_CONFIG, (uint32_t) (0x80000000 | (bus << 16) | (device << 11) | (function << 8) | offset));
+	if (size == 8) ProcessorOut8(IO_PCI_DATA, value);
+	else if (size == 16) ProcessorOut16(IO_PCI_DATA, value);
+	else if (size == 32) ProcessorOut32(IO_PCI_DATA, value);
+	else KernelPanic("PCIController::WriteConfig - Invalid size %d.\n", size);
+}
+
 #endif
diff --git a/kernel/x86_64.h b/kernel/x86_64.h
index 59e5e7a..382d472 100644
--- a/kernel/x86_64.h
+++ b/kernel/x86_64.h
@@ -4,6 +4,50 @@
 #define LOW_MEMORY_MAP_START (0xFFFFFE0000000000)
 #define LOW_MEMORY_LIMIT (0x100000) // The first 1MB is mapped here.
 
+// --------------------------------- Standardised IO ports.
+
+#define IO_PIC_1_COMMAND		(0x0020)
+#define IO_PIC_1_DATA			(0x0021)
+#define IO_PIT_DATA			(0x0040)
+#define IO_PIT_COMMAND			(0x0043)
+#define IO_PS2_DATA			(0x0060)
+#define IO_PC_SPEAKER			(0x0061)
+#define IO_PS2_STATUS			(0x0064)
+#define IO_PS2_COMMAND			(0x0064)
+#define IO_RTC_INDEX 			(0x0070)
+#define IO_RTC_DATA 			(0x0071)
+#define IO_PIC_2_COMMAND		(0x00A0)
+#define IO_PIC_2_DATA			(0x00A1)
+#define IO_BGA_INDEX			(0x01CE)
+#define IO_BGA_DATA			(0x01CF)
+#define IO_ATA_1			(0x0170) // To 0x0177.
+#define IO_ATA_2			(0x01F0) // To 0x01F7.
+#define IO_COM_4			(0x02E8) // To 0x02EF.
+#define IO_COM_2			(0x02F8) // To 0x02FF.
+#define IO_ATA_3			(0x0376)
+#define IO_VGA_AC_INDEX 		(0x03C0)
+#define IO_VGA_AC_WRITE 		(0x03C0)
+#define IO_VGA_AC_READ  		(0x03C1)
+#define IO_VGA_MISC_WRITE 		(0x03C2)
+#define IO_VGA_MISC_READ  		(0x03CC)
+#define IO_VGA_SEQ_INDEX 		(0x03C4)
+#define IO_VGA_SEQ_DATA  		(0x03C5)
+#define IO_VGA_DAC_READ_INDEX  		(0x03C7)
+#define IO_VGA_DAC_WRITE_INDEX 		(0x03C8)
+#define IO_VGA_DAC_DATA        		(0x03C9)
+#define IO_VGA_GC_INDEX 		(0x03CE)
+#define IO_VGA_GC_DATA  		(0x03CF)
+#define IO_VGA_CRTC_INDEX 		(0x03D4)
+#define IO_VGA_CRTC_DATA  		(0x03D5)
+#define IO_VGA_INSTAT_READ 		(0x03DA)
+#define IO_COM_3			(0x03E8) // To 0x03EF.
+#define IO_ATA_4			(0x03F6)
+#define IO_COM_1			(0x03F8) // To 0x03FF.
+#define IO_PCI_CONFIG 			(0x0CF8)
+#define IO_PCI_DATA   			(0x0CFC)
+
+// --------------------------------- Forward declarations.
+
 extern "C" uint64_t ProcessorReadCR3();
 extern "C" void gdt_data();
 
diff --git a/res/Theme Source.dat b/res/Theme Source.dat
index 546cca0..8173ec6 100644
Binary files a/res/Theme Source.dat and b/res/Theme Source.dat differ