Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
Um buffer de E/S que abrange uma gama de endereços de memória virtual contíguos pode ser espalhado por várias páginas físicas, e essas páginas podem ser descontíguas. O sistema operacional usa uma lista de descritores de memória (MDL) para descrever o layout de página física para um buffer de memória virtual.
Um MDL consiste em uma estrutura MDL que é seguida por uma matriz de dados que descreve a memória física na qual o buffer de E/S reside. O tamanho de um MDL varia de acordo com as características do buffer de E/S que o MDL descreve. Rotinas do sistema estão disponíveis para calcular o tamanho necessário de um MDL e para alocar e liberar o MDL.
Uma estrutura MDL é semi-opaca. Seu driver deve acessar diretamente apenas os membros Next e MdlFlags dessa estrutura. Para obter um exemplo de código que usa esses dois membros, consulte a seção Exemplo a seguir.
Os restantes membros de um MDL são opacos. Não aceda diretamente aos membros opacos de um MDL. Em vez disso, use as seguintes macros, que o sistema operacional fornece para executar operações básicas na estrutura:
MmGetMdlVirtualAddress retorna o endereço de memória virtual do buffer de E/S descrito pelo MDL.
MmGetMdlByteCount retorna o tamanho, em bytes, do buffer de E/S.
MmGetMdlByteOffset retorna o deslocamento dentro de uma página física do início do buffer de E/S.
Você pode alocar um MDL com a rotina IoAllocateMdl . Para liberar o MDL, use a rotina IoFreeMdl . Como alternativa, você pode alocar um bloco de memória não paginada e, em seguida, formatar esse bloco de memória como um MDL chamando a rotina MmInitializeMdl .
Nem IoAllocateMdl nem MmInitializeMdl inicializam a matriz de dados que segue imediatamente a estrutura MDL. Para um MDL que reside em um bloco de memória não paginada alocado pelo driver, use MmBuildMdlForNonPagedPool para inicializar essa matriz para descrever a memória física na qual o buffer de I/O reside.
Para memória paginável, a correspondência entre memória virtual e física é temporária, portanto, a matriz de dados que segue a estrutura MDL é válida apenas em determinadas circunstâncias. Chame MmProbeAndLockPages para bloquear a memória paginável no lugar e inicializar essa matriz de dados para o layout atual. A memória não será paginada até que o chamador use a rotina MmUnlockPages , momento em que o conteúdo da matriz de dados não é mais válido.
A rotina MmGetSystemAddressForMdlSafe mapeia as páginas físicas descritas pelo MDL especificado para um endereço virtual no espaço de endereçamento do sistema, se ainda não estiverem mapeadas para o espaço de endereçamento do sistema. Esse endereço virtual é útil para drivers que podem ter que olhar para as páginas para executar E/S, porque o endereço virtual original pode ser um endereço de usuário que pode ser usado apenas em seu contexto original e pode ser excluído a qualquer momento.
Observe que quando você cria uma MDL parcial usando a rotina IoBuildPartialMdl que MmGetMdlVirtualAddress retorna o endereço inicial original para a MDL parcial. Esse endereço é um endereço de modo de usuário se o MDL foi originalmente criado como resultado de uma solicitação de modo de usuário. Como tal, o endereço não tem relevância fora do contexto do processo de origem do pedido.
Normalmente, um driver em vez disso cria um endereço de modo de sistema chamando a macro MmGetSystemAddressForMdlSafe para mapear o MDL parcial. Isso garante que o driver possa continuar a acessar as páginas com segurança, independentemente do contexto do processo.
Quando um driver chama IoAllocateMdl, ele pode associar um IRP com o MDL recém-alocado especificando um ponteiro para o IRP como o parâmetro Irp de IoAllocateMdl. Um IRP pode ter uma ou mais MDLs associadas a ele. Se o IRP tiver um único MDL associado a ele, o membro MdlAddress do IRP apontará para esse MDL. Se o IRP tiver várias MDLs associadas a ele, MdlAddress apontará para o primeiro MDL em uma lista vinculada de MDLs associadas ao IRP, conhecida como uma cadeia MDL. Os MDLs são vinculados por seus membros Next . O próximo membro do último MDL na cadeia é definido como NULL.
Se, quando o driver chama IoAllocateMdl, ele especifica FALSE para o parâmetro SecondaryBuffer , o membro MdlAddress do IRP é definido para apontar para o novo MDL. Caso SecondaryBuffer seja TRUE, a rotina insere o novo MDL no final da cadeia MDL.
Quando o IRP é concluído, o sistema desbloqueia e libera todas as MDLs associadas ao IRP. O sistema desbloqueia as MDLs antes de enfileirar a rotina de conclusão de E/S e as libera depois que a rotina de conclusão de E/S é executada.
Os drivers podem percorrer a cadeia MDL usando o membro Next de cada MDL para acessar o próximo MDL na cadeia. Os drivers podem inserir manualmente MDLs na cadeia ao atualizar os membros Next.
As cadeias MDL são normalmente usadas para gerenciar uma matriz de buffers associados a uma única solicitação de E/S. (Por exemplo, um driver de rede pode usar um buffer para cada pacote IP em uma operação de rede.) Cada buffer na matriz tem seu próprio MDL na cadeia. Quando o driver conclui a solicitação, ele combina os buffers em um único buffer grande. Em seguida, o sistema limpa automaticamente todas as MDLs alocadas para a solicitação.
O gerenciador de E/S é uma fonte frequente de solicitações de E/S. Quando o gerente de E/S conclui uma solicitação de E/S, o gerente de E/S libera o IRP e libera todas as MDLs anexadas ao IRP. Algumas dessas MDLs podem ter sido anexadas ao IRP por drivers localizados abaixo do gestor de E/S na pilha de dispositivos. Da mesma forma, se o seu driver for a fonte de um pedido de E/S, ele deve limpar o IRP e quaisquer MDLs anexados ao IRP quando o pedido de E/S for concluído.
Exemplo
O exemplo de código a seguir é uma função implementada por driver que libera uma cadeia MDL de um IRP:
VOID MyFreeMdl(PMDL Mdl)
{
PMDL currentMdl, nextMdl;
for (currentMdl = Mdl; currentMdl != NULL; currentMdl = nextMdl)
{
nextMdl = currentMdl->Next;
if (currentMdl->MdlFlags & MDL_PAGES_LOCKED)
{
MmUnlockPages(currentMdl);
}
IoFreeMdl(currentMdl);
}
}
Se as páginas físicas descritas por um MDL na cadeia estiverem bloqueadas, a função de exemplo chamará a rotina MmUnlockPages para desbloquear as páginas antes de chamar IoFreeMdl para liberar o MDL. No entanto, a função de exemplo não precisa explicitamente desmapear as páginas antes de chamar IoFreeMdl. Em vez disso, o IoFreeMdl desmapeia automaticamente as páginas quando libera o MDL.