Acessando buffers de dados em drivers UMDF 1.x

Aviso

O UMDF 2 é a versão mais recente do UMDF e substitui o UMDF 1. Todos os novos drivers UMDF devem ser gravados usando UMDF 2. Nenhum novo recurso está sendo adicionado ao UMDF 1 e há suporte limitado para UMDF 1 em versões mais recentes do Windows 10. Drivers universais do Windows devem usar UMDF 2.

Para obter mais informações, consulte Introdução com UMDF.

Para obter informações sobre como acessar buffers de dados para UMDF 2, consulte Acessando buffers de dados em drivers WDF.

Quando um driver 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 ou um buffer de saída ou ambos. (Algumas solicitações de controle de E/S do dispositivo fornecem dois buffers de entrada, duas saídas ou dois buffers de entrada/saída.)

Os buffers de entrada contêm informações de que o driver precisa. Para solicitações de gravação, normalmente essas informações são dados que um driver de função deve enviar para um dispositivo. Para solicitações de controle de E/S do 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, normalmente essas informações são dados que um driver de função recebe de um dispositivo. Para solicitações de controle de E/S do dispositivo, um buffer de saída pode receber status ou outras informações que o código de controle de E/S da solicitação especificou.

A técnica usada pelo driver para acessar os buffers de dados de uma solicitação pode depender do método do driver para acessar buffers de dados de um dispositivo. O UMDF dá suporte aos seguintes métodos de acesso ao buffer:

Um terceiro método de acesso, que não é chamado de E/S direta nem em buffer, não está disponível para drivers baseados em UMDF, mas o UMDF pode converter algumas solicitações de E/S do método "nenhum" para um método compatível com a versão UMDF.

Na maioria dos casos, os drivers baseados em UMDF chamam os mesmos métodos de objeto UMDF para acessar buffers de dados, quer UMDF e o driver estejam usando E/S em buffer ou E/S direta. A E/S direta geralmente fornece melhor desempenho do que a E/S do buffer fornece.

As seguintes seções deste tópico explicam:

Especificando um método de acesso de buffer preferencial

As versões 1.9 e posteriores do UMDF dão suporte aos métodos de acesso de E/S em buffer e diretos. Os drivers podem especificar o método de acesso que você prefere usar para todas as solicitações de controle de E/S de leitura, gravação e dispositivo de um dispositivo chamando IWDFDeviceInitialize2::SetIoTypePreference antes de chamar IWDFDriver::CreateDevice para criar um objeto de dispositivo. Por exemplo, se um driver especificar uma preferência apenas pelo método de E/S armazenado em buffer para solicitações de leitura e gravação para um de seus dispositivos, o processo de host do driver UMDF usará o método de E/S em buffer quando fornecer solicitações de leitura e gravação para o driver desse dispositivo. Se um driver especificar uma preferência por E/S direta, o UMDF poderá (mas talvez não) usar E/S direta. Para obter mais informações sobre quando o UMDF usa E/S direta, consulte Como o UMDF escolhe um método de acesso de buffer para uma solicitação de E/S.

Para cada dispositivo compatível com um driver, o driver pode especificar uma preferência por E/S em buffer, por E/S direta ou por E/S em buffer ou direta para o dispositivo. O driver pode especificar um tipo de método de acesso para solicitações de leitura e gravação e outro tipo de método de acesso para solicitações de controle de E/S do dispositivo. Se o driver não especificar uma preferência de método de acesso, o UMDF usará o método armazenado em buffer.

Para solicitações de controle de E/S do dispositivo, o IOCTL (código de controle de E/S) especifica o método de acesso ao buffer. (Para obter mais informações sobre como ioctls especificam um método de acesso, consulte Definindo códigos de controle de E/S.) No entanto, o método de acesso usado pelo UMDF pode não corresponder ao método de acesso especificado pelo IOCTL.

Especificando um modo de recuperação de buffer

Nas versões do UMDF anteriores à versão 1.9, o UMDF sempre disponibiliza buffers de uma solicitação de E/S para o driver (copiando os buffers para o processo de host do driver UMDF) assim que o UMDF recebe a solicitação de E/S. Esse modo de recuperação de buffer é chamado de recuperação imediata. Se ocorrer uma falha, o UMDF concluirá a solicitação de E/S com uma falha status valor e não entregará a solicitação de E/S ao driver.

As versões 1.9 e posteriores do UMDF dão suporte aos modos de recuperação imediata e adiada. O modo de recuperação adiado adia a cópia do buffer de uma solicitação de E/S para o processo de host do driver até que o driver tente acessar o buffer. Se ocorrer uma falha, as funções de acesso ao buffer retornarão um erro status valor para o driver.

O driver pode especificar um modo de recuperação de buffer quando chama IWDFDeviceInitialize2::SetIoTypePreference para cada dispositivo. Use as seguintes regras:

  • Se o driver especificar o método de acesso direto de E/S, ele também deverá especificar o modo de recuperação adiado. A E/S direta só funciona com a recuperação adiada.

  • Todos os drivers gravados para execução com as versões 1.9 e posteriores do UMDF devem especificar o modo de recuperação adiada para todas as solicitações de E/S, independentemente de o driver escolher o método de acesso de E/S em buffer ou direto. A recuperação adiada fornece melhor desempenho porque não acessa buffers que o driver não usa.

Se o driver não especificar um modo de recuperação de buffer, o UMDF usará a recuperação imediata.

Todos os drivers baseados em UMDF em uma pilha de driver devem usar o mesmo modo de recuperação. Se alguns drivers especificarem recuperação imediata e alguns especificarem a recuperação adiada, o UMDF usará a recuperação imediata.

Como o UMDF escolhe um método de acesso de buffer para uma solicitação de E/S

O método de acesso que um driver especifica quando chama IWDFDeviceInitialize2::SetIoTypePreference, pode não ser o que umDF usa. O UMDF usa as seguintes regras para determinar qual método de acesso usar:

  • Todos os drivers baseados em UMDF em uma pilha de driver devem usar o mesmo método para acessar os buffers de um dispositivo. Se o UMDF determinar que alguns drivers preferem E/S em buffer ou E/S direta para um dispositivo, enquanto outros drivers preferem apenas E/S em buffer para o dispositivo, o UMDF usa E/S em buffer para todos os drivers. Se um ou mais drivers de uma pilha preferirem apenas E/S em buffer, enquanto outros preferem apenas E/S direta, o UMDF registra um evento no log de eventos do sistema e não inicia a pilha de drivers.

    Seu driver pode chamar IWDFDevice2::GetDeviceStackIoTypePreference para determinar os métodos de acesso ao buffer atribuídos pela UMDF a solicitações de leitura/gravação e solicitações de controle de E/S de um dispositivo.

  • Em alguns casos, um driver especifica uma preferência por E/S direta quando chama IWDFDeviceInitialize2::SetIoTypePreference, mas para obter o melhor desempenho, o UMDF usa E/S em buffer para uma ou mais solicitações do dispositivo. Por exemplo, o UMDF usa E/S em buffer para buffers pequenos se puder copiar os dados para o buffer do driver mais rapidamente do que pode mapear os buffers para acesso direto.

    Opcionalmente, você pode definir um valor do Registro DirectTransferThreshold com tipo REG_DWORD que a estrutura usa para determinar o menor tamanho de buffer para o qual a estrutura usará E/S direta. Normalmente, você não precisa fornecer esse valor de Registro porque a estrutura usa um valor que fornece o melhor desempenho. O valor DirectTransferThreshold está localizado na subchave Device Parameters\WUDF do dispositivo, que está sob a chave de hardware do dispositivo.

    A estrutura usa as regras a seguir para determinar o limite com base no valor fornecido em DirectTransferThreshold. Os números fornecidos pressupõem um PAGE_SIZE de 4096, que é válido, exceto em sistemas baseados em Itanium.

    • Se você definir DirectTransferThreshold como qualquer valor menor ou igual a 8192 (ou 2 * PAGE_SIZE), a estrutura definirá o limite como 8192. A estrutura usa E/S em buffer para buffers menores que 8192 bytes e E/S direta para buffers iguais ou maiores que 8.192 bytes.

    • Se você definir DirectTransferThreshold como qualquer valor maior que 8192, a estrutura arredondará para o próximo múltiplo exato de PAGE_SIZE. Novamente, a estrutura usa E/S em buffer para buffers menores que o limite e E/S direta para buffers iguais ou maiores que o limite.

  • O UMDF usa E/S direta somente para o espaço em buffer que começa e termina em um limite de página de memória. Se o início ou o fim de um buffer não estiver em um limite de página, o UMDF usará E/S em buffer para essa parte do buffer. Em outras palavras, o UMDF pode usar E/S em buffer e E/S direta para uma transferência de dados grande que consiste em várias solicitações de E/S.

  • Para solicitações de controle de E/S do dispositivo, o UMDF usará E/S direta somente se o IOCTL (código de controle de E/S) especificar E/S direta e somente se todos os drivers baseados em UMDF do dispositivo tiverem chamado IWDFDeviceInitialize2::SetIoTypePreference para especificar o método de acesso direto.

Os drivers usam o mesmo conjunto de métodos de objeto de solicitação para acessar buffers de dados, independentemente do método de acesso ao buffer. Portanto, a maioria dos drivers normalmente não precisa saber se o UMDF está usando E/S em buffer ou E/S direta para uma solicitação de E/S.

Como um driver pode obter o método de acesso para uma solicitação de E/S

Em alguns casos, você poderá melhorar o desempenho do dispositivo e do driver se o método de acesso for conhecido. Nesses casos, o driver pode chamar IWDFIoRequest2::GetEffectiveIoType para obter o método de acesso ao buffer de uma solicitação de E/S.

Por exemplo, considere um dispositivo de alta taxa de transferência que normalmente usa E/S direta. Como ele está usando E/S direta, o driver deve copiar parâmetros especificados pelo aplicativo para a memória do driver local antes de validar os parâmetros, para garantir que o aplicativo não modifique os parâmetros após a validação.

Como o driver pode receber ocasionalmente um buffer que usa E/S em buffer e como os buffers de E/S em buffer já foram copiados, o aplicativo não pode modificar os dados e o driver não precisa copiar parâmetros antes de validá-los. Portanto, o driver deve marcar o método de acesso ao buffer de cada solicitação para determinar se ele deve copiar parâmetros antes de validá-los.

Usando E/S em buffer em drivers UMDF

Se o driver estiver usando E/S em buffer, o comportamento do UMDF será diferente dependendo do tipo de solicitação. Para solicitações de leitura e gravação, o processo de host do driver cria um único buffer intermediário que o driver pode acessar.

Para solicitações de gravação, o processo de host do driver transfere informações de entrada do buffer de entrada do aplicativo de chamada antes de chamar a pilha de driver. Os drivers normalmente leem informações de entrada do buffer intermediário e as gravam no dispositivo.

Para solicitações de leitura, os drivers normalmente leem informações de um dispositivo e as armazenam no buffer intermediário. O processo de host do driver copia os dados de saída do buffer intermediário para o buffer de saída do aplicativo.

No entanto, para solicitações de controle de E/S do dispositivo, o processo de host do driver cria dois buffers separados que o driver pode acessar. Observe que isso difere do comportamento dos drivers WDM e KMDF, para os quais as solicitações de controle de E/S de dispositivo, leitura, gravação e dispositivo enviadas usando E/S em buffer resultam no driver acessando um único buffer intermediário. Nesse caso, o buffer de saída inicialmente não contém nada e o driver não deve ler dele. Além disso, todos os dados que o driver grava no buffer de entrada são descartados e não são retornados ao aplicativo de chamada.

Para obter diretrizes sobre quando escolher E/S em buffer, consulte WDF_DEVICE_IO_TYPE.

As versões 1.9 e posteriores do UMDF podem dar suporte à recuperação imediata ou adiada de buffers de solicitação. Para obter mais informações, consulte WDF_DEVICE_IO_BUFFER_RETRIEVAL.

Um driver que usa o modo de recuperação de buffer imediato deve usar IWDFIoRequest::GetInputMemory e IWDFIoRequest::GetOutputMemory para acessar os buffers.

Um driver que usa o modo de recuperação de buffer adiado pode acessar os buffers chamando IWDFIoRequest2::RetrieveInputBuffer, IWDFIoRequest2::RetrieveInputMemory, IWDFIoRequest2::RetrieveOutputBuffer ou IWDFIoRequest2::RetrieveOutputMemory.

Usando e/S direta em drivers UMDF

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

Para obter diretrizes sobre quando escolher E/S direta, consulte WDF_DEVICE_IO_TYPE.

Seu driver pode acessar os buffers chamando IWDFIoRequest2::RetrieveInputBuffer, IWDFIoRequest2::RetrieveInputMemory, IWDFIoRequest2::RetrieveOutputBuffer ou IWDFIoRequest2::RetrieveOutputMemory.

Usando E/S não armazenada em buffer nem E/S direta em drivers UMDF

O método de acesso ao buffer que não é conhecido como o método de E/S em buffer nem o método direto de E/S (ou, o método "nem", para abreviar) permite que os drivers acessem diretamente os ponteiros de buffer de solicitação de um aplicativo. Os drivers baseados em UMDF não podem usar esse método de acesso.

No entanto, as definições de alguns IOCTLs (códigos de controle de E/S do dispositivo) especificam que as solicitações usam o método "nenhum" . Opcionalmente, o UMDF pode converter o método de acesso ao buffer dessas solicitações de controle de E/S do dispositivo em E/S em buffer ou E/S direta. Use as seguintes etapas:

  1. Inclua a diretiva UmdfMethodNeitherAction em uma seção INF DDInstall do arquivo INF do driver. Você pode definir o valor da diretiva para indicar que o UMDF deve passar solicitações de controle de E/S do dispositivo que usam o método de acesso "nenhum" para o driver. (Caso contrário, o UMDF concluirá essas solicitações de E/S com um erro status valor.)

  2. Acesse os buffers da solicitação de E/S usando os métodos de objeto que o UMDF fornece para E/S em buffer ou E/S direta.

Você deve habilitar o suporte a solicitações IOCTL que usam o método "nenhum" somente se tiver certeza de que o UMDF pode converter o método de acesso em E/S em buffer ou E/S direta. Por exemplo, se o IOCTL especificar uma solicitação personalizada que não segue as regras de especificação de buffer descritas em Descrições de buffer para códigos de controle de E/S, o UMDF não poderá converter os buffers.