replace nob with ms' build, move disk creation to build.bat, major comment cleanup, remove old and stupid tests, overhaul interrupt management with per-CPU vector allocation, affinity migration and safe teardown, add proper IOAPIC routing and PCI MSI/MSI-X/INTx support, migrate drivers to the new interrupt API, integrate ACPICA with a proper OS services layer, move ACPI firmware events, power button handling and S5 shutdown into acpi.sys, add parallel driver startup and atomic publication, replace PnP arrays with dynamic lists, redesign service startup again to be asynchronous, add delayed startup mode for services, allow omitting keys in services.ini, fix acpi ec deferred work handling, fix kernel threads having garbage exit code.

This commit is contained in:
maksw committed 2026-10-28 15:18:43 +01:00
1 parent d36f19509c
commit 36eef8f58d
696 files changed
+147281 -7530

No files matched your search

+45 -96
View File
@@ -5,8 +5,6 @@
DRIVER_OBJECT g_driver;
static AHCI_CONTROLLER* g_controllers[MAX_AHCI_CONTROLLERS];
static int g_controllerCount;
static uint8_t g_nextDiskIndex;
#define AHCI_COMMAND_TIMEOUT_MS 10000ull
@@ -26,7 +24,6 @@ static const IO_DRIVER_ID_TABLE g_ahciIdTable = {
// Helpers.
static KSTATUS AhciStartController(AHCI_CONTROLLER* ctl);
static void AhciUnregisterController(AHCI_CONTROLLER* ctl);
// Accessors for port structure memory at known CPU and device-address offsets.
static inline HBA_CMD_HEADER* cmd_list(AHCI_DRIVE* drv) {
@@ -255,42 +252,40 @@ static void AhciCompletionDpc(KDPC* dpc, void* context,
// Walks all registered drives, checks if their port raised an interrupt,
// captures IS, clears it, and queues the per-drive completion DPC.
static void AhciIsr(void) {
for (int c = 0; c < g_controllerCount; c++) {
AHCI_CONTROLLER* ctl = g_controllers[c];
if (!ctl || !ctl->hba || ctl->removed)
continue;
static void AhciIsr(void* context) {
AHCI_CONTROLLER* ctl = (AHCI_CONTROLLER*)context;
if (!ctl || !ctl->hba || ctl->removed) return;
// GHC.IS tells us which ports are pending for this HBA.
uint32_t pending = ctl->hba->is;
if (!pending)
return;
// GHC.IS tells us which ports are pending for this HBA.
uint32_t pending = ctl->hba->is;
if (!pending)
continue;
for (uint32_t i = 0; i < ctl->driveCount; i++) {
AHCI_DRIVE* drv = &ctl->drives[i];
uint32_t portBit = (1u << drv->portNo);
if (!(pending & portBit)) continue;
for (uint32_t i = 0; i < ctl->driveCount; i++) {
AHCI_DRIVE* drv = &ctl->drives[i];
uint32_t portBit = (1u << drv->portNo);
if (!(pending & portBit)) continue;
// Capture and clear port IS before queueing the bottom half. The
// waiter reads lastIs to check for errors without racing the next
// command. OR in case hardware reports multiple causes before the
// DPC releases the worker.
uint32_t portIs = drv->port->is;
drv->port->is = portIs; // W1C - write back to clear
drv->lastIs |= portIs;
// Capture and clear port IS before queueing the bottom half. The
// waiter reads lastIs to check for errors without racing the next
// command. OR in case hardware reports multiple causes before the
// DPC releases the worker.
uint32_t portIs = drv->port->is;
drv->port->is = portIs; // W1C - write back to clear
drv->lastIs |= portIs;
// Clear the HBA-level bit.
ctl->hba->is = portBit;
// Clear the HBA-level bit.
ctl->hba->is = portBit;
// DMA Setup, PIO Setup, and other progress interrupts are not
// command completion. Only wake the worker for D2H completion or
// an error that terminates the command.
if (portIs & AHCI_PORT_TERMINAL_MASK)
KeInsertQueueDpc(&drv->completionDpc, (void*)0, (void*)0);
}
// DMA Setup, PIO Setup, and other progress interrupts are not
// command completion. Only wake the worker for D2H completion or
// an error that terminates the command.
if (portIs & AHCI_PORT_TERMINAL_MASK)
KeInsertQueueDpc(&drv->completionDpc, (void*)0, (void*)0);
}
}
// Issue a command - interrupt-driven (runtime path).
// Caller has already built slot 0 via build_rw_cmd / port_identify.
// Blocks the current thread until the ISR signals completionEvent.
@@ -700,7 +695,8 @@ static KSTATUS AhciDispatchControllerPnp(DEVICE_OBJECT* device, IRP* irp) {
AhciReleaseDriveDma(drv);
}
}
AhciUnregisterController(ctl);
if (ctl->InterruptRequest.Interrupt)
PciDisconnectInterrupts(ctl->pdo, &ctl->InterruptRequest, 1u);
IoDmaPutAdapter(ctl->dmaAdapter);
ctl->dmaAdapter = (IO_DMA_ADAPTER*)0;
IoDetachDevice(device);
@@ -818,33 +814,6 @@ static void AhciWorker(uintptr_t arg) {
// Runtime commands are non-NCQ DMA commands. DHRS is their completion signal;
// setup/progress FIS interrupts must not wake the serialized command waiter.
// Registers controller.
static KSTATUS AhciRegisterController(AHCI_CONTROLLER* ctl) {
if (!ctl) return NTLSTATUS_INVALID_PARAMETER;
for (int i = 0; i < g_controllerCount; i++) {
if (g_controllers[i] == ctl)
return NTLSTATUS_SUCCESS;
}
if (g_controllerCount >= MAX_AHCI_CONTROLLERS)
return NTLSTATUS_NO_MEMORY;
g_controllers[g_controllerCount++] = ctl;
return NTLSTATUS_SUCCESS;
}
// Removes a controller from the interrupt registry.
static void AhciUnregisterController(AHCI_CONTROLLER* ctl) {
if (!ctl)
return;
for (int i = 0; i < g_controllerCount; i++) {
if (g_controllers[i] != ctl)
continue;
g_controllerCount--;
g_controllers[i] = g_controllers[g_controllerCount];
g_controllers[g_controllerCount] = (AHCI_CONTROLLER*)0;
return;
}
}
// Starts controller.
static KSTATUS AhciStartController(AHCI_CONTROLLER* ctl) {
if (!ctl || ctl->magic != AHCI_CONTROLLER_MAGIC || !ctl->pdo || !ctl->fdo)
@@ -866,25 +835,12 @@ static KSTATUS AhciStartController(AHCI_CONTROLLER* ctl) {
ctl->pciInfo.VendorId,
ctl->pciInfo.DeviceId);
ctl->irq = 0xFFu;
ctl->usingMsi = false;
ctl->pollingMode = false;
st = PciEnableMsiAuto(ctl->pdo, &ctl->irq);
if (KSUCCESS(st)) {
ctl->usingMsi = true;
DbgPrint("AHCI: using MSI IRQ slot %u\n", (unsigned)ctl->irq);
} else {
KSTATUS intxStatus = PciGetInterrupt(ctl->pdo, &ctl->irq);
if (KSUCCESS(intxStatus) && ctl->irq != 0xFFu) {
DbgPrint("AHCI: using legacy INTx IRQ %u\n", (unsigned)ctl->irq);
} else {
ctl->irq = 0xFFu;
ctl->pollingMode = true;
DbgPrint("AHCI: no MSI/INTx interrupt available; using polled command completion (msi=0x%x intx=0x%x)\n",
st, intxStatus);
}
}
ctl->InterruptRequest.Routine = AhciIsr;
ctl->InterruptRequest.Context = ctl;
ctl->InterruptRequest.Affinity = 0;
ctl->InterruptRequest.Interrupt = (KE_INTERRUPT*)0;
st = PciGetBar(ctl->pdo, AHCI_PCI_BAR_ABAR, &ctl->abar);
if (!KSUCCESS(st)) {
@@ -907,10 +863,7 @@ static KSTATUS AhciStartController(AHCI_CONTROLLER* ctl) {
}
uint32_t enableFlags = PCI_ENABLE_MEMORY | PCI_ENABLE_BUSMASTER;
if (ctl->usingMsi || ctl->pollingMode)
enableFlags |= PCI_DISABLE_INTX;
else
enableFlags |= PCI_ENABLE_INTX;
enableFlags |= PCI_DISABLE_INTX;
st = PciEnableDevice(ctl->pdo, enableFlags);
if (!KSUCCESS(st)) {
@@ -946,19 +899,14 @@ static KSTATUS AhciStartController(AHCI_CONTROLLER* ctl) {
return st;
}
st = AhciRegisterController(ctl);
if (!KSUCCESS(st)) {
DbgPrint("AHCI: controller registry full (0x%x)\n", st);
IoDmaPutAdapter(ctl->dmaAdapter);
ctl->dmaAdapter = (IO_DMA_ADAPTER*)0;
return st;
}
// IoRegisterDiskDevice publishes arrival synchronously, and partition/filesystem
// consumers may issue reads from that callback. Install the controller ISR before
// any disk is published so an interrupt-driven drive can complete those reads.
if (!ctl->pollingMode)
KeIrqRegister(ctl->irq, AhciIsr);
st = PciConnectInterrupts(ctl->pdo, &ctl->InterruptRequest, 1u, &ctl->usingMsi);
if (!KSUCCESS(st)) {
ctl->pollingMode = true;
DbgPrint("AHCI: polling fallback status=0x%x\n", st);
}
uint32_t pi = ctl->hba->pi;
for (uint32_t portno = 0; portno < 32 && ctl->driveCount < MAX_AHCI_DRIVES; portno++) {
@@ -1119,8 +1067,11 @@ static KSTATUS AhciStartController(AHCI_CONTROLLER* ctl) {
ctl->pciInfo.Address.Function);
if (!ctl->pollingMode) {
DbgPrint("AHCI: ISR registered on IRQ %u (%s); controller drives=%u\n",
(unsigned)ctl->irq, ctl->usingMsi ? "MSI" : "INTx", (unsigned)ctl->driveCount);
KE_INTERRUPT_INFO info;
if (KSUCCESS(KeInterruptQuery(ctl->InterruptRequest.Interrupt, &info)))
DbgPrint("AHCI: ISR cpu=%u vector=0x%02x mode=%s drives=%u\n",
info.CpuIndex, info.Vector, ctl->usingMsi ? "MSI/MSI-X" : "INTx",
(unsigned)ctl->driveCount);
} else {
DbgPrint("AHCI: controller started in polling mode; controller drives=%u\n",
(unsigned)ctl->driveCount);
@@ -1131,7 +1082,6 @@ static KSTATUS AhciStartController(AHCI_CONTROLLER* ctl) {
return NTLSTATUS_SUCCESS;
}
// Implements the add Device operation.
static KSTATUS AhciAddDevice(DRIVER_OBJECT* driver, DEVICE_OBJECT* physicalDeviceObject) {
if (!driver || !physicalDeviceObject || physicalDeviceObject->Type != DeviceObjectPhysical)
return NTLSTATUS_INVALID_PARAMETER;
@@ -1146,7 +1096,7 @@ static KSTATUS AhciAddDevice(DRIVER_OBJECT* driver, DEVICE_OBJECT* physicalDevic
ctl->magic = AHCI_CONTROLLER_MAGIC;
ctl->fdo = fdo;
ctl->pdo = physicalDeviceObject;
ctl->irq = 0xFF;
ctl->pciInfo.InterruptLine = 0xFF;
(void)IoSetDeviceName(fdo, SYS_SV_LITERAL("ahci-controller"));
ctl->lowerDevice = IoAttachDeviceToDeviceStack(fdo, physicalDeviceObject);
@@ -1164,7 +1114,6 @@ static KSTATUS DriverInitialize(NTL_MODULE* module) {
DbgPrint("AHCI: driver loading...\n");
g_controllerCount = 0;
g_nextDiskIndex = 0;
memset(&g_driver, 0, sizeof(g_driver));
+1 -1
View File
@@ -373,7 +373,7 @@ struct AHCI_CONTROLLER {
PCI_BAR abar;
HBA_MEM* hba;
uint64_t abarLength;
uint8_t irq;
PCI_INTERRUPT_REQUEST InterruptRequest;
bool usingMsi;
bool pollingMode;
-8
View File
@@ -2,7 +2,6 @@
#include "ahci.h"
// Implements the ahci map mmio operation.
KSTATUS ahci_map_mmio(uint64_t physBase, uint64_t length) {
if (length == 0)
length = AHCI_MMIO_PAGES * 4096ull;
@@ -25,7 +24,6 @@ KSTATUS ahci_map_mmio(uint64_t physBase, uint64_t length) {
return NTLSTATUS_SUCCESS;
}
// Implements the port stop operation.
void port_stop(HBA_PORT* port) {
// Clear ST (bit 0).
port->cmd &= ~PORT_CMD_ST;
@@ -41,7 +39,6 @@ void port_stop(HBA_PORT* port) {
}
}
// Implements the port start operation.
void port_start(HBA_PORT* port) {
// Wait until CR is clear before setting ST.
for (int i = 0; i < POLL_TIMEOUT; i++) {
@@ -51,7 +48,6 @@ void port_start(HBA_PORT* port) {
port->cmd |= PORT_CMD_ST;
}
// Implements the hba reset operation.
KSTATUS hba_reset(HBA_MEM* hba) {
// BIOS/OS handoff (spec §10.6.3).
if (hba->cap2 & CAP2_BOH) {
@@ -85,25 +81,21 @@ KSTATUS hba_reset(HBA_MEM* hba) {
return NTLSTATUS_SUCCESS;
}
// Implements the port link up operation.
bool port_link_up(HBA_PORT* port) {
uint32_t det = port->ssts & 0x0F;
uint32_t ipm = (port->ssts >> 8) & 0x0F;
return (det == PORT_DET_PRESENT && ipm == PORT_IPM_ACTIVE);
}
// Implements the port is sata disk operation.
bool port_is_sata_disk(HBA_PORT* port) {
return port->sig == SATA_SIG_ATA;
}
// Implements the ahci delay ms operation.
void ahci_delay_ms(uint32_t ms) {
for (uint32_t i = 0; i < ms * 1000; i++)
__outbyte(0x80, 0);
}
// Implements the port comreset operation.
KSTATUS port_comreset(AHCI_DRIVE* drv) {
HBA_PORT* port = drv->port;
+1
View File
@@ -0,0 +1 @@
!include $(BASEDIR)\makefile.def
+7
View File
@@ -0,0 +1,7 @@
TARGETNAME=ahci
TARGETPATH=obj
TARGETTYPE=DRIVER
FLAVOR=DRIVER
TARGETLIBS="$(BASEDIR)\bin\kernel.lib" "$(BASEDIR)\bin\libc.lib" "$(BASEDIR)\bin\pci.lib"
EXTRA_LFLAGS=/NOENTRY
SOURCES=@/code/drivers/storage/ahci/ahci.c @/code/drivers/storage/ahci/ahci_port.c
-13
View File
@@ -16,37 +16,30 @@ static const IO_DRIVER_ID_TABLE gAtaIdTable = {
sizeof(gAtaIds) / sizeof(gAtaIds[0]),
};
// Implements the in8 operation.
static uint8_t AtaIn8(ATA_CHANNEL* ch, uint8_t reg) {
return __inbyte((unsigned short)(ch->CommandBase + reg));
}
// Implements the in16 operation.
static uint16_t AtaIn16(ATA_CHANNEL* ch, uint8_t reg) {
return __inword((unsigned short)(ch->CommandBase + reg));
}
// Implements the out8 operation.
static void AtaOut8(ATA_CHANNEL* ch, uint8_t reg, uint8_t value) {
__outbyte((unsigned short)(ch->CommandBase + reg), value);
}
// Implements the out16 operation.
static void AtaOut16(ATA_CHANNEL* ch, uint8_t reg, uint16_t value) {
__outword((unsigned short)(ch->CommandBase + reg), value);
}
// Implements the alt Status operation.
static uint8_t AtaAltStatus(ATA_CHANNEL* ch) {
return __inbyte((unsigned short)(ch->ControlBase + ATA_REG_ALT_STATUS));
}
// Implements the device Control operation.
static void AtaDeviceControl(ATA_CHANNEL* ch, uint8_t value) {
__outbyte((unsigned short)(ch->ControlBase + ATA_REG_DEVICE_CONTROL), value);
}
// Implements the delay400ns operation.
static void AtaDelay400ns(ATA_CHANNEL* ch) {
(void)AtaAltStatus(ch);
(void)AtaAltStatus(ch);
@@ -142,7 +135,6 @@ static KSTATUS AtaResetChannel(ATA_CHANNEL* ch) {
return status;
}
// Implements the select Drive operation.
static void AtaSelectDrive(ATA_DEVICE* dev) {
ATA_CHANNEL* ch = dev->Channel;
AtaOut8(ch, ATA_REG_DRIVE_HEAD, (uint8_t)(0xA0u | (dev->Drive ? 0x10u : 0u)));
@@ -241,7 +233,6 @@ static KSTATUS AtaIdentify(ATA_DEVICE* dev) {
return dev->SectorCount ? NTLSTATUS_SUCCESS : NTLSTATUS_NOT_FOUND;
}
// Implements the program Lba operation.
static KSTATUS AtaProgramLba(ATA_DEVICE* dev, uint64_t lba, uint16_t count, bool write) {
ATA_CHANNEL* ch = dev->Channel;
@@ -407,7 +398,6 @@ static KSTATUS AtaGetIrpReadWrite(IRP* irp, bool* outWrite, uint64_t* outLba,
return NTLSTATUS_SUCCESS;
}
// Implements the worker operation.
static void AtaWorker(uintptr_t arg) {
ATA_DEVICE* dev = (ATA_DEVICE*)arg;
if (!dev)
@@ -572,7 +562,6 @@ static uint8_t AtaFindFreeDiskIndex(void) {
return 0xFFu;
}
// Implements the bar Io Base operation.
static uint16_t AtaBarIoBase(ATA_CONTROLLER* ctl, uint8_t barIndex, uint16_t fallback) {
PCI_BAR bar;
KSTATUS st = PciGetBar(ctl->Pdo, barIndex, &bar);
@@ -709,7 +698,6 @@ static KSTATUS AtaProbeDrive(ATA_CONTROLLER* ctl, ATA_CHANNEL* ch, uint8_t drive
return NTLSTATUS_SUCCESS;
}
// Registers controller.
static KSTATUS AtaRegisterController(ATA_CONTROLLER* ctl) {
if (!ctl) return NTLSTATUS_INVALID_PARAMETER;
for (uint32_t i = 0; i < gAtaControllerCount; i++) {
@@ -895,7 +883,6 @@ KSTATUS AtaDispatchPnp(DEVICE_OBJECT* device, IRP* irp) {
return NTLSTATUS_INVALID_PARAMETER;
}
// Implements the add Device operation.
KSTATUS AtaAddDevice(DRIVER_OBJECT* driver, DEVICE_OBJECT* physicalDeviceObject) {
if (!driver || !physicalDeviceObject || physicalDeviceObject->Type != DeviceObjectPhysical)
return NTLSTATUS_INVALID_PARAMETER;
+1
View File
@@ -0,0 +1 @@
!include $(BASEDIR)\makefile.def
+7
View File
@@ -0,0 +1,7 @@
TARGETNAME=ata
TARGETPATH=obj
TARGETTYPE=DRIVER
FLAVOR=DRIVER
TARGETLIBS="$(BASEDIR)\bin\kernel.lib" "$(BASEDIR)\bin\libc.lib" "$(BASEDIR)\bin\pci.lib"
EXTRA_LFLAGS=/NOENTRY
SOURCES=@/code/drivers/storage/ata/ata.c
+1
View File
@@ -0,0 +1 @@
DIRS=ahci ata