Usando E/S Direta com PIO
Um driver que usa E/S (E/S) programada em vez de DMA deve mapear duplamente buffers de espaço do usuário em um intervalo de endereços de espaço do sistema. A figura a seguir ilustra como o gerente de E/S configura uma solicitação IRP_MJ_READ para uma operação de transferência de PIO que usa E/S direta.
A figura mostra como um dispositivo que usa PIO manipula a mesma tarefa.
Alguns intervalos de endereços virtuais de espaço do usuário representam o buffer do thread atual e o conteúdo desse buffer pode realmente ser armazenado em algumas páginas fisicamente descontínuas. Se o comprimento do buffer não for zero, o gerenciador de E/S criará um MDL para descrever esse buffer.
O gerenciador de E/S atende à solicitação de leitura do thread atual, para a qual o thread passa por um intervalo de endereços virtuais de espaço do usuário que representam um buffer.
O gerenciador de E/S ou FSD verifica a acessibilidade do buffer fornecido pelo usuário. Se o gerente de E/S tiver criado um MDL, ele chamará MmProbeAndLockPages com um MDL, que especifica o intervalo de endereços virtuais para o buffer de usuário. MmProbeAndLockPages também preenche o intervalo de endereços físicos correspondente no MDL.
O gerenciador de E/S fornece um ponteiro para o MDL (MdlAddress) em um IRP que solicita uma operação de transferência. Até que o gerenciador de E/S ou o sistema de arquivos chame MmUnlockPages depois que o driver concluir o IRP, as páginas físicas descritas no MDL permanecerão bloqueadas e atribuídas ao buffer. No entanto, os endereços virtuais em tal MDL podem se tornar invisíveis (e inválidos), mesmo antes de o IRP ser enviado para o driver do dispositivo ou para qualquer driver intermediário que possa estar em camadas acima do driver do dispositivo.
Se o driver exigir endereços do sistema (virtual), o driver chamará MmGetSystemAddressForMdlSafe com o ponteiro MdlAddress do IRP para mapear duplamente os endereços virtuais de espaço do usuário no MDL para um intervalo de endereços de espaço do sistema. Na figura acima, AliasBuff representa o MDL que descreve os endereços duplamente mapeados.
O driver usa o intervalo de endereços virtuais de espaço do sistema do AliasBuff (MDL duplamente mapeado) para ler dados na memória.
Quando o driver conclui o IRP chamando IoCompleteRequest, o gerenciador de E/S ou sistema de arquivos libera o intervalo de espaço do sistema duplamente mapeado do MDL se o driver chamado MmGetSystemAddressForMdlSafe. O gerenciador de E/S ou o sistema de arquivos desbloqueia as páginas descritas no MDL e descarta o MDL e o IRP em nome do driver. Para melhorar o desempenho, os drivers devem evitar o mapeamento dupla de endereços físicos MDL para o espaço do sistema, conforme descrito na etapa 3, a menos que eles precisem usar endereços virtuais. Isso usa entradas de tabela de página do sistema desnecessariamente e pode diminuir o desempenho e a escalabilidade do driver. Além disso, o sistema poderá falhar se ficar sem entradas de tabela de página, pois a maioria dos drivers mais antigos não consegue lidar com essa situação.
Os buffers do thread de usuário atual e o thread em si têm a garantia de serem residentes na memória física somente enquanto esse thread estiver atual. Para o thread mostrado na figura anterior, o conteúdo do buffer de usuário pode ser paginado para o armazenamento secundário enquanto os threads de outro processo são executados. Quando o thread de outro processo é executado, a memória física do sistema para o buffer do thread solicitante pode ser substituída, a menos que o gerenciador de memória tenha bloqueado e preservado as páginas físicas correspondentes que contêm o buffer do thread original.
No entanto, os endereços virtuais do thread original para seu buffer não permanecem visíveis enquanto outro thread é atual, mesmo que o gerenciador de memória preserve as páginas físicas do buffer. Consequentemente, os drivers não podem usar um endereço virtual retornado por MmGetMdlVirtualAddress para acessar a memória. Os chamadores dessa rotina devem passar seus resultados para MapTransfer (juntamente com o ponteiro MdlAddress do IRP) para transferir dados usando o sistema baseado em pacotes ou o DMA do bus-master.