一、先看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开始,这一切都没那么自由了。