VirtualAlloc,VirtualCopy和MmMapIoSpace

VirtualAlloc,VirtualCopy和MmMapIoSpace


在WinCE的驱动程序里经常要去访问硬件设备,对硬件设备寄存器进行操作,如CPU的IOPORT,中断寄存器等,这就要使用VirtualAlloc,VirtualCopyMmMapIoSpace进行地址的分配及映射.

如SMDK2410 BSP中的SDHC驱动中Sdiocontrollerbase.cpp:

  1. //----- 1. Map the GPIO registers needed to enable the SDI controller -----  
  2. vm_pIOPreg = (S3C2410X_IOPORT_REG *)VirtualAlloc(0, sizeof(S3C2410X_IOPORT_REG), MEM_RESERVE, PAGE_NOACCESS);  
  3. if (vm_pIOPreg == NULL)   
  4. {  
  5.     DEBUGMSG (1,(TEXT("GPIO registers not allocated")));  
  6.     status = SD_API_STATUS_INSUFFICIENT_RESOURCES;  
  7.     goto INIT_ERROR;  
  8. }  
  9. if (!VirtualCopy((PVOID)vm_pIOPreg, (PVOID)(S3C2410X_BASE_REG_PA_IOPORT >> 8), sizeof(S3C2410X_IOPORT_REG), PAGE_PHYSICAL | PAGE_READWRITE | PAGE_NOCACHE)) {  
  10.     DEBUGMSG (1,(TEXT("GPIO registers not mapped")));  
  11.     status = SD_API_STATUS_INSUFFICIENT_RESOURCES;  
  12.     goto INIT_ERROR;  

又如串口驱动Ser_smdk2410.cpp:
  1. if (TranslateBusAddr(m_hParent,Internal,0, ioPhysicalBase,&inIoSpace,&ioPhysicalBase)) {  
  2.     // Map it if it is Memeory Mapped IO.  
  3.     m_pIOPregs = (S3C2410X_IOPORT_REG *)MmMapIoSpace(ioPhysicalBase, sizeof(S3C2410X_IOPORT_REG),FALSE);  
  4. }  

首先来看看VirtualAlloc的原型:
LPVOID VirtualAlloc(
  LPVOID
  lpAddress
  DWORD
  dwSize
  DWORD
  flAllocationType
  DWORD
  flProtect 
); 
VirtualAlloc 是在虚拟地址空间中申请一段dwSize大小的虚拟地址.
lpAddress为指定虚拟地址的起始地址,为0则由系统来自动分配地址.
flAllocationType有两个选项MEM_COMMIT和MEM_RESERVE,MEM_RESERVE为系统保留,不会被其他内存分配函数占用.使用MEM_COMMIT参数可以将上次使用MEM_RESERVE保留的地址空间进行实际的分配.如第一次调用使用MEM_RESERVE,第二次调用使用MEM_COMMIT.在驱动程序中我们只用MEM_RESERVE保留,然后使用VirtualCopy将物理地址映射到该虚拟地址上.

VirtualCopy的原型
BOOL VirtualCopy( 
  LPVOID 
lpvDest
  LPVOID 
lpvSrc
  DWORD 
cbSize
  DWORD 
fdwProtect 
);
VirtualCopy将分配的虚拟地址空间与物理地址进行了映射.
LPVOID lpvSrc 可以是虚拟地址也可以是物理地址.
fdwProtect程序用了PAGE_PHYSICAL | PAGE_READWRITE | PAGE_NOCACHE的组合.PAGE_PHYSICAL 表明是用来映射物理内存区域,这样 lpvSrc为物理地址,需要右移8位.(这是由于VirtualCopy的实现决定的)

MmMapIoSpace实际上就是调用了VirtualAlloc,VirtualCopy,并做了一些地址检验,源代码位于/PUBLIC/COMMON/OAK/DRIVERS/CEDDK/DDK_MAP/ddk_map.c
原型为:
PVOID MmMapIoSpace( 
  PHYSICAL_ADDRESS 
PhysicalAddress
  ULONG
  NumberOfBytes
  BOOLEAN 
CacheEnable 
);
同样还有个MmUnmapIoSpace进行内存的释放.
更多详细内容可参考MSDN.
在CE驱动程序中基本就是通过上述两种方法进行物理地址到虚拟地址的内存分配(VirtualAlloc+VirtualCopy或者MmMapIoSpace)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 C++ 中,可以使用 `VirtualAlloc` 函数来分配内存,并将其用作 Thunk 函数的代码。下面是一个示例代码,展示了如何使用 `VirtualAlloc` 来创建一个简单的 Thunk 函数: ```cpp #include <iostream> #include <windows.h> // 定义一个函数指针类型 typedef int (*FuncPtr)(int); // Thunk 函数 int __stdcall ThunkFunction(int num) { std::cout << "Thunk function called with parameter: " << num << std::endl; // 调用原始函数 return num * 2; } int main() { // 分配内存空间 DWORD dwSize = 4096; // 分配的内存大小,这里假设为 4KB LPVOID lpAddress = VirtualAlloc(NULL, dwSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE); // 将 Thunk 函数的代码复制到分配的内存中 memcpy(lpAddress, ThunkFunction, dwSize); // 创建函数指针并将其设置为分配的内存地址 FuncPtr thunk = (FuncPtr)lpAddress; // 使用函数指针调用 Thunk 函数 int result = thunk(5); std::cout << "Result: " << result << std::endl; // 释放分配的内存 VirtualFree(lpAddress, 0, MEM_RELEASE); return 0; } ``` 在这个示例中,我们使用 `VirtualAlloc` 函数分配了一块内存空间,大小为 4KB。然后,使用 `memcpy` 函数将 Thunk 函数的代码复制到这块内存中。 接下来,我们创建了一个函数指针 `thunk`,并将其设置为分配的内存地址。通过这个函数指针,我们可以调用 Thunk 函数。 最后,我们使用函数指针调用 Thunk 函数,并打印出结果。完成后,使用 `VirtualFree` 函数释放分配的内存。 需要注意的是,使用 `VirtualAlloc` 分配的内存需要适当地设置内存保护属性,以确保其可执行和可读写。在本示例中,使用了 `PAGE_EXECUTE_READWRITE` 属性,表示内存既可执行又可读写。具体的内存保护属性需要根据实际需求进行选择。 此外,需要注意 Thunk 函数的参数传递和调用约定,以及在不同平台和编译器下可能存在的差异。这些细节需要根据具体情况进行处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值