Extensões de dispositivo

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

  • Manter informações de estado do dispositivo.

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

  • Mantenha os dados que o driver deve ter residentes e no espaço do sistema para realizar 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) é executada 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 que o driver precisa. Por exemplo, qualquer driver que implementa 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 do 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 do dispositivo e a extensão do pool de memória nãopagado.

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 driver podem acessar a extensão de dispositivo correspondente por meio desse 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 dispositivo de um objeto de dispositivo de driver de nível mais baixo. 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 os objetos de temporizador e 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 bloqueio de rotação executivo e uma fila de trabalho interligada.

diagrama ilustrando uma extensão de dispositivo de exemplo 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 o 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 mais baixo 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 mais baixo em um IRP, conforme 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 chamar IoMakeAssociatedIrp, IoAllocateIrp ou IoInitializeIrp, ele deverá 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.

Embora um driver de nível superior possa ler dados do objeto de dispositivo do driver de nível inferior seguinte por meio 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 essa diretriz são os sistemas de arquivos, que definem e limpam DO_VERIFY_VOLUME nos Sinalizadores de objetos de dispositivo de drivers de mídia removível de nível inferior.

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

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

    • Um par de drivers que implementam esse esquema de comunicação de backdoor não pode ser atualizado individualmente, não pode ter um driver intermediário inserido entre eles sem alterar a origem do driver existente e não pode ser recompilado e movido prontamente de uma plataforma windows para a 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 ou criar novos IRPs, e eles devem usar IoCallDriver para comunicar solicitações a drivers de nível inferior.