Partilhar via


Gerenciando prioridades de hardware

O nível de IRQL no qual uma rotina de driver é executada determina quais rotinas de suporte de driver em modo kernel podem ser chamadas. Por exemplo, algumas rotinas de suporte ao driver exigem que quem chama esteja a operar no nível IRQL = DISPATCH_LEVEL. Outros não podem ser chamados com segurança se o chamador estiver executando em qualquer IRQL superior a PASSIVE_LEVEL.

A seguir está uma lista de IRQLs nos quais as rotinas de driver padrão mais comumente implementadas são chamadas. Os IRQLs são listados da prioridade mais baixa para a mais alta.

PASSIVE_LEVEL
Interrupções desativadas - Nenhuma.

Rotinas dos drivers chamadas em PASSIVE_LEVEL - DriverEntry, AddDevice, Reinitialize, Unload rotinas, a maioria das rotinas de envio, threads criadas pelo driver, retornos de chamada de threads de trabalho.

APC_LEVEL
Interrupções mascaradas - As interrupções de nível APC estão mascaradas.

Rotinas dos motoristas chamadas em APC_LEVEL - Algumas rotinas de despacho (ver Rotinas de despacho e IRQLs).

DISPATCH_LEVEL
Interrupções mascaradas - DISPATCH_LEVEL e APC_LEVEL interrupções são mascaradas. Podem ocorrer interrupções devido a falhas de dispositivo, relógio e energia.

Rotinas de driver chamadas em DISPATCH_LEVEL - StartIo, AdapterControl, AdapterListControl, ControllerControl, IoTimer, Cancel (enquanto mantém a tranca de rotação de cancelamento), DpcForIsr, CustomTimerDpc, CustomDpc.

DIRQL
Interrupts Masked Off - Todas as interrupções no IRQL <= DIRQL do objeto de interrupção do driver. Podem ocorrer interrupções do dispositivo com um valor DIRQL mais elevado, juntamente com interrupções por falha de relógio e interrupções por falha de energia.

Rotinas de Driver Chamadas na DIRQL - InterruptService, SynchCritSection rotinas.

A única diferença entre APC_LEVEL e PASSIVE_LEVEL é que um processo em execução no APC_LEVEL não pode ser interrompido pelo APC. Mas ambos os IRQLs implicam um contexto de thread e ambos implicam que o código pode ser paginado.

Drivers de nível mais baixo processam IRPs enquanto executam em um dos três IRQLs:

  • PASSIVE_LEVEL, sem interrupções mascaradas no processador, nas rotinas de Despacho do motorista

    As rotinas DriverEntry, AddDevice, Reinitialize e Unload também são executadas em PASSIVE_LEVEL, assim como qualquer thread de sistema criado por driver.

  • DISPATCH_LEVEL, com as interrupções DISPATCH_LEVEL e APC_LEVEL desativadas no processador, na rotina StartIo

    As rotinas AdapterControl, AdapterListControl, ControllerControl, IoTimer, Cancel (enquanto mantém o bloqueio de rotação cancelar) e CustomTimerDpc também são executadas em DISPATCH_LEVEL, assim como as rotinas DpcForIsr e CustomDpc.

  • IRQL do dispositivo (DIRQL), com todas as interrupções em menor ou igual ao SynchronizeIrql dos objetos de interrupção do driver mascarados no processador, nas rotinas ISR e SynchCritSection

A maioria dos drivers de nível superior processa IRPs enquanto executa em qualquer um dos dois IRQLs:

  • PASSIVE_LEVEL, sem interrupções mascaradas no processador, nas rotinas de despacho do motorista

    As rotinas DriverEntry, Reinitialize, AddDevice e Unload também são executadas em PASSIVE_LEVEL, assim como quaisquer threads de sistema criados por driver ou rotinas de retorno de chamada de thread de trabalho ou drivers de sistema de arquivos.

  • nas rotinas IoCompletion do driver, com as interrupções DISPATCH_LEVEL e APC_LEVEL desativadas no processador

    As rotinas IoTimer, Cancel e CustomTimerDpc também são executadas em DISPATCH_LEVEL.

Em algumas circunstâncias, os drivers intermediários e de nível mais baixo de dispositivos de armazenamento em massa são chamados no IRQL APC_LEVEL. Em particular, isso pode ocorrer em uma falha de página para a qual um driver de sistema de arquivos envia uma solicitação de IRP_MJ_READ para drivers inferiores.

A maioria das rotinas de driver padrão são executadas em um IRQL que lhes permite simplesmente chamar as rotinas de suporte apropriadas. Por exemplo, um driver de dispositivo deve chamar AllocateAdapterChannel enquanto estiver em execução no IRQL DISPATCH_LEVEL. Como a maioria dos drivers de dispositivo chama essas rotinas de uma rotina StartIo , geralmente eles já estão sendo executados em DISPATCH_LEVEL.

Um driver de dispositivo que não tem rotina StartIo porque configura e gerencia suas próprias filas de IRPs não está necessariamente sendo executado em DISPATCH_LEVEL IRQL quando deveria chamar AllocateAdapterChannel. Esse driver deve aninhar sua chamada para AllocateAdapterChannel entre chamadas para KeRaiseIrql e KeLowerIrql para que ele seja executado no IRQL necessário quando chamar AllocateAdapterChannel e restaure o IRQL original quando a rotina de chamada recuperar o controle.

Ao chamar rotinas de suporte ao motorista, esteja ciente do seguinte.

  • Chamar KeRaiseIrql com um valor NewIrql de entrada que é menor do que o IRQL atual causa um erro fatal. Chamar KeLowerIrql , exceto para restaurar o IRQL original (ou seja, após uma chamada para KeRaiseIrql) também causa um erro fatal.

  • Durante a execução em IRQL >= DISPATCH_LEVEL, chamar KeWaitForSingleObject ou KeWaitForMultipleObjects para objetos dispatcher definidos pelo kernel para aguardar um intervalo diferente de zero causa um erro fatal.

  • As únicas rotinas de driver que podem aguardar com segurança que eventos, semáforos, mutexes ou temporizadores sejam definidos para o estado sinalizado são aquelas que são executadas em um contexto de thread não arbitrário no IRQL PASSIVE_LEVEL, como threads criadas pelo driver, as rotinas DriverEntry e Reinitialize ou rotinas de despacho para operações de I/O inerentemente síncronas (como a maioria das solicitações de controle de I/O de dispositivo).

  • Mesmo durante a execução no IRQL PASSIVE_LEVEL, o código do driver paginável não deve chamar KeSetEvent, KeReleaseSemaphore ou KeReleaseMutex com o parâmetro de entrada Wait definido como TRUE. Essa chamada pode causar uma falha fatal na página.

  • Qualquer rotina que esteja a ser executada acima do IRQL APC_LEVEL não pode alocar memória do pool paginado ou aceder à memória no pool paginado de forma segura. Se uma rotina em execução no IRQL maior que APC_LEVEL causar uma falha de página, é um erro fatal.

  • Um driver deve estar em execução no IRQL DISPATCH_LEVEL ao chamar KeAcquireSpinLockAtDpcLevel e KeReleaseSpinLockFromDpcLevel.

    Um driver pode estar sendo executado em IRQL <= DISPATCH_LEVEL quando chama KeAcquireSpinLock , mas deve liberar esse bloqueio de rotação chamando KeReleaseSpinLock. Em outras palavras, é um erro de programação liberar um bloqueio de rotação adquirido com KeAcquireSpinLock chamando KeReleaseSpinLockFromDpcLevel.

    Um driver não deve chamar KeAcquireSpinLockAtDpcLevel, KeReleaseSpinLockFromDpcLevel, KeAcquireSpinLock ou KeReleaseSpinLock quando executado no IRQL > DISPATCH_LEVEL.

  • Chamar uma rotina de suporte que usa um bloqueio de rotação, como uma rotina ExInterlocked Xxx, gera IRQL no processador atual para DISPATCH_LEVEL ou para DIRQL se o chamador ainda não estiver em execução em um IRQL elevado.

  • O código do driver que é executado no IRQL > PASSIVE_LEVEL deve ser executado o mais rápido possível. Quanto maior o IRQL em que uma rotina é executada, mais importante é para um bom desempenho geral ajustar essa rotina para executar o mais rápido possível. Por exemplo, qualquer driver que chame KeRaiseIrql deve fazer a chamada recíproca para KeLowerIrql assim que puder.

Para obter mais informações sobre como determinar prioridades, consulte o white paper Agendamento, contexto de thread e IRQL .