VirtualAlloc,VirtualCopy和MmMapIoSpace
在WinCE的驱动程序里经常要去访问硬件设备,对硬件设备寄存器进行操作,如CPU的IOPORT,中断寄存器等,这就要使用VirtualAlloc,VirtualCopyMmMapIoSpace进行地址的分配及映射.
如SMDK2410 BSP中的SDHC驱动中Sdiocontrollerbase.cpp:
-
- vm_pIOPreg = (S3C2410X_IOPORT_REG *)VirtualAlloc(0, sizeof(S3C2410X_IOPORT_REG), MEM_RESERVE, PAGE_NOACCESS);
- if (vm_pIOPreg == NULL)
- {
- DEBUGMSG (1,(TEXT("GPIO registers not allocated")));
- status = SD_API_STATUS_INSUFFICIENT_RESOURCES;
- goto INIT_ERROR;
- }
- if (!VirtualCopy((PVOID)vm_pIOPreg, (PVOID)(S3C2410X_BASE_REG_PA_IOPORT >> 8), sizeof(S3C2410X_IOPORT_REG), PAGE_PHYSICAL | PAGE_READWRITE | PAGE_NOCACHE)) {
- DEBUGMSG (1,(TEXT("GPIO registers not mapped")));
- status = SD_API_STATUS_INSUFFICIENT_RESOURCES;
- goto INIT_ERROR;
又如串口驱动Ser_smdk2410.cpp:
- if (TranslateBusAddr(m_hParent,Internal,0, ioPhysicalBase,&inIoSpace,&ioPhysicalBase)) {
-
- m_pIOPregs = (S3C2410X_IOPORT_REG *)MmMapIoSpace(ioPhysicalBase, sizeof(S3C2410X_IOPORT_REG),FALSE);
- }
首先来看看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)