// Kernel IRQL model. This file owns the software interrupt-priority state used by IRQ and scheduler code. #include #include #include #include // Implements the irql Name operation. __declspec(dllexport) const char* KeIrqlName(KIRQL irql) { switch (irql) { case PASSIVE_LEVEL: return "PASSIVE_LEVEL"; case APC_LEVEL: return "APC_LEVEL"; case DISPATCH_LEVEL: return "DISPATCH_LEVEL"; case HIGH_LEVEL: return "HIGH_LEVEL"; default: if (irql >= DIRQL_BASE && irql < HIGH_LEVEL) return "DIRQL"; return "INVALID_IRQL"; } } // Returns current Irql. __declspec(dllexport) KIRQL KeGetCurrentIrql(void) { return KeGetCurrentCpu()->CurrentIrql; } // Implements the raise Irql operation. __declspec(dllexport) KIRQL KeRaiseIrql(KIRQL newIrql) { KCPU* cpu = KeGetCurrentCpu(); KIRQL oldIrql = cpu->CurrentIrql; if (newIrql > HIGH_LEVEL) { KePanic(KE_PANIC_CODE_IRQL, "KeRaiseIrql: invalid target IRQL %u\n", (unsigned)newIrql); } if (newIrql < oldIrql) { KePanic(KE_PANIC_CODE_IRQL, "KeRaiseIrql: attempted raise from %s(%u) down to %s(%u)\n", KeIrqlName(oldIrql), (unsigned)oldIrql, KeIrqlName(newIrql), (unsigned)newIrql); } cpu->CurrentIrql = newIrql; return oldIrql; } // Implements the lower Irql operation. __declspec(dllexport) void KeLowerIrql(KIRQL oldIrql) { KCPU* cpu = KeGetCurrentCpu(); KIRQL currentIrql = cpu->CurrentIrql; if (oldIrql > HIGH_LEVEL) { KePanic(KE_PANIC_CODE_IRQL, "KeLowerIrql: invalid target IRQL %u\n", (unsigned)oldIrql); } if (oldIrql > currentIrql) { KePanic(KE_PANIC_CODE_IRQL, "KeLowerIrql: attempted lower from %s(%u) up to %s(%u)\n", KeIrqlName(currentIrql), (unsigned)currentIrql, KeIrqlName(oldIrql), (unsigned)oldIrql); } cpu->CurrentIrql = oldIrql; if (oldIrql == PASSIVE_LEVEL && currentIrql != PASSIVE_LEVEL) KiDeliverKernelApcs(); } // Implements the assert Irql operation. __declspec(dllexport) void KeAssertIrql(KIRQL expected) { KIRQL currentIrql = KeGetCurrentIrql(); if (currentIrql != expected) { KePanic(KE_PANIC_CODE_IRQL, "IRQL assertion failed: expected %s(%u), current %s(%u)\n", KeIrqlName(expected), (unsigned)expected, KeIrqlName(currentIrql), (unsigned)currentIrql); } } // Implements the assert Irql At Or Below operation. __declspec(dllexport) void KeAssertIrqlAtOrBelow(KIRQL maxIrql) { KIRQL currentIrql = KeGetCurrentIrql(); if (currentIrql > maxIrql) { KePanic(KE_PANIC_CODE_IRQL, "IRQL assertion failed: expected <= %s(%u), current %s(%u)\n", KeIrqlName(maxIrql), (unsigned)maxIrql, KeIrqlName(currentIrql), (unsigned)currentIrql); } } // Checks whether wait. __declspec(dllexport) int KeCanWait(void) { return KeGetCurrentIrql() == PASSIVE_LEVEL; }