技术的乐趣在于分享,欢迎多多交流,多多沟通。
全部博文(877)
分类: Windows平台
2015-04-23 16:06:26
我们知道,在内核模式,使用内存要非常小心,搞不好,会让系统崩溃。直接蓝屏重启!如果是驱动的问题,那就麻烦了。如果在接触硬件之前,出问题,那只有重新装系统了。如果不是必须的驱动,我们可以进入安全模式。或者在另外的系统里,删除这个驱动文件。
在WDM时期,我们分配内存,一般用如下,这些函数:ExAllocateXXXXXX,这些函数,而在WDF中,我们变成了WdfMemoryXXXXXX这样的函数。我们主要来看下,WDF这些函数的使用。
我们先来看WdfMemoryCreate:
NTSTATUS WdfMemoryCreate(
IN OPTIONAL PWDF_OBJECT_ATTRIBUTES Attributes,
IN POOL_TYPE PoolType,
IN OPTIONAL ULONG PoolTag,
IN size_t BufferSize,
OUT WDFMEMORY* Memory,
OUT OPTIONAL PVOID* Buffer
);
我们使用它来创建一个内存对象,PWDF_OBJECT_ATTRIBUTES 这个是对象都有的,PoolType的定义如下:
typedef enum _POOL_TYPE {
NonPagedPool,
PagedPool,
NonPagedPoolMustSucceed,
DontUseThisType,
NonPagedPoolCacheAligned,
PagedPoolCacheAligned,
NonPagedPoolCacheAlignedMustS
} POOL_TYPE;
具体的意思不用解释,看字面也可以猜出来。PoolTag,这个是记号,便于对于你分配的内存,做个记号,我们可以使用DriverPoolTag设置一个默认的,也可以设置为0.
例子代码:
NTSTATUS status;
WDF_OBJECT_ATTRIBUTES attributes;
DFMEMORY writeBufferMemHandle;
PVOID writeBufferPointer;
WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
attributes.ParentObject = requestHandle;
status = WdfMemoryCreate(
&attributes,
NonPagedPool,
0,
WRITE_BUFFER_SIZE,
&writeBufferMemHandle,
&writeBufferPointer
);
我们对于输入和输出空间的处理,也需要借助WdfMemoryXXXXXXX的处理。
我们重点看一下
NTSTATUS WdfMemoryCopyFromBuffer(
IN WDFMEMORY DestinationMemory,
IN size_t DestinationOffset,
IN PVOID Buffer,
IN size_t NumBytesToCopyFrom
) ;
例子代码:
WDFMEMORY memoryBuffer;
NTSTATUS status;
status = WdfRequestRetrieveOutputMemory(
Request,
&memoryBuffer
);
if (!NT_SUCCESS(status)) {
goto Error;
}
status = WdfMemoryCopyFromBuffer(
memoryBuffer,
0,
deviceContext->Buffer,
Length
);
if (!NT_SUCCESS(status)) {
goto Error;
}
再看,
NTSTATUS
WdfMemoryCopyToBuffer(
IN WDFMEMORY SourceMemory,
IN size_t SourceOffset,
IN PVOID Buffer,
IN size_t NumBytesToCopyTo
);
例子代码:
PVOID pOutputBuffer = NULL;
NTSTATUS status = STATUS_SUCCESS;
pOutputBuffer = ExAllocatePoolWithTag(
NonPagedPool,
MY_BUFFER_LENGTH,
MY_POOL_TAG
);
if (pOutputBuffer != NULL){
status = WdfMemoryCopyToBuffer(
outputMemoryHandle,
0,
pOutputBuffer,
MY_BUFFER_LENGTH
);
}
else{
status = STATUS_INSUFFICIENT_RESOURCES;
}
这个里面比较复杂的是
NTSTATUS
WdfMemoryCreateFromLookaside(
IN WDFLOOKASIDE Lookaside,
OUT WDFMEMORY* Memory
);
这个是为了多此申请内存准备的,我们看到有个输入参数WDFLOOKASIDE,所以先要创建它。
例子代码:
PDRIVER_CONTEXT driverContext;
WDFMEMORY memHandle;
driverContext = GetDriverContext(driver);
status = WdfLookasideListCreate(
WDF_NO_OBJECT_ATTRIBUTES,
sizeof(MY_LOOKASIDE_BUFFER),
NonPagedPool,
WDF_NO_OBJECT_ATTRIBUTES,
MY_POOL_TAG,
&driverContext->LookasideListHandle
);
…
status = WdfMemoryCreateFromLookaside(
driverContext->LookasideListHandle,
&memHandle
);
后面还有一点需要强调的是,我们发送异步请求是,用的WDFMEMORY对象,而同步则是PWDF_MEMORY_DESCRIPTOR ,我们来看这个结构体:
typedef struct _WDF_MEMORY_DESCRIPTOR {
WDF_MEMORY_DESCRIPTOR_TYPE Type;
union {
struct {
PVOID Buffer;
ULONG Length;
} BufferType;
struct {
PMDL Mdl;
ULONG BufferLength;
} MdlType;
struct {
WDFMEMORY Memory;
PWDFMEMORY_OFFSET Offsets;
} HandleType;
} u;
} WDF_MEMORY_DESCRIPTOR, *PWDF_MEMORY_DESCRIPTOR;
我们来看两段代码WdfIoTargetFormatRequestForRead,WdfIoTargetSendReadSynchronously。
先看异步的:
WDFREQUEST request;
NTSTATUS status;
WDFMEMORY memory;
WDF_OBJECT_ATTRIBUTES attributes;
WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
status = WdfMemoryCreate(
&attributes,
NonPagedPool,
DRIVER_TAG,
READ_BUF_SIZE,
&memory,
NULL
);
if (!NT_SUCCESS(status)) {
return status;
}
status = WdfIoTargetFormatRequestForRead(
IoTarget,
request,
memory,
NULL,
NULL
);
if (!NT_SUCCESS(status)) {
return status;
}
WdfRequestSetCompletionRoutine(
request,
MyReadRequestCompletionRoutine,
targetInfo
);
if (WdfRequestSend(
request,
IoTarget,
WDF_NO_SEND_OPTIONS
) == FALSE) {
status = WdfRequestGetStatus(request);
}
再看同步的:
WDF_MEMORY_DESCRIPTOR MemoryDescriptor;
WDFMEMORY MemoryHandle = NULL;
ULONG_PTR bytesRead = NULL;
status = WdfMemoryCreate(
NULL,
NonPagedPool,
POOL_TAG,
MY_BUFFER_SIZE,
&MemoryHandle,
NULL
);
WDF_MEMORY_DESCRIPTOR_INIT_HANDLE(
&MemoryDescriptor,
MemoryHandle,
NULL
);
status = WdfIoTargetSendReadSynchronously(
ioTarget,
NULL,
&MemoryDescriptor,
NULL,
NULL,
&bytesRead
);
我们可以给创建的内存对象,指定缓冲区,用到WdfMemoryAssignBuffer。但是这个内存对象,必须由WdfMemoryCreatePreallocated创建。
PVOID pBuffer = NULL;
WDF_OBJECT_ATTRIBUTES attributes;
WDFMEMORY memHandle;
pBuffer = ExAllocatePoolWithTag(
NonPagedPool,
MY_BUFFER_SIZE,
MY_DRIVER_TAG
);
if (pBuffer == NULL){
goto Error;
}
WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
attributes.ParentObject = requestHandle;
status = WdfMemoryCreatePreallocated(
attributes,
pBuffer,
MY_BUFFER_SIZE,
&memHandle
);
当然我们可以从内存对象中,得到其空间,用到WdfMemoryGetBuffer。
我们再整体来看一下,请求对象,内存对象,和缓冲区的关系,用下图来表示。