Partilhar via


Extensões de dispositivo

Para a maioria dos drivers de nível intermediário e mais baixo, a extensão de dispositivo é a estrutura de dados mais importante associada a um objeto de dispositivo. Sua estrutura interna é definida pelo motorista e normalmente é usada para:

  • Mantenha as informações de estado do dispositivo.

  • Forneça armazenamento para quaisquer objetos definidos pelo kernel ou outros recursos do sistema, como bloqueios de rotação, usados pelo driver.

  • Armazenar dados que o controlador deve ter em memória e na área do sistema para realizar as suas operações de E/S.

Como a maioria dos drivers de barramento, função e filtro (drivers intermediários e de nível mais baixo) são executados em um contexto de thread arbitrário (o de qualquer thread atual), uma extensão de dispositivo é o local principal de cada driver para manter o estado do dispositivo e todos os outros dados específicos do dispositivo de que o driver precisa. Por exemplo, qualquer driver que implemente uma rotina CustomTimerDpc ou CustomDpc geralmente fornece armazenamento para o temporizador definido pelo kernel necessário e/ou objetos DPC em uma extensão de dispositivo.

Cada driver que tem um ISR deve fornecer armazenamento para um ponteiro para um conjunto de objetos de interrupção definidos pelo kernel, e a maioria dos drivers de dispositivo armazena esse ponteiro em uma extensão de dispositivo. Cada driver determina o tamanho da extensão de dispositivo quando cria um objeto de dispositivo e cada driver define o conteúdo e a estrutura de suas próprias extensões de dispositivo.

As rotinas IoCreateDevice e IoCreateDeviceSecure do gerenciador de E/S alocam memória para o objeto e a extensão do dispositivo do pool de memória não paginada.

Cada rotina de driver padrão que recebe um IRP também recebe um ponteiro para um objeto de dispositivo que representa o dispositivo de destino para a operação de E/S solicitada. Essas rotinas de controlador de dispositivo podem acessar a extensão de dispositivo correspondente através deste ponteiro. Normalmente, um ponteiro DeviceObject também é um parâmetro de entrada para o ISR de um driver de nível mais baixo.

A figura a seguir mostra um conjunto representativo de dados definidos pelo driver para a extensão de um objeto de dispositivo do driver de nível inferior. Um driver de nível superior não forneceria armazenamento para um ponteiro de objeto de interrupção retornado por IoConnectInterrupt e passado para KeSynchronizeExecution e IoDisconnectInterrupt. No entanto, um driver de nível superior forneceria armazenamento para o temporizador e objetos DPC mostrados na figura a seguir se o driver tiver uma rotina CustomTimerDpc . Um driver de nível superior também pode fornecer armazenamento para um spin lock executivo e uma fila de trabalho interbloqueada.

Diagrama ilustrando um exemplo de extensão de dispositivo para um driver de nível mais baixo.

Além de fornecer armazenamento para um ponteiro de objeto de interrupção, um driver de dispositivo de nível mais baixo deve fornecer armazenamento para um bloqueio de rotação de interrupção se seu ISR manipular interrupções para dois ou mais dispositivos em vetores diferentes ou se tiver mais de um ISR. Para obter mais informações sobre como registrar um ISR, consulte Registrando um ISR.

Normalmente, os drivers armazenam ponteiros para seus objetos de dispositivo em suas extensões de dispositivo, conforme mostrado na figura. Um driver também pode manter uma cópia da lista de recursos para o dispositivo na extensão.

Um driver de nível superior normalmente armazena um ponteiro para o objeto de dispositivo do driver inferior seguinte em sua extensão de dispositivo. Um driver de nível superior deve passar um ponteiro para o objeto de dispositivo do próximo driver inferior para IoCallDriver, depois de configurar o local da pilha de E/S do driver inferior seguinte em um IRP, como explicado em Manipulando IRPs.

Observe também que qualquer driver de nível superior que aloca IRPs para drivers de nível inferior deve especificar quantos locais de pilha os novos IRPs devem ter. Em particular, se um driver de nível superior chama IoMakeAssociatedIrp, IoAllocateIrp ou IoInitializeIrp, ele deve acessar o objeto de dispositivo de destino do driver de nível inferior seguinte para ler seu valor StackSize , a fim de fornecer o StackSize correto como um argumento para essas rotinas de suporte.

Enquanto um driver de nível superior pode ler dados do objeto de dispositivo do driver de nível inferior seguinte através do ponteiro retornado por IoAttachDeviceToDeviceStack, esse driver deve seguir estas diretrizes de implementação:

  • Nunca tente gravar dados no objeto de dispositivo do driver inferior.

    As únicas exceções a esta directriz são os sistemas de ficheiros, que definem e limpam DO_VERIFY_VOLUME nos Flags dos objetos de dispositivo dos drivers de nível inferior de mídias removíveis.

  • Nunca tente acessar a extensão de dispositivo do driver inferior pelos seguintes motivos:

    • Não há uma maneira segura de sincronizar o acesso a uma única extensão de dispositivo entre dois drivers.

    • Um par de drivers que implementa esse esquema de comunicação backdoor não pode ser atualizado individualmente, não pode ter um driver intermediário inserido entre eles sem alterar o código-fonte dos drivers existentes e não pode ser recompilado e transferido prontamente de uma plataforma Windows para outra.

Para preservar sua interoperabilidade com drivers de nível inferior de uma plataforma ou versão do Windows para a próxima, os drivers de nível superior devem reutilizar os IRPs fornecidos a eles ou devem criar novos IRPs, e eles devem usar IoCallDriver para comunicar solicitações a drivers de nível inferior.