usb hubs, hotplug support, unplug support, saving log files to disk, smt
This commit is contained in:
1 parent
b838f8d83d
commit
27b31f62b6
39 files changed
+6294
-735
No files matched your search
@@ -382,6 +382,28 @@ static KSTATUS do_write(AHCI_DRIVE *drv, uint64_t lba,
|
||||
// Async IRP dispatch
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
static KSTATUS AhciGetIrpReadWrite(IRP* irp, bool* outWrite, uint64_t* outLba,
|
||||
uint32_t* outSectors, void** outBuffer) {
|
||||
if (!irp || !outWrite || !outLba || !outSectors || !outBuffer)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
IO_STACK_LOCATION* ios = IoGetCurrentIrpStackLocation(irp);
|
||||
if (!ios) return STATUS_INVALID_PARAMETER;
|
||||
if (ios->MajorFunction != IRP_MJ_READ && ios->MajorFunction != IRP_MJ_WRITE)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
if ((ios->Parameters.ReadWrite.ByteOffset & 511ull) ||
|
||||
(ios->Parameters.ReadWrite.Length & 511u))
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
if (!irp->UserBuffer || ios->Parameters.ReadWrite.Length == 0)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
*outWrite = (ios->MajorFunction == IRP_MJ_WRITE);
|
||||
*outLba = ios->Parameters.ReadWrite.ByteOffset >> 9;
|
||||
*outSectors = ios->Parameters.ReadWrite.Length >> 9;
|
||||
*outBuffer = irp->UserBuffer;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// AhciDispatchReadWrite - DEVICE_OBJECT dispatch entry for disk IRPs.
|
||||
// Accepted IRPs are queued to the per-drive worker and completed later with
|
||||
// IoCompleteRequest(). Rejected IRPs are returned synchronously and are not
|
||||
@@ -390,8 +412,22 @@ static KSTATUS AhciDispatchReadWrite(DEVICE_OBJECT *device, IRP *irp) {
|
||||
if (!device || !irp) return STATUS_INVALID_PARAMETER;
|
||||
AHCI_DRIVE *drv = (AHCI_DRIVE *)device->DeviceExtension;
|
||||
if (!drv) return STATUS_INVALID_PARAMETER;
|
||||
if (irp->SectorCount == 0 || !irp->Buffer) return STATUS_INVALID_PARAMETER;
|
||||
if (irp->Lba + irp->SectorCount > drv->sectorCount) return STATUS_INVALID_PARAMETER;
|
||||
|
||||
KSTATUS st = IoAcquireRemoveLock(&drv->removeLock, irp);
|
||||
if (!KSUCCESS(st))
|
||||
return st;
|
||||
|
||||
bool write = false;
|
||||
uint64_t lba = 0;
|
||||
uint32_t sectors = 0;
|
||||
void* buffer = (void*)0;
|
||||
st = AhciGetIrpReadWrite(irp, &write, &lba, §ors, &buffer);
|
||||
(void)write;
|
||||
(void)buffer;
|
||||
if (!KSUCCESS(st) || lba + sectors > drv->sectorCount) {
|
||||
IoReleaseRemoveLock(&drv->removeLock, irp);
|
||||
return KSUCCESS(st) ? STATUS_INVALID_PARAMETER : st;
|
||||
}
|
||||
|
||||
irp->Status = STATUS_FAILURE;
|
||||
irp->Information = 0;
|
||||
@@ -399,6 +435,49 @@ static KSTATUS AhciDispatchReadWrite(DEVICE_OBJECT *device, IRP *irp) {
|
||||
return STATUS_PENDING;
|
||||
}
|
||||
|
||||
static void AhciCancelReleaseRemoveLock(IRP* irp, void* context) {
|
||||
AHCI_DRIVE* drv = (AHCI_DRIVE*)context;
|
||||
if (drv)
|
||||
IoReleaseRemoveLock(&drv->removeLock, irp);
|
||||
}
|
||||
|
||||
static KSTATUS AhciDispatchPnp(DEVICE_OBJECT* device, IRP* irp) {
|
||||
if (!device || !irp) return STATUS_INVALID_PARAMETER;
|
||||
AHCI_DRIVE* drv = (AHCI_DRIVE*)device->DeviceExtension;
|
||||
if (!drv) return STATUS_INVALID_PARAMETER;
|
||||
|
||||
IO_STACK_LOCATION* ios = IoGetCurrentIrpStackLocation(irp);
|
||||
if (!ios || ios->MajorFunction != IRP_MJ_PNP)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
switch ((IO_PNP_MINOR_FUNCTION)ios->MinorFunction) {
|
||||
case IRP_MN_START_DEVICE:
|
||||
device->PnpState = DevicePnpStarted;
|
||||
return STATUS_SUCCESS;
|
||||
case IRP_MN_QUERY_REMOVE_DEVICE:
|
||||
device->PnpState = DevicePnpRemovePending;
|
||||
return STATUS_SUCCESS;
|
||||
case IRP_MN_CANCEL_REMOVE_DEVICE:
|
||||
device->PnpState = DevicePnpStarted;
|
||||
return STATUS_SUCCESS;
|
||||
case IRP_MN_SURPRISE_REMOVAL:
|
||||
drv->surpriseRemoved = true;
|
||||
device->PnpState = DevicePnpSurpriseRemoved;
|
||||
IrpQueueCancelAllEx(&drv->irpQueue, STATUS_OBJECT_DEAD, AhciCancelReleaseRemoveLock, drv);
|
||||
return STATUS_SUCCESS;
|
||||
case IRP_MN_REMOVE_DEVICE:
|
||||
drv->removed = true;
|
||||
device->PnpState = DevicePnpDeleted;
|
||||
IrpQueueCancelAllEx(&drv->irpQueue, STATUS_OBJECT_DEAD, AhciCancelReleaseRemoveLock, drv);
|
||||
IoReleaseRemoveLockAndWait(&drv->removeLock, irp);
|
||||
IoDeleteDevice(device);
|
||||
drv->deviceObject = (DEVICE_OBJECT*)0;
|
||||
return STATUS_SUCCESS;
|
||||
default:
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
// AhciWorker - kernel thread, one per drive.
|
||||
// Dequeues IRPs and executes them one at a time using the existing
|
||||
// single-slot interrupt-driven path. Completion fires the IRP's event
|
||||
@@ -420,17 +499,24 @@ static void AhciWorker(uintptr_t arg) {
|
||||
KeWaitSemaphore(drv->irpQueue.Semaphore);
|
||||
|
||||
IRP *irp = IrpQueueDequeue(&drv->irpQueue);
|
||||
if (!irp) KePanic(KE_PANIC_CODE_DRIVER, "AhciWorker: semaphore fired but queue is empty - IRP accounting bug\n");
|
||||
if (!irp)
|
||||
continue;
|
||||
|
||||
bool write = !!(irp->Flags & IRP_FLAG_WRITE);
|
||||
KSTATUS st;
|
||||
if (write)
|
||||
st = do_write(drv, irp->Lba, irp->SectorCount, irp->Buffer);
|
||||
else
|
||||
st = do_read (drv, irp->Lba, irp->SectorCount, irp->Buffer);
|
||||
bool write = false;
|
||||
uint64_t lba = 0;
|
||||
uint32_t sectors = 0;
|
||||
void* buffer = (void*)0;
|
||||
KSTATUS st = AhciGetIrpReadWrite(irp, &write, &lba, §ors, &buffer);
|
||||
if (KSUCCESS(st)) {
|
||||
if (write)
|
||||
st = do_write(drv, lba, sectors, buffer);
|
||||
else
|
||||
st = do_read (drv, lba, sectors, buffer);
|
||||
}
|
||||
|
||||
// Publish result then fire completion hooks through the common I/O path.
|
||||
IoCompleteRequest(irp, st, KSUCCESS(st) ? ((size_t)irp->SectorCount * 512u) : 0);
|
||||
IoReleaseRemoveLock(&drv->removeLock, irp);
|
||||
IoCompleteRequest(irp, st, KSUCCESS(st) ? ((size_t)sectors * 512u) : 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -467,9 +553,10 @@ KSTATUS AhciInitialize(const HAL_API *hal) {
|
||||
g_driveCount = 0;
|
||||
|
||||
memset(&g_driver, 0, sizeof(g_driver));
|
||||
g_driver.Name = "ahci";
|
||||
IoInitializeDriverObject(&g_driver, SYS_SV_LITERAL("ahci"));
|
||||
g_driver.MajorFunction[IRP_MJ_READ] = AhciDispatchReadWrite;
|
||||
g_driver.MajorFunction[IRP_MJ_WRITE] = AhciDispatchReadWrite;
|
||||
g_driver.MajorFunction[IRP_MJ_PNP] = AhciDispatchPnp;
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Locate AHCI controller via PCI class scan
|
||||
@@ -588,6 +675,11 @@ KSTATUS AhciInitialize(const HAL_API *hal) {
|
||||
continue;
|
||||
}
|
||||
IrpQueueInit(&drv->irpQueue, irpSem);
|
||||
st = IoInitializeRemoveLock(&drv->removeLock);
|
||||
if (!KSUCCESS(st)) {
|
||||
DbgPrint("AHCI: port %u: remove-lock init failed (0x%x)\n", portno, st);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Phase 6: IDENTIFY (polled - scheduler not yet running)
|
||||
st = port_identify(drv);
|
||||
@@ -613,7 +705,8 @@ KSTATUS AhciInitialize(const HAL_API *hal) {
|
||||
continue;
|
||||
}
|
||||
drv->deviceObject->DeviceExtension = drv;
|
||||
drv->deviceObject->SectorCount = drv->sectorCount;
|
||||
drv->deviceObject->u.Disk.SectorCount = drv->sectorCount;
|
||||
drv->deviceObject->u.Disk.SectorSize = 512;
|
||||
drv->deviceObject->AlignmentRequirement = 512;
|
||||
|
||||
st = IoRegisterDiskDevice((uint8_t)driveIdx, drv->deviceObject);
|
||||
|
||||
@@ -344,6 +344,9 @@ typedef struct {
|
||||
// AhciWorker blocks here waiting for work. AHCI dispatch enqueues an IRP
|
||||
// and signals the semaphore to wake the worker.
|
||||
IRP_QUEUE irpQueue;
|
||||
IO_REMOVE_LOCK removeLock;
|
||||
bool surpriseRemoved;
|
||||
bool removed;
|
||||
THREAD* workerThread;
|
||||
DEVICE_OBJECT* deviceObject;
|
||||
|
||||
|
||||
+104
-17
@@ -21,6 +21,9 @@ IRP_QUEUE gIrpQueue;
|
||||
SEMAPHORE *gIrpSemaphore = NULL;
|
||||
EVENT *gDmaEvent = NULL; // auto-reset; DPC signals after each xfer
|
||||
KDPC gDmaDpc; // bottom half for DMA completion
|
||||
IO_REMOVE_LOCK gRemoveLock;
|
||||
bool gSurpriseRemoved = false;
|
||||
bool gRemoved = false;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Bus Master I/O helpers
|
||||
@@ -307,6 +310,28 @@ static KSTATUS IdeDmaRw(uint64_t lba, uint32_t count, void *buf, bool write) {
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static KSTATUS IdeGetIrpReadWrite(IRP* irp, bool* outWrite, uint64_t* outLba,
|
||||
uint32_t* outSectors, void** outBuffer) {
|
||||
if (!irp || !outWrite || !outLba || !outSectors || !outBuffer)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
IO_STACK_LOCATION* ios = IoGetCurrentIrpStackLocation(irp);
|
||||
if (!ios) return STATUS_INVALID_PARAMETER;
|
||||
if (ios->MajorFunction != IRP_MJ_READ && ios->MajorFunction != IRP_MJ_WRITE)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
if ((ios->Parameters.ReadWrite.ByteOffset & 511ull) ||
|
||||
(ios->Parameters.ReadWrite.Length & 511u))
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
if (!irp->UserBuffer || ios->Parameters.ReadWrite.Length == 0)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
*outWrite = (ios->MajorFunction == IRP_MJ_WRITE);
|
||||
*outLba = ios->Parameters.ReadWrite.ByteOffset >> 9;
|
||||
*outSectors = ios->Parameters.ReadWrite.Length >> 9;
|
||||
*outBuffer = irp->UserBuffer;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// IdeWorker — kernel thread, one per IDE controller.
|
||||
//
|
||||
@@ -320,17 +345,22 @@ void IdeWorker(uintptr_t arg) {
|
||||
|
||||
IRP *irp = IrpQueueDequeue(&gIrpQueue);
|
||||
if (!irp)
|
||||
KePanic(KE_PANIC_CODE_DRIVER, "IdeWorker: semaphore fired but IRP queue is empty — accounting bug\n");
|
||||
continue;
|
||||
|
||||
KSTATUS st;
|
||||
if (irp->Lba + irp->SectorCount > gSectorCount) {
|
||||
st = STATUS_INVALID_PARAMETER;
|
||||
} else {
|
||||
bool write = !!(irp->Flags & IRP_FLAG_WRITE);
|
||||
st = IdeDmaRw(irp->Lba, irp->SectorCount, irp->Buffer, write);
|
||||
bool write = false;
|
||||
uint64_t lba = 0;
|
||||
uint32_t sectors = 0;
|
||||
void* buffer = (void*)0;
|
||||
KSTATUS st = IdeGetIrpReadWrite(irp, &write, &lba, §ors, &buffer);
|
||||
if (KSUCCESS(st)) {
|
||||
if (lba + sectors > gSectorCount)
|
||||
st = STATUS_INVALID_PARAMETER;
|
||||
else
|
||||
st = IdeDmaRw(lba, sectors, buffer, write);
|
||||
}
|
||||
|
||||
IoCompleteRequest(irp, st, KSUCCESS(st) ? ((size_t)irp->SectorCount * 512u) : 0);
|
||||
IoReleaseRemoveLock(&gRemoveLock, irp);
|
||||
IoCompleteRequest(irp, st, KSUCCESS(st) ? ((size_t)sectors * 512u) : 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -344,8 +374,20 @@ void IdeWorker(uintptr_t arg) {
|
||||
// ---------------------------------------------------------------------------
|
||||
static KSTATUS IdeDispatchReadWrite(DEVICE_OBJECT *device, IRP *irp) {
|
||||
(void)device;
|
||||
if (!irp || !irp->Buffer || irp->SectorCount == 0) return STATUS_INVALID_PARAMETER;
|
||||
if (irp->Lba + irp->SectorCount > gSectorCount) return STATUS_INVALID_PARAMETER;
|
||||
|
||||
KSTATUS st = IoAcquireRemoveLock(&gRemoveLock, irp);
|
||||
if (!KSUCCESS(st))
|
||||
return st;
|
||||
|
||||
bool write = false;
|
||||
uint64_t lba = 0;
|
||||
uint32_t sectors = 0;
|
||||
void* buffer = (void*)0;
|
||||
st = IdeGetIrpReadWrite(irp, &write, &lba, §ors, &buffer);
|
||||
if (!KSUCCESS(st) || lba + sectors > gSectorCount) {
|
||||
IoReleaseRemoveLock(&gRemoveLock, irp);
|
||||
return KSUCCESS(st) ? STATUS_INVALID_PARAMETER : st;
|
||||
}
|
||||
|
||||
irp->Status = STATUS_FAILURE;
|
||||
irp->Information = 0;
|
||||
@@ -355,13 +397,53 @@ static KSTATUS IdeDispatchReadWrite(DEVICE_OBJECT *device, IRP *irp) {
|
||||
return STATUS_PENDING;
|
||||
}
|
||||
|
||||
bool write = !!(irp->Flags & IRP_FLAG_WRITE);
|
||||
KSTATUS st = write ? IdeWrite(NULL, irp->Lba, irp->SectorCount, irp->Buffer)
|
||||
: IdeRead (NULL, irp->Lba, irp->SectorCount, irp->Buffer);
|
||||
IoCompleteRequest(irp, st, KSUCCESS(st) ? ((size_t)irp->SectorCount * 512u) : 0);
|
||||
st = write ? IdeWrite(NULL, lba, sectors, buffer)
|
||||
: IdeRead (NULL, lba, sectors, buffer);
|
||||
IoReleaseRemoveLock(&gRemoveLock, irp);
|
||||
IoCompleteRequest(irp, st, KSUCCESS(st) ? ((size_t)sectors * 512u) : 0);
|
||||
return STATUS_PENDING;
|
||||
}
|
||||
|
||||
static void IdeCancelReleaseRemoveLock(IRP* irp, void* context) {
|
||||
(void)context;
|
||||
IoReleaseRemoveLock(&gRemoveLock, irp);
|
||||
}
|
||||
|
||||
static KSTATUS IdeDispatchPnp(DEVICE_OBJECT* device, IRP* irp) {
|
||||
if (!device || !irp) return STATUS_INVALID_PARAMETER;
|
||||
|
||||
IO_STACK_LOCATION* ios = IoGetCurrentIrpStackLocation(irp);
|
||||
if (!ios || ios->MajorFunction != IRP_MJ_PNP)
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
|
||||
switch ((IO_PNP_MINOR_FUNCTION)ios->MinorFunction) {
|
||||
case IRP_MN_START_DEVICE:
|
||||
device->PnpState = DevicePnpStarted;
|
||||
return STATUS_SUCCESS;
|
||||
case IRP_MN_QUERY_REMOVE_DEVICE:
|
||||
device->PnpState = DevicePnpRemovePending;
|
||||
return STATUS_SUCCESS;
|
||||
case IRP_MN_CANCEL_REMOVE_DEVICE:
|
||||
device->PnpState = DevicePnpStarted;
|
||||
return STATUS_SUCCESS;
|
||||
case IRP_MN_SURPRISE_REMOVAL:
|
||||
gSurpriseRemoved = true;
|
||||
device->PnpState = DevicePnpSurpriseRemoved;
|
||||
IrpQueueCancelAllEx(&gIrpQueue, STATUS_OBJECT_DEAD, IdeCancelReleaseRemoveLock, (void*)0);
|
||||
return STATUS_SUCCESS;
|
||||
case IRP_MN_REMOVE_DEVICE:
|
||||
gRemoved = true;
|
||||
device->PnpState = DevicePnpDeleted;
|
||||
IrpQueueCancelAllEx(&gIrpQueue, STATUS_OBJECT_DEAD, IdeCancelReleaseRemoveLock, (void*)0);
|
||||
IoReleaseRemoveLockAndWait(&gRemoveLock, irp);
|
||||
IoDeleteDevice(device);
|
||||
gDevice = (DEVICE_OBJECT*)0;
|
||||
return STATUS_SUCCESS;
|
||||
default:
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// IdeDmaInit — locate the PCI IDE controller, grab BAR4, allocate the PRDT,
|
||||
// create sync objects, and register IRQ 14.
|
||||
@@ -427,13 +509,18 @@ KSTATUS DriverEntry(const HAL_API *hal) {
|
||||
|
||||
// ---- Register definitive DEVICE_OBJECT --------------------------------
|
||||
memset(&gDriver, 0, sizeof(gDriver));
|
||||
gDriver.Name = "ide";
|
||||
IoInitializeDriverObject(&gDriver, SYS_SV_LITERAL("ide"));
|
||||
gDriver.MajorFunction[IRP_MJ_READ] = IdeDispatchReadWrite;
|
||||
gDriver.MajorFunction[IRP_MJ_WRITE] = IdeDispatchReadWrite;
|
||||
gDriver.MajorFunction[IRP_MJ_PNP] = IdeDispatchPnp;
|
||||
|
||||
KSTATUS st = IoCreateDevice(&gDriver, 0, &gDevice);
|
||||
KSTATUS st = IoInitializeRemoveLock(&gRemoveLock);
|
||||
if (!KSUCCESS(st)) return st;
|
||||
gDevice->SectorCount = gSectorCount;
|
||||
|
||||
st = IoCreateDevice(&gDriver, 0, &gDevice);
|
||||
if (!KSUCCESS(st)) return st;
|
||||
gDevice->u.Disk.SectorCount = gSectorCount;
|
||||
gDevice->u.Disk.SectorSize = 512;
|
||||
gDevice->AlignmentRequirement = 512;
|
||||
|
||||
// ---- Try to initialise Bus Master DMA ---------------------------------
|
||||
|
||||
Reference in new issue
Block a user