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:
1 parent
d36f19509c
commit
36eef8f58d
696 files changed
+147281
-7530
No files matched your search
@@ -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));
|
||||
|
||||
Reference in new issue
Block a user