Compartilhar via


Extensões de dispositivo

Para a maioria dos drivers intermediários e de nível mais baixo, a extensão do dispositivo é a estrutura de dados mais importante associada a um objeto de dispositivo. A estrutura interna é definida pelo driver e geralmente é utilizada 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.

  • Os dados que o driver precisa ter residentes e no espaço do sistema para realizar suas operações de E/S devem ser mantidos.

Como a maioria dos drivers de barramento, de função e de filtro (drivers de nível mais baixo e intermediário) são executados em um contexto de thread arbitrário (o de qualquer thread que esteja atual), a extensão de dispositivo é o local principal de cada driver para manter o estado do dispositivo e todos os outros dados específicos que o driver necessita. 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 possui um ISR deve fornecer armazenamento para um ponteiro destinado a um conjunto de objetos de interrupção definidos pelo próprio kernel, e a maioria dos drivers de dispositivos 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 sua extensão no 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 driver podem acessar a extensão de dispositivo correspondente através 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 do 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 fornecerá 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 bloqueio de rotação executivo e uma fila de trabalho intertravada.

diagrama ilustrando um exemplo de extensão de dispositivo para um driver de nível mais inferior.

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 ele tiver mais de um ISR. Para obter mais informações sobre como registrar um ISR, consulte Registrar 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 do dispositivo na extensão.

Um driver de nível superior normalmente armazena um ponteiro para o objeto de dispositivo do driver imediatamente inferior em sua extensão de dispositivo. Um driver de nível superior deve passar um ponteiro para o objeto de dispositivo do driver de nível inferior para o IoCallDriver, depois de configurar a posição da pilha de E/S desse driver em um IRP, conforme explicado em Manipulação de 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 do dispositivo do driver inferior.

    As únicas exceções a essa diretriz são os sistemas de arquivos, que definem e limpam DO_VERIFY_VOLUME nas Flags de objetos de dispositivo de drivers de mídia removível de baixo nível.

  • Nunca tente acessar a extensão de dispositivo do driver de nível 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 do Windows para a próxima.

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 determinados a eles ou devem criar novos IRPs, e eles devem usar o IoCallDriver para comunicar solicitações a drivers de nível inferior.