Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Všichni vývojáři ovladačů musí zvážit úrovně žádostí o přerušení (IRQLS). IRQL je celé číslo mezi 0 a 31; PASSIVE_LEVEL, DISPATCH_LEVEL a APC_LEVEL se obvykle označují symbolicky a ostatní se označují jejich číselnými hodnotami. Zvýšení a snížení irQL by mělo dodržovat striktní disciplínu zásobníku. Funkce by měla cílit na vrácení ve stejné technologii IRQL, ve které byla volána. Hodnoty IRQL se v zásobníku nesmí snižovat. Funkce nemůže snížit IRQL bez nejprve jeho zvýšení. Poznámky IRQL jsou určené k vynucování těchto pravidel.
Pokud kód ovladače obsahuje poznámky IRQL, nástroje pro analýzu kódu můžou zlepšit odvozování rozsahu úrovní, na kterých by měla funkce běžet, a můžou přesněji najít chyby. Můžete například přidat poznámky, které určují maximální hodnotu IRQL, při které lze volat funkci; Pokud je funkce volána na vyšší úrovni IRQL, nástroje pro analýzu kódu mohou identifikovat nekonzistence.
Funkce ovladačů by měly být opatřeny poznámkami o tolika informacích o IRQL, které by mohly být vhodné. Pokud jsou k dispozici další informace, pomůže nástroji pro analýzu kódu při následné kontrole volající funkce i volané funkce. V některých případech je přidání poznámky dobrým způsobem, jak potlačit falešně pozitivní. Některé funkce, jako je například funkce nástroje, lze volat v libovolném irQL. V tomto případě je absence poznámky IRQL správná poznámka.
Při přidávání poznámek pro IRQL je důležité zvážit, jak se funkce může vyvíjet, nejen její aktuální implementaci. Například funkce, jak je implementována, může správně fungovat na vyšší úrovni IRQL, než původně zamýšlel návrhář. I když je lákavé funkci komentovat na základě toho, co kód skutečně dělá, může návrhář vědět o budoucích požadavcích, jako je potřeba snížit maximální počet IRQL pro některé budoucí vylepšení nebo čekající požadavky na systém. Poznámka by měla být odvozena od záměru návrháře funkcí, ne ze skutečné implementace.
Poznámky v následující tabulce můžete použít k označení správné technologie IRQL pro funkci a její parametry. Hodnoty IRQL jsou definovány v wdm.h.
| Anotace IRQL | Popis |
|---|---|
| _IRQL_requires_max_(irql) | Irql je maximální hodnota IRQL, při které lze funkci volat. |
| _IRQL_requires_min_(irql) | Irql je minimální hodnota IRQL, při které lze funkci volat. |
| _IRQL_requires_(irql) | Funkce musí být zadána na IRQL určené irql. |
| _IRQL_raises_(irql) | Funkce se ukončí na zadaném irql, ale dá se volat pouze pro zvýšení (nikoli snížení) aktuálního IRQL. |
| _Ukládání úrovní IRQL_ | Anotovaný parametr uloží aktuální irQL k pozdějšímu obnovení. |
| _IRQL_restores_ | Anotovaný parametr obsahuje hodnotu IRQL z IRQL_saves , která se má obnovit při vrácení funkce. |
| _IRQL_saves_global_(typ, param) | Aktuální irQL se uloží do umístění, které je interní pro nástroje pro analýzu kódu, ze kterých se má irQL obnovit. Tato poznámka slouží k anotaci funkce. Umístění je identifikováno druhem a dále upřesněno parametrem. OldIrql může být například druh a FastMutex může být parametr, který držel starou hodnotu IRQL. |
| _IRQL_restores_global_(typ, param) | IrQL uložená funkcí anotovanou IRQL_saves_global se obnoví z umístění, které je interní pro nástroje analýzy kódu. |
| _IRQL_always_function_min_(hodnota) | Hodnota IRQL je minimální hodnota, na kterou může funkce snížit hodnotu IRQL. |
| _IRQL_always_function_max_(hodnota) | Hodnota IRQL je maximální hodnota, na kterou může funkce zvýšit hodnotu IRQL. |
| _IRQL_requires_same_ | Anotovaná funkce musí zadávat a ukončovat ve stejné technologii IRQL. Funkce může změnit irQL, ale před ukončením musí obnovit hodnotu IRQL na původní hodnotu. |
| _IRQL_uses_cancel_ | Anotovaný parametr je hodnota IRQL, kterou by měla obnovit funkce DRIVER_CANCEL zpětného volání. Ve většině případů místo toho použijte IRQL_is_cancel poznámku. |
Poznámky pro DRIVER_CANCEL
Mezi _IRQL_uses_cancel_ a _IRQL_is_cancel_ poznámkami je rozdíl. Poznámka _IRQL_uses_cancel_ jednoduše určuje, že anotovaný parametr je hodnota IRQL, kterou by měla obnovit funkce zpětného volání DRIVER_CANCEL. _IRQL_is_cancel_ poznámka je složená anotace, která se skládá z _IRQL_uses_cancel_ a několika dalších poznámek, které zajišťují správné chování funkce zpětného volání DRIVER_CANCEL. Sama o sobě je _IRQL_uses_cancel_ poznámka pouze příležitostně užitečná; Pokud například ostatní povinnosti popsané _IRQL_is_cancel_ již byly splněny jiným způsobem.
| Anotace IRQL | Popis |
|---|---|
| _IRQL_is_cancel_ | Anotovaný parametr je IRQL, který byl předán jako součást volání funkce zpětného volání DRIVER_CANCEL. Tato poznámka označuje, že funkce je pomocná funkce, která je volána z rutin Cancel a která splňuje požadavky pro funkce DRIVER_CANCEL, včetně uvolnění spinlocku. |
Interakce poznámek IRQL
Poznámky parametrů IRQL vzájemně komunikují více než s jinými poznámkami, protože hodnota IRQL je nastavena, resetována, uložena a obnovena různými volanými funkcemi.
Určení maximální a minimální úrovně IRQL
Poznámky _IRQL_requires_max_ a _IRQL_requires_min_ určují, že by funkce neměla být volána z knihovny IRQL, která je vyšší nebo nižší než zadaná hodnota. Například když PREfast uvidí posloupnost volání funkcí, která nemění IRQL, a najde hodnotu s _IRQL_requires_max_, která je nižší než blízký _IRQL_requires_min_, hlásí upozornění při druhém volání. K chybě může dojít ve skutečnosti při prvním volání; zpráva označuje, kde došlo k druhé polovině konfliktu.
Pokud poznámky funkce zmiňují IRQL a nepoužívají explicitně _IRQL_requires_max_, nástroj Analýza kódu implicitně použije anotaci _IRQL_requires_max_(DISPATCH_LEVEL), která je obvykle správná se vzácnými výjimkami. Implicitní použití tohoto jako výchozího eliminuje spoustu nepořádku v anotacích a zviditelní výjimky.
Poznámka _IRQL_requires_min_(PASSIVE_LEVEL) se vždy předpokládá, protože IRQL nemůže jít dolů; v důsledku toho neexistuje žádné odpovídající explicitní pravidlo týkající se minimálního irQL. Velmi málo funkcí má kromě DISPATCH_LEVEL i dolní mez jinou než PASSIVE_LEVEL.
Některé funkce se volají v kontextu, ve kterém volaná funkce nemůže bezpečně zvýšit hodnotu IRQL nad určitou maximální hodnotu nebo častěji ji nemůže bezpečně snížit pod určitou minimální hodnotu. Poznámky _IRQL_always_function_max_ a _IRQL_always_function_min_ pomáhají prEfast najít případy, kdy k tomu dojde neúmyslně.
Například funkce typu DRIVER_STARTIO jsou opatřeny poznámkami _IRQL_always_function_min_(DISPATCH_LEVEL). To znamená, že při provádění funkce DRIVER_STARTIO je chybou snížit úroveň IRQL pod DISPATCH_LEVEL. Další poznámky označují, že funkce musí být zadána a ukončena v DISPATCH_LEVEL.
Určení explicitního IRQL
Pomocí anotací _IRQL_raises_ nebo _IRQL_requires_ umožníte nástroji PREfast lépe identifikovat nekonzistence, které se objevují při použití anotací _IRQL_requires_max_ nebo _IRQL_requires_min_, protože pak zná úroveň IRQL.
_IRQL_raises_ poznámka označuje, že funkce vrátí hodnotu IRQL nastavenou na novou hodnotu. Při použití poznámky _IRQL_raises_ se také efektivně nastavuje poznámka _drv_maxFunctionIRQL na stejnou hodnotu IRQL. Pokud ale funkce zvýší hodnotu IRQL nad konečnou hodnotu a pak ji sníží na konečnou hodnotu, měli byste přidat explicitní _IRQL_always_function_max_ poznámku za _IRQL_raises_ poznámkou, aby byla povolena vyšší hodnota IRQL.
Zvýšení nebo snížení IRQL
_IRQL_raises_ anotace označuje, že funkci lze použít pouze ke zvýšení IRQL a nesmí být použita ke snížení IRQL, i když to syntaxe funkce umožňuje. KeRaiseIrql je příkladem funkce, která by neměla být použita pro snížení irQL.
Ukládání a obnovení IRQL
Pomocí poznámkových _IRQL_saves_ a _IRQL_restores_ označte, že aktuální IRQL (ať už je známo přesně nebo pouze přibližně) je uložen z nebo obnoven do anotovaného parametru.
Některé funkce implicitně ukládají a obnoví IRQL. Například systémová funkce ExAcquireFastMutex uloží IRQL do skrytého umístění, které je přidruženo k objektu rychlého mutexu, který první parametr identifikuje; uložená hodnota IRQL je obnovena odpovídající funkcí ExReleaseFastMutex pro tento objekt rychlého mutexu. K explicitní označení těchto akcí použijte _IRQL_saves_global_ a _IRQL_restores_global_ poznámky. Parametry typu a parametru označují, kde je uložena hodnota IRQL. Umístění, kde je hodnota uložena, nemusí být přesně zadáno, pokud jsou poznámky, které ukládají a obnovují hodnotu konzistentní.
Údržba stejné knihovny IRQL
Měli byste přidat poznámky ke všem funkcím, které váš ovladač vytvoří a které změní IRQL, pomocí poznámky _IRQL_requires_same_ nebo jedné z dalších poznámek IRQL, aby bylo uvedeno, že změna IRQL je předpokládaná. V případě absence poznámek, které indikují jakoukoli změnu v IRQL, nástroje pro analýzu kódu zobrazí upozornění pro jakoukoli funkci, která neskončí na stejném IRQL, na které byla funkce zadána. Pokud je změna v IRQL zamýšlená, přidejte příslušnou poznámku, která tuto chybu potlačí. Pokud změna v IRQL není zamýšlená, měl by se kód opravit.
Ukládání a obnovení IRQL pro rutiny zrušení vstupně-výstupních operací
Pomocí poznámky _IRQL_uses_cancel_ označte, že anotovaný parametr je hodnota IRQL, kterou by měla obnovit funkce zpětného volání DRIVER_CANCEL. Tato poznámka označuje, že funkce je nástroj, který je volán z rutin zrušení a že splňuje požadavky kladené na funkce DRIVER_CANCEL (to znamená, že uvolňuje volajícího z odpovědnosti).
Například následující je deklarace pro typ funkce zpětného volání DRIVER_CANCEL. Jedním z parametrů je IRQL, který by měla tato funkce obnovit. Poznámky označují všechny požadavky funkce 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;