直接方式读写设备,操作系统会将用户模式下的缓冲区锁住。然后操作系统将这段缓冲区在内核模式地址再次映射一遍
这样 ,用户模式的缓冲区和内核模式的缓冲区指向的是同一区域的物理内存。
在创建完设备对象后,在设置设备对象的时候,设置为 DO_DIRECT_IO 而不是DO_BUFFERED
//创建设备 status = IoCreateDevice( pDriverObject, sizeof(DEVICE_EXTENSION), &(UNICODE_STRING)devName, FILE_DEVICE_UNKNOWN, 0, TRUE, &pDevObj ); if (!NT_SUCCESS(status)) return status; pDevObj->Flags |= DO_DIRECT_IO;
驱动程序读取设备:
NTSTATUS HelloDDKRead(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp) { KdPrint(("Enter HelloDDKRead ")); PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension; NTSTATUS status = STATUS_SUCCESS; PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp); ULONG ulReadLength = stack->Parameters.Read.Length; KdPrint(("ulReadLength:%d ",ulReadLength)); //通过这个三个宏来获取 MDL数据结构信息 ULONG mdl_length = MmGetMdlByteCount(pIrp->MdlAddress); PVOID mdl_address = MmGetMdlVirtualAddress(pIrp->MdlAddress); ULONG mdl_offset = MmGetMdlByteOffset(pIrp->MdlAddress); KdPrint(("mdl_address:0X%08X ",mdl_address)); KdPrint(("mdl_length:%d ",mdl_length)); KdPrint(("mdl_offset:%d ",mdl_offset)); if (mdl_length!=ulReadLength) { //MDL的长度应该和读长度相等,否则该操作应该设为不成功 pIrp->IoStatus.Information = 0; status = STATUS_UNSUCCESSFUL; }else { //用MmGetSystemAddressForMdlSafe得到MDL在内核模式下的映射 PVOID kernel_address = MmGetSystemAddressForMdlSafe(pIrp->MdlAddress,NormalPagePriority); KdPrint(("kernel_address:0X%08X ",kernel_address)); memset(kernel_address,0XAA,ulReadLength); pIrp->IoStatus.Information = ulReadLength; // bytes xfered } pIrp->IoStatus.Status = status; IoCompleteRequest( pIrp, IO_NO_INCREMENT ); KdPrint(("Leave HelloDDKRead ")); return status; }