Interrupts Interrupt request level (IRQL) -> Cada interrupt tem uma (IRQL) associada ->Pode ser considerado sua prioridade -> Cada processado inclui seu IRQL atual -> Uma CPU corre sempre o código da IRQL mais alta -> Consertando ainterrupt aumenta-s o processador IRQL para o nível do interrupt IRQL -> As mascara (disables) interrompe àquele IRQL(pedida) e as baixas ->Despedindo um interrupt restabelece o IRQL do processador -> Permitindo qualquer mascara interrupt para ser consertado -> alta IRQL interrupt preempts a baixa IRQL -> WinDbg s!pcr < processador #> shows IRQL atual
Uma IRQ (abreviação para Interrupt Request) é a forma pela qual componentes de hardware requisitam tempo computacional da CPU. Uma IRQ é a sinalização de um pedido de interrupção de hardware.
IRQs para computadores compatíveis com o IBM PC Os computadores modernos compatíveis com o IBM PC possuem 16 designações de IRQ (0-15), cada uma delas representando uma peça física (ou virtual) de hardware. Por exemplo, a IRQ0 é reservada para o temporizador do sistema, enquanto a IRQ1 é reservada para o teclado. Quanto menor for o número da IRQ, mais crítica é sua função. No passado existiam apenas 8 designações de IRQ (0-7). À medida que novos hardwares emergiram, emergiu a necessidade de novas IRQs. A solução foi criar mais 8 IRQs, adicionadas pelo desvio da IRQ2 para a nova IRQ9. Em computadores da classe Pentium (e alguns da classe 80486) as IRQs podem ser manipuladas via APIC. A lista das IRQs é: • • • • • • • • • • • • • • • •
IRQ0 = temporizador de intervalos 8253/8254 (temporizador do sistema) IRQ1 = teclado IRQ2 = reservada para a 8259B (amarrada à IRQ 9) IRQ3 = COM2 e COM4 IRQ4 = COM1 e COM3 IRQ5 = LPT2 ou placa de som IRQ6 = disquetes IRQ7 = LPT1 IRQ8 = relógio de tempo real (real time clock, RTC) IRQ9 = amarrada à IRQ2 IRQ10 = não definida IRQ11 = não definida IRQ12 = mouse PS/2 IRQ13 = co-processador matemático IRQ14 = Drives IDE primários IRQ15 = Drives IDE secundários
IRQL Levels (1): • • •
Passive_Level(0): nível normal de IRQL, o codigo do user mode sempre corre a este nível APC_LEVEL(1): usado para APCs kernel especiais, não é usado para escrita de drivers DISPATCH_LEVEL ou DPC_LEVEL(2): muitas retinas de drivers correm neste IRQL, o escalonador do kernel corre a este nível…
IRQL Levels (2): • •
dispositivos IRQL (DIRQL) (3-26) estão reservados para dispositivos de hardware e o nivel que corre a ISR é sempre acima de DISPATCH_LEVEL(2) High_Level (31): o nível maior, se o código corre a este nível, nada pode interferir naquele cpu (usar quando absolutamente necessário)
Manipulação de IRQL -> KIRQL é há pouco um UCHAR -> KeRaiseIrql eleva o IRQL e KeLowerIrql abaixa a IRQL! -> Porém, elevando através de zero é o OK -> Adquirir o IRQL atual chamam KeGetCurrentIRQL Algumas IRQL uso de regras: -> cada data activa é protegida em particular na IRQL -> Deve ser àquele IRQL modificar -> Leitura de Unsynchronized às vezes é aceitável ->Um baixo-IRQL rotina tem que ensinar seu IRQL para ganhar acesso para dados sincronizaram àquele IRQL -> Alto-IRQL código não deve modificar dados que podem ser escritos por baixo-IRQL código -> Assista para restrições de IRQL em toda rotina no DDK! -> Em geral: -> KeRaiseIrql e KeLowerIrql deveriam entrar em pares -> Sempre deixe uma rotina ao mesmo nivel de IRQL da k foi chamada -> Se você elevar IRQL, assegure todos os caminhos de saída par abaixar o IRQL Chamada de processo adiada ( DPC – Deferred Procedure Call):
• • • •
Usado para atrasar um processamento de alta prioridade para um nível mais baixo (dispatch) Implementado via objectos DPC(definidos em <wdm.h> e ) e software de interrupções Objectos de DPC definem um procedimento e um argumento Executa o procedimento especificado no dispatch IRQL
•
Usado pelo driver depois das funções de interrupção
DPC Queue: -> Uma lista de "pedidos de trabalho" -> Uma fila por CPU -> Mas uma CPU pode processar um DPC da fila de outra CPU -> Implicitamente ordenou antes de tempo (FIFO) -> Pode ser manipulado um pouco com o campo de Importância ->Cada especifica procedimentos e argumentos -> Processou todas altas-IRQL work(interrupt) completado -> O DpcListEntry campo sócio asegura os apontadores para o seguinte e o anterios DPC objecto (se houver)
Ciclo de processo de DPC: • •
DPCs estão em filas e não podem interromper um ao outro em qualquer cpu Cada CPU no sistema pode estar a executar diferentes DPCs ao mxm tempo
DPC serialization: • •
Objectos DPC podem estar numa fila apenas uma vez ( caso já la esteja e tentamos inserir o mxm returna False senão returna True de IOrequestDPC ou KeInsertDpcQueue) The DPC object é removido da fila antes da rotina DPC executar
Synchronization on MP Systems ->Elevando o IRQL em um processador não mascarado interrompe o trabalho em outros processadores -> Assim, IRQL sincronizado só trabalha para um cpu solteiro ->DPCs não estão necessariamente MP-seguros ->Dois DPCs poderia correr simultaneamente em dois CPUs e aceder aos mesmos dados ->A spin lock fé usada para proteger dados compartilhados em um sistema MP -> Um driver deveria sempre assumir que corre em um sistema MP e usa spin lock
The Spin Lock: • Um “spin lock” é um bloqueio que pode ser executado por mais de uma thread de execução. Se uma thread tenta obter o “spin lock” enquanto este está fechado (já bloqueado), a thread fica ocupada em um loop esperando o “spin lock” se tornar disponível. Se o “spin lock” não está bloqueado, a thread pode imediatamente obter o “spin lock” e continuar sua execução. O “spin lock” previne que mais de uma thread entre na região crítica por vez. – O comportamento do “spin lock” gasta tempo de processamento enquanto espera o recurso ficar disponível. Por isso o “spin lock” é útil para tarefas de
pequena duração. Uma alternativa seria colocar o processo no estado sleep quando este tentasse obter um recurso já ocupado e acordá-lo quando o recurso for liberado •
KSPIN_LOCK do tipo ULONG_PTR
Spin locks e IRQls: • Cada spin lock tem associado um IRQL: ->Dispatch_level: "executivo spin locks" – accionado por KeAcquireSpinLock or KeAcquireSpinLockAtDpcLevel ->Device IRQL: "interrupt object spin locks" - acquired by KeSynchronizeExecution, interrupt dispatcher -> HIGH_LEVEL: nao accionado directamente por drivers, apenas por algumas retinas (“interlocked” routines) • Codigo que queira possuir um spin lock primeiro tens de elevar a uma associação IRQL para sincronizar com outros pedidos nos mxm cpu ->tem de seguir as regras do IRQL, senão é possível um deadlock Conceitos de Spin Lock: ->Aquisição de spin lock e liberação de rotinas, implementa um algoritmo de um-dono-aum-tempo -> Análogo em conceito para mutexes -> Mas nenhuma propriedade! ->Onde estao os Spin lock? -> Alguns estão definidos no sistema -> Alguns são automaticamente associados com dispositivos de I/O e objetos relacionados -> Os device drivers podem criar e usar spin lock adicionais -> Uma spin lock ou é grátis ou possuiu por uma CPU específica -> Uma CPU deveria possuir uma spin lock que protege os dados partilhados antes de serem manipulados
Aquisição da spin lock: ->IRQL está implícito na escolha de rotina ->Usos de KeAcquireSpinLock IRQL=DISPATCH_LEVEL ->KeAcquireSpinLockAtDpcLevel faz não mudar o IRQL ->KeSynchronizeExecution e interrupt dispatcher usam SyncIrql que se encontra nos obejctos de interrupçao ->ExInterlockedXxx rotinas uso IRQL=HIGH_LEVEL ->spin lock não deveriam ser pedido se já o possuiu. ->Causa uma paralisação completa(deadlock) spin locks e Singles CPU systems: -> Todos os drivers deveriam usar rotinas de spin lock, não KeRaise / LowerIrql -> Assume que o driver corre ou poderia correr em um sistema MP -> Com exceção de código que é inerentemente a single thread (por exemplo. DriverEntry rotina, Descarregue rotina) -> 1 e multi sistemas de CPU usam uma versão diferente dE KERNEL -> NTOSKRNL.EXE contra
-> NTOSKRNL.EXE contra. NTKRNLMP.EXE ->Em SINGLE CPU systems, construção grátis: -> KeAcquire / ReleaseSpinLock ignoram o argumento de spin lock e Simplesmente chamam o KeRaise / LowerIrql -> KeAcquire / ReleaseSpinLockAtDpcLevel não fazem nada -> KeSynchronizeExecution faz só mudanças(trocas) de IRQL
IRQLs e spin locks no build de verificação • As rotinas de spin lock de adquirem e liberam o spin lock, mxm num único cpu (isto significa que o MP kernel esta sempre a correr no buil de verificação apesar do numero de cpus) • Vericaçao de consistência: verifica se a release não possui spin lock, verificação de bug se mais de 250 mseg passram no Dispatch_Level_IRQL ou acima…
Queues Spin lock -> Novo no Windows XP -> Versão eficiente de spin lock de despachar-nível (IRQL 2) -> Assegura que o spin lock é adquirida em um primeiro-venha primeiro-saque. A forma de escalonamento mais elementar consiste em simplesmente atender as tarefas em seqüência, à medida em que elas se tornam prontas (ou seja, conforme sua ordem de chegada na fila de tarefas prontas). Esse algoritm é conhecido como FCFS – First Come First Served – e tem como principal vantagem sua simplicidade ->Confira KeAcquireInStackQueuedSpinLock e KeReleaseInStackQueuedSpinLock no DDK