I’m not a device driver developer - Mostly doing filter development - Is there any situation you think I will encounter:
running code in > DISPATCH_LEVEL?
Using KeInsertQueueDpc?
Using IPI?
Out of all the above, only KeInsertQueueDpc() may THEORETICALLY apply to filter drivers. In practical terms, I hardly imagine why
someone would want to use it in any “proper” driver that does not actually handle interrupts. However, in case if you are just desperate to use it in order to implement some"hack", you can do it in any context.
For example, IIRC, one of the infamous DRM schemes that was used around 15 years ago (I think it was called StarForce or something similar to that) was filtering a CD drive. What it was actually doing was re-queuing a DPC to the head of the queue over and over again
( in order to work around 100us limitation required for driver certification), effectively freezing the system ( UP systems were prevalent at the time) for indefinite periods of time so that the game could not get copied.
Running at DIRQL applies only to ISRs and to the code that synchronises with them, so that this part is reserved only for certain types of hardware devices (normally only PCI and PCIe ones). Concerning IPIs, Windows drivers are not supposed to send the ones.
This is done (or at lest was done at the time when I was writing Windows drivers 12 years ago) by, IIRC, HalRequestSoftwareInterrupt(), but this function was undocumented and was not supposed to be called by anyone, apart from the kernel. AFAIK, nothing had changed in this respect since.
Is there any synchronization object that is allowed in DISPATCH_LEVEL and not allowed in DIRQL?
Of course…
For example, you cannot use “regular” DISPATCH_LEVEL spinlocks at DIRQL. In order to understand why, consider what happens if a CPU acquires a spinlock at DISPATCH_LEVEL, then gets interrupted while still holding it, and ISR tries to acquire the same spinlock again. Once you cannot acquire spinlocks recursively, a deadlock is guaranteed in this situation.
This is why you cannot use “regular” DISPATCH_LEVEL spinlocks at DIRQL. In order to synchronise with ISR you need a special interrupt spinlock that elevates IRQL to DIRL, rather than to DISPATCH_LEVEL.
Why can’t I queue a work item in > DISPATCH_LEVEL?
Apparently, queuing a workitem involves a “regular” spinlock acquisition - after all, workitem queue must be a global one, and,hence,
must be accessible to multiple CPUs at once. Therefore, you need to get a lock before you can add new items to it . You already know why you cannot use “regular” spinlocks at IRQL > DISPATCH_LEVEL, right. This is the reason why you cannot queue a workitem
at IRQL > DISPATCH_LEVEL
Why can’t I call KeInsertQueue in > DISPATCH_LEVEL?
Well, I don’t really know what you mean by “KeInsertQueue”, but assuming that you mean KeInsertQueueDpc(), I can assure you that this
function may be used at IRQL > DISPATCH_LEVEL without a slightest problem. Otherwise, how would you queue a DPC, in the first place???
https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-keinsertqueuedpc
This function inserts a DPC into the queue that is local to the caller CPU, and, hence,does not require locking - simply disabling interrupts on the CPU may suffice here. Therefore, this function does not have IRQL-related requirements…
Anton Bassov