PVOID
CreateAndMapMemory()
{
PVOID buffer;
PMDL mdl;
PVOID userVAToReturn;
//
// Allocate a 4K buffer to share with the application
//
buffer = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, 'MpaM ');
if(!buffer) {
return(NULL);
}
//
// Allocate and initalize an MDL that describes the buffer
//
mdl = IoAllocateMdl(buffer,
PAGE_SIZE,
FALSE,
FALSE,
NULL);
if(!mdl) {
ExFreePool(buffer);
return(NULL);
}
//
// Finish building the MDL -- Fill in the "page portion "
//
MmBuildMdlForNonPagedPool(mdl);
//
// The preferred V5 way to map the buffer into user space
//
userVAToReturn =
MmMapLockedPagesSpecifyCache(mdl, // MDL
UserMode, // Mode
MmCached, // Caching
NULL, // Address
FALSE, // Bugcheck?
NormalPagePriority); // Priority
//
// If we get NULL back, the request didn 't work.
// I 'm thinkin ' that 's better than a bug check anyday.
//
if(!userVAToReturn) {
IoFreeMdl(mdl);
ExFreePool(buffer);
return(NULL);
}
//
// Store away both the mapped VA and the MDL address, so that
// later we can call MmUnmapLockedPages(StoredPointer, StoredMdl)
//
StoredPointer = userVAToReturn;
StoredMdl = mdl;
DbgPrint( "UserVA = 0x%0x\n ", userVAToReturn);
return(userVAToReturn);
}
程序工作原理:
驱动程序可以使用任意标准的方法来分配要共享的缓冲,如果没有特殊的要求并且大小适度,可以将它分配在非分页池中。
驱动程序使用IoAllocateMdl()分配一个MDL来描述这个缓冲,然后调用MmBuildMdlForNonPagedPool()。这个函数修改MDL以描述内核模式中一个非分页内存区域。
当用来描述共享缓冲的MDL建立起来以后,驱动程序现在可以准备将缓冲映射到用户进程的地址空间了,由MmMapLockedPagesSpecifyCache() 这个函数完成。
你必须要在你想要映射共享缓冲的进程上下文环境中调用MmMapLockedPagesSpecifyCache(),并且指定AccessMode参数为UserMode。这个函数返回由MDL映射的用户态虚拟地址。 驱动程序可以把这个值作为用户程序发送IOCTL请求时的返回值返回给用户程序。
注意:IoAllocateMd只分配MDL,并不负责更新MDL里面内容中的page numbers,需要使用MmBuildMdlForNonPagedPool来全完初始化。
ref: A Common Topic Explained - Sharing Memory Between Drivers and Applications