Udostępnij przez


Zarządzanie priorytetami sprzętu

Poziom IRQL, na którym wykonywana jest procedura sterownika, określa, które procedury obsługowe trybu jądra może wywołać. Na przykład niektóre procedury obsługi sterowników wymagają, aby wywołujący działał na poziomie IRQL = DISPATCH_LEVEL. Inne osoby nie mogą być wywoływane bezpiecznie, jeśli obiekt wywołujący działa w dowolnym środowisku IRQL wyższym niż PASSIVE_LEVEL.

Poniżej znajduje się lista poziomów IRQL, na których najczęściej wywoływane są standardowe procedury sterowników. Listy IRQLs są wymienione od najniższego do najwyższego priorytetu.

PASSIVE_LEVEL
Przerwania maskowane i wyłączone — brak.

Procedury sterownika wywoływane na PASSIVE_LEVEL — DriverEntry, AddDevice, Reinitialize, rutyna rozładowywania, większość rutyn wysyłania, wątki utworzone przez sterownik, wywołania zwrotne wątku roboczego.

APC_LEVEL
Przerwania wyłączone maskowanie - przerwania na poziomie APC są maskowane.

Procedury kierowcy wywoływane na poziomie APC_LEVEL — niektóre procedury wysyłania (patrz Procedury wysyłania i IRQLs).

DISPATCH_LEVEL
Przerwania Maskowane Wyłączone — przerwania na poziomie DISPATCH_LEVEL i APC_LEVEL są maskowane. Mogą wystąpić przerwy w pracy urządzenia, zegara i awarii zasilania.

Procedury sterownika wywoływane na DISPATCH_LEVEL — StartIo, AdapterControl, AdapterListControl, ControllerControl, IoTimer, Cancel (przytrzymując blokadę spin anulowania), DpcForIsr, CustomTimerDpc, CustomDpc.

DIRQL
Maskowanie Przerwań Wyłączone — wszystkie przerwania na poziomie IRQL równym DIRQL obiektu przerwania sterownika. Mogą wystąpić przerwania urządzenia z wyższą wartością DIRQL, a także przerwania zegara i zasilania.

Procedury sterowników wywoływane w DIRQL — Usługa przerwań, rutiny SynchCritSection.

Jedyną różnicą między APC_LEVEL a PASSIVE_LEVEL jest to, że proces wykonywany na poziomie APC_LEVEL nie może otrzymać przerwań APC. Jednak oba zestawy IRQLs oznaczają kontekst wątku i oznaczają, że kod można stronicować.

Sterowniki najniższego poziomu przetwarzają pakiety IRP działając na jednym z trzech poziomów IRQL.

  • PASSIVE_LEVEL, bez przerw zamaskowanych na procesorze, w procedurach dispatch kierowcy

    DriverEntry, AddDevice, Reinitialize i Unload procedury są również uruchamiane w PASSIVE_LEVEL, podobnie jak w przypadku wszelkich wątków systemowych utworzonych przez sterowników.

  • DISPATCH_LEVEL, z przerwaniami na poziomach DISPATCH_LEVEL i APC_LEVEL zamaskowanymi na procesorze, w procedurze StartIo

    AdapterControl, AdapterListControl, ControllerControl, IoTimer, Cancel (podczas gdy przechowuje blokadę anulowania spin), a procedury CustomTimerDpc są również uruchamiane w DISPATCH_LEVEL, podobnie jak procedury DpcForIsr i CustomDpc.

  • Device IRQL (DIRQL) ze wszystkimi przerwaniami przy mniejszym lub równym SynchronizeIrql obiektów przerwań sterownika zmaskowane na procesorze, w procedurach ISR i SynchCritSection

Większość sterowników wyższego poziomu przetwarza pakiety IRP podczas działania na jednym z dwóch poziomów IRQL.

  • PASSIVE_LEVEL, bez zmaskowanych przerwań na procesorze, w procedurach odpowiedzialnych za dyspozycję sterownika

    DriverEntry, Reinitialize, AddDevice i Unload procedury są również uruchamiane w PASSIVE_LEVEL, podobnie jak wszelkie wątki systemowe utworzone przez sterownik lub procedury wywołania zwrotnego wątku roboczego lub sterowniki systemu plików.

  • DISPATCH_LEVEL, z przerwaniami DISPATCH_LEVEL i APC_LEVEL zamaskowanymi na procesorze, w procedurach IoCompletion sterownika

    Procedury IoTimer, Cancel i CustomTimerDpc są również uruchamiane w DISPATCH_LEVEL.

W niektórych okolicznościach sterowniki pośrednie i najniższego poziomu urządzeń pamięci masowej są wywoływane na poziomie APC_LEVEL IRQL. W szczególności może to wystąpić w przypadku błędu strony, dla którego sterownik systemu plików wysyła żądanie IRP_MJ_READ do niższych sterowników.

Większość standardowych procedur sterowników jest uruchamiana na poziomie IRQL, co pozwala im po prostu wywołać odpowiednie procedury wsparcia. Na przykład sterownik urządzenia musi wywołać AllocateAdapterChannel podczas działania na poziomie IRQL DISPATCH_LEVEL. Ponieważ większość sterowników urządzeń wywołuje te funkcje z funkcji StartIo, zwykle działają już na poziomie DISPATCH_LEVEL.

Sterownik urządzenia, który nie ma procedury StartIo, ponieważ konfiguruje własne kolejki IRP-ów i zarządza nimi, nie musi działać w DISPATCH_LEVEL IRQL, gdy powinien wywołać AllocateAdapterChannel. Taki sterownik musi zagnieżdżać wywołanie AllocateAdapterChannel między wywołaniami KeRaiseIrql i KeLowerIrql, tak aby działał na wymaganym poziomie IRQL, gdy wywołuje AllocateAdapterChannel, i przywracał oryginalny poziom IRQL, gdy procedura wywołująca odzyska kontrolę.

Podczas wywoływania rutyn wsparcia sterowników należy pamiętać o następujących kwestiach.

  • Wywołanie metody KeRaiseIrql z wartością wejściową NewIrql mniejszą niż bieżąca funkcja IRQL powoduje błąd krytyczny. Wywołanie metody KeLowerIrql z wyjątkiem przywrócenia oryginalnego środowiska IRQL (tj. po wywołaniu metody KeRaiseIrql) powoduje również błąd krytyczny.

  • Podczas pracy na poziomie IRQL >= DISPATCH_LEVEL, wywołanie KeWaitForSingleObject lub KeWaitForMultipleObjects dla obiektów dyspozytora zdefiniowanych przez jądro w celu oczekiwania na niezerowy interwał powoduje błąd krytyczny.

  • Jedynymi procedurami sterowników, które mogą bezpiecznie czekać na zdarzenia, semafory, muteksy lub czasomierze w stanie zasygnalizowanym, są te, które działają w kontekście wątku niearbitralnym na poziomie IRQL PASSIVE_LEVEL, takie jak wątki utworzone przez sterownik, procedury DriverEntry i Reinitialize, lub procedury wysyłania dla z natury synchronicznych operacji we/wy (takich jak większość żądań sterowania we/wy urządzeń).

  • Nawet podczas działania na poziomie IRQL PASSIVE_LEVEL kod sterownika z możliwością stronicowania nie może wywoływać KeSetEvent, KeReleaseSemaphore lub KeReleaseMutex z wejściowym parametrem Wait ustawionym na TRUE. Takie wywołanie może spowodować krytyczny błąd strony.

  • Rutyna uruchomiona na poziomie IRQL wyższym niż APC_LEVEL nie może bezpiecznie przydzielić pamięci z puli stronicowanej ani uzyskać do niej dostępu. Jeśli rutyna działająca na poziomie IRQL większym niż APC_LEVEL powoduje błąd strony, to jest to fatalny błąd.

  • Sterownik musi być uruchomiony na poziomie IRQL DISPATCH_LEVEL, gdy wywołuje KeAcquireSpinLockAtDpcLevel i KeReleaseSpinLockFromDpcLevel.

    Sterownik może być uruchomiony na poziomie IRQL <= DISPATCH_LEVEL, gdy wywołuje KeAcquireSpinLock, ale musi zwolnić tę blokadę spinową, wywołując KeReleaseSpinLock. Innymi słowy, jest to błąd programowania, aby zwolnić spinlock uzyskany za pomocą KeAcquireSpinLock przez wywołanie KeReleaseSpinLockFromDpcLevel.

    Sterownik nie może wywoływać KeAcquireSpinLockAtDpcLevel, KeReleaseSpinLockFromDpcLevel, KeAcquireSpinLock lub KeReleaseSpinLock, będąc na poziomie IRQL > DISPATCH_LEVEL.

  • Wywoływanie procedury pomocniczej, która używa blokady spin, takiej jak procedura ExInterlockedXxx, podnosi IRQL na bieżącym procesorze do DISPATCH_LEVEL lub DIRQL, jeśli wywołujący nie działa już na podniesionym poziomie IRQL.

  • Kod sterownika, który działa na poziomie IRQL PASSIVE_LEVEL, powinien być wykonywany tak szybko, jak to możliwe. Im wyższy IRQL, na którym działa dana procedura, tym ważniejsze jest, aby dla dobrej ogólnej wydajności dostosować tę procedurę, aby wykonywała się tak szybko, jak to możliwe. Na przykład każdy sterownik, który wywołuje KeRaiseIrql, powinien wykonać odwrotne wywołanie KeLowerIrql tak szybko, jak to możliwe.

Aby uzyskać więcej informacji na temat określania priorytetów, zapoznaj się z białą księgą Planowanie, Kontekst wątku i IRQL.