Partilhar via


Acessando buffers de dados em drivers WDF (KMDF ou UMDF)

Quando um driver WDF (Windows Driver Frameworks) recebe uma solicitação de controle de E/S de leitura, gravação ou dispositivo, o objeto de solicitação contém um buffer de entrada, um buffer de saída ou ambos.

Os buffers de entrada contêm informações de que o driver precisa. Para solicitações de gravação, essas informações geralmente são dados que um driver de função deve enviar para um dispositivo. Para solicitações de controle de E/S de dispositivo, um buffer de entrada pode conter informações que indicam o tipo de operação que o driver deve executar.

Os buffers de saída recebem informações do driver. Para solicitações de leitura, essas informações geralmente são dados que um driver de função recebe de um dispositivo. Para solicitações de controle de E/S de dispositivo, um buffer de saída pode receber status ou outras informações especificadas pelo código de controle de E/S da solicitação.

A técnica que o driver usa para acessar os buffers de dados de uma solicitação depende do método do driver para acessar os buffers de dados de um dispositivo. Existem três métodos de acesso:

  • Entrada/Saída com buffer. O gerenciador de E/S cria buffers intermediários que compartilha com o driver.
  • E/S diretas. O gerenciador de E/S bloqueia o espaço do buffer na memória física e, em seguida, fornece ao driver acesso direto ao espaço do buffer.
  • Nem entrada/saída com buffer nem direta. O gerenciador de E/S fornece ao driver os endereços virtuais do espaço de buffer da solicitação. O gerenciador de E/S não valida o espaço de buffer da solicitação, portanto, o driver deve verificar se o espaço de buffer está acessível e bloquear o espaço de buffer na memória física.

Um driver KMDF (Kernel-Mode Driver Framework) pode usar qualquer um dos três métodos de acesso. Um driver do User-Mode Driver Framework (UMDF) pode usar entrada/saída direta ou em buffer para solicitações de leitura, gravação e IOCTL, e pode converter solicitações que especificam o método METHOD_NEITHER.

Especificando o método de acesso ao buffer

de drivers KMDF

Para solicitações de leitura e gravação, todos os drivers em uma pilha de drivers devem usar o mesmo método para acessar os buffers de um dispositivo, com exceção do driver de nível mais alto, que pode usar o método "nenhum", independentemente de qual método é usado pelos drivers de nível inferior.

A partir da versão 1.13, um driver KMDF especifica o método de acesso para todas as solicitações de leitura e gravação de um dispositivo chamando WdfDeviceInitSetIoTypeEx para cada dispositivo. Por exemplo, se um driver especificar o método de E/S em buffer para um de seus dispositivos, o gerenciador de E/S usará o método de E/S em buffer ao entregar solicitações de leitura e gravação ao driver desse dispositivo.

Para solicitações de controle de E/S de dispositivo, o código de controle de E/S (IOCTL) contém bits que especificam o método de acesso ao buffer. Como resultado, um driver KMDF não precisa executar nenhuma ação para selecionar um método de buffer para IOCTLs. Para obter mais informações sobre IOCTLs, consulte Definindo códigos de controle de E/S. Ao contrário das solicitações de leitura e gravação, todas as IOCTLs de um dispositivo não precisam especificar o mesmo método de acesso.

Drivers UMDF

Um driver UMDF especifica preferências para o método de acesso que a estrutura usa para solicitações de leitura e gravação, bem como solicitações de controle de E/S do dispositivo. Os valores que um driver UMDF fornece são apenas preferências e não é garantido que sejam usados pela estrutura. Para obter mais informações, consulte Gestão de Métodos de Acesso a Buffers em Drivers UMDF.

Um driver UMDF especifica o método de acesso para todas as solicitações de leitura, gravação e IOCTL de um dispositivo chamando WdfDeviceInitSetIoTypeEx para cada dispositivo. Por exemplo, se um driver especificar o método de E/S em buffer para um de seus dispositivos, a estrutura usará o método de E/S em buffer ao entregar solicitações de leitura, gravação e IOCTL ao driver desse dispositivo.

Note a diferença na técnica de acesso ao buffer para IOCTLs entre KMDF e UMDF. Os drivers KMDF não especificam o método de acesso ao buffer para IOCTLs, enquanto os drivers UMDF o fazem.

Se um driver WDF descrever o buffer de uma solicitação de E/S usando uma técnica incorreta para o método de E/S usado por um destino de E/S, a estrutura corrigirá a descrição do buffer. Por exemplo, se um driver usa um MDL para descrever um buffer que ele passa para WdfIoTargetSendReadSynchronouslye se o destino de E/S usa E/S em buffer (o que requer que os buffers sejam especificados usando endereços virtuais em vez de MDLs), a estrutura converte a descrição do buffer de um MDL para um endereço virtual e comprimento. No entanto, é mais eficiente se o seu driver especificar os buffers no formato correto.

Para mais informações sobre objetos de memória de framework, listas lookaside, MDLs e buffers locais, consulte Usando buffers de memória.

Para obter informações sobre quando os buffers de memória são excluídos, consulte Memory Buffer Life Cycle.

Acessando buffers de dados para E/S em buffer

Se o driver estiver usando E/S em buffer, seu comportamento mudará dependendo do tipo de solicitação de dados e se estiver usando KMDF ou UMDF.

de drivers KMDF

Quando um driver KMDF usa E/S em buffer, o gerenciador de E/S cria um buffer intermediário que o driver pode acessar para cada tipo de solicitação. Veja o que acontece:

  • Escreva solicitações. O gestor de E/S transfere as informações de entrada do buffer de entrada da aplicação de chamada antes de acionar a pilha de controladores. Em seguida, o driver KMDF lê as informações de entrada do buffer intermediário e as grava no dispositivo.
  • Ler pedidos. O driver KMDF lê informações do dispositivo e as armazena no buffer intermediário. Em seguida, o gerenciador de E/S copia os dados de saída do buffer intermediário para o buffer de saída do aplicativo.
  • Solicitações de controle de E/S do dispositivo. O driver KMDF lê ou grava dados para essa solicitação de ou para o buffer intermediário.

Drivers de UMDF

Quando um driver UMDF usa E/S em buffer, o processo de host do driver cria um ou dois buffers intermediários, dependendo do tipo de solicitação. Veja o que acontece:

  • Escreva solicitações. O framework cria um buffer, transfere informações de entrada do buffer de entrada da aplicação que o chamou e, em seguida, chama a pilha de drivers. O driver UMDF lê informações de entrada do buffer intermediário e as grava no dispositivo.
  • Ler pedidos. Um driver UMDF lê informações de um dispositivo e as armazena em um buffer que a estrutura criou. O processo de host do driver copia os dados de saída do buffer intermediário para o buffer de saída do aplicativo.
  • Solicitações de controle de E/S do dispositivo. A estrutura cria dois buffers correspondentes aos buffers de entrada e saída do IOCTL que o driver pode acessar. A estrutura copia as informações de entrada do IOCTL para o novo buffer intermediário e as disponibiliza para o driver. A estrutura não copia o conteúdo do buffer de saída, então o driver não deve tentar ler a partir dele (caso contrário, ele acabará lendo dados de lixo). Todos os dados que o driver grava no buffer de saída são copiados de volta para o buffer IOCTL original e retornam ao aplicativo após a conclusão bem-sucedida da solicitação de E/S. Observe que todos os dados que o driver grava no buffer de entrada são descartados e não retornam ao aplicativo de chamada.

Para obter um identificador para um objeto de memória de um framework que representa o buffer, os drivers KMDF e UMDF chamam WdfRequestRetrieveInputMemory ou WdfRequestRetrieveOutputMemory, dependendo de ser uma solicitação de leitura ou de escrita. O driver pode recuperar um ponteiro para o buffer chamando WdfMemoryGetBuffer. Para ler e gravar o buffer, o driver chama WdfMemoryCopyFromBuffer ou WdfMemoryCopyToBuffer.

Para recuperar o endereço virtual e o comprimento do buffer, o driver chama WdfRequestRetrieveInputBuffer ou WdfRequestRetrieveOutputBuffer.

Para alocar e criar uma lista de descritores de memória (MDL) para o buffer, um driver KMDF chama WdfRequestRetrieveInputWdmMdl ou WdfRequestRetrieveOutputWdmMdl.

Acessando buffers de dados para E/S direta

de drivers KMDF

Se o driver estiver usando E/S direta, o gerenciador de E/S verificará a acessibilidade do espaço de buffer especificado pelo originador da solicitação de E/S (normalmente um aplicativo de modo de usuário), bloqueará o espaço de buffer na memória física e fornecerá ao driver acesso direto ao espaço de buffer.

Drivers UMDF

Se o driver tiver especificado uma preferência por E/S direta e todos os requisitos UMDF para E/S direta tiverem sido atendidos (consulte Gerenciando métodos de acesso ao buffer em drivers UMDF), a estrutura mapeia o buffer de memória que recebe do gerenciador de E/S diretamente para o espaço de endereçamento do processo do host e, assim, fornece ao driver acesso direto ao espaço do buffer.

Para obter um identificador de um objeto de memória do framework que representa o espaço de buffer, o driver chama WdfRequestRetrieveInputMemory ou WdfRequestRetrieveOutputMemory. O driver pode recuperar um ponteiro para o buffer chamando WdfMemoryGetBuffer. Para ler e gravar o buffer, o driver chama WdfMemoryCopyFromBuffer ou WdfMemoryCopyToBuffer.

Para recuperar o endereço virtual e o comprimento do espaço do buffer, o driver chama WdfRequestRetrieveInputBuffer ou WdfRequestRetrieveOutputBuffer.

Se os drivers de um dispositivo estiverem usando E/S direta, o gerenciador de E/S descreverá buffers usando MDLs. Para recuperar um ponteiro para o MDL do buffer, um driver KMDF chama WdfRequestRetrieveInputWdmMdl ou WdfRequestRetrieveOutputWdmMdl. Um driver UMDF não pode acessar MDLs.

Acesso a Buffers de Dados para E/S Sem Buffer ou Direta

de drivers KMDF

Se o driver estiver usando o método de acesso ao buffer conhecido como nem E/S em buffer nem método de E/S direta (ou, o método "nem", para abreviar), o gerenciador de E/S simplesmente fornece ao driver os endereços virtuais que o originador da solicitação de E/S especificou para o espaço de buffer da solicitação. O gerenciador de E/S não valida o espaço de buffer da solicitação de E/S, portanto, o driver deve verificar se o espaço de buffer está acessível e bloquear o espaço de buffer na memória física.

Os endereços virtuais que o gerenciador de E/S fornece podem ser acessados somente no contexto do processo do originador da solicitação de E/S. Apenas o driver de nível mais alto na pilha de drivers tem a garantia de ser executado no contexto do processo do originador.

Para obter acesso ao espaço de buffer de uma solicitação de E/S, o driver de nível mais alto deve fornecer uma função de retorno de chamada EvtIoInCallerContext . O framework chama esta função callback cada vez que recebe uma solicitação de E/S para o driver.

Se o método de acesso ao buffer de uma solicitação for "nenhum dos dois", um driver KMDF deverá fazer o seguinte para cada buffer:

  1. Chame WdfRequestRetrieveUnsafeUserInputBuffer ou WdfRequestRetrieveUnsafeUserOutputBuffer para obter o endereço virtual do buffer.

  2. Chame WdfRequestProbeAndLockUserBufferForRead ou WdfRequestProbeAndLockUserBufferForWrite para testar e bloquear o buffer e obter um identificador para um objeto de memória da infraestrutura para o buffer.

  3. Salve os handles do objeto de memória no espaço de contexto da solicitação.

  4. Chame WdfDeviceEnqueueRequest, que devolve a solicitação ao framework.

Posteriormente, a estrutura adiciona a solicitação a uma das filas de E/S do driver. Se o driver tiver fornecido os manipuladores de solicitação , a estrutura irá eventualmente chamar o manipulador de solicitação apropriado.

O manipulador de solicitação pode recuperar os identificadores de objeto de memória da solicitação do espaço de contexto da solicitação. O driver pode passar as alças para WdfMemoryGetBuffer para obter o endereço do buffer.

Ocasionalmente, um driver de nível superior deve usar as etapas anteriores para aceder a um buffer em modo de utilizador, mesmo que o driver não esteja a usar o método de acesso "neither". Por exemplo, suponha que o driver esteja usando E/S em buffer. Um código de controle de E/S que usa o método de acesso em buffer pode passar uma estrutura que contém um ponteiro incorporado para um buffer de modo de usuário. Nesse caso, o driver deve fornecer uma EvtIoInCallerContext função de retorno de chamada que extrai os ponteiros da estrutura e utiliza as etapas anteriores de 2 a 4.

Drivers UMDF

O UMDF não suporta buffers nem buffers do tipo E/S direta, portanto, um driver UMDF nunca precisa lidar diretamente com esse tipo de buffer.

No entanto, se a estrutura receber esses buffers para leitura ou gravação do gerenciador de E/S, ele os disponibilizará para um driver UMDF como E/S em buffer ou E/S direta, dependendo do método de acesso selecionado pelo driver. Se a estrutura receber uma IOCTL especificando o método de buffer "neither", pode, opcionalmente, converter o método de acesso ao buffer da solicitação IOCTL para E/S em buffer ou E/S direta, com base na presença de uma diretiva INF. Consulte Gestão de Métodos de Acesso ao Buffer em Drivers UMDF para obter mais informações.