Správa priorit hardwaru

Úroveň IRQL, při které se vykonává rutina ovladače, určuje, které podpůrné rutiny režimu jádra může volat. Například některé rutiny podpory ovladačů vyžadují, aby volající operoval na úrovni IRQL = DISPATCH_LEVEL. Ostatní se nedají volat bezpečně, pokud volající běží v jakékoli technologii IRQL vyšší než PASSIVE_LEVEL.

Následuje seznam seznamů IRQLs, u kterých se volají nejčastěji implementované standardní rutiny ovladačů. Úrovně IRQL jsou uvedeny od nejnižší po nejvyšší prioritu.

PASSIVE_LEVEL
přeruší maskované - Žádné.

Rutiny ovladačů volané na PASSIVE_LEVEL - DriverEntry, AddDevice, Reinitialize, Unload rutiny, většina dispečerských rutin, vlákna vytvořená ovladačem, zpětná volání pracovníka.

APC_LEVEL
Přerušení blokovaná – Přerušení na úrovni APC jsou blokována.

rutiny ovladačů volané na úrovni APC_LEVEL – některé dispečerské rutiny (viz dispečerské rutiny a IRQL).

DISPATCH_LEVEL
Přerušení jsou vypnuta – přerušení DISPATCH_LEVEL a APC_LEVEL jsou vypnuta. Může dojít k přerušení zařízení, hodin a napájení.

Rutiny ovladače volané na DISPATCH_LEVEL - StartIo, AdapterControl, AdapterListControl, ControllerControl, IoTimer, Zrušit (při podržení zámku zrušení), DpcForIsr, CustomTimerDpc, CustomDpc rutiny.

DIRQL
Maskování přerušení – všechna přerušení na úrovni IRQL <= DIRQL objektu přerušení ovladače. K přerušení zařízení s vyšší hodnotou DIRQL může dojít spolu s přerušeními hodin a napájení.

Rutiny ovladače volané v DIRQL - InterruptService, SynchCritSection rutiny.

Jediným rozdílem mezi APC_LEVEL a PASSIVE_LEVEL je, že proces spuštěný na úrovni APC_LEVEL nemůže přijímat přerušení APC. Ale oba IRQLs naznačují kontext vlákna a oba naznačují, že kód může být odstraněn.

Řidiče na nejnižší úrovni zpracovávají IRP při běhu na jednom ze tří úrovní IRQL:

  • PASSIVE_LEVEL, bez maskování přerušení na procesoru, v rutinách Dispatch ovladače

    DriverEntry, AddDevice, Reinitializea Unload rutiny se také spouští na PASSIVE_LEVEL, stejně jako všechna systémová vlákna vytvořená ovladačem.

  • DISPATCH_LEVEL, s přerušením DISPATCH_LEVEL a APC_LEVEL maskováno na procesoru, v rutině StartIo

    AdapterControl, AdapterListControl, ControllerControl, IoTimer, Zrušit (zatímco drží zámek pro spin zrušení) a rutiny CustomTimerDpc jsou také spuštěny na úrovni DISPATCH_LEVEL, stejně jako rutiny DpcForIsr a CustomDpc.

  • IrQL zařízení (DIRQL), s veškerými přerušeními menšími nebo rovnými SynchronizeIrql objektů přerušení ovladače, které jsou maskovány na procesoru, v ISR a rutiny SynchCritSection.

Většina ovladačů vyšší úrovně zpracovává IRP při provádění na jedné ze dvou úrovní IRQL.

  • PASSIVE_LEVEL, když nejsou na procesoru maskována žádná přerušení, v dispečerských rutinách ovladače

    DriverEntry, Reinitialize, AddDevicea rutiny Unload jsou také spuštěny na PASSIVE_LEVEL, stejně jako všechny rutiny vytvořené ovladačem pro systémové vlákna nebo zpětné volání pracovních vláken či ovladače systému souborů.

  • DISPATCH_LEVEL, se zakázanými přerušeními DISPATCH_LEVEL a APC_LEVEL na procesoru, v rutinách IoCompletion ovladače.

    IoTimer, Cancel, a CustomTimerDpc rutiny se také spouštějí na DISPATCH_LEVEL.

V některých případech se na úrovni IRQL APC_LEVEL volají přechodné a nejnižší ovladače zařízení pro masové úložiště. Konkrétně k tomu může dojít v chybě stránky, pro kterou ovladač systému souborů odešle požadavek IRP_MJ_READ nižším ovladačům.

Většina standardních rutin ovladačů se spouští v IRQL, která jim umožňuje jednoduše volat příslušné rutiny podpory. Ovladač zařízení musí například volat AllocateAdapterChannel, když běží na úrovni IRQL DISPATCH_LEVEL. Vzhledem k tomu, že většina ovladačů zařízení volá tyto rutiny z rutiny StartIo, obvykle běží již na úrovni DISPATCH_LEVEL.

Ovladač zařízení, který nemá rutinu StartIo, protože nastavuje a spravuje vlastní fronty IRP, nemusí nutně běžet na DISPATCH_LEVEL IRQL, když by měl volat AllocateAdapterChannel. Takový ovladač musí vnořit své volání AllocateAdapterChannel mezi voláními KeRaiseIrql a KeLowerIrql tak, aby běžel na požadované úrovni IRQL při volání AllocateAdapterChannel a obnovil původní úroveň IRQL, když volající rutina znovu získá kontrolu.

Při volání rutin podpory ovladačů mějte na paměti následující skutečnosti.

  • Volání KeRaiseIrql se vstupní hodnotou NewIrql, která je menší než aktuální IRQL, způsobí fatální chybu. Volání KeLowerIrql s výjimkou obnovení původního irQL (tj. po volání KeRaiseIrql) také způsobí závažnou chybu.

  • Při běhu na úrovni IRQL >= DISPATCH_LEVEL, zavolání KeWaitForSingleObject nebo KeWaitForMultipleObjects k čekání na objekty dispečera definované jádrem po nenulový interval vede k závažné chybě.

  • Jediné rutiny řidiče, které mohou bezpečně čekat na události, semafory, mutexy nebo časovače, které mají být nastaveny na signalizovaný stav, jsou ty, které běží v kontextu neurčeného vlákna v prostředí IRQL PASSIVE_LEVEL, jako jsou vlákna vytvořená ovladačem, DriverEntry a Reinitialize rutiny nebo dispečerské rutiny pro inherentně synchronní vstupně-výstupní operace (například většina vstupně-výstupních požadavků zařízení).

  • I když běží na PASSIVE_LEVEL IRQL, stránkovatelný kód ovladače nesmí volat KeSetEvent, KeReleaseSemaphorenebo KeReleaseMutex se vstupním parametrem Wait nastaveným na TRUE. Takové volání může způsobit závažnou chybu stránky.

  • Jakákoli rutina běžící na vyšší úrovni IRQL než APC_LEVEL nemůže přidělit paměť ze stránkovaného fondu ani bezpečně přistupovat k paměti ve stránkovaném fondu. Pokud rutina spuštěná v IRQL větší než APC_LEVEL způsobí chybu stránky, jedná se o závažnou chybu.

  • Ovladač musí běžet na úrovni IRQL DISPATCH_LEVEL, když volá KeAcquireSpinLockAtDpcLevel a KeReleaseSpinLockFromDpcLevel.

    Ovladač může běžet na IRQL <= DISPATCH_LEVEL, když volá KeAcquireSpinLock, ale musí uvolnit tento spinový zámek voláním KeReleaseSpinLock. Jinými slovy, jedná se o programovací chybu při uvolnění spinlocku získaného pomocí KeAcquireSpinLock pomocí volání KeReleaseSpinLockFromDpcLevel.

    Ovladač nesmí volat KeAcquireSpinLockAtDpcLevel, KeReleaseSpinLockFromDpcLevel, KeAcquireSpinLocknebo KeReleaseSpinLock během běhu na úrovni IRQL > DISPATCH_LEVEL.

  • Volání podpůrné rutiny, která používá spinlock, jako je rutina ExInterlockedXxx, zvyšuje úroveň IRQL na aktuálním procesoru buď na DISPATCH_LEVEL, nebo DIRQL, jestliže volající již neběží na zvýšené úrovni IRQL.

  • Kód ovladače, který běží na > IRQL PASSIVE_LEVEL, by měl být proveden co nejrychleji. Čím vyšší je IRQL, při kterém se spouští rutina, tím důležitější je pro dobrý celkový výkon tuto rutinu optimalizovat tak, aby se spustila co nejrychleji. Například každý ovladač, který volá KeRaiseIrql by měl provést reciproční volání KeLowerIrql co nejdříve.

Další informace o určování priorit najdete v odborném dokumentu Plánování, kontext vláken a IRQL.