关于VirtualAlloc和VirtualCopy的奇怪问题

以前,对这个VirtualAlloc和VirtualCopy一点都不了解,只是从网上看到一些介绍,这次我发现他们在4.2BSP和5.0BSP下使用有些不同,但是4.2BSP照样在wince5.0下使用也没有问题,现在以4.2BSP和5.0BSP下下的按键驱动为例子。

     先看4.2BSP的例子:

 

/* IO Register Allocation */

 v_pIOPregs = (volatile IOPreg *)VirtualAlloc(0, sizeof(IOPreg), 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)(IOP_BASE), sizeof(IOPreg), PAGE_READWRITE | PAGE_NOCACHE))
  {
   ERRORMSG(1,(TEXT("For IOPregs: VirtualCopy failed!/r/n")));
   RetValue = FALSE;
  }
 }

 

在VirtualCopy的IOP_BASE是个虚拟地址

#define IOP_BASE      0xB1600000 // 0x56000000

但是在5.0BSP却不一样,非常让人震惊。

v_pIOPregs = (volatile S3C2440A_IOPORT_REG *)VirtualAlloc(0, sizeof(S3C2440A_IOPORT_REG), MEM_RESERVE, PAGE_NOACCESS);
 VirtualCopy((PVOID)v_pIOPregs, (PVOID)(S3C2440A_BASE_REG_PA_IOPORT >> 8), sizeof(S3C2440A_IOPORT_REG), PAGE_PHYSICAL|PAGE_READWRITE|PAGE_NOCACHE );

S3C2440A_BASE_REG_PA_IOPORT 是个物理地址#define S3C2440A_BASE_REG_PA_IOPORT             (0x56000000)     

这个本来和4.2的虚拟地址就很大不同了,但是还要弄成     S3C2440A_BASE_REG_PA_IOPORT >> 8,右移八位,真是不可思议。

不过这个VirtualCopy的最后一个参数不同,在5.0BSP中多了一个PAGE_PHYSICAL,哦这个估计是关键因素。这里使用物理地址了,但是为什么还要右移八位,要知道答案就看PB的帮助了。

 

This function dynamically maps a virtual address to a physical address by creating a new page-table entry. Terminate the mapping by calling VirtualFree.

BOOL VirtualCopy( 
LPVOID lpvDest, 
LPVOID lpvSrc, 
DWORD cbSize, 
DWORD fdwProtect 
);
Parameters
lpvDest
[in] Pointer to the destination memory, which must be reserved.
lpvSrc
[in] Pointer to committed memory.
cbSize
[in] Size, in bytes, of the region. The allocated pages include all pages containing one or more bytes in the range from lpAddress to lpAddress+ cbSize. This means that a 2-byte range straddling a page boundary causes both pages to be included in the allocated region.

 

fdwProtect
[in] Type of access protection. If the pages are being committed, any one of a number of flags can be specified, along with the PAGE_GUARD and PAGE_NOCACHE, protection modifier flags. The following table shows the flags that can be specified.
ValueDescription
PAGE_READONLYEnables read access to the committed region of pages. An attempt to write to the committed region results in an access violation. If the system differentiates between read-only access and execute access, an attempt to execute code in the committed region results in an access violation.
PAGE_READWRITEEnables both read and write access to the committed region of pages.
PAGE_EXECUTEEnables execution access to the committed region of pages. An attempt to read or write to the committed region results in an access violation.
PAGE_EXECUTE_READEnables execute and read access to the committed region of pages. An attempt to write to the committed region results in an access violation.
PAGE_EXECUTE_READWRITEEnables execute, read, and write access to the committed region of pages.
PAGE_GUARDPages in the region become guard pages. Any attempt to read from or write to a guard page causes the operating system to raise the STATUS_GUARD_PAGE exception and turn off the guard page status. Guard pages thus act as a one-shot access alarm.

The PAGE_GUARD flag is a page protection modifier. An application uses it with one of the other page protection flags, with one exception: it cannot be used with PAGE_NOACCESS.

When an access attempt leads the operating system to turn off guard page status, the underlying page protection takes over.

If a guard page exception occurs during a system service, the service typically returns a failure status indicator.

PAGE_NOACCESSDisables all access to the committed region of pages. An attempt to read from, write to, or execute in the committed region results in an access violation exception, called a general protection (GP) fault.
PAGE_NOCACHEAllows no caching of the committed regions of pages. The hardware attributes for the physical memory should be specified as no cache. It is useful for device drivers; when, for example, mapping a video frame buffer with no caching. This flag is a page protection modifier and is valid only when used with one of the page protections other than PAGE_NOACCESS.
PAGE_PHYSICALUsed to map a physical memory region. When using this flag, divide the physical address — that is, lpvSrc — by 256. Memory mapped with PAGE_PHYSICAL is not freed until the device is rebooted. Calling VirtualFree will not free this mapped physical memory. PAGE_PHYSICAL is intended for use with dedicated hardware buffers, so it cannot be freed after being mapped.

 

      PAGE_PHYSICAL这个参数决定了要右移八位(除以256),哈哈,这样就达到了异曲同工之妙。不过还有一点就是使用了PAGE_PHYSICAL之后就不要使用VirtualFree 了因为,使用了也无济于事。

     现在来看看这个VirtualAlloc 吧。

 

This function reserves or commits a region of pages in the virtual address space of the calling process.

Memory allocated by VirtualAlloc is initialized to zero.

LPVOID VirtualAlloc(
LPVOID lpAddress, 
DWORD dwSize, 
DWORD flAllocationType, 
DWORD flProtect 
); 
Parameters
lpAddress
[in] Long pointer to the specified starting address of the region to be allocated.

If the memory is being reserved, the specified address is rounded down to the next 64-KB boundary.

If the memory is reserved and is being committed, the address is rounded down to the next page boundary.

To determine the size of a page on the host computer, use the GetSystemInfo function.

If this parameter is NULL, the system determines where to allocate the region.

dwSize
[in] Specifies the size, in bytes, of the region. It is an error to set this parameter to 0.

If the lpAddress parameter is NULL, this value is rounded up to the next page boundary.

Otherwise, the allocated pages include all pages containing one or more bytes in the range from lpAddress to lpAddress+dwSize. This means that a 2-byte range straddling a page boundary causes both pages to be included in the allocated region.

flAllocationType
[in] Specifies the type of allocation.

The following table shows flags you can specify for this parameter in any combination

     关于wince的内存管理,还是很复杂的,如果开源就好了,水平太菜,学习的东西越来越多,但是感觉越来越慌张。   

 

 

 

 

 

弄清楚这个问题首先要了解VirtualCopy和VirtualAlloc这2个函数的实现和目的,以及wince下动态虚拟内存映射和静态虚拟内存映射
先说VirtualAlloc 和VirtualCopy
VirtualAlloc 首先会从我们的虚拟地址空间中申请(或者说预留)一块虚拟空间,准备接下来要用它。注意此时,可用的物理内存并没有减少,只是虚拟地址少了一块可用的区域。
真正把这块之前reserved的虚拟空间映射到物理的内存区域就是由VirtualCopy来干的,此时,MMU的页表就会增加一个entry,来表示物理--虚拟的映射关系。


再说动态虚拟内存映射和静态虚拟内存映射
OEMaddressTable只是建立了一个一级的静态虚拟--物理的映射关系,一般给kernel(NK.EXE)通过直接访问的形式来用(OALPAtoVA);
MmMapIOSpace(VirtualAlloc +VirtualCopy)是一种动态虚拟映射的手段,一般给驱动根据当前需要(对硬件操作)动态申请并建立映射。

 

 

那就是说VirtualCopy 可以直接把物理内存映射到虚拟内存中
而OEMaddressTable所建立的静态虚拟--物理的映射不是必须的

也就是说比如对寄存器的映射:
可以通过VirtualAlloc申请(预留)一块虚拟内存给寄存器(如:v_pIOPregs)
然后用
VirtualCopy直接把寄存器的物理地址映射到刚才申请(预留)的虚拟地址空间

而在OEMaddressTable中所做的寄存器物理地址与虚拟地址的映射这步可以省略

不是省略不省略的问题,是这两种方法是在不同的场合下使用的,如2楼说的,内核部分就要用这个OEMaddressTable来转换,wince5.0下 用户态的驱动(wince6.0驱动貌似是在内核态)就要用这个VirtualAlloc+VirtualCopy来进行地址映射。

OEMaddressTable的定义,你可以查看 bsp/src/inc/oemaddrtab_cfg.inc ,那个g_oalAddressTable便是。

 

 

 

 

 

  • 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、付费专栏及课程。

余额充值