WDF驱动中的内存管理

来源:互联网 发布:淘宝中怎么发布宝贝 编辑:程序博客网 时间:2024/04/30 20:02

               今年的经济形势不太好,目前很多公司都受其影响了!看来,需要冬眠了,正好抓住这个时间,好好总结总结,冲冲电,梳理梳理!

              我们知道,在内核模式,使用内存要非常小心,搞不好,会让系统崩溃。直接蓝屏重启!如果是驱动的问题,那就麻烦了。如果在接触硬件之前,出问题,那只有重新装系统了。如果不是必须的驱动,我们可以进入安全模式。或者在另外的系统里,删除这个驱动文件。

             在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。

                 我们再整体来看一下,请求对象,内存对象,和缓冲区的关系,用下图来表示。

                

                    


 

           

原创粉丝点击