MmMapIoSpace以及MmUnmapIoSpace,VirtualAlloc和VirtualCopy 函数的实现原理以及实现方法

来源:互联网 发布:eclipse开发java教程 编辑:程序博客网 时间:2024/04/29 08:33
 

首先说明:

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

LPVOID lpvSrc 可以是虚拟地址也可以是物理地址 ,物理地址必需右移8位,且   DWORD fdwProtect 含PAGE_PHYSICAL

分析之前,要看看一个很关键的东西——PHYSICAL_ADDRESS,这个参数很重要,是地址的组织形式。
   5 // in ceddk.h
   6 typedef LARGE_INTEGER PHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS;
   7 // in winnt.h
   8 typedef struct _LARGE_INTEGER {
   9 #else // MIDL_PASS
10 typedef union _LARGE_INTEGER {
11     struct {
12          DWORD LowPart;
13          LONG HighPart;
14      };
15     struct {
16          DWORD LowPart;
17          LONG HighPart;
18      } u;
19 #endif //MIDL_PASS
20      LONGLONG QuadPart;
21 } LARGE_INTEGER;
22 在MSDN中有这样的解释:
23 LARGE_INTEGER Union
24
25 The LARGE_INTEGER structure is used to represent a 64-bit signed integer value.
26
27 Note   Your C compiler may support 64-bit integers natively. For example, Microsoft Visual C++ supports the __int64 sized integer type. For
28
29 more information, see the documentation included with your C compiler.
30
31 Members
32 LowPart
33 Low-order 32 bits.
34
35 HighPart
36 High-order 32 bits.
37
38 u
39 LowPart
40 Low-order 32 bits.
41
42 HighPart
43 High-order 32 bits.
44
45 QuadPart
46 Signed 64-bit integer.
47
48 Remarks
49 The LARGE_INTEGER structure is actually a union. If your compiler has built-in support for 64-bit integers, use the QuadPart member to store
50
51 the 64-bit integer. Otherwise, use the LowPart and HighPart members to store the 64-bit integer.
52
53
54 OK,现在就来看看MmMapIoSpace吧。
55 首先看它的一个成功使用例子:
56
57 void CDlgDemoDlg::OnButton1()  
58 {  
59 // TODO: Add your control notification handler code here  
60 //unsigned char *gpio_base;  
61 unsigned int *gpio_base;  
62 OutputDebugString(L"TestDrv - LedDrive1/n");  
63 //PUCHAR ioPortBase;  
64 PHYSICAL_ADDRESS PortAddress = {0x56000060, 0}; //   LowPart=0x56000060;HighPart=0;
65 gpio_base =(unsigned int *)MmMapIoSpace( PortAddress, 0x04,FALSE ); // 获得内存,4字节大小。  
66 *gpio_base = 0x0585ff87; // 直接访问硬件  
67 MmUnmapIoSpace(gpio_base,0x04);//释放内存  
68 } 
69
70
71 再看MmMapIoSpace实现过程H:/WINCE600/PUBLIC/COMMON/OAK/DRIVERS/CEDDK/DDK_MAP
72
73 /*++
74 Routine Description:
75    map the given physical address range to nonpaged system space
76
77 Arguments:
78    PhysicalAddress - starting physical address of the I/O range to be mapped
79    NumberOfBytes - number of bytes to be mapped
80    CacheEnable - TRUE if the physical address range can be mapped as cached
81                  memory
82
83 Return Value:
84    base virtual address that maps the base physical address for the range, or
85    NULL if space for mapping the range is insufficient
86 --*/
87 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 }
133
134 =================================================================================
135    从这个看来MmMapIoSpace也是使用了驱动中常用的VirtualAlloc、VirtualCopy、VirtualFree来实现的,只不过是加入了页对齐,使用起来较安全。
136    再看看MmUnmapIoSpace
137
138 /*++
139 Routine Description:
140    unmap a specified range of physical addresses previously mapped by
141    MmMapIoSpace
142
143 Arguments:
144    BaseAddress - pointer to the base virtual address to which the physical
145                  pages were mapped
146    NumberOfBytes - number of bytes that were mapped
147
148 Return Value:
149    None
150 --*/
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 }

原创粉丝点击