I'm new to Windows device driver programming. I know that certain operations can only be performed at IRQL PASSIVE_开发者_高级运维LEVEL
. For example, Microsoft have this sample code of how to write to a file from a kernel driver:
if (KeGetCurrentIrql() != PASSIVE_LEVEL)
return STATUS_INVALID_DEVICE_STATE;
Status = ZwCreateFile(...);
My question is this: What is preventing the IRQL from being raised after the KeGetCurrentIrql()
check above? Say a context or thread swithch occurs, couldn't the IRQL suddenly be DISPATCH_LEVEL
when it gets back to my driver which would then result in a system crash?
If this is NOT possible then why not just check the IRQL in the DriverEntry
function and be done with it once for all?
The irql of a thread can only be raised by itself.
Because you are called from upper/lower drivers, the irql of the current running context may be different. And there are a couple of functions that raise/lower the irql.
A couple examples :
IRP_MJ_READ
NTSTATUS DispatchRead(
__in struct _DEVICE_OBJECT *DeviceObject,
__in struct _IRP *Irp
)
{
// this will be called at irql == PASSIVE_LEVEL
...
// we have acquire a spinlock
KSSPIN_LOCK lck;
KeInititializeSpinLock( &lck );
KIRQL prev_irql;
KeAcquireSpinLock( &lck,&prev_irql );
// KeGetCurrentIrql() == DISPATCH_LEVEL
KeReleaseSpinLock( &lck, prev_irql );
// KeGetCurrentIrql() == PASSIVE_LEVEL
...
}
(Io-)Completion routines may be called at DISPATCH_LEVEL
and so should behave accordingly.
NTSTATUS CompleteSth(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PVOID Context)
{
// KeGetCurrentIrql() >= PASSIVE_LEVEL
}
The IRQL can only change in any meaningful way under your control by setting it. There are two "thread specific" IRQLs - PASSIVE_LEVEL and APC_LEVEL. You control going in and out of these levels with things like fast mutexes, and a context switch to your thread will always leave you at the level you were in before. Above that are "processor specific" IRQLs. That is DISPATCH_LEVEL or above. In these levels a context switch cannot occur. You get into these levels using spin locks and such. ISRs will occur at higher IRQLs on your thread, but you can't see them. When they return control to you your IRQL is restored.
DriverEntry is also called at PASSIVE_LEVEL.
If you want to have a job done at PASSIVE_LEVEL then use functions like IoQueueWorkItem
精彩评论