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中代码如下。

 

//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
/* File:    oaliocontrol.cpp
 *
 * Purpose: OAL updatabale module which will be called from kernel for user
 * mode threads. OEMs can update the list of ioctls supported by user mode
 * threads by updating the IOControl function in this module.
 *
 * OEMs can do the following updates:
*
 * a) Change this dll name: In which case make sure to update oalioctl.h
 * file in public\common\oak\inc to update OALIOCTL_DLL symbol to relfect the 
 * new name for this dll.
*
 * b) Change the entry point name from IOControl to something else: In this case
 * make sure to update OALIOCTL_DLL_IOCONTROL symbol in public\common\
 * oak\inc\oalioctl.h file to reflect the new name of the entry point
*
 * c) Add/Delete from the list of ioctls in IOControl function below: This entry point
 * is called whenever a user mode thread calls into kernel via KernelIoControl or
 * via KernelLibIoControl (with KMOD_OAL). For kernel mode threads, all the 
 * handling for KernelIoControl and KernelLibIoControl happens inside kernel and
 * this module is not involved.
 *
 */

#include <windows.h>
#include <oalioctl.h>
#include "bsp.h"

typedef struct {
	void*	pvDestMem;
	DWORD	dwPhysAddr;
	DWORD	dwSize;
} VIRTUAL_COPY_EX_DATA;

#define IOCTL_VIRTUAL_COPY_EX CTL_CODE (FILE_DEVICE_UNKNOWN, 3333, METHOD_BUFFERED, FILE_ANY_ACCESS)

PFN_Ioctl g_pfnExtOALIoctl;

//------------------------------------------------------------------------------
// Function: IOControl
//
// Arguments: Same signature as KernelIoControl
//    DWORD dwIoControlCode: io control code
//    PBYTE pInBuf: pointer to input buffer
//    DWORD nInBufSize: length of input buffer in bytes
//    PBYTE pOutBuf: pointer to out buffer
//    DWORD nOutBufSize: length of output buffer in bytes
//    PDWORD pBytesReturned: number of bytes returned in output buffer
//
// Return Values:
// If the function call is successful, TRUE is returned from this API call.
// If the function call is not successful, FALSE is returned from this API
// call and the last error is set to:
// a) ERROR_INVALID_PARAMETER: any of the input arguments are invalid
// b) ERROR_NOT_SUPPORTED: given ioctl is not supported
// c) any other ioctl set by OAL code
//
// Abstract:
// This is called by kernel whenever a user mode thread makes a call to
// KernelIoControl or KernelLibIoControl with io control code being an OAL
// io control code. OEMs can override what ioctls a user mode thread can call
// by enabling or disabling ioctl codes in this function.
//
//------------------------------------------------------------------------------

DWORD buf=0;

EXTERN_C
BOOL
IOControl(
    DWORD dwIoControlCode,
    PBYTE pInBuf,
    DWORD nInBufSize,
    PBYTE pOutBuf,
    DWORD nOutBufSize,
    PDWORD pBytesReturned
    )
{
    BOOL fRet = FALSE;

    //
    // By default the following ioctls are supported for user mode threads.
    // If a new ioctl is being added to this list, make sure the corresponding
    // data associated with that ioctl is marshalled properly to the OAL
    // ioctl implementation. In normal cases, one doesn't need any 
    // marshaling as first level user specified buffers are already validated 
    // by kernel that:
    // -- the buffers are within the user process space
    // Check out IsValidUsrPtr() function in vmlayout.h for details on kernel
    // validation of user specified buffers. Kernel doesn't validate that the
    // buffers are accessible; it only checks that the buffer start and end
    // addresses are within the user process space.
    //


    switch (dwIoControlCode) {     
        case IOCTL_HAL_GET_CACHE_INFO:
        case IOCTL_HAL_GET_DEVICE_INFO:
        case IOCTL_HAL_GET_DEVICEID:
        case IOCTL_HAL_GET_UUID:
        case IOCTL_PROCESSOR_INFORMATION:
            // request is to service the ioctl - forward the call to OAL code
            // OAL code will set the last error if there is a failure
            fRet = (*g_pfnExtOALIoctl)(dwIoControlCode, pInBuf, nInBufSize, pOutBuf, nOutBufSize, pBytesReturned);
        break;
		case IOCTL_VIRTUAL_COPY_EX:
			{
				VIRTUAL_COPY_EX_DATA *p = (VIRTUAL_COPY_EX_DATA*)pInBuf;
 				HANDLE hDst = (HANDLE)GetDirectCallerProcessId();
 				HANDLE hSrc = (HANDLE)GetCurrentProcessId();
				fRet = VirtualCopyEx(hDst,p->pvDestMem,hSrc,(LPVOID)p->dwPhysAddr,p->dwSize,
					PAGE_READWRITE|PAGE_PHYSICAL|PAGE_NOCACHE);
			}
			break;
        default:
            SetLastError(ERROR_NOT_SUPPORTED);
        	break;
    }

    return fRet;
}

BOOL
WINAPI
DllMain(HANDLE hDll, DWORD dwReason, LPVOID lpReserved)
{
    switch (dwReason)
    {
        case DLL_PROCESS_ATTACH:
            DisableThreadLibraryCalls((HINSTANCE)hDll);
            g_pfnExtOALIoctl = (PFN_Ioctl) lpReserved;
        break;
        case DLL_PROCESS_DETACH:
        default:
        break;
    }

    return TRUE;
}

应用程序中进行内存映射的关键代码如下。

volatile LPVOID GetVirtual(DWORD dwPhyBaseAddress, DWORD dwSize)
  {
      volatile LPVOID pVirtual;
      VIRTUAL_COPY_EX_DATA vced;
      
      if(dwPhyBaseAddress&0xFFF)
      {
          return NULL;
      }
     vced.dwPhysAddr = dwPhyBaseAddress>>8;
     pVirtual = VirtualAlloc(0,dwSize,MEM_RESERVE,PAGE_NOACCESS);
     vced.pvDestMem = pVirtual;
     vced.dwSize = dwSize;
     KernelIoControl(IOCTL_VIRTUAL_COPY_EX,&vced, sizeof(vced), NULL, NULL, NULL);
     return pVirtual;
 }
 
// WinCE6.0模拟器中应用程序直接写屏
 PBYTE pLCDBuf = (PBYTE)GetVirtual(0x33f00000,0x100000);
 memset(pLCDBuf,0,0x100000);



 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值