I am trying to bring a driver that I inherited into compliance with Microsoft's standards. When I run the Standard Driver Verifier on the source code it says that it fails the StartDeviceWait rule.
The StartDeviceWait rule specifies that the driver should not call KeWaitForSingleObject in the context of start device IRP.
Here is the source code in question:
1: NTSTATUS Cam_Pnp(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
2: {
3: NTSTATUS ntStatus = STATUS_SUCCESS;
4: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
5: PIO_STACK_LOCATION IrpSp;
6: PDEVICE_CAPABILITIES DeviceCapabilities;
7:
8: IrpSp = IoGetCurrentIrpStackLocation(Irp);
9: switch (IrpSp->MinorFunction)
10: {
11: case IRP_MN_START_DEVICE:
12: IoMarkIrpPending(Irp);
13:
14: // Pass down to layer below us first.
15: ntStatus = Cam_SubmitIrpSynch(DeviceObject, Irp, NULL);
16: if (NT_SUCCESS(ntStatus))
17: {
18: Cam_PnpStartDevice(DeviceObject, Irp);
19: }
20:
21: Irp->IoStatus.Status = ntStatus;
22:
23: IoCompleteRequest(Irp, IO_NO_INCREMENT);
24: break;
25: }
26:
27: return (ntStatus);
28: }
29:
30:
31: NTSTATUS Cam_SubmitIrpSynch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PIRB Irb)
32: {
33: NTSTATUS ntStatus = STATUS_SUCCESS;
34: KEVENT Event;
35: PIO_STACK_LOCATION NextIrpStack;
36:
37: if (Irb)
38: {
39: NextIrpStack = IoGetNextIrpStackLocation(Irp);
40: NextIrpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
41: NextIrpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_1394_CLASS;
42: NextIrpStack->Parameters.Others.Argument1 = Irb;
43: }
44: else
45: {
46: IoCopyCurrentIrpStackLocationToNext(Irp);
47: }
48:
49: KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
50:
51: IoSetCompletionRoutine(Irp, Cam_SynchCompletionRoutine, &Event, TRUE, TRUE, TRUE);
52:
53: ntStatus = IoCallDriver(DeviceObject, Irp);
54: if (ntStatus == STATUS_PENDING)
55: {
56: // We can only wait for our completion routine if we are less than dispatch level
57: if (KeGetCurrentIrql() < DISPATCH_LEVEL)
58: {
59: KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); // This is the line it doesn't like
60: }
61: }
62:
63: ntStatus = Irp->IoStatus.Status;
64: return (ntStatus);
65: }
66:
67:
68: NTSTATUS Cam_SynchCompletionRoutine(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PKEVENT Event)
69: {
70: if (Event)
71: {
72: KeSetEvent(Event, 0, FALSE);
73: }
74:
75: return (STATUS_MORE_PROCESSING_REQUIRED);
76: }
According to the Static Driver Verifier:
1: Cam_Pnp
3: NTSTATUS ntStatus = STATUS_SUCCESS;
4: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
8: sdv_IoGetCurrentIrpStackLocation
9: switch (IrpSp->MinorFunction)
12: sdv_IoMarkIrpPending
15: Cam_SubmitIrpSynch
33: NTSTATUS ntStatus = STATUS_SUCCESS;
37: if (Irb)
46: sdv_IoCopyCurrentIrpStackLocationToNext
49: KeInitializeEvent
49: SLIC_KeInitializeEvent_exit
51: sdv_IoSetCompletionRoutine
53: sdv_IoCallDriver
54: if (ntStatus == STATUS_PENDING)
57: sdv_KeGetCurrentIrql
57: if (KeGetCurrentIrql() < DISPATCH_LEVEL)
59: KeWaitForSingleObject
59: SLIC_KeWaitForSingleObject_exit
52: if(($return==STATUS_SUCCESS)&&(irp_event == set_in_completion))
52: if(($return==STATUS_SUCCESS)&&(irp_event == set_in_completion))
54: SLIC_ABORT_3_0
If I can't use KeWaitForSingleObject what am I supposed to use in its place. The Microsoft documentation doesn't make it clear. I hope that I have provided enough info, but please let me know if there is anything else that I can provide that will help.
It took a complete rewrite, but I got it to work and pass the test.
NTSTATUS StartCompletionRoutine(IN PDEVICE_OBJECT nullDeviceObject, IN PIRP Irp, IN PVOID context)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)context;
if (NT_SUCCESS(Irp->IoStatus.Status))
{
ntStatus = Cam_PnpStartDevice(DeviceObject, Irp);
Irp->IoStatus.Status = ntStatus;
}
return ntStatus;
}
NTSTATUS Cam_Pnp(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
PIO_STACK_LOCATION IrpSp;
IrpSp = IoGetCurrentIrpStackLocation(Irp);
ntStatus = IoAcquireRemoveLock(&deviceExtension->ioRemoveLock, Irp);
if (ntStatus != STATUS_SUCCESS)
{
IoCompleteRequest(Irp, IO_NO_INCREMENT);
goto Exit_Cam_Pnp;
}
switch (IrpSp->MinorFunction)
{
case IRP_MN_START_DEVICE:
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(Irp, StartCompletionRoutine, DeviceObject, TRUE, TRUE, TRUE);
IoMarkIrpPending(Irp);
IoCallDriver(deviceExtension->pStackDeviceObject, Irp);
ntStatus = STATUS_PENDING;
break;
}
IoReleaseRemoveLock(&deviceExtension->ioRemoveLock, Irp);
Exit_Cam_Pnp:
return (ntStatus);
}