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

quando um driver WDF (estruturas de Driver Windows) 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 normalmente 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 normalmente 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 o status ou outras informações que foram 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 buffers de dados para um dispositivo. Há três métodos de acesso:

  • E/s armazenada em buffer. O Gerenciador de e/s cria buffers intermediários que ele compartilha com o driver.
  • E /s direta. 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.
  • Nenhuma e/s de buffer nem direta. O Gerenciador de e/s fornece o driver com 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 do buffer está acessível e bloquear o espaço do buffer na memória física.

Um driver KMDF (estrutura de driver Kernel-Mode) pode usar qualquer um dos três métodos de acesso. Um driver de estrutura de driver User-Mode (UMDF) pode usar e/s em buffer ou direta 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

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, exceto para o driver de nível mais alto, que pode usar o método "nenhum", independentemente de qual método é usado por drivers inferiores.

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 fornecer solicitações de leitura e gravação ao driver para o 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 realizar nenhuma ação para selecionar um método de buffer para os IOCTLs. Para obter mais informações sobre os IOCTLs, consulte definindo códigos de controle de e/s. Ao contrário das solicitações de leitura e gravação, todos os 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 de dispositivo. Os valores que um driver do UMDF fornece são apenas preferências e não são garantidos para serem usados pelo Framework. Para obter mais informações, consulte Managing buffer Access Methods in UMDF drivers.

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 fornecer solicitações de leitura, gravação e IOCTL ao driver para o dispositivo.

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

Se um driver WDF descrever um buffer de 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 (que exige 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 driver especificar buffers no formato correto.

Para obter informações sobre objetos de memória de estrutura, listas à parte, 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 ciclo de vida do buffer de memória.

Acessando buffers de dados para e/s em buffer

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

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:

  • Solicitações de gravação. O Gerenciador de e/s transfere informações de entrada do buffer de entrada do aplicativo de chamada antes de chamar a pilha de driver. Em seguida, o driver KMDF lê informações de entrada do buffer intermediário e grava-as no dispositivo.
  • Solicitações de leitura. 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 de dispositivo. O driver KMDF lê ou grava dados para essa solicitação de ou para o buffer intermediário.

Drivers 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:

  • Solicitações de gravação. A estrutura cria um buffer, transfere informações de entrada do buffer de entrada do aplicativo de chamada e, em seguida, chama a pilha de driver. O driver UMDF lê informações de entrada do buffer intermediário e grava-as no dispositivo.
  • Solicitações de leitura. Um driver UMDF lê informações de um dispositivo e as armazena em um buffer criado pela estrutura. 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 de 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 a disponibiliza para o driver. A estrutura não copia o conteúdo do buffer de saída, portanto, 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 original do IOCTL e retornados 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 retornados para o aplicativo de chamada.

Para recuperar um identificador para um objeto de memória de estrutura que representa o buffer, os drivers KMDF e UMDF chamam WdfRequestRetrieveInputMemory ou WdfRequestRetrieveOutputMemory, dependendo se esta é uma solicitação de leitura ou gravação. O driver pode então 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 compilar uma MDL (lista de descritores de memória) para o buffer, um driver KMDF chama WdfRequestRetrieveInputWdmMdl ou WdfRequestRetrieveOutputWdmMdl.

Acessando buffers de dados para e/s direta

Drivers KMDF

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

Drivers UMDF

Se o driver tiver especificado uma preferência para e/s direta e todos os requisitos de UMDF para e/s direta tiverem sido atendidos (consulte Gerenciando métodos de acesso de buffer em drivers UMDF), a estrutura mapeará o buffer de memória que receberá do Gerenciador de e/s diretamente para o espaço de endereço de processo de host do driver e, portanto, fornecerá acesso direto ao espaço

Para recuperar um identificador para um objeto de memória de estrutura que representa o espaço de buffer, o driver chama WdfRequestRetrieveInputMemory ou WdfRequestRetrieveOutputMemory. O driver pode então 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 descreve os buffers usando MDLs. Para recuperar um ponteiro para o MDL de um buffer, um driver KMDF chama WdfRequestRetrieveInputWdmMdl ou WdfRequestRetrieveOutputWdmMdl. Um driver UMDF não pode acessar o MDLs.

Acessando buffers de dados para nenhuma e/s de buffer nem direta

Drivers KMDF

Se o seu driver estiver usando o método de acesso de buffer conhecido como o método de e/s em buffer e e/s direto (ou, o método "nenhum", para curto), o Gerenciador de e/s simplesmente fornecerá o driver com os endereços virtuais que o originador da solicitação de e/s especificado 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 do buffer está acessível e bloquear o espaço do buffer na memória física.

Os endereços virtuais que o gerenciador de E/S fornece podem ser acessados somente no contexto de processo do originador da solicitação de E/S. Apenas o driver de nível mais alto na pilha de driver tem a garantia de ser executado no contexto de 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 . A estrutura chama essa função de retorno de chamada sempre que recebe uma solicitação de E/S para o driver.

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

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

  2. Chame WdfRequestProbeAndLockUserBufferForRead ou WdfRequestProbeAndLockUserBufferForWrite para investigar e bloquear o buffer e obter um identificador para um objeto de memória de estrutura para o buffer.

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

  4. Chame WdfDeviceEnqueueRequest, que retorna a solicitação para a estrutura.

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

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

Ocasionalmente, um driver de nível mais alto deve usar as etapas anteriores para acessar um buffer de modo de usuário, mesmo se o driver não estiver usando o método de acesso "nenhum". Por exemplo, suponha que o driver está usando E/S em buffer. Um código de controle de E/S que usa o método de acesso armazenado em buffer pode passar uma estrutura que contém um ponteiro inserido para um buffer de modo de usuário. Nesse caso, o driver deve fornecer uma função de retorno de chamada EvtIoInCallerContext que extrai os ponteiros da estrutura e, em seguida, usa as etapas anteriores de 2 a 4.

UMDF Drivers

O UMDF não dá suporte a buffers nem buffers de tipo de E/S diretos, portanto, um driver UMDF nunca precisa lidar com esse tipo de buffer diretamente.

No entanto, se a estrutura receber esses buffers para leitura ou gravação do gerenciador de E/S, ele os disponibiliza 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 um IOCTL especificando o método de buffer "nenhum", ele poderá, opcionalmente, converter o método de acesso de buffer da solicitação IOCTL em E/S em buffer ou E/S direta com base na presença de uma diretiva INF. Consulte Gerenciando métodos de acesso de buffer em drivers UMDF para obter mais informações.