하드웨어 우선 순위 관리

드라이버 루틴이 실행되는 IRQL은 호출할 수 있는 커널 모드 드라이버 지원 루틴을 결정합니다. 예를 들어 일부 드라이버 지원 루틴에서는 호출자가 IRQL = DISPATCH_LEVEL 실행되어야 합니다. 호출자가 PASSIVE_LEVEL보다 높은 IRQL에서 실행 중인 경우에는 다른 호출을 안전하게 호출할 수 없습니다.

다음은 가장 일반적으로 구현되는 표준 드라이버 루틴이 호출되는 IRQL 목록입니다. IRQL은 가장 낮은 우선 순위에서 가장 높은 우선 순위로 나열됩니다.

PASSIVE_LEVEL
마스킹된 인터럽트 - 없음.

에서 호출되는 드라이버 루틴 PASSIVE_LEVEL — DriverEntry, AddDevice, 다시 초기화, 언로드 루틴, 대부분의 디스패치 루틴, 드라이버 생성 스레드, 작업자 스레드 콜백.

APC_LEVEL
마스킹된 인터럽트 - APC_LEVEL 인터럽트는 마스킹 해제됩니다.

에서 호출되는 드라이버 루틴 APC_LEVEL — 일부 디스패치 루틴( 디스패치 루틴 및 IRQL 참조).

DISPATCH_LEVEL
마스킹된 인터럽트 - DISPATCH_LEVEL 및 APC_LEVEL 인터럽트는 마스킹 해제됩니다. 디바이스, 클록 및 전원 오류 중단이 발생할 수 있습니다.

에서 호출되는 드라이버 루틴 DISPATCH_LEVEL — StartIo, AdapterControl, AdapterListControl, ControllerControl, IoTimer, Cancel (취소 스핀 잠금을 보유하는 동안), DpcForIsr, CustomTimerDpc, CustomDpc 루틴.

DIRQL
마스킹된 인터럽트 - 드라이버 인터럽트 개체의 IRQL <= DIRQL의 모든 인터럽트입니다. DIRQL 값이 더 높은 디바이스 인터럽트는 클록 및 전원 오류 인터럽트와 함께 발생할 수 있습니다.

DIRQL에서 호출되는 드라이버 루틴 - InterruptService, SynchCritSection 루틴.

APC_LEVEL PASSIVE_LEVEL 간의 유일한 차이점은 APC_LEVEL 실행 중인 프로세스가 APC 인터럽트에서 가져올 수 없다는 것입니다. 그러나 두 IRQL 모두 스레드 컨텍스트를 의미하며 둘 다 코드를 페이징할 수 있음을 의미합니다.

가장 낮은 수준의 드라이버는 세 가지 IRQL 중 하나에서 실행되는 동안 IRP를 처리합니다.

  • PASSIVE_LEVEL 드라이버의 디스패치 루틴에서 프로세서에서 마스킹된 인터럽트 없이

    DriverEntry, AddDevice, Reinitialize언로드 루틴도 드라이버에서 만든 시스템 스레드와 마찬가지로 PASSIVE_LEVEL 실행됩니다.

  • DISPATCH_LEVEL DISPATCH_LEVEL 및 APC_LEVEL 인터럽트는 StartIo 루틴에서 프로세서에서 마스킹됩니다.

    AdapterControl, AdapterListControl, ControllerControl, IoTimer, Cancel (취소 스핀 잠금을 보유하는 동안) 및 CustomTimerDpc 루틴도 DpcForIsrCustomDpc 루틴과 마찬가지로 DISPATCH_LEVEL 실행됩니다.

  • 모든 인터럽트가 ISR 및 SynchCritSection 루틴에서 프로세서에서 마스킹된 드라이버 인터럽트 개체의 SynchronizeIrql보다 작거나 같은 디바이스 IRQL(DIRQL)

대부분의 상위 수준 드라이버는 두 개의 IRQL 중 하나에서 실행되는 동안 IRP를 처리합니다.

  • PASSIVE_LEVEL 드라이버의 디스패치 루틴에서 프로세서에서 마스킹된 인터럽트 없이

    드라이버에서 만든 시스템 스레드 또는 작업자 스레드 콜백 루틴 또는 파일 시스템 드라이버와 마찬가지로 DriverEntry, Reinitialize, AddDevice언로드 루틴도 PASSIVE_LEVEL 실행됩니다.

  • DISPATCH_LEVEL 드라이버의 IoCompletion 루틴에서 프로세서에서 마스킹된 DISPATCH_LEVEL 및 APC_LEVEL 인터럽트 사용

    IoTimer, CancelCustomTimerDpc 루틴도 DISPATCH_LEVEL 실행됩니다.

경우에 따라 IRQL APC_LEVEL 대용량 스토리지 디바이스의 중간 및 최저 수준 드라이버가 호출됩니다. 특히 파일 시스템 드라이버가 드라이버를 낮추기 위해 IRP_MJ_READ 요청을 보내는 페이지 오류에서 발생할 수 있습니다.

대부분의 표준 드라이버 루틴은 단순히 적절한 지원 루틴을 호출할 수 있는 IRQL에서 실행됩니다. 예를 들어 디바이스 드라이버는 IRQL DISPATCH_LEVEL 실행하는 동안 AllocateAdapterChannel 을 호출해야 합니다. 대부분의 디바이스 드라이버는 StartIo 루틴에서 이러한 루틴을 호출하므로 일반적으로 이미 DISPATCH_LEVEL 실행 중입니다.

자체 IRP 큐를 설정하고 관리하기 때문에 StartIo 루틴이 없는 디바이스 드라이버가 AllocateAdapterChannel을 호출해야 할 때 반드시 DISPATCH_LEVEL IRQL에서 실행되는 것은 아닙니다. 이러한 드라이버는 AllocateAdapterChannel 을 호출할 때 필요한 IRQL에서 실행되고 호출 루틴이 제어를 다시 받을 때 원래 IRQL을 복원하도록 KeRaiseIrqlKeLowerIrql 호출 사이에 AllocateAdapterChannel 호출을 중첩해야 합니다.

드라이버 지원 루틴을 호출할 때는 다음 사항에 유의해야 합니다.

  • 현재 IRQL보다 작은 입력 NewIrql 값으로 KeRaiseIrql을 호출하면 심각한 오류가 발생합니다. 원래 IRQL(즉, KeRaiseIrql 호출 후)을 복원하는 것을 제외하고 KeLowerIrql을 호출하면 치명적인 오류가 발생합니다.

  • IRQL >= DISPATCH_LEVEL 실행하는 동안 커널 정의 디스패처 개체에 대해 KeWaitForSingleObject 또는 KeWaitForMultipleObjects 를 호출하여 0이 아닌 간격을 기다리는 동안 치명적인 오류가 발생합니다.

  • 이벤트, 세마포, 뮤텍스 또는 타이머가 신호 상태로 설정될 때까지 안전하게 기다릴 수 있는 유일한 드라이버 루틴은 드라이버에서 만든 스레드, DriverEntryReinitialize 루틴 또는 기본적으로 동기 I/O 작업(예: 대부분의 디바이스 I/O 제어 요청)에 대한 디스패치 루틴과 같은 IRQL PASSIVE_LEVEL 비비트 스레드 컨텍스트에서 실행되는 루틴입니다.

  • IRQL PASSIVE_LEVEL 실행하는 동안에도 호출 가능한 드라이버 코드는 입력 대기 매개 변수가 TRUE로 설정된 KeSetEvent, KeReleaseSemaphore 또는 KeReleaseMutex를 호출하지 않아야 합니다. 이러한 호출로 인해 페이지 오류가 발생할 수 있습니다.

  • IRQL보다 큰 APC_LEVEL 실행되는 루틴은 페이징된 풀에서 메모리를 할당하거나 페이징된 풀의 메모리에 안전하게 액세스할 수 없습니다. IRQL에서 실행되는 루틴이 APC_LEVEL 초과하면 페이지 오류가 발생하는 경우 심각한 오류입니다.

  • 드라이버는 KeAcquireSpinLockAtDpcLevelKeReleaseSpinLockFromDpcLevel을 호출할 때 IRQL DISPATCH_LEVEL 실행되어야 합니다.

    드라이버는 KeAcquireSpinLock을 호출할 때 IRQL <= DISPATCH_LEVEL 실행할 수 있지만 KeReleaseSpinLock을 호출하여 해당 스핀 잠금을 해제해야 합니다. 즉, KeReleaseSpinLockFromDpcLevel을 호출하여 KeAcquireSpinLock으로 획득한 스핀 잠금을 해제하는 것은 프로그래밍 오류입니다.

    드라이버가 IRQL > DISPATCH_LEVEL 실행하는 동안 KeAcquireSpinLockAtDpcLevel, KeReleaseSpinLockFromDpcLevel, KeAcquireSpinLock 또는 KeReleaseSpinLock을 호출해서는 안 됩니다.

  • ExInterlockedXxx 루틴과 같은 스핀 잠금을 사용하는 지원 루틴을 호출하면 호출자가 발생한 IRQL에서 아직 실행되고 있지 않은 경우 현재 프로세서에서 IRQL이 DISPATCH_LEVEL 또는 DIRQL로 발생합니다.

  • IRQL > PASSIVE_LEVEL 실행되는 드라이버 코드는 가능한 한 빨리 실행되어야 합니다. 루틴이 실행되는 IRQL이 높을수록 해당 루틴을 최대한 빨리 실행하도록 전체 성능이 양호하게 조정되는 것이 더 중요합니다. 예를 들어 KeRaiseIrql 을 호출하는 모든 드라이버는 가능한 한 빨리 KeLowerIrql 에 대한 상호 호출을 수행해야 합니다.

우선 순위 확인에 대한 자세한 내용은 예약, 스레드 컨텍스트 및 IRQL 백서를 참조하세요.