Partilhar via


Usando o DMA do sistema Common-Buffer

Um driver que usa o modo de inicialização automática de um controlador de DMA do sistema deve alocar memória para um buffer no qual ou a partir do qual as transferências de DMA podem ser realizadas. O driver chama AllocateCommonBuffer para obter esse buffer, normalmente da rotina DispatchPnP que manipula uma solicitação de IRP_MN_START_DEVICE . A figura a seguir mostra como um driver aloca o buffer e mapeia seu intervalo de endereços virtuais para a memória física do sistema.

diagrama ilustrando como um driver aloca um buffer comum para o dma do sistema.

Como mostra a figura anterior, um driver executa as seguintes etapas para alocar um buffer para o DMA do sistema:

  1. O driver chama AllocateCommonBuffer, passando um ponteiro para o objeto do adaptador que foi retornado por IoGetDmaAdapter, juntamente com o comprimento em bytes solicitados para seu buffer. Para usar a memória economicamente, o valor length de entrada para o buffer deve ser menor ou igual a PAGE_SIZE ou deve ser um múltiplo integral de PAGE_SIZE.

  2. Se AllocateCommonBuffer retornar um ponteiro NULL , o driver deverá liberar todos os recursos do sistema já reivindicados e retornar STATUS_INSUFFICIENT_RESOURCES em resposta à solicitação de IRP_MN_START_DEVICE .

    Caso contrário, AllocateCommonBuffer aloca a quantidade solicitada de memória no espaço de endereço virtual do sistema e retorna dois tipos diferentes de ponteiros para esse buffer:

    • O LogicalAddress do buffer (BufferLogicalAddress na figura anterior), para o qual o driver deve fornecer armazenamento, mas que deve ignorar depois disso

    • O endereço virtual do buffer (BufferVirtualAddress na figura anterior), que o driver também deve armazenar para que ele possa criar um MDL descrevendo seu buffer para operações de DMA

    O driver deve armazenar esses ponteiros na extensão do dispositivo ou em outra memória residente alocada pelo driver.

  3. O driver chama IoAllocateMdl para alocar um MDL para o buffer. O driver passa o VirtualAddress do buffer retornado por AllocateCommonBuffer e o Comprimento de seu buffer para alocar um MDL.

  4. O driver chama MmBuildMdlForNonPagedPool com o ponteiro retornado por IoAllocateMdl para mapear o intervalo de endereços virtuais do buffer residente para a memória física do sistema.

Depois de alocar um buffer comum e mapear seu intervalo de endereços virtuais, o driver de um dispositivo subordinado pode começar a processar um IRP que solicita uma transferência de DMA. Para fazer isso, o driver chama a seguinte sequência geral de rotinas de suporte:

  1. A critério do gravador de driver, RtlMoveMemory para copiar dados de um buffer de usuário bloqueado para o buffer comum alocado pelo driver para uma transferência para o dispositivo

  2. AllocateAdapterChannel quando o driver estiver pronto para programar seu dispositivo para DMA e precisar do controlador de DMA do sistema

  3. MapTransfer, com o MDL que descreve o buffer comum alocado pelo driver, para configurar o controlador de DMA do sistema para a operação de transferência

    Observe que o driver chama MapTransfer apenas uma vez para configurar o controlador de DMA do sistema para usar seu buffer comum. Durante uma transferência, o driver pode chamar ReadDmaCounter para determinar quantos bytes ainda serão transferidos e, se necessário, chamar RtlMoveMemory para copiar mais dados de ou para um buffer de usuário.

  4. FlushAdapterBuffers quando o driver tiver concluído sua transferência de DMA de/para o dispositivo subordinado

  5. FreeAdapterChannel assim que todos os dados solicitados forem transferidos ou se o driver precisar falhar no IRP devido a um erro de E/S do dispositivo

O ponteiro de objeto do adaptador retornado por IoGetDmaAdapter é um parâmetro necessário para cada uma dessas rotinas de suporte, exceto RtlMoveMemory.

Drivers individuais chamam essa sequência de rotinas de suporte em pontos diferentes, dependendo de como cada driver é implementado para atender seu dispositivo. Por exemplo, a rotina StartIo de um driver pode fazer a chamada para AllocateAdapterChannel, outro driver pode fazer essa chamada de uma rotina que remove IRPs de uma fila interconectada criada pelo driver e ainda outro driver pode fazer essa chamada quando seu dispositivo DMA subordinado indicar que está pronto para transferir dados.