2014-06-20 64 views
1

我需要以運行Windows Embedded Compact 2013的平臺的用戶模式訪問物理內存。我找到了一篇文章。內存映射在內核模式驅動程序中完成,地址返回給用戶模式程序。Windows CE:在用戶模式下映射物理內存

在內核驅動

BOOL BTN_IOControl(DWORD context, DWORD code, UCHAR *pInBuffer, DWORD inSize, UCHAR *pOutBuffer,DWORD outSize, DWORD *pOutSize) 
{ 

     PDWORD tValue = (PDWORD)pOutBuffer; 
      switch(code) 
      { 

      case IOCTL_MAP_MEMORY: 
       *tValue = GetVirtualAddress(); 
       *pOutSize = 4; 
       break; 
      ..... 
} 

功能GetVirtualMemory是如下

LPOID GetVirtualAddress() 
{ 
    volatile DWORD sDevPhysAddr = 0xe000a000; 
    volatile DWORD dwSize = PAGE_SIZE; 

    LPVOID lpUserAddr; 
    volatile ULONG SourceSize; 
    volatile ULONG SourcePhys; 
    void* pvProcess = (void*)GetCallerVMProcessId(); 
    SourcePhys = sDevPhysAddr & ~(PAGE_SIZE - 1); 
    SourceSize = PAGE_SIZE; 
    RETAILMSG(1, (L"Address: %08x Size: %08x.\r\n", SourcePhys, SourceSize)); 

    lpUserAddr = (LPDWORD)VirtualAllocEx(pvProcess, 0, SourceSize, MEM_RESERVE, PAGE_NOACCESS); 
    if (lpUserAddr == NULL) { 
     RETAILMSG(1, (L"VirtualAllocEx failed. GetLastError %d.\r\n", GetLastError())); 
     return NULL; 
    } 

    if (!VirtualCopyEx(pvProcess, lpUserAddr, GetCurrentProcess(), (PVOID) 
    /*(*/SourcePhys/* >> 8)*/, SourceSize, 
    /*PAGE_PHYSICAL | */PAGE_READWRITE | PAGE_NOCACHE)) { 
    RETAILMSG(1, (L"VirtualCopyEx failed. Error %d.\r\n", GetLastError())); 
    return NULL; 
    } 
    RETAILMSG(1, (L"Before round up lpUserAddr=0x%x\r\n", lpUserAddr)); 
    lpUserAddr = (LPVOID)((ULONG)lpUserAddr + (sDevPhysAddr & (PAGE_SIZE - 1))); 
    shared_mem = lpUserAddr; 
    RETAILMSG(1, (L"After round up gUserAddr=0x%x\r\n", shared_mem)); 
    return lpUserAddr; 
} 

的代碼被映射物理存儲器0xe000a000(在ZYNQ芯片GPIO基地址)。 VirtualCopyEx中的代碼失敗,出現錯誤87(無效的參數)。但是代碼在0x81F00000處使用基本物理地址(該地址被原始程序員使用)。我的問題是如何啓用GPIO地址的映射。我也願意嘗試其他可能的方法。

回答

2

經過漫長的鬥爭,我找到了答案。

DWORD GetVirtualAddress() 
{ 
     HANDLE hCurrentProcess; 
     HANDLE hCallerProcess; 
     DWORD pAddr; 
     PHYSICAL_ADDRESS pa; 
     hCurrentProcess = (HANDLE)GetCurrentProcess(); 
     hCallerProcess = (HANDLE)GetDirectCallerProcessId(); 
     pa.QuadPart = 0xe000a000; 
     pGpioRegs = MmMapIoSpace(pa, sizeof(XILINX_GPIO_REGS), FALSE); 
     if (!pGpioRegs) 
      RETAILMSG(1, (L"Cannot map the gpio register.\r\n")); 
     pAddr = (DWORD)VirtualAllocCopyEx(hCurrentProcess, hCallerProcess, pGpioRegs, 
       PAGE_SIZE, PAGE_READWRITE | PAGE_NOCACHE); 
     if (!pAddr) 
     RETAILMSG(1, (L"VirtualAllocCopy: Error: %d.\r\n", GetLastError())); 
     return pAddr; 
} 

這將返回給調用者在DeviceIoControl上調用一個虛擬地址映射到設備基地址的物理地址。