您的位置:首页 > 其它

关于MDL的一些事(2)

2009-11-16 16:45 603 查看
对驱动程序采用
Direct I/O
方式进行数据读的测试



采用这种方式进行读数据时,
I/O Manager

调用
MmProbeAndLockPages


ReadFile

参数提供的用户空间缓冲区对应的物理页面锁定为不可换出,然后将得到的MDL放在Irp->MdlAddress里,将IRP传递给相应驱动程序的DispatchRead。根据Walter
Oney在书中的描述,此时I/O
Manager的行为可以用下面的代码来描述:

KPROCESSOR_MODE mode;   // <== either KernelMode or UserMode
PMDL mdl = IoAllocateMdl(uva, length, FALSE, TRUE, Irp);
MmProbeAndLockPages(mdl, mode,
reading ? IoWriteAccess : IoReadAccess);
<code to send and await IRP>
MmUnlockPages(mdl);
IoFreeMdl(mdl);


这里主要关注的地方是MmProbeAndLockPages有没有进行实际的虚拟地址的映射,即将物理页面映射到内核地址空间中。我们用下面的驱动代码来测试这一行为。

NTSTATUS DispatchRead(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp)
{
PVOID pSysAddr;
PMDL pMDL = pIrp->MdlAddress;
DbgPrint("******************DispatchRead******************/n");
DbgPrint("Before MmGetSystemAddressForMdlSafe/n");
OutputMDL(pMDL);
pSysAddr = MmGetSystemAddressForMdlSafe(pMDL,LowPagePriority);
if(!pSysAddr) {
DbgPrint("MmGetSystemAddressForMdlSafe failed./n");
return STATUS_SUCCESS;
}

DbgPrint("After MmGetSystemAddressForMdlSafe/n");
OutputMDL(pMDL);
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = MmGetMdlByteCount(pMDL);
IoCompleteRequest(pIrp,IO_NO_INCREMENT);

return STATUS_SUCCESS;
}


再写一个应用程序来发起一个读操作:

void TestMDLDriver()
{
HANDLE hDevice;
BOOL bRet;
DWORD dwRead;
BYTE buf[10000] = {'S','Q','U','I'};
hDevice = CreateFile(_T("////.//MDLTest"),GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if(hDevice==INVALID_HANDLE_VALUE)
{
fprintf(stderr,"CreateFile error : %d/n",GetLastError());
return;
}
//issue a read request
bRet = ReadFile(hDevice,buf,sizeof(buf),&dwRead,NULL);
if(!bRet)
{
fprintf(stderr,"ReadFile error : %d/n",GetLastError());
return;
}
printf("Read bytes:%d/n",dwRead);
//
CloseHandle(hDevice);
}


导致的内核输出如下:

00000009	4.27463436	******************DispatchRead******************
00000010	4.27464771	Before MmGetSystemAddressForMdlSafe
00000011	4.27465439	MDL_TEST: Size=40
00000012	4.27466011	MDL_TEST: MdlFlags=0x008a
00000013	4.27466583	MDL_TEST: Process=0x86ca7b58
00000014	4.27467155	MDL_TEST: MappedSystemVa=0x92b1f000
00000015	4.27467775	MDL_TEST: StartVa=0x001ad000
00000016	4.27468348	MDL_TEST: ByteCount=10000
00000017	4.27468824	MDL_TEST: ByteOffset=1148
00000018	4.27469397	MDL_TEST: p[0]=0x00064429
00000019	4.27469969	MDL_TEST: p[1]=0x000619fc
00000020	4.27470541	MDL_TEST: p[2]=0x000618ee
00000021	4.27471066	MDL_TEST: p[3]=0x00060749
00000022	4.27471685	MDL_TEST: p[4]=0x86abca24
00000023	4.27472448	After MmGetSystemAddressForMdlSafe
00000024	4.27472973	MDL_TEST: Size=40
00000025	4.27473545	MDL_TEST: MdlFlags=0x008b
00000026	4.27474070	MDL_TEST: Process=0x86ca7b58
00000027	4.27474689	MDL_TEST: MappedSystemVa=0xb01e747c
00000028	4.27475214	MDL_TEST: StartVa=0x001ad000
00000029	4.27475786	MDL_TEST: ByteCount=10000
00000030	4.27476311	MDL_TEST: ByteOffset=1148
00000031	4.27476835	MDL_TEST: p[0]=0x00064429
00000032	4.27477455	MDL_TEST: p[1]=0x000619fc
00000033	4.27477980	MDL_TEST: p[2]=0x000618ee
00000034	4.27478504	MDL_TEST: p[3]=0x00060749
00000035	4.27479029	MDL_TEST: p[4]=0x86abca24


此时从VS的调试器中看到,应用程序中buf[10000]的地址为0x001ad47c

从输出可以得到如下结论:

1.MmProbeAndLockPages并不将物理页面映射到内核地址空间,而仅锁定物理页面;MappedSystemVa的变化可以显示这一点

2.buf的地址=StartVa+ByteOffset;

3.MmGetSystemAddressForMdlSafe进行实际的映射操作,并设置MdlFlags的MDL_MAPPED_TO_SYSTEM_VA标志。

4.MmProbeAndLockPages将MdlFlags=MDL_WRITE_OPERATION |
MDL_ALLOCATED_FIXED_SIZE | MDL_PAGES_LOCKED
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: