WinCE6.0中應用程序如何直接訪問物理空間

 在實際開發過程中,經常希望能在應用程序中直接讀寫設備的物理空間。以前在做WinCE6.0下的MEMMgr時通過祕密加載一個內核態驅動實現了這個需求。但這種方式有一個明顯的缺陷,每次讀寫都必須經由它才能完成。如果只是讀取GPIO,那問題不算大。如果想通過這種方式實現視頻播放的加速就比較困難了。估計非但不能加速,反而會變得更慢。

      早先曾與ZL仔細的討論過這個問題,他當時在WinCE6.0上移植TCPMP,發現播放視頻不太流暢,於是想通過直接寫顯存進行加速。目的很明確,在應用中申請一段虛擬空間,通過某種方法將其映射到顯存上,視頻解碼過程中直接往映射過的虛擬空間上寫。這種方法與使用GAPI有一點類似。

      實現這個需求,需要用到函數VirtualCopyEx()。看看幫助中關於它的說明,This function dynamically maps a virtual address to a physical address by creating a new page-table entry.This function is callable in kernel mode and in user mode, when the source and destination process handles are the active process.This function is similar to VirtualCopy, except VirtualCopyEx requires handles to the source and destination process.

      據此基本可以確定,我們的確可以在應用中申請一段虛擬空間,然後通過這個函數將其映射到某段物理空間上。其中目標進程是我們的應用,而源進程是NK.exe。爲了實現在NK.exe中執行VirtualCopyEx(),可以加載一個內核態的驅動。更爲方便的方法是移植一個OALIOCTL,並在IOControl()中添加一個case。這樣,應用程序在做內存映射時就無需打開某個流驅動,直接調用KernelIoControl()即可。

      OALIOCTL中添加的關鍵代碼如下。 

 1 typedef struct {
 2     void*    pvDestMem;
 3     DWORD    dwPhysAddr;
 4     DWORD    dwSize;
 5 } VIRTUAL_COPY_EX_DATA;
 6 
 7 #define IOCTL_VIRTUAL_COPY_EX CTL_CODE (FILE_DEVICE_UNKNOWN,3333,METHOD_BUFFERED,FILE_ANY_ACCESS)
 8 
 9 
10 case IOCTL_VIRTUAL_COPY_EX:
11 {
12     VIRTUAL_COPY_EX_DATA *= (VIRTUAL_COPY_EX_DATA*)pInBuf;
13     HANDLE hDst = (HANDLE)GetDirectCallerProcessId();
14     HANDLE hSrc = (HANDLE)GetCurrentProcessId();
15     fRet = VirtualCopyEx(hDst,p->pvDestMem,hSrc,(LPVOID)p->dwPhysAddr,p->dwSize,
16      PAGE_READWRITE|PAGE_PHYSICAL|PAGE_NOCACHE);
17 }break;

       應用程序中進行內存映射的關鍵代碼如下。

 1 volatile LPVOID GetVirtual(DWORD dwPhyBaseAddress, DWORD dwSize)
 2 {
 3     volatile LPVOID pVirtual;
 4     VIRTUAL_COPY_EX_DATA vced;
 5     
 6     if(dwPhyBaseAddress&0xFFF)
 7     {
 8         return NULL;
 9     }
10     vced.dwPhysAddr = dwPhyBaseAddress>>8;
11     pVirtual = VirtualAlloc(0,dwSize,MEM_RESERVE,PAGE_NOACCESS);
12     vced.pvDestMem = pVirtual;
13     vced.dwSize = dwSize;
14     KernelIoControl(IOCTL_VIRTUAL_COPY_EX,&vced, sizeof(vced), NULL, NULL, NULL);
15     return pVirtual;
16 }
17 
18 // WinCE6.0模擬器中應用程序直接寫屏
19 PBYTE pLCDBuf = (PBYTE)GetVirtual(0x33f00000,0x100000);
20 memset(pLCDBuf,0,0x100000);
21 

       這種方法在WinCE6.0的模擬器中測試了一下,能達到預期的效果。

http://www.cnblogs.com/we-hjb/archive/2010/02/25/1673815.html

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