다음을 통해 공유


드라이버에 대한 IRQL 주석

모든 드라이버 개발자는 인터럽트 요청 수준(IRQL)을 고려해야 합니다. IRQL은 0에서 31 사이의 정수입니다. PASSIVE_LEVEL, DISPATCH_LEVEL 및 APC_LEVEL 일반적으로 기호적으로 참조되고 다른 값은 숫자 값으로 참조됩니다. IRQL을 높이고 낮추는 것은 엄격한 스택 분야를 따라야 합니다. 함수는 호출된 동일한 IRQL을 반환하는 것을 목표로 해야 합니다. IRQL 값은 스택에서 감소하지 않아야 합니다. 그리고 함수는 IRQL을 먼저 발생하지 않고는 낮출 수 없습니다. IRQL 주석은 이러한 규칙을 적용하는 데 도움이 됩니다.

드라이버 코드에 IRQL 주석이 있는 경우 코드 분석 도구는 함수가 실행되어야 하는 수준 범위에 대해 더 나은 유추를 수행하고 오류를 보다 정확하게 찾을 수 있습니다. 예를 들어 함수를 호출할 수 있는 최대 IRQL을 지정하는 주석을 추가할 수 있습니다. 함수가 더 높은 IRQL에서 호출되면 코드 분석 도구는 불일치를 식별할 수 있습니다.

드라이버 함수는 적절한 IRQL에 대한 많은 정보로 주석을 추가해야 합니다. 추가 정보를 사용할 수 있는 경우 호출 함수와 호출된 함수를 모두 후속 검사할 때 코드 분석 도구에 도움이 됩니다. 경우에 따라 주석을 추가하는 것이 가양성 표시를 표시하지 않는 좋은 방법입니다. 유틸리티 함수와 같은 일부 함수는 모든 IRQL에서 호출할 수 있습니다. 이 경우 IRQL 주석이 없는 것이 적절한 주석입니다.

IRQL에 대한 함수에 주석을 추가할 때는 현재 구현뿐만 아니라 함수가 어떻게 발전할 수 있는지 고려하는 것이 특히 중요합니다. 예를 들어 구현된 함수는 디자이너가 의도한 것보다 높은 IRQL에서 올바르게 작동할 수 있습니다. 코드가 실제로 수행하는 작업에 따라 함수에 주석을 추가하려는 경우 디자이너는 향후 개선 또는 보류 중인 시스템 요구 사항을 위해 최대 IRQL을 낮출 필요성과 같은 향후 요구 사항을 알고 있을 수 있습니다. 주석은 실제 구현이 아니라 함수 디자이너의 의도에서 파생되어야 합니다.

다음 표의 주석을 사용하여 함수 및 해당 매개 변수에 대한 올바른 IRQL을 나타낼 수 있습니다. IRQL 값은 Wdm.h에 정의되어 있습니다.

IRQL 주석 Description
_IRQL_requires_max_(irql) irql은 함수를 호출할 수 있는 최대 IRQL입니다.
_IRQL_requires_min_(irql) irql은 함수를 호출할 수 있는 최소 IRQL입니다.
_IRQL_requires_(irql) 함수는 irql로 지정된 IRQL에 입력해야 합니다.
_IRQL_raises_(irql) 함수는 지정된 irql에서 종료되지만 현재 IRQL을 발생(낮지 않음)하기 위해 호출할 수 있습니다.
_IRQL_saves_ 주석이 추가된 매개 변수는 나중에 복원할 현재 IRQL을 저장합니다.
_IRQL_restores_ 주석이 추가된 매개 변수에는 함수가 반환될 때 복원할 IRQL_saves IRQL 값이 포함되어 있습니다.
_IRQL_saves_global_(kind, param) 현재 IRQL은 IRQL을 복원할 코드 분석 도구의 내부 위치에 저장됩니다. 이 주석은 함수에 주석을 추가하는 데 사용됩니다. 위치는 종류별로 식별되며 매개 변수로 더 구체화됩니다. 예를 들어 OldIrql은 종류일 수 있고 FastMutex는 이전 IRQL 값을 보유하는 매개 변수일 수 있습니다.
_IRQL_restores_global_(kind, param) IRQL_saves_global 주석이 추가된 함수에 의해 저장된 IRQL은 코드 분석 도구 내부 위치에서 복원됩니다.
_IRQL_always_function_min_(value) IRQL 값은 함수가 IRQL을 낮출 수 있는 최소값입니다.
_IRQL_always_function_max_(value) IRQL 값은 함수가 IRQL을 발생시키는 최대값입니다.
_IRQL_requires_same_ 주석이 추가된 함수는 동일한 IRQL에서 를 입력하고 종료해야 합니다. 함수는 IRQL을 변경할 수 있지만 종료하기 전에 IRQL을 원래 값으로 복원해야 합니다.
_IRQL_uses_cancel_ 주석이 추가된 매개 변수는 DRIVER_CANCEL 콜백 함수에서 복원해야 하는 IRQL 값입니다. 대부분의 경우 대신 IRQL_is_cancel 주석을 사용합니다.

DRIVER_CANCEL 대한 주석

_IRQL_uses_cancel_ 주석과 _IRQL_is_cancel_ 주석 사이에는 차이가 있습니다. _IRQL_uses_cancel_ 주석은 주석이 추가된 매개 변수가 DRIVER_CANCEL 콜백 함수에서 복원해야 하는 IRQL 값임을 지정합니다. _IRQL_is_cancel_ 주석은 _IRQL_uses_cancel_ 및 DRIVER_CANCEL 콜백 유틸리티 함수의 올바른 동작을 보장하는 몇 가지 다른 주석으로 구성된 복합 주석입니다. 그 자체로 _IRQL_uses_cancel_ 주석은 경우에 따라 유용합니다. 예를 들어 _IRQL_is_cancel_ 설명한 나머지 의무가 이미 다른 방식으로 이행된 경우입니다.

IRQL 주석 Description
_IRQL_is_cancel_ 주석이 추가된 매개 변수는 DRIVER_CANCEL 콜백 함수 호출의 일부로 전달된 IRQL입니다. 이 주석은 함수가 Cancel 루틴에서 호출되고 취소 스핀 잠금 해제를 포함하여 DRIVER_CANCEL 함수에 대한 요구 사항을 완료하는 유틸리티임을 나타냅니다.

IRQL 주석이 상호 작용하는 방법

IRQL 값이 다양한 호출된 함수에 의해 설정, 다시 설정, 저장 및 복원되기 때문에 IRQL 매개 변수 주석은 다른 주석보다 상호 작용합니다.

최대 및 최소 IRQL 지정

_IRQL_requires_max_ 및 _IRQL_requires_min_ 주석은 지정된 값보다 높거나 낮은 IRQL에서 함수를 호출하지 않도록 지정합니다. 예를 들어 PREfast에서 IRQL을 변경하지 않는 함수 호출 시퀀스가 표시되면 가까운 _IRQL_requires_min_ 미만인 _IRQL_requires_max_ 값을 찾으면 두 번째 호출에서 발생하는 경고를 보고합니다. 오류는 실제로 첫 번째 호출에서 발생할 수 있습니다. 메시지는 충돌의 나머지 절반이 발생한 위치를 나타냅니다.

함수의 주석이 IRQL을 멘션 _IRQL_requires_max_ 명시적으로 적용하지 않는 경우 코드 분석 도구는 일반적으로 드문 예외에서 올바른 주석 _IRQL_requires_max_(DISPATCH_LEVEL)을 암시적으로 적용합니다. 이를 기본값으로 암시적으로 적용하면 주석이 많이 복잡해지지 않고 예외가 훨씬 더 잘 표시됩니다.

_IRQL_REQUIRES_MIN_(PASSIVE_LEVEL) 주석은 IRQL이 더 낮아지지 않으므로 항상 암시됩니다. 따라서 최소 IRQL에 대한 해당 명시적 규칙이 없습니다. DISPATCH_LEVEL 이외의 상한과 PASSIVE_LEVEL 이외의 하한을 가진 함수는 거의 없습니다.

일부 함수는 호출된 함수가 IRQL을 최대값 이상으로 안전하게 올릴 수 없거나 더 자주 최소값보다 안전하게 낮출 수 없는 컨텍스트에서 호출됩니다. _IRQL_always_function_max_ 및 _IRQL_always_function_min_ 주석은 PREfast가 의도치 않게 발생하는 사례를 찾는 데 도움이 됩니다.

예를 들어 DRIVER_STARTIO 형식의 함수는 _IRQL_always_function_min_(DISPATCH_LEVEL)로 주석을 추가합니다. 즉, DRIVER_STARTIO 함수를 실행하는 동안 DISPATCH_LEVEL 아래 IRQL을 낮추는 것은 오류입니다. 다른 주석은 함수를 입력하고 DISPATCH_LEVEL 종료해야 함을 나타냅니다.

명시적 IRQL 지정

_IRQL_RAISES_ 또는 _IRQL_requires_ 주석을 사용하여 IRQL을 알고 있기 때문에 _IRQL_requires_max_ 또는 _IRQL_requires_min_ 주석으로 검색되는 불일치를 더 잘 보고할 수 있습니다.

_IRQL_raises_ 주석은 함수가 IRQL이 새 값으로 설정된 상태에서 반환됨을 나타냅니다. _IRQL_raises_ 주석을 사용하면 _drv_maxFunctionIRQL 주석을 동일한 IRQL 값으로 효과적으로 설정합니다. 그러나 함수가 IRQL을 최종 값보다 높게 올린 다음 최종 값으로 낮추면 더 높은 IRQL 값을 허용하려면 _IRQL_raises_ 주석 다음에 명시적 _IRQL_always_function_max_ 주석을 추가해야 합니다.

IRQL 발생 또는 낮추기

_IRQL_raises_ 주석은 함수가 IRQL을 발생시키는 데만 사용해야 하며, 함수 구문에서 허용하는 경우에도 IRQL을 낮추는 데 사용해서는 안 됨을 나타냅니다. KeRaiseIrql은 IRQL을 낮추는 데 사용하면 안 되는 함수의 예입니다.

IRQL 저장 및 복원

_IRQL_saves_ 및 _IRQL_restores_ 주석을 사용하여 현재 IRQL(정확히 또는 대략적으로 알려진지 여부)이 주석이 추가된 매개 변수에 저장되거나 복원되었음을 나타냅니다.

일부 함수는 IRQL을 암시적으로 저장하고 복원합니다. 예를 들어 ExAcquireFastMutex 시스템 함수는 첫 번째 매개 변수가 식별하는 빠른 뮤텍스 개체와 연결된 불투명 위치에 IRQL을 저장합니다. 저장된 IRQL은 해당 빠른 뮤텍스 개체에 대한 해당 ExReleaseFastMutex 함수에 의해 복원됩니다. 이러한 작업을 명시적으로 나타내려면 _IRQL_saves_global_ 및 _IRQL_restores_global_ 주석을 사용합니다. 종류매개 변수는 IRQL 값이 저장되는 위치를 나타냅니다. 값을 저장하고 복원하는 주석이 일치하기만 하면 값이 저장된 위치를 정확하게 지정할 필요가 없습니다.

동일한 IRQL 유지 관리

드라이버에서 만드는 모든 함수에 주석을 추가해야 하며, IRQL의 변경이 예상됨을 나타내려면 _IRQL_requires_same_ 주석 또는 다른 IRQL 주석 중 하나를 사용하여 IRQL을 변경합니다. IRQL의 변경 내용을 나타내는 주석이 없는 경우 코드 분석 도구는 함수가 입력된 동일한 IRQL에서 종료되지 않는 함수에 대해 경고를 실행합니다. IRQL의 변경이 의도된 경우 적절한 주석을 추가하여 오류를 표시하지 않습니다. IRQL의 변경이 의도되지 않은 경우 코드를 수정해야 합니다.

I/O 취소 루틴에 대한 IRQL 저장 및 복원

주석이 추가된 매개 변수가 DRIVER_CANCEL 콜백 함수에서 복원해야 하는 IRQL 값임을 나타내려면 _IRQL_uses_cancel_ 주석을 사용합니다. 이 주석은 함수가 취소 루틴에서 호출되는 유틸리티이며 DRIVER_CANCEL 함수에 대해 수행된 요구 사항을 완료했음을 나타냅니다(즉, 호출자에 대한 의무를 배출함).

예를 들어 다음은 DRIVER_CANCEL 콜백 함수 형식에 대한 선언입니다. 매개 변수 중 하나는 이 함수에서 복원해야 하는 IRQL입니다. 주석은 취소 함수의 모든 요구 사항을 나타냅니다.

// 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;  

드라이버용 SAL 2.0 주석