應用層與驅動層同步事件處理方法

應用層與驅動層同步事件處理方法

              關於這個問題高手略過吧。

              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);
}

以上就是整個處理過程。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章