2005/02/19

瞭解Windows Kernel的IRQL運作機制

* IRQL與CPU rings/thread/priority/hardware IRQ的關係
IRQL = Interrupt Request Level
IRQL簡單的說就是『Interrupt執行的優先等級』。
若某個Interrupt產生了,且IRQL等於或低於目前Processor的IRQL setting。那麼他將不會影響目前程式執行。反之,若Interrupt的IRQL高於目前Processor的IRQL setting,那麼將會造成目前的執行中斷,而去執行Interrupt的工作。總而言之,較高優先權的Interrupt會中斷較低優先權的Interrupt。當這個狀況發生時,所有其他等於或是低於這個IRQL的中斷都將成為等待狀態。透過KeGetCurrentIRQL()這個System routine可以得到目前Processor的IRQL。
可用的IRQL如下:Software IRQL:
PASSIVE_LEVEL 0 // Passive release level
LOW_LEVEL 0 // Lowest interrupt level
APC_LEVEL 1 // APC interrupt level
DISPATCH_LEVEL 2 // Dispatch level
Hardware IRQL:
DIRQL: from 3 to 26 for device ISR
PROFILE_LEVEL 27, 0x1B // Timer used for profiling.
CLOCK1_LEVEL 28, 0x1C // Interval clock 1 level - not used on x86
CLOCK2_LEVEL 28, 0x1C // Interval clock 2 level
SYNCH_LEVEL 28, 0x1C // Synchronization level
IPI_LEVEL 29, 0x1D // Interprocessor interrupt level
POWER_LEVEL 30, 0x1E // Power failure level
HIGH_LEVEL 31, 0x1F // Highest interrupt level

數值越大代表其IRQL的優先權越高。
在Driver programming中,常見的有
PASSIVE_LEVEL,
DISPATCH_LEVEL,
DIRQL
使用SpinLock的可解決在多個驅動程式中同步的問題。DDK提供了兩組function。
KeAcquireSpinLock()
KeReleaseSpinLock()

KeAcquireSpinLockAtDpcLevel()
KeReleaseSpinLockAtDpcLevel()
根據DDK上所說,KeAcquireSpinLock()僅能在IRQL < = DISPATCH_LEVEL的狀況下執行。不過,如果想在DISPATCH_LEVEL來執行,最好還是用KeAcquireSpinLickAtDpcLevel().
DDK上也說了,不要太過份依賴SpinLock作為資料同步的機制。原因在於KeAcquireSpinLock()一旦被呼叫,將會導致目前的IRQL LEVEL提升至DISPATCH_LEVEL。此時,Windows Dispatcher的scheduler將會無法被執行。導致系統正常的response變慢。因此,在IRQL已經位於DISPATCH_LEVEL時,就應該呼叫KeAcquireSpinLockAtDpcLevel()。實際上,KeAcquireSpinLockAtDpcLevel()什麼也沒有作。因為,在DISPATCH_LEVEL時,所有routine的執行已經是同步了。所以沒有進一步進行SpinLock()的必要了。
如果是在IRQL < LEVEL的狀況下呢?這個時候去呼叫KeAcquireSpinLock(),將會導致企圖將IRQL降低到DISPATCH_LEVEL的狀況發生。而routine自行降低IRQL是不可以的。

0 意見: