管理硬體優先順序

執行驅動程式常式的 IRQL 會決定哪些核心模式驅動程式支援它可以呼叫的常式。 例如,某些驅動程式支援常式需要呼叫端在 IRQL = DISPATCH_LEVEL執行。 如果呼叫端在任何 IRQL 執行高於 PASSIVE_LEVEL,則無法安全地呼叫其他人。

以下是呼叫最常實作的標準驅動程式常式的 IRQL 清單。 IRQL 會從最低到最高優先順序列出。

PASSIVE_LEVEL
中斷已遮罩 — 無。

在 呼叫的驅動程式常式 PASSIVE_LEVEL — DriverEntryAddDeviceReinitializeUnload 常式、大部分分派常式、驅動程式建立的執行緒、背景工作執行緒回呼。

APC_LEVEL
中斷遮罩關閉 — APC_LEVEL中斷會遮罩關閉。

在 呼叫的驅動程式常式 APC_LEVEL — 某些分派常式 (請參閱 分派常式和 IRQL) 。

DISPATCH_LEVEL
中斷遮罩關閉 — DISPATCH_LEVEL和APC_LEVEL中斷會遮罩關閉。 可能會發生裝置、時鐘和電源故障中斷。

在 呼叫的驅動程式常式DISPATCH_LEVEL — StartIoAdapterControl、AdapterListControlControllerControlIoTimerCancel (,同時按住取消微調鎖定) 、DpcForIsrCustomTimerDpc、CustomDpc常式。

DIRQL
中斷遮罩關閉 — IRQL < = DIRQL 中驅動程式中斷物件的所有中斷。 可能會發生具有較高 DIRQL 值的裝置中斷,以及時鐘和電源故障中斷。

在 DIRQL 呼叫的驅動程式常式 - InterruptServiceSynchCritSection 常式。

APC_LEVEL與PASSIVE_LEVEL之間唯一的差異在於,在 APC_LEVEL 執行的進程無法取得 APC 中斷。 但兩個 IRQL 都表示執行緒內容,而且兩者都表示可以分頁程式碼。

最低層級驅動程式會在三個 IRQL 的其中一個執行時處理 IRP:

  • 在驅動程式的 Dispatch 常式中,PASSIVE_LEVEL在處理器上未遮罩中斷, ()

    DriverEntryAddDeviceReinitializeUnload 常式也會在PASSIVE_LEVEL執行,如同任何驅動程式建立的系統執行緒一樣。

  • DISPATCH_LEVEL,在 StartIo 常式中,具有DISPATCH_LEVEL和APC_LEVEL中斷已遮罩的處理器

    AdapterControl、AdapterListControlControllerControlIoTimerCancel (同時保留取消微調鎖定) ,而CustomTimerDpc常式也會在DISPATCH_LEVEL執行,如同DpcForIsrCustomDpc常式。

  • 裝置 IRQL (DIRQL) ,在 ISR 和SynchCritSection常式中,所有中斷小於或等於驅動程式中斷物件的SyncIrql () 遮罩

大部分較高層級的驅動程式會在兩個 IRQL 其中一個執行時處理 IRP:

  • PASSIVE_LEVEL,在驅動程式的分派常式中,處理器上沒有遮罩中斷

    DriverEntryReinitializeAddDeviceUnload 常式也會在PASSIVE_LEVEL執行,如同任何驅動程式建立的系統執行緒或背景工作執行緒回呼常式或檔案系統驅動程式。

  • DISPATCH_LEVEL,在驅動程式的 IoCompletion 例) (程中,在驅動程式的 IoCompletion 常式中,DISPATCH_LEVEL和APC_LEVEL中斷中斷

    IoTimerCancelCustomTimerDpc 常式也會在DISPATCH_LEVEL執行。

在某些情況下,大量儲存體裝置的中繼和最低層級驅動程式會在 IRQL APC_LEVEL呼叫。 特別是,這可能會發生在檔案系統驅動程式傳送 IRP_MJ_READ 要求給較低驅動程式的分頁錯誤。

大部分的標準驅動程式常式都是在 IRQL 上執行,只允許它們呼叫適當的支援常式。 例如,裝置驅動程式必須在 IRQL DISPATCH_LEVEL上執行時呼叫 AllocateAdapterChannel 。 由於大部分的設備磁碟機都會從 StartIo 常式呼叫這些常式,因此通常它們已在DISPATCH_LEVEL執行。

請注意,沒有 StartIo 常式的裝置驅動程式,因為它設定和管理自己的 IRP 佇列,在應該呼叫 AllocateAdapterChannel時,不一定在 DISPATCH_LEVEL IRQL 上執行。 這類驅動程式必須在呼叫KeRaiseIrqlKeLowerIrql之間巢狀對AllocateAdapterChannel 的呼叫,以便在呼叫 AllocateAdapterChannel時于必要的 IRQL 上執行,並在呼叫常式重新取得控制權時還原原始 IRQL。

呼叫驅動程式支援常式時,請注意下列事項。

  • 使用小於目前IRQL 的輸入 NewIrql值呼叫KeRaiseIrql會導致嚴重錯誤。 除了還原原始 IRQL (以外,呼叫KeLowerIrql) 也會造成嚴重錯誤。

  • 在 IRQL > = DISPATCH_LEVEL執行時,針對核心定義的發送器物件呼叫 KeWaitForSingleObjectKeWaitForMultipleObjects 以等候非零間隔會造成嚴重錯誤。

  • 唯一可以安全地等候事件、旗號、mutex 或計時器設定為訊號狀態的驅動程式常式,就是在 IRQL PASSIVE_LEVEL的非量子執行緒內容中執行,例如驅動程式建立的執行緒、 DriverEntryReinitialize 常式,或分派固有同步 I/O 作業的常式 (,例如大部分的裝置 I/O 控制要求) 。

  • 即使在 IRQL PASSIVE_LEVEL執行時,可分頁驅動程式程式碼不能呼叫 KeSetEventKeReleaseSemaphoreKeReleaseMutex ,且輸入 Wait 參數設定為 TRUE。 這類呼叫可能會導致嚴重分頁錯誤。

  • 執行于 IRQL APC_LEVEL的任何常式都無法從分頁集區配置記憶體,也無法安全地存取分頁集區中的記憶體。 如果在 IRQL 上執行的常式大於 APC_LEVEL造成分頁錯誤,則為嚴重錯誤。

  • 驅動程式必須在 IRQL DISPATCH_LEVEL呼叫 KeAcquireSpinLockAtDpcLevelKeReleaseSpinLockFromDpcLevel時執行。

    驅動程式可以在 IRQL < = DISPATCH_LEVEL呼叫 KeAcquireSpinLock 時執行,但必須呼叫 KeReleaseSpinLock釋放該微調鎖定。 換句話說,呼叫KeReleaseSpinLockFromDpcLevel,以釋放使用KeAcquireSpinLock取得的微調鎖定是程式設計錯誤。

    驅動程式在 IRQL > DISPATCH_LEVEL執行時,不得呼叫KeAcquireSpinLockAtDpcLevelKeReleaseSpinLockFromDpcLevelKeAcquireSpinLockKeReleaseSpinLock

  • 呼叫使用微調鎖定的支援常式,例如ExInterlockedXxx常式,如果呼叫端尚未在引發的 IRQL 上執行,則會在目前的處理器上引發 IRQL,以DISPATCH_LEVEL或 DIRQL。

  • 在 IRQL > PASSIVE_LEVEL執行的驅動程式程式碼應該儘快執行。 執行常式的 IRQL 愈高,整體效能就越重要,可微調該常式以儘快執行。 例如,任何呼叫 KeRaiseIrql 的驅動程式都應該儘快對 KeLowerIrql 進行相互呼叫。

如需決定優先順序的詳細資訊,請參閱 排程、執行緒內容和 IRQL 白皮書。