source: trunk/src/kernel32/mmap.cpp@ 695

Last change on this file since 695 was 695, checked in by sandervl, 26 years ago

Readonly memory mapped files work now + PE loader uses those apis

File size: 11.5 KB
Line 
1/* $Id: mmap.cpp,v 1.12 1999-08-25 15:27:19 sandervl Exp $ */
2
3/*
4 * Win32 Memory mapped file class
5 *
6 * Copyright 1999 Sander van Leeuwen (sandervl@xs4all.nl)
7 *
8 * NOTE: Memory mapping DOES NOT work when kernel-mode code causes
9 * a pagefault in the memory mapped object. (exceptions aren't
10 * dispatched to our exception handler until after the kernel mode
11 * call returns (too late))
12 *
13 * NOTE: There's no easy way to determine which pages were modified. Temporary
14 * solution is to write all paged-in memory to disk.
15 *
16 * NOTE: Are apps allowed to change the protection flags of memory mapped pages?
17 * I'm assuming they aren't for now.
18 *
19 * TODO: Handles returned should be usable by all apis that accept file handles
20 * TODO: Sharing memory mapped files between multiple processes
21 *
22 * Project Odin Software License can be found in LICENSE.TXT
23 *
24 */
25#include <os2win.h>
26#include <stdlib.h>
27#include <string.h>
28#include <win\virtual.h>
29#include <vmutex.h>
30#include <handlemanager.h>
31#include "mmap.h"
32
33VMutex globalmapMutex;
34
35//******************************************************************************
36//TODO: sharing between processes
37//******************************************************************************
38Win32MemMap::Win32MemMap(HFILE hfile, ULONG size, ULONG fdwProtect, LPSTR lpszName)
39 : fMapped(FALSE), pMapping(NULL), mMapAccess(0), referenced(0)
40{
41 globalmapMutex.enter();
42 next = memmaps;
43 memmaps = this;
44 globalmapMutex.leave();
45
46 hMemFile = hfile;
47
48 mSize = size;
49 mProtFlags = fdwProtect;
50
51 if(lpszName) {
52 lpszMapName = (char *)malloc(strlen(lpszName)+1);
53 strcpy(lpszMapName, lpszName);
54 }
55 else lpszMapName = NULL;
56}
57//******************************************************************************
58//******************************************************************************
59BOOL Win32MemMap::Init(HANDLE hMemMap)
60{
61 mapMutex.enter();
62 if(hMemFile != -1)
63 {
64 if(DuplicateHandle(GetCurrentProcess(), hMemFile, GetCurrentProcess(),
65 &hMemFile, 0, FALSE, DUPLICATE_SAME_ACCESS) == FALSE)
66 {
67 dprintf(("Win32MemMap::Init: DuplicateHandle failed!"));
68 goto fail;
69 }
70 mSize = SetFilePointer(hMemFile, 0, NULL, FILE_END);
71 if(mSize == -1) {
72 dprintf(("Win32MemMap::init: SetFilePointer failed to set pos end"));
73 goto fail;
74 }
75 }
76 this->hMemMap = hMemMap;
77 mapMutex.leave();
78 return TRUE;
79fail:
80 mapMutex.leave();
81 return FALSE;
82}
83//******************************************************************************
84//******************************************************************************
85Win32MemMap::~Win32MemMap()
86{
87 unmapViewOfFile();
88 if(lpszMapName) {
89 free(lpszMapName);
90 }
91 mapMutex.enter();
92 if(pMapping) {
93 VirtualFree(pMapping, mSize, MEM_RELEASE);
94 pMapping = NULL;
95 }
96 if(hMemFile != -1) {
97 CloseHandle(hMemFile);
98 hMemFile = -1;
99 }
100 mapMutex.leave();
101
102 globalmapMutex.enter();
103 Win32MemMap *map = memmaps;
104
105 if(map == this) {
106 memmaps = next;
107 }
108 else {
109 while(map->next) {
110 if(map->next == this)
111 break;
112 map = map->next;
113 }
114 if(map->next) {
115 map->next = next;
116 }
117 else dprintf(("Win32MemMap::~Win32MemMap: map not found!! (%x)", this));
118 }
119 globalmapMutex.leave();
120}
121//******************************************************************************
122//******************************************************************************
123BOOL Win32MemMap::hasReadAccess()
124{
125 return TRUE; //should have at least this
126}
127//******************************************************************************
128//******************************************************************************
129BOOL Win32MemMap::hasWriteAccess()
130{
131 return !(mProtFlags & PAGE_READONLY);
132}
133//******************************************************************************
134//Might want to add this feature for memory mapping executable & dll files in
135//the loader (done in Win32 with the SEC_IMAGE flag?)
136//******************************************************************************
137BOOL Win32MemMap::hasExecuteAccess()
138{
139 return FALSE;
140}
141//******************************************************************************
142//******************************************************************************
143BOOL Win32MemMap::commitPage(LPVOID lpPageFaultAddr, ULONG nrpages)
144{
145 DWORD pageAddr = (DWORD)lpPageFaultAddr & ~0xFFF;
146 DWORD oldProt, newProt, nrBytesRead, offset, size;
147
148// mapMutex.enter();
149 newProt = mProtFlags & (PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY);
150
151 dprintf(("Win32MemMap::commitPage %x (faultaddr %x), nr of pages %d", pageAddr, lpPageFaultAddr, nrpages));
152 if(hMemFile != -1) {
153 if(VirtualAlloc((LPVOID)pageAddr, nrpages*PAGE_SIZE, MEM_COMMIT, PAGE_READWRITE) == FALSE) {
154 goto fail;
155 }
156 offset = pageAddr - (ULONG)pMapping;
157 size = nrpages*PAGE_SIZE;
158 if(offset + size > mSize) {
159 size = mSize - offset;
160 }
161 if(SetFilePointer(hMemFile, offset, NULL, FILE_BEGIN) != offset) {
162 dprintf(("Win32MemMap::commitPage: SetFilePointer failed to set pos to %x", offset));
163 goto fail;
164 }
165 if(ReadFile(hMemFile, (LPSTR)pageAddr, size, &nrBytesRead, NULL) == FALSE) {
166 dprintf(("Win32MemMap::commitPage: ReadFile failed for %x", pageAddr));
167 goto fail;
168 }
169 if(nrBytesRead != size) {
170 dprintf(("Win32MemMap::commitPage: ReadFile didn't read all bytes for %x", pageAddr));
171 goto fail;
172 }
173 if(mProtFlags & PAGE_READONLY) {
174//DosSetMem returns flags with EXECUTE bit set, even though the initial allocation is without this bit set!
175//Also returns access denied when trying to set it back to READONLY
176 VirtualProtect((LPVOID)pageAddr, nrpages*PAGE_SIZE, newProt, &oldProt);
177// if(VirtualProtect((LPVOID)pageAddr, nrpages*PAGE_SIZE, newProt, &oldProt) == FALSE) {
178// goto fail;
179// }
180 }
181 }
182 else {
183 if(VirtualAlloc((LPVOID)pageAddr, nrpages*PAGE_SIZE, MEM_COMMIT, newProt) == FALSE) {
184 goto fail;
185 }
186 }
187
188// mapMutex.leave();
189 return TRUE;
190fail:
191// mapMutex.leave();
192 return FALSE;
193}
194//******************************************************************************
195//******************************************************************************
196BOOL Win32MemMap::unmapViewOfFile()
197{
198 if(fMapped == FALSE)
199 return FALSE;
200
201 flushView(pMapping, mSize);
202 mapMutex.enter();
203 if(pMapping) {
204 VirtualFree(pMapping, mSize, MEM_RELEASE);
205 }
206 pMapping = NULL;
207 fMapped = FALSE;
208 mapMutex.leave();
209 return TRUE;
210}
211//******************************************************************************
212//******************************************************************************
213LPVOID Win32MemMap::mapViewOfFile(ULONG size, ULONG offset, ULONG fdwAccess)
214{
215 mapMutex.enter();
216 ULONG memFlags = (mProtFlags & (PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY));
217 ULONG fAlloc = 0;
218 LPVOID mapview;
219
220 if((fdwAccess & FILE_MAP_WRITE) && !(mProtFlags & PAGE_READWRITE))
221 goto parmfail;
222 if((fdwAccess & FILE_MAP_READ) && !(mProtFlags & (PAGE_READWRITE|PAGE_READONLY)))
223 goto parmfail;
224 if((fdwAccess & FILE_MAP_COPY) && !(mProtFlags & PAGE_WRITECOPY))
225 goto parmfail;
226
227//TODO: If committed, read file into memory
228#if 0
229 if(mProtFlags & SEC_COMMIT)
230 fAlloc |= MEM_COMMIT;
231 else
232 if(mProtFlags & SEC_RESERVE)
233 fAlloc |= MEM_RESERVE;
234#else
235 fAlloc = MEM_RESERVE;
236#endif
237
238 if(fMapped == FALSE) {//if not mapped, reserve/commit entire view
239 pMapping = VirtualAlloc(0, mSize, fAlloc, memFlags);
240 if(pMapping == NULL) {
241 dprintf(("Win32MemMap::mapFileView: VirtualAlloc %x %x %x failed!", mSize, fAlloc, memFlags));
242 goto fail;
243 }
244 fMapped = TRUE;
245 }
246 mapview = (LPVOID)((ULONG)pMapping + offset);
247 mapMutex.leave();
248 return mapview;
249
250parmfail:
251 dprintf(("Win32MemMap::mapFileView: ERROR_INVALID_PARAMETER"));
252 SetLastError(ERROR_INVALID_PARAMETER);
253fail:
254 mapMutex.leave();
255 return 0;
256}
257//******************************************************************************
258// NOTE: There's no easy way to determine which pages were modified. Temporary
259// solution is to write all paged-in memory to disk.
260//TODO: Are apps allowed to change the protection flags of memory mapped pages?
261// I'm assuming they aren't for now.
262//******************************************************************************
263BOOL Win32MemMap::flushView(LPVOID lpvBase, ULONG cbFlush)
264{
265 MEMORY_BASIC_INFORMATION memInfo;
266 ULONG nrpages, nrBytesWritten, offset, size;
267 int i;
268
269// mapMutex.enter();
270 dprintf(("Win32MemMap::flushView: %x %x", lpvBase, cbFlush));
271 if(fMapped == FALSE)
272 goto parmfail;
273
274 if(cbFlush == 0)
275 cbFlush = mSize;
276
277 if(lpvBase < pMapping || (ULONG)lpvBase+cbFlush > (ULONG)pMapping+mSize)
278 goto parmfail;
279
280 if(mProtFlags & PAGE_READONLY)
281 goto parmfail;
282
283 if(hMemFile == -1)
284 goto success; //TODO: Return an error here?
285
286 nrpages = cbFlush/PAGE_SIZE;
287 if(cbFlush & 0xFFF) nrpages++;
288
289 for(i=0;i<nrpages;i++) {
290 if(VirtualQuery((LPSTR)lpvBase+i*PAGE_SIZE, &memInfo, PAGE_SIZE) == 0) {
291 dprintf(("Win32MemMap::flushView: VirtualQuery (%x,%x) failed for %x", lpvBase, cbFlush, (ULONG)lpvBase+i*PAGE_SIZE));
292 goto fail;
293 }
294 //If a page is reserved or write protected, we won't bother flushing it to disk
295 if(memInfo.State & MEM_COMMIT &&
296 memInfo.AllocationProtect & (PAGE_READWRITE|PAGE_WRITECOPY|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY))
297 {//committed and allowed for writing?
298 offset = (ULONG)lpvBase+i*PAGE_SIZE - (ULONG)pMapping;
299 size = PAGE_SIZE;
300 if(offset + size > mSize) {
301 size = mSize - offset;
302 }
303 dprintf(("Win32MemMap::flushView for offset %x, size %d", offset, size));
304
305 if(SetFilePointer(hMemFile, offset, NULL, FILE_BEGIN) != offset) {
306 dprintf(("Win32MemMap::flushView: SetFilePointer failed to set pos to %x", offset));
307 goto fail;
308 }
309 if(WriteFile(hMemFile, (LPSTR)lpvBase+i*PAGE_SIZE, size, &nrBytesWritten, NULL) == FALSE) {
310 dprintf(("Win32MemMap::flushView: WriteFile failed for %x", (ULONG)lpvBase+i*PAGE_SIZE));
311 goto fail;
312 }
313 if(nrBytesWritten != size) {
314 dprintf(("Win32MemMap::flushView: WriteFile didn't write all bytes for %x", (ULONG)lpvBase+i*PAGE_SIZE));
315 goto fail;
316 }
317 }
318 }
319success:
320// mapMutex.leave();
321 return TRUE;
322parmfail:
323 SetLastError(ERROR_INVALID_PARAMETER);
324// mapMutex.leave();
325 return FALSE;
326fail:
327// mapMutex.leave();
328 return FALSE;
329}
330//******************************************************************************
331//******************************************************************************
332Win32MemMap *Win32MemMap::findMap(LPSTR lpszName)
333{
334 globalmapMutex.enter();
335 Win32MemMap *map = memmaps;
336
337 if(map != NULL) {
338 while(map) {
339 if(map->lpszMapName && !strcmp(map->lpszMapName, lpszName))
340 break;
341 map = map->next;
342 }
343 }
344 globalmapMutex.leave();
345 dprintf(("Win32MemMap::findMap: couldn't find map %s", lpszName));
346 return map;
347}
348//******************************************************************************
349//******************************************************************************
350Win32MemMap *Win32MemMap::findMap(ULONG address)
351{
352 globalmapMutex.enter();
353 Win32MemMap *map = memmaps;
354
355 if(map != NULL) {
356 while(map) {
357 if(map->pMapping && (ULONG)map->pMapping <= address &&
358 (ULONG)map->pMapping + map->mSize > address)
359 {
360 break;
361 }
362 map = map->next;
363 }
364 }
365 globalmapMutex.leave();
366 return map;
367}
368//******************************************************************************
369//******************************************************************************
370void Win32MemMap::deleteAll()
371{
372 while(memmaps) {
373 CloseHandle(memmaps->hMemMap);
374 }
375}
376//******************************************************************************
377//******************************************************************************
378Win32MemMap *Win32MemMap::memmaps = NULL;
Note: See TracBrowser for help on using the repository browser.