应用层与驱动层同步事件处理方法

时间:2021-08-22 20:32:23

应用层与驱动层同步事件处理方法

              关于这个问题高手略过吧。

              Ring3与Ring0同步是很有用的手段,在此做一个简要的整理,希望对开发这方面程序的朋友有帮助,好了,开始吧。

             1 同步的策略

             初写驱动的朋友都知道,通过DeviceIoControl这个API函数, 可以将Ring3的数据及控制请求发送给Ring0.但这是单向的,由Ring3主动发起,Ring0被动接受。可以说这是单向轮询的。

                                              询问(CTL_CODE)

            Ring3     ---------------------------------------------------------------- >     Ring0  

                                              回答(通过OUT参数)

            Ring3     <----------------------------------------------------------------       Ring0  

            这种方式用于主动获取Ring0数据,又不要求效率,和具有实时性的开发情况。

            但做监控类软件却与此相反,是Ring0先监控到事件,具有主动权,发起询问通知Ring3。

                                           监控到事件(通知)

             Ring0(监控)----------------------------------------------------------------> Ring3  

             在实时性要求不高的情况下可以采用Ring3定时询问Ring0,当然Ring0保存了事件的状态。

            这里介绍的就是高实时性,大数据传输的同步解决办法。

            原理:通过Ring3创建事件,并将该事件传递给Ring0,同时Ring3创建监控线程,等待Ring0发起事件,此为应用层驱动层共享事件。同时Ring0在内核分配非分页内存,通过DeviceIoControl 传递给Ring3,此为应用层驱动层共享内存。因在DeviceIoControl 中传送Buffer,涉及到内核数据拷贝,大数据量下使用效率很低,故用共享内存的方法。

             2     具体实现

Ring3 CODE     :

HANDLE m_hEvent = CreateEvent(NULL,FALSE,FALSE,NULL);     // 创建事件

// 发事件给ring 0

if (0 == DeviceIoControl(hFile, \    
     SET_EVENT, \                                      
     &m_hEvent, \
     sizeof(HANDLE), \
     NULL, \
     0,\
     &uRetBytes,
     NULL)) 
{
     CloseHandle(hFile);
     CloseHandle(m_hEvent); 
     return ;
}

// 获得ring 0 的共享内存

unsigned int add = 0;
if (0 == DeviceIoControl(hFile, \                 
GET_SHARE_ADD, \
NULL, \
0, \
&add, \
sizeof (unsigned int),\
&uRetBytes,
NULL)) 
{
     CloseHandle(hFile);
     CloseHandle(m_hEvent); 
     return ;

m_pShareMem =(PVOID)add;                            //映射的共享内存

当Ring0有事件产生时,Ring3的线程就可处理m_pShareMen了。

UINT      WorkThread(PVOID param)

{              ...............

                while(!bExit)

                 {

                             WaitForSingleObject(g_hEvent,INFINITE);   

                             ......................

                             // 可以处理分析m_pShareMen 了

                 }

}

Ring0 CODE :

PVOID g_pSysAdd         = NULL; 
PMDL     g_pMdl                 = NULL;      // 与ring 3 的共享内存描述

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pRegistryString)
     {
                                    ......
             g_pSysAdd = ExAllocatePool(NonPagedPool, SHARE_MLEN + IPHEDLEN);
             g_pMdl = IoAllocateMdl(g_pSysAdd, SHARE_MLEN + IPHEDLEN, FALSE, FALSE, NULL);
             MmBuildMdlForNonPagedPool(g_pMdl);                    
                                     ......

     }

// I/O控制派遣例程
NTSTATUS DispatchIoctl(PDEVICE_OBJECT pDevObj, PIRP pIrp)

{

PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(pIrp);

// 取得I/O控制代码
ULONG uIoControlCode = pIrpStack->Parameters.DeviceIoControl.IoControlCode;

       switch(uIoControlCode)
       {
         case SET_EVENT:     // 处理Ring3的事件


             if(g_pInBuffer == NULL||g_nInBuffSize < sizeof(HANDLE))
             {
                       status = STATUS_INVALID_BUFFER_SIZE;
                       break;
             }
            hEvent = *(HANDLE *)g_pInBuffer;


            status = ObReferenceObjectByHandle(hEvent,
             SYNCHRONIZE,
             *ExEventObjectType,
             KernelMode,
             (PVOID *)&g_pEvent,
             &objHandleInfo
             );


           if(!NT_SUCCESS(status))
           {
                    g_pEvent = NULL;
           }
           DbgPrint("g_pEvent: %x\n",g_pEvent);       // 得到了ring 3 事件句柄
           break;

        
         case GET_SHARE_ADD:                           //     传给ring 3 内存地址

     
             UserAddr = MmMapLockedPages(g_pMdl, UserMode);
             *((PVOID *)(pIrp->AssociatedIrp.SystemBuffer)) = UserAddr;
             status = STATUS_SUCCESS;   
              break;  

     }

..............

}

RtlCopyMemory(g_pSysAdd,pSource,dwLen)               //     将写数据到共享内存,

KeSetEvent((PKEVENT)g_pEvent,0,false);                 //      此刻Ring3就可以接受数据了。

最后一步记得释放内存。

void DriverUnload(PDRIVER_OBJECT pDriverObj)

// 清除共享内存

IoFreeMdl(g_pMdl);
ExFreePool(g_pSysAdd);

// 删除设备对象
IoDeleteDevice(pDriverObj->DeviceObject);
}

以上就是整个处理过程。