Nice one crU

("Good Spot" in the birding world)
If I use KeGetCurrentIrql in regular driver code it returns 0 or PASSIVE_LEVEL, which is normal. If I use it in my Softice extension it returns at a whopping what is the 3rd highest IRQL level of 29 or IPI_LEVEL. Softice itself (or its extensions at least) must run at an elevated level so it doesn't get interrupted by anything lower, in fact the only things which could interrupt its execution are Machine checks/bus errors and Power-fail interrupts. Interestingly there is no KeRaiseIrql API in Sice code, so it must do it some other way during initialization.
Programming the MS WDM by Oney talks about IRQL and Paging:
--------------------------------------------
IRQL and Paging
One consequence of running at elevated IRQL is that the system becomes incapable of servicing page faults. The rule this fact implies is simply stated:
Code executing at or above DISPATCH_LEVEL must not cause page faults.
One implication of this rule is that any of the subroutines in your driver that execute at or above DISPATCH_LEVEL must be in nonpaged memory.
Furthermore, all the data you access in such a subroutine must also be in nonpaged memory. Finally, as IRQL rises, fewer and fewer kernel-mode support routines are available for your use.
...it’s well to point out that the rule against page faults is really a rule prohibiting any sort of hardware exception, including page faults, divide checks, bounds exceptions, and so on.
-------------------------------------------
During testing I was able to change the IRQL level within a Sice extension to that of PASSIVE_LEVEL (0) or DISPATCH_LEVEL (2) in the following way.
Code:
LOCAL OldIrql

WORD
LOCAL DummyIrql

WORD
invoke KeGetCurrentIrql ; (include hal.inc/hal.lib)
mov OldIrql, eax
; returns IPI_LEVEL equ 29 ; Interprocessor interrupt level
invoke KeLowerIrql, PASSIVE_LEVEL ; // DISPATCH_LEVEL
invoke KeGetCurrentIrql
; returns PASSIVE_LEVEL or DISPATCH_LEVEL
; Do our memory copy here?
; Raise it back
lea eax, DummyIrql ; storage for returned value, we won't use
invoke KeRaiseIrql, OldIrql, eax
invoke KeGetCurrentIrql
; returns IPI_LEVEL
Btw, This ignored the DDK, again from Oney:
-----------------------------
The DDK documentation says that you must always call KeLowerIrql with the same value as that returned by the immediately preceding call to KeRaiseIrql, but this information isn’t exactly right. The only rule that KeLowerIrql actually applies is that the new IRQL must be less than or equal to the current one.
-----------------------------
The one possible caveat to lowering the Irql is that something other than the page fault(s) we want to occur might interrupt the mem copy, so ExAllocatePool should likely be done beforehand, then raise the Irql again as soon as possible:
-----------------------------
It’s a mistake (and a big one!) to lower IRQL below whatever it was when a system routine called your driver, even if you raise it back before returning. Such a break in synchronization might allow some activity to preempt you and interfere with a data object that your caller assumed would remain inviolate.
-----------------------------
It makes sense now that the error is probably coming from the source buffer side of things (generally pageable user code), and not the destination buffer (non-pageable allocated memory):
-----------------------------
Paged pool.
Driver routines running below DISPATCH_LEVEL IRQL can use a heap area called paged pool. As the name implies, memory in this area is pagable, and a page fault can occur when it is accessed.
Nonpaged pool.
Driver routines running at elevated IRQLs need to allocate temporary storage from another heap area called nonpaged pool. The system guarantees that the virtual memory in nonpaged pool is always physically resident. The device and controller extensions created by the I/O Manager come from this pool area.
----------------------------------------------------------
So it sounds like either page everything in before copying or temporarily lower the IRQL.