Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować się zalogować lub zmienić katalog.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Wszyscy deweloperzy sterowników muszą brać pod uwagę poziomy żądań przerwania (IRQL). IrQL jest liczbą całkowitą z zakresu od 0 do 31; PASSIVE_LEVEL, DISPATCH_LEVEL i APC_LEVEL są zwykle określane symbolicznie, a inne według ich wartości liczbowych. Podnoszenie i obniżanie poziomu IRQL powinno być zgodne ze ścisłą dyscypliną stosu. Funkcja powinna mieć na celu powrót do tego samego poziomu IRQL, na którym została wywołana. Wartości IRQL nie mogą maleć na stosie. Funkcja nie może obniżyć irQL bez uprzedniego podniesienia go. Adnotacje IRQL mają na celu ułatwienie wymuszania tych reguł.
Gdy kod sterownika zawiera adnotacje IRQL, narzędzia do analizy kodu mogą lepiej wnioskować o zakresie poziomów, na których powinna działać funkcja i może dokładniej znaleźć błędy. Można na przykład dodać adnotacje określające maksymalną liczbę wywołań IRQL, w których można wywołać funkcję; Jeśli funkcja jest wywoływana w wyższym irQL, narzędzia do analizy kodu mogą identyfikować niespójności.
Funkcje sterowników powinny być oznaczone adnotacjami zawierającymi jak najwięcej informacji o IRQL, które mogą być istotne. Jeśli są dostępne dodatkowe informacje, pomaga to narzędziom analizy kodu w kolejnych sprawdzaniu zarówno funkcji wywołującej, jak i wywoływanej funkcji. W niektórych przypadkach dodanie adnotacji jest dobrym sposobem pomijania wyników fałszywie dodatnich. Niektóre funkcje, takie jak funkcja narzędzia, mogą być wywoływane w dowolnym środowisku IRQL. W takim przypadku brak adnotacji IRQL jest właściwą adnotacją.
Podczas dodawania adnotacji do funkcji IRQL jest szczególnie ważne, aby rozważyć, jak funkcja może ewoluować, a nie tylko jej bieżąca implementacja. Na przykład, zaimplementowana funkcja może poprawnie działać na wyższym poziomie IRQL, niż projektant zamierzał. Chociaż może być kuszące, aby dodać adnotację do funkcji w oparciu o to, co faktycznie robi kod, projektant może być świadomy przyszłych wymagań, takich jak konieczność obniżenia maksymalnego poziomu IRQL w związku z przyszłymi ulepszeniami lub oczekującymi wymaganiami systemowymi. Adnotacja powinna pochodzić z intencji projektanta funkcji, a nie z rzeczywistej implementacji.
Adnotacje w tabeli poniżej mogą być użyte do wskazania poprawnego poziomu IRQL dla funkcji i jej parametrów. Wartości IRQL są definiowane w pliku Wdm.h.
| Adnotacja IRQL | Opis |
|---|---|
| _IRQL_requires_max_(irql) | IRQL jest maksymalnym poziomem IRQL, na którym można wywołać funkcję. |
| _IRQL_requires_min_(irql) | Minimalny poziom IRQL to poziom, na którym można wywołać funkcję. |
| _IRQL_requires_(irql) | Funkcja musi zostać wprowadzona na poziomie IRQ określonym przez irql. |
| _IRQL_raises_(irql) | Funkcja kończy działanie na określonym poziomie irql, ale może być wywoływana tylko w celu podniesienia (a nie obniżenia) bieżącego poziomu IRQL. |
| _IRQL_saves_ | Parametr z adnotacją zapisuje bieżący poziom IRQL do przywrócenia później. |
| _IRQL_restores_ | Parametr z adnotacjami zawiera wartość IRQL z IRQL_saves , która ma zostać przywrócona po powrocie funkcji. |
| _IRQL_saves_global_(rodzaj, param) | Bieżący poziom IRQL jest zapisywany w lokalizacji wewnętrznej narzędzi do analizy kodu, z której poziom IRQL ma zostać przywrócony. Ta adnotacja służy do oznaczania funkcji. Lokalizacja jest identyfikowana przez typ i dodatkowo uściślana przez parametr. Na przykład OldIrql może być typem, a FastMutex może być parametrem, który przechowywał tę starą wartość IRQL. |
| _IRQL_restores_global_(rodzaj, param) | IRQL zapisane przez funkcję z adnotacją IRQL_saves_global jest przywracane z wewnętrznej lokalizacji w narzędziach analizy kodu. |
| _IRQL_always_function_min_(wartość) | Wartość IRQL jest minimalną wartością, do której funkcja może obniżyć IRQL. |
| _IRQL_always_function_max_(wartość) | Wartość IRQL jest maksymalną wartością, do której funkcja może podnieść IRQL. |
| _IRQL_requires_same_ | Funkcja z adnotacjami musi wprowadzić i zakończyć działanie na tym samym poziomie IRQL. Funkcja może zmienić poziom IRQL, ale przed zakończeniem musi przywrócić jego oryginalną wartość. |
| _IRQL_uses_cancel_ | Parametr z adnotacjami jest wartością IRQL, która powinna zostać przywrócona przez funkcję wywołania zwrotnego DRIVER_CANCEL. W większości przypadków należy użyć adnotacji IRQL_is_cancel zamiast. |
Adnotacje dla DRIVER_CANCEL
Istnieje różnica między adnotacjami _IRQL_uses_cancel_ i _IRQL_is_cancel_. Adnotacja _IRQL_uses_cancel_ po prostu określa, że anotowany parametr jest wartością IRQL, która powinna zostać przywrócona przez funkcję wywołania zwrotnego DRIVER_CANCEL. Adnotacja _IRQL_is_cancel_ jest adnotacją złożoną, która składa się z _IRQL_uses_cancel_ oraz kilku innych adnotacji, które zapewniają prawidłowe działanie funkcji narzędziowej DRIVER_CANCEL wywołania zwrotnego. Sama adnotacja _IRQL_uses_cancel_ jest przydatna tylko od czasu do czasu; na przykład jeśli pozostałe zobowiązania opisane przez _IRQL_is_cancel_ zostały już spełnione w inny sposób.
| Adnotacja IRQL | Opis |
|---|---|
| _IRQL_is_cancel_ | Parametr z adnotacjami to IRQL przekazany w ramach wywołania funkcji zwrotnej DRIVER_CANCEL. Ta adnotacja wskazuje, że funkcja jest narzędziem wywoływanym z procedur Anuluj i spełnia wymagania dotyczące funkcji DRIVER_CANCEL, w tym zwolnienie blokady anulowania spin. |
Jak współdziałają adnotacje IRQL
Adnotacje parametrów IRQL współdziałają ze sobą bardziej niż inne adnotacje, ponieważ wartość IRQL jest ustawiana, resetowana, zapisywana i przywracana przez różne wywoływane funkcje.
Określanie maksymalnego i minimalnego poziomu IRQL
Adnotacje _IRQL_requires_max_ i _IRQL_requires_min_ określają, że funkcja nie powinna być wywoływana z środowiska IRQL o wartości wyższej lub niższej niż określona wartość. Na przykład gdy funkcja PREfast widzi sekwencję wywołań funkcji, które nie zmieniają środowiska IRQL, jeśli znajdzie ją z wartością _IRQL_requires_max_ poniżej pobliskiej _IRQL_requires_min_, zgłasza ostrzeżenie podczas drugiego wywołania, które napotka. Błąd może wystąpić w pierwszym wywołaniu; komunikat wskazuje, gdzie wystąpiła druga połowa konfliktu.
Jeśli adnotacje w funkcji wspominają środowisko IRQL i nie mają jawnego zastosowania _IRQL_requires_max_, narzędzie Analizy kodu niejawnie stosuje adnotację _IRQL_requires_max_(DISPATCH_LEVEL), która jest zwykle poprawna z rzadkimi wyjątkami. Niejawnie zastosowanie tej funkcji jako domyślnej eliminuje wiele bałaganu adnotacji i sprawia, że wyjątki są znacznie bardziej widoczne.
Adnotacja _IRQL_requires_min_(PASSIVE_LEVEL) jest zawsze implikowana, ponieważ IRQL nie może być niższy; w związku z tym nie ma odpowiedniej jawnej reguły dotyczącej minimalnego poziomu IRQL. Bardzo niewiele funkcji ma zarówno górną granicę inną niż DISPATCH_LEVEL, jak i dolną granicę inną niż PASSIVE_LEVEL.
Niektóre funkcje są wywoływane w kontekście, w którym wywołana funkcja nie może bezpiecznie podnieść IRQL powyżej pewnego maksymalnego poziomu lub, częściej, nie może bezpiecznie obniżyć go poniżej pewnego minimalnego poziomu. Adnotacje _IRQL_always_function_max_ i _IRQL_always_function_min_ pomagają PREfast znaleźć przypadki, w których występuje to przypadkowo.
Na przykład funkcje o typie DRIVER_STARTIO są adnotowane _IRQL_always_function_min_(DISPATCH_LEVEL). Oznacza to, że podczas wykonywania funkcji DRIVER_STARTIO błędem jest obniżenie IRQL poniżej DISPATCH_LEVEL. Inne adnotacje wskazują, że funkcja musi zostać wprowadzona i zakończona w DISPATCH_LEVEL.
Określanie jawnego poziomu IRQL
Użyj adnotacji _IRQL_raises_ lub _IRQL_requires_, aby PREfast lepiej zgłaszał niespójności wykrywane za pomocą adnotacji _IRQL_requires_max_ lub _IRQL_requires_min_, ponieważ zna wtedy poziom IRQL.
Adnotacja _IRQL_raises_ wskazuje, że funkcja kończy działanie z IRQL ustawionym na nową wartość. Jeśli używasz adnotacji _IRQL_raises_, skutecznie ustawia ona również adnotację _drv_maxFunctionIRQL na tę samą wartość IRQL. Jeśli jednak funkcja podniesie wartość IRQL wyższą niż wartość końcowa, a następnie obniży ją do wartości końcowej, należy dodać jawną adnotację _IRQL_always_function_max_ po adnotacji _IRQL_raises_, aby umożliwić uzyskanie wyższej wartości IRQL.
Podnoszenie lub obniżanie poziomu IRQL
Adnotacja _IRQL_raises_ wskazuje, że funkcja musi być używana tylko do podnoszenia poziomu IRQL i nie może być używana do jego obniżenia, nawet jeśli składnia funkcji by na to pozwalała. KeRaiseIrql jest przykładem funkcji, która nie powinna być używana do obniżenia irQL.
Zapisywanie i przywracanie środowiska IRQL
Użyj adnotacji _IRQL_saves_ i _IRQL_restores_, aby wskazać, że bieżący protokół IRQL (niezależnie od tego, czy jest znany dokładnie, czy tylko w przybliżeniu) jest zapisywany lub przywracany z adnotacji parametru.
Niektóre funkcje zapisują i przywracają niejawnie środowisko IRQL. Na przykład funkcja systemowa ExAcquireFastMutex zapisuje wartość IRQL w ukrytej lokalizacji skojarzonej z obiektem fast mutex, który identyfikuje pierwszy parametr; zapisana wartość IRQL jest przywracana przez odpowiednią funkcję ExReleaseFastMutex dla tego obiektu fast mutex. Aby jawnie wskazać te akcje, użyj adnotacji _IRQL_saves_global_ i _IRQL_restores_global_. Parametry typu i parametru wskazują, gdzie jest zapisywana wartość IRQL. Lokalizacja, w której zapisano wartość, nie musi być dokładnie określona, o ile adnotacje, które zapisują i przywracają wartość, są spójne.
Utrzymanie tego samego poziomu IRQL
Należy dodać adnotacje do wszystkich funkcji tworzonych przez sterownik, które zmieniają poziom IRQL, używając adnotacji _IRQL_requires_same_ lub jednej z pozostałych adnotacji IRQL, aby wskazać, że zmiana IRQL jest oczekiwana. W przypadku braku adnotacji, które wskazują na jakąkolwiek zmianę w środowisku IRQL, narzędzia do analizy kodu będą wyświetlać ostrzeżenie dla każdej funkcji, która nie kończy się w tym samym środowisku IRQL, w którym wprowadzono funkcję. Jeśli zmiana IRQL jest zamierzona, dodaj odpowiednią adnotację, aby wyeliminować błąd. Jeśli zmiana poziomu IRQL nie jest zamierzona, kod powinien zostać poprawiony.
Zapisywanie i przywracanie poziomu IRQL dla procedur anulowania wejścia/wyjścia
Użyj adnotacji _IRQL_uses_cancel_, aby wskazać, że parametr z adnotacjami jest wartością IRQL, która powinna zostać przywrócona przez funkcję wywołania zwrotnego DRIVER_CANCEL. Ta adnotacja wskazuje, że funkcja jest narzędziem użytkowym wywoływaną z procedur anulowania i że spełnia wymagania stawiane funkcjom DRIVER_CANCEL, co oznacza, że zwalnia obowiązek wywołującego.
Na przykład poniżej znajduje się deklaracja typu funkcji wywołania zwrotnego DRIVER_CANCEL. Jednym z parametrów jest irQL, który powinien zostać przywrócony przez tę funkcję. Adnotacje wskazują wszystkie wymagania funkcji cancel.
// Define driver cancel routine type. //
__drv_functionClass(DRIVER_CANCEL)
_Requires_lock_held_(_Global_cancel_spin_lock_)
_Releases_lock_(_Global_cancel_spin_lock_)
_IRQL_requires_min_(DISPATCH_LEVEL)
_IRQL_requires_(DISPATCH_LEVEL)
typedef
VOID
DRIVER_CANCEL (
_Inout_ struct _DEVICE_OBJECT *DeviceObject,
_Inout_ _IRQL_uses_cancel_ struct _IRP *Irp
);
typedef DRIVER_CANCEL *PDRIVER_CANCEL;