WINCE下内存操作函数的使用:MmMapIoSpace和MmUnmapIoSpace,VirtualAlloc、VirtualCopy和 VirtualFree。

本文深入探讨了Windows CE环境下虚拟内存的分配、复制和释放,以及映射物理内存的技术实现,包括VirtualAlloc、VirtualCopy、VirtualFree、MmMapIoSpace和MmUnmapIoSpace函数的应用,以及在不同物理地址范围内的使用技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、先看VirtualAlloc 、VirtualCopy 和 VirtualFree

LPVOID VirtualAlloc(
LPVOID lpAddress ,
DWORD dwSize ,
DWORD flAllocationType ,
DWORD flProtect
);

VirtualAlloc 只是在虚拟地址申请一个空间,lpAddress 大多数为0指由系统来自动分配虚拟地址

BOOL VirtualCopy(
LPVOID lpvDest ,
LPVOID lpvSrc ,
DWORD cbSize ,
DWORD fdwProtect
);

VirtualCopy 把 VirtualAlloc 的虚拟地址绑定 LPVOID lpvSrc

看使用实例:

PRIVATE BOOL PIO_InitializeAddresses(void)
{
    BOOL    RetValue = TRUE;

    //    IO Register Allocation
    v_pIOPregs = (volatile S3C2410X_IOPORT_REG *)VirtualAlloc(0, sizeof(S3C2410X_IOPORT_REG), MEM_RESERVE, PAGE_NOACCESS);
    if (v_pIOPregs == NULL)
    {
        ERRORMSG(1,(TEXT("For IOPregs : VirtualAlloc failed!/r/n")));
        RetValue = FALSE;
    }
    else
    {
        if (!VirtualCopy((PVOID)v_pIOPregs, (PVOID)(S3C2410X_BASE_REG_PA_IOPORT >> 8), sizeof(S3C2410X_IOPORT_REG), PAGE_PHYSICAL | PAGE_READWRITE | PAGE_NOCACHE))
        {
            ERRORMSG(1,(TEXT("For IOPregs: VirtualCopy failed!/r/n")));
            RetValue = FALSE;
        }
    }
   
    if (!RetValue)
    {
        RETAILMSG (1, (TEXT("::: PIO_InitializeAddresses - Fail!!/r/n") ));

        if (v_pIOPregs)
        {
            VirtualFree((PVOID) v_pIOPregs, 0, MEM_RELEASE);
        }

        v_pIOPregs = NULL;

        RetValue = FALSE;
        return RetValue;
    }

    return(RetValue);
}

注意:1.使用VirtualAlloc要包含Winbase.h;使用VirtualCopy时要包含plfuncs.h.两者都要链接coredll.lib.

         2.VirtualCopy用来绑定一块物理内存到当前进程虚拟地址空间。参数里的lpvSrc既可以是内核段的虚拟地址也可以是物理地址(用page_physical来标记)。使用VirtualCopy要注意lpvSrc的右移与否?

本段引自:http://xiechaochaohb.blog.163.com/blog/static/48308479200951045327335/

  • 1. 如果copy的物理地址在512M范围内,那么由于静态映射的存在,lpvSrc可以为静态映射的虚拟地址,也可以为物理地址。采用后者需要指定page_physical,同时lpvSrc右移8位。

分析如下:

/***************************************************************************************************************************************/

比如:方法1)

 pBspArgs = (BSP_ARGS_CONFIG *)VirtualAlloc(0, 512, MEM_RESERVE, PAGE_NOACCESS);
    if(!pBspArgs)
    {
     //OALMSG(TRUE, (TEXT("VirtualAlloc failed/n")));
    }
    else
    {
     if(!VirtualCopy((LPVOID)pBspArgs, (PVOID)(BSP_CONFIG_BUFFER_BASE), sizeof(BSP_ARGS_CONFIG), PAGE_READWRITE | PAGE_NOCACHE))
     {
      //OALMSG(TRUE, (TEXT("VirtualCopy failed/n")));
     }
     else
     {

  }
    }

   其中#define BSP_CONFIG_BUFFER_BASE   0xA0021000     //该地址为静态映射到虚拟地址(不带缓存),

 

方法2)

  v_pIOPregs = (volatile S3C2450_IOPORT_REG *) VirtualAlloc(0,sizeof(S3C2450_IOPORT_REG),MEM_RESERVE, PAGE_NOACCESS);
  if(v_pIOPregs == NULL)
  {
    RETAILMSG(1,(TEXT("For v_pIOPregs: VirtualAlloc failed!/r/n")));
   goto Fail;
  }
  else if(!VirtualCopy((PVOID)v_pIOPregs, (PVOID)(S3C2450_BASE_REG_PA_IOPORT>>8),sizeof(S3C2450_IOPORT_REG), PAGE_PHYSICAL | PAGE_READWRITE | PAGE_NOCACHE ))
  {
   RETAILMSG(1,(TEXT("For v_pIOPregs: VirtualCopy failed!/r/n")));
   goto Fail;
  }

#define S3C2450_BASE_REG_PA_IOPORT                  0x56000000    //该地址为物理地址

/********************************************************************************************************************************************/

 

  • 2. 如果copy的物理地址在512M范围外,那么由于微软的如下规定“

VirtualCopy also supports the PAGE_PHYSICAL flag. You must set this flag when you are mapping physical memory that resides beyond 512 MB, that is, physical memory with an address above 0x1FFFFFFF.”
lpvSrc只能为物理地址,同时需要右移。

分析如下:

/******************************************************************************************************************************/

WINCE 最大只能通过映射表把512M的物理地址(包括SDRAM(0X30000000),CPU寄存器的物理地址)映射到0X80000000 的缓存NK使用空间和0XA0000000不带缓存驱动使用的空间中去。

那么对于内存大于512M的物理地址,如果使用VirtualCopy  ,只能使用上面的方法2,因为该物理地址没有映射到512M的虚拟地址空间中去,所以不能直接使用该静态虚拟地址,

 PAGE_PHYSICAL | PAGE_READWRITE | PAGE_NOCACHE 为方法2使用的参数值 。此时物理地址要右移动8位

PAGE_READWRITE | PAGE_NOCACHE  为方法1)使用的参数值。

  • 3.可以简单认为,只要设置了PAGE_PHYSICAL 为真,那么就需要把lpvSrc右移8位。

二、MmMapIoSpace和MmUnmapIoSpace

函数原型:

PVOID MmMapIoSpace(
PHYSICAL_ADDRESS PhysicalAddress,     参数1:需要映射的物理地址
ULONG NumberOfBytes,                   参数2:映射的地址长度
BOOLEAN CacheEnable                    参数3:是否使用cache(驱动中要使用uncached)
);

VOID MmUnmapIoSpace(
PVOID BaseAddress,                      参数1:被映射后的虚拟地址
ULONG NumberOfBytes                     参数2:映射的地址长度
);

再看函数的实现:

PVOID
88 MmMapIoSpace (
89      IN PHYSICAL_ADDRESS PhysicalAddress,
90      IN ULONG NumberOfBytes,
91      IN BOOLEAN CacheEnable
92      )
93 {
94      PVOID    pVirtualAddress;
95      ULONGLONG    SourcePhys;
96      ULONG    SourceSize;
97      BOOL     bSuccess;
98
99      //
100      // Page align source and adjust size to compensate
101      //
102
103      SourcePhys = PhysicalAddress.QuadPart & ~ (PAGE_SIZE - 1 ); // for page align
104      SourceSize = NumberOfBytes + (PhysicalAddress.LowPart & (PAGE_SIZE - 1 ));
105
106      if (SourceSize < NumberOfBytes) { // Prevent Integer overflow.
107          SetLastError(ERROR_INVALID_PARAMETER);
108          return NULL;
109      }
110     
111
112      pVirtualAddress = VirtualAlloc( 0 , SourceSize, MEM_RESERVE, PAGE_NOACCESS);
113
114      if (pVirtualAddress != NULL)
115      {
116          bSuccess = VirtualCopy(
117              pVirtualAddress, (PVOID)(SourcePhys >> 8 ), SourceSize,
118              PAGE_PHYSICAL | PAGE_READWRITE | (CacheEnable ? 0 : PAGE_NOCACHE));
119
120          if (bSuccess)
121          {
122              (ULONG)pVirtualAddress += PhysicalAddress.LowPart & (PAGE_SIZE - 1 ); // 保证虚拟地址是页对齐
123          }
124          else
125          {
126              VirtualFree(pVirtualAddress, 0 , MEM_RELEASE); // 释放内存。
127              pVirtualAddress = NULL;
128          }
129      }
130
131      return pVirtualAddress; // 返回虚拟内存地址。
132 }

135    从这个看来MmMapIoSpace也是使用了驱动中常用的VirtualAlloc、VirtualCopy、VirtualFree来实现的,只不过是加入了页对齐,使用起来较安全。
136    再看看MmUnmapIoSpace

151 VOID
152 MmUnmapIoSpace (
153      IN PVOID BaseAddress,
154      IN ULONG NumberOfBytes
155      )
156 {
157      VirtualFree((PVOID)((ULONG)BaseAddress & ~ (ULONG)(PAGE_SIZE - 1 )), 0 , MEM_RELEASE);
158 }

PS:在非full kern模式下,映射物理内存可能会失败,但是可以调用。
可以用setkmode去让ap临时进入kernel模式,然后在对内存进行操作。——哦,那wince6.0 也可以这样哦
在ce5下,AP可以做任何驱动可以做的事情,你可以写个程序访问kernel的空间,破解系统,也可以dump或修改flash上面的raw data。但是从ce6开始,这一切都没那么自由了。


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值