source: trunk/src/kernel32/virtual.cpp@ 708

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

Workaround for OS/2 bug + VirtualProtect/VirtualQuery bugfixes

File size: 19.7 KB
Line 
1/* $Id: virtual.cpp,v 1.10 1999-08-26 17:56:26 sandervl Exp $ */
2
3/*
4 * Win32 virtual memory functions
5 *
6 * Copyright 1998-1999 Sander van Leeuwen (sandervl@xs4all.nl)
7 * Copyright 1998 Knut St. Osmundsen
8 * Copyright 1998 Peter FitzSimmons
9 *
10 * Parts (VIRTUAL_MapFileA/W) based on Wine code (memory\virtual.c):
11 *
12 * Copyright 1997 Alexandre Julliard
13 *
14 * Project Odin Software License can be found in LICENSE.TXT
15 *
16 */
17
18#include <os2win.h>
19#include <stdlib.h>
20#include <string.h>
21#include <win\virtual.h>
22#include <heapstring.h>
23#include <handlemanager.h>
24#include "mmap.h"
25#include "oslibdos.h"
26
27/***********************************************************************
28 * CreateFileMapping32A (KERNEL32.46)
29 * Creates a named or unnamed file-mapping object for the specified file
30 *
31 * RETURNS
32 * Handle: Success
33 * 0: Mapping object does not exist
34 * NULL: Failure
35 */
36HANDLE WINAPI CreateFileMappingA(
37 HFILE hFile, /* [in] Handle of file to map */
38 SECURITY_ATTRIBUTES *sa, /* [in] Optional security attributes*/
39 DWORD protect, /* [in] Protection for mapping object */
40 DWORD size_high, /* [in] High-order 32 bits of object size */
41 DWORD size_low, /* [in] Low-order 32 bits of object size */
42 LPCSTR name /* [in] Name of file-mapping object */ )
43{
44 return HMCreateFileMapping(hFile, sa, protect, size_high, size_low, name);
45}
46
47
48/***********************************************************************
49 * CreateFileMapping32W (KERNEL32.47)
50 * See CreateFileMapping32A
51 */
52HANDLE WINAPI CreateFileMappingW( HFILE hFile, LPSECURITY_ATTRIBUTES attr,
53 DWORD protect, DWORD size_high,
54 DWORD size_low, LPCWSTR name )
55{
56 LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name );
57 HANDLE ret = CreateFileMappingA( hFile, attr, protect,
58 size_high, size_low, nameA );
59 HeapFree( GetProcessHeap(), 0, nameA );
60 return ret;
61}
62
63
64/***********************************************************************
65 * OpenFileMapping32A (KERNEL32.397)
66 * Opens a named file-mapping object.
67 *
68 * RETURNS
69 * Handle: Success
70 * NULL: Failure
71 */
72HANDLE WINAPI OpenFileMappingA(
73 DWORD access, /* [in] Access mode */
74 BOOL inherit, /* [in] Inherit flag */
75 LPCSTR name ) /* [in] Name of file-mapping object */
76{
77 dprintf(("OpenFileMappingA: %x %d %s", access, inherit, name));
78 return HMOpenFileMapping(access, inherit, name);
79}
80
81
82/***********************************************************************
83 * OpenFileMapping32W (KERNEL32.398)
84 * See OpenFileMapping32A
85 */
86HANDLE WINAPI OpenFileMappingW( DWORD access, BOOL inherit, LPCWSTR name)
87{
88 LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name );
89 HANDLE ret = OpenFileMappingA( access, inherit, nameA );
90 HeapFree( GetProcessHeap(), 0, nameA );
91 return ret;
92}
93
94
95/***********************************************************************
96 * MapViewOfFile (KERNEL32.385)
97 * Maps a view of a file into the address space
98 *
99 * RETURNS
100 * Starting address of mapped view
101 * NULL: Failure
102 */
103LPVOID WINAPI MapViewOfFile(
104 HANDLE mapping, /* [in] File-mapping object to map */
105 DWORD access, /* [in] Access mode */
106 DWORD offset_high, /* [in] High-order 32 bits of file offset */
107 DWORD offset_low, /* [in] Low-order 32 bits of file offset */
108 DWORD count /* [in] Number of bytes to map */
109)
110{
111 return MapViewOfFileEx( mapping, access, offset_high,
112 offset_low, count, NULL );
113}
114
115
116/***********************************************************************
117 * MapViewOfFileEx (KERNEL32.386)
118 * Maps a view of a file into the address space
119 *
120 * RETURNS
121 * Starting address of mapped view
122 * NULL: Failure
123 */
124LPVOID WINAPI MapViewOfFileEx(
125 HANDLE handle, /* [in] File-mapping object to map */
126 DWORD access, /* [in] Access mode */
127 DWORD offset_high, /* [in] High-order 32 bits of file offset */
128 DWORD offset_low, /* [in] Low-order 32 bits of file offset */
129 DWORD count, /* [in] Number of bytes to map */
130 LPVOID addr /* [in] Suggested starting address for mapped view */
131)
132{
133 return HMMapViewOfFileEx(handle, access, offset_high, offset_low, count, addr);
134}
135
136
137/***********************************************************************
138 * FlushViewOfFile (KERNEL32.262)
139 * Writes to the disk a byte range within a mapped view of a file
140 *
141 * RETURNS
142 * TRUE: Success
143 * FALSE: Failure
144 */
145BOOL WINAPI FlushViewOfFile(
146 LPCVOID base, /* [in] Start address of byte range to flush */
147 DWORD cbFlush /* [in] Number of bytes in range */
148)
149{
150 Win32MemMap *map;
151
152 if (!base)
153 {
154 SetLastError( ERROR_INVALID_PARAMETER );
155 return FALSE;
156 }
157 map = Win32MemMap::findMap((ULONG)base);
158 if(map == NULL) {
159 SetLastError( ERROR_FILE_NOT_FOUND );
160 return FALSE;
161 }
162 return map->flushView((LPVOID)base, cbFlush);
163}
164
165
166/***********************************************************************
167 * UnmapViewOfFile (KERNEL32.540)
168 * Unmaps a mapped view of a file.
169 *
170 * NOTES
171 * Should addr be an LPCVOID?
172 *
173 * RETURNS
174 * TRUE: Success
175 * FALSE: Failure
176 */
177BOOL WINAPI UnmapViewOfFile(LPVOID addr /* [in] Address where mapped view begins */
178)
179{
180 Win32MemMap *map;
181
182 if (!addr)
183 {
184 SetLastError( ERROR_INVALID_PARAMETER );
185 return FALSE;
186 }
187 map = Win32MemMap::findMap((ULONG)addr);
188 if(map == NULL) {
189 SetLastError( ERROR_FILE_NOT_FOUND );
190 return FALSE;
191 }
192 return map->unmapViewOfFile();
193}
194
195/***********************************************************************
196 * VIRTUAL_MapFileW
197 *
198 * Helper function to map a file to memory:
199 * name - file name
200 * [RETURN] ptr - pointer to mapped file
201 */
202HANDLE WINAPI VIRTUAL_MapFileW( LPCWSTR name , LPVOID *lpMapping)
203{
204 HANDLE hFile, hMapping = -1;
205
206 hFile = CreateFileW( name, GENERIC_READ, FILE_SHARE_READ, NULL,
207 OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, 0);
208 if (hFile != INVALID_HANDLE_VALUE)
209 {
210 hMapping = CreateFileMappingA( hFile, NULL, PAGE_READONLY, 0, 0, NULL );
211 CloseHandle( hFile );
212 if (hMapping != INVALID_HANDLE_VALUE)
213 {
214 *lpMapping = MapViewOfFile( hMapping, FILE_MAP_READ, 0, 0, 0 );
215 }
216 }
217 return hMapping;
218}
219
220/***********************************************************************
221 * VIRTUAL_MapFileA
222 *
223 * Helper function to map a file to memory:
224 * name - file name
225 * [RETURN] ptr - pointer to mapped file
226 */
227HANDLE WINAPI VIRTUAL_MapFileA( LPCSTR name , LPVOID *lpMapping)
228{
229 HANDLE hFile, hMapping = -1;
230
231 hFile = CreateFileA(name, GENERIC_READ, FILE_SHARE_READ, NULL,
232 OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, 0);
233 if (hFile != INVALID_HANDLE_VALUE)
234 {
235 hMapping = CreateFileMappingA( hFile, NULL, PAGE_READONLY, 0, 0, NULL );
236 CloseHandle( hFile );
237 if (hMapping != INVALID_HANDLE_VALUE)
238 {
239 *lpMapping = MapViewOfFile( hMapping, FILE_MAP_READ, 0, 0, 0 );
240 }
241 }
242 return hMapping;
243}
244
245//******************************************************************************
246//******************************************************************************
247LPVOID WIN32API VirtualAlloc(LPVOID lpvAddress, DWORD cbSize, DWORD fdwAllocationType,
248 DWORD fdwProtect)
249{
250 PVOID Address = lpvAddress;
251 ULONG flag = 0, base;
252 APIRET rc;
253
254 dprintf(("VirtualAlloc at %X; %d bytes, fAlloc %d, fProtect %d\n", (int)lpvAddress, cbSize, fdwAllocationType, fdwProtect));
255
256 if (cbSize > 0x7fc00000) /* 2Gb - 4Mb */
257 {
258 dprintf(("VirtualAlloc: size too large"));
259 SetLastError( ERROR_OUTOFMEMORY );
260 return NULL;
261 }
262
263 if (!(fdwAllocationType & (MEM_COMMIT | MEM_RESERVE)) ||
264 (fdwAllocationType & ~(MEM_COMMIT | MEM_RESERVE)))
265 {
266 dprintf(("VirtualAlloc: Invalid parameter"));
267 SetLastError( ERROR_INVALID_PARAMETER );
268 return NULL;
269 }
270
271 if(fdwAllocationType & MEM_COMMIT) {
272 dprintf(("VirtualAlloc: commit\n"));
273 flag = PAG_COMMIT;
274 }
275 if(fdwProtect & PAGE_READONLY) flag |= PAG_READ;
276 if(fdwProtect & PAGE_READWRITE) flag |= (PAG_READ | PAG_WRITE);
277 if(fdwProtect & PAGE_WRITECOPY) flag |= (PAG_READ | PAG_WRITE);
278
279 if(fdwProtect & PAGE_EXECUTE_READWRITE) flag |= (PAG_EXECUTE | PAG_WRITE | PAG_READ);
280 if(fdwProtect & PAGE_EXECUTE_READ) flag |= (PAG_EXECUTE | PAG_READ);
281 if(fdwProtect & PAGE_EXECUTE) flag |= PAG_EXECUTE;
282
283 if(fdwProtect & PAGE_GUARD) flag |= PAG_GUARD;
284
285 //just do this if other options are used
286 if(!(flag & (PAG_READ | PAG_WRITE | PAG_EXECUTE)) || flag == 0)
287 {
288 dprintf(("VirtualAlloc: Unknown protection flags, default to read/write"));
289 flag |= PAG_READ | PAG_WRITE;
290 }
291
292 if(fdwAllocationType & MEM_COMMIT && lpvAddress != NULL)
293 {
294 Address = lpvAddress;
295
296 rc = OSLibDosSetMem(lpvAddress, cbSize, flag);
297
298 //might try to commit larger part with same base address
299 if(rc == OSLIB_ERROR_ACCESS_DENIED && cbSize > 4096 )
300 { //knut: AND more than one page
301 char *newbase = (char *)lpvAddress + ((cbSize-1) & 0xFFFFF000); //knut: lets not start after the last page!
302 ULONG size, os2flags;
303
304 while(newbase >= (char *)lpvAddress)
305 { //knut: should check first page to!!
306 size = 4096;
307 os2flags = 0;
308 rc = OSLibDosQueryMem(newbase, &size, &os2flags);
309 if(rc)
310 break;
311
312 if(os2flags & PAG_COMMIT)
313 {
314 newbase += 4096;
315 break;
316 }
317 newbase -= 4096;
318 }
319
320 if(rc == 0)
321 {
322 //In case it wants to commit bytes that fall into the last
323 //page of the previous commit command
324 if(cbSize > ((int)newbase - (int)lpvAddress))
325 rc = OSLibDosSetMem(newbase, cbSize - ((int)newbase - (int)lpvAddress), flag);
326 }
327 else return(NULL);
328
329 }
330 else
331 {
332 if(rc == OSLIB_ERROR_INVALID_ADDRESS) {
333 rc = OSLibDosAllocMem(&Address, cbSize, flag );
334 }
335 else
336 if(rc) dprintf(("Unexpected DosSetMem error %x", rc));
337 }
338 }
339 else
340 {
341 rc = OSLibDosAllocMem(&Address, cbSize, flag);
342 }
343
344 if(rc)
345 {
346 dprintf(("DosSetMem returned %d\n", rc));
347 SetLastError( ERROR_OUTOFMEMORY );
348 return(NULL);
349 }
350
351 dprintf(("VirtualAlloc returned %X\n", Address));
352 return(Address);
353}
354//******************************************************************************
355//******************************************************************************
356BOOL WIN32API VirtualFree(LPVOID lpvAddress, DWORD cbSize, DWORD FreeType)
357{
358 APIRET rc;
359
360 dprintf(("VirtualFree at %d; %d bytes, freetype %d\n", (int)lpvAddress, cbSize, FreeType));
361
362 if(lpvAddress == NULL || cbSize == 0) {
363 SetLastError(ERROR_INVALID_PARAMETER);
364 return(FALSE);
365 }
366 if(FreeType & MEM_DECOMMIT) {
367 rc = OSLibDosSetMem(lpvAddress, cbSize, PAG_DECOMMIT);
368 }
369 else rc = OSLibDosFreeMem(lpvAddress); //MEM_RELEASE, cbSize == 0 (or should be)
370
371 if(rc) {
372 SetLastError(ERROR_GEN_FAILURE);
373 return(FALSE);
374 }
375 return(TRUE);
376}
377//******************************************************************************
378//LPVOID lpvAddress; /* address of region of committed pages */
379//DWORD cbSize; /* size of the region */
380//DWORD fdwNewProtect; /* desired access protection */
381//PDWORD pfdwOldProtect; /* address of variable to get old protection */
382//TODO: Not 100% complete
383//TODO: SetLastError on failure
384//******************************************************************************
385BOOL WIN32API VirtualProtect(LPVOID lpvAddress, DWORD cbSize, DWORD fdwNewProtect,
386 DWORD *pfdwOldProtect)
387{
388 APIRET rc;
389 ULONG pageFlags = 0;
390 int npages;
391
392 dprintf(("VirtualProtect %X; %d bytes, new flags %X (%X)\n", (int)lpvAddress, cbSize, fdwNewProtect, pfdwOldProtect));
393 if(pfdwOldProtect == NULL)
394 return(FALSE);
395
396 rc = OSLibDosQueryMem(lpvAddress, &cbSize, &pageFlags);
397 if(rc) {
398 dprintf(("DosQueryMem returned %d\n", rc));
399 return(FALSE);
400 }
401 dprintf(("Old memory flags %X\n", pageFlags));
402 *pfdwOldProtect = 0;
403 if(pageFlags & PAG_READ && !(pageFlags & PAG_WRITE))
404 *pfdwOldProtect |= PAGE_READONLY;
405 if(pageFlags & (PAG_WRITE))
406 *pfdwOldProtect |= PAGE_READWRITE;
407
408 if((pageFlags & (PAG_WRITE | PAG_EXECUTE)) == (PAG_WRITE | PAG_EXECUTE))
409 *pfdwOldProtect |= PAGE_EXECUTE_READWRITE;
410 else
411 if(pageFlags & PAG_EXECUTE)
412 *pfdwOldProtect |= PAGE_EXECUTE_READ;
413
414 if(pageFlags & PAG_GUARD)
415 *pfdwOldProtect |= PAGE_GUARD;
416 pageFlags = 0;
417
418 if(fdwNewProtect & PAGE_READONLY) pageFlags |= PAG_READ;
419 if(fdwNewProtect & PAGE_READWRITE) pageFlags |= (PAG_READ | PAG_WRITE);
420 if(fdwNewProtect & PAGE_WRITECOPY) pageFlags |= (PAG_READ | PAG_WRITE);
421 if(fdwNewProtect & PAGE_EXECUTE_READ) pageFlags |= (PAG_EXECUTE | PAG_READ);
422 if(fdwNewProtect & PAGE_EXECUTE_READWRITE)
423 pageFlags |= (PAG_EXECUTE | PAG_WRITE | PAG_READ);
424 if(fdwNewProtect & PAGE_EXECUTE_WRITECOPY)
425 pageFlags |= (PAG_EXECUTE | PAG_WRITE | PAG_READ);
426 if(fdwNewProtect & PAGE_GUARD) pageFlags |= PAG_GUARD;
427//Not supported in OS/2??
428// if(fdwNewProtect & PAGE_NOACCESS)
429
430 dprintf(("New memory flags %X\n", pageFlags));
431 if(pageFlags == 0) {
432 dprintf(("pageFlags == 0\n"));
433 return(TRUE); //nothing to do
434 }
435 ULONG offset = ((ULONG)lpvAddress & 0xFFF);
436 npages = (cbSize >> 12);
437 if(cbSize & 0xFFF + offset) {
438 npages++;
439 }
440
441 lpvAddress = (LPVOID)((int)lpvAddress & ~0xFFF);
442 cbSize = npages*4096;
443 dprintf(("lpvAddress = %X, cbSize = %d\n", lpvAddress, cbSize));
444
445 rc = OSLibDosSetMem(lpvAddress, cbSize, pageFlags);
446 if(rc) {
447 dprintf(("DosSetMem returned %d\n", rc));
448 return(FALSE);
449 }
450 return(TRUE);
451}
452//******************************************************************************
453//******************************************************************************
454DWORD WIN32API VirtualQuery(LPCVOID lpvAddress, LPMEMORY_BASIC_INFORMATION pmbiBuffer,
455 DWORD cbLength)
456{
457 ULONG cbRangeSize, dAttr;
458 APIRET rc;
459
460 if(lpvAddress == NULL || pmbiBuffer == NULL || cbLength == 0) {
461 return 0;
462 }
463 cbRangeSize = cbLength;
464 rc = OSLibDosQueryMem((LPVOID)lpvAddress, &cbRangeSize, &dAttr);
465 if(rc) {
466 dprintf(("VirtualQuery - DosQueryMem %x %x returned %d\n", lpvAddress, cbLength, rc));
467 return 0;
468 }
469 memset(pmbiBuffer, 0, sizeof(MEMORY_BASIC_INFORMATION));
470 pmbiBuffer->BaseAddress = (LPVOID)lpvAddress;
471 pmbiBuffer->RegionSize = cbRangeSize;
472 if(dAttr & PAG_READ && !(dAttr & PAG_WRITE))
473 pmbiBuffer->Protect |= PAGE_READONLY;
474 if(dAttr & PAG_WRITE)
475 pmbiBuffer->Protect |= PAGE_READWRITE;
476
477 if((dAttr & (PAG_WRITE | PAG_EXECUTE)) == (PAG_WRITE | PAG_EXECUTE))
478 pmbiBuffer->Protect |= PAGE_EXECUTE_READWRITE;
479 else
480 if(dAttr & PAG_EXECUTE)
481 pmbiBuffer->Protect |= PAGE_EXECUTE_READ;
482
483 if(dAttr & PAG_GUARD)
484 pmbiBuffer->Protect |= PAGE_GUARD;
485
486 if(dAttr & PAG_FREE)
487 pmbiBuffer->State = MEM_FREE;
488 else
489 if(dAttr & PAG_COMMIT)
490 pmbiBuffer->State = MEM_COMMIT;
491 else pmbiBuffer->State = MEM_RESERVE;
492
493 if(!(dAttr & PAG_SHARED))
494 pmbiBuffer->Type = MEM_PRIVATE;
495
496 //TODO: This is not correct: AllocationProtect should contain the protection
497 // flags used in the initial call to VirtualAlloc
498 pmbiBuffer->AllocationProtect = pmbiBuffer->Protect;
499 if(dAttr & PAG_BASE) {
500 pmbiBuffer->AllocationBase = (LPVOID)lpvAddress;
501 }
502 else {
503 while(lpvAddress > 0) {
504 rc = OSLibDosQueryMem((LPVOID)lpvAddress, &cbRangeSize, &dAttr);
505 if(rc) {
506 dprintf(("VirtualQuery - OSLibDosQueryMem %x %x returned %d\n", lpvAddress, cbLength, rc));
507 break;
508 }
509 if(dAttr & PAG_BASE) {
510 pmbiBuffer->AllocationBase = (LPVOID)lpvAddress;
511 break;
512 }
513 lpvAddress = (LPVOID)((ULONG)lpvAddress - PAGE_SIZE);
514 }
515 }
516 return sizeof(MEMORY_BASIC_INFORMATION);
517}
518//******************************************************************************
519//******************************************************************************
520BOOL WIN32API VirtualLock( LPVOID lpAddress, DWORD dwSize )
521{
522 dprintf(("VirtualLock at %d; %d bytes - stub (TRUE)\n", (int)lpAddress, dwSize));
523 return TRUE;
524}
525
526//******************************************************************************
527BOOL WIN32API VirtualUnlock( LPVOID lpAddress, DWORD dwSize )
528{
529 dprintf(("VirtualUnlock at %d; %d bytes - stub (TRUE)\n", (int)lpAddress, dwSize));
530 return TRUE;
531}
532
533/*****************************************************************************
534 * Name : BOOL VirtualProtectEx
535 * Purpose : The VirtualProtectEx function changes the access protection on
536 * a region of committed pages in the virtual address space of a specified
537 * process. Note that this function differs from VirtualProtect,
538 * which changes the access protection on the calling process only.
539 * Parameters: HANDLE hProcess handle of process
540 * LPVOID lpvAddress address of region of committed pages
541 * DWORD cbSize size of region
542 * DWORD fdwNewProtect desired access protection
543 * PDWORD pfdwOldProtect address of variable to get old protection
544 * Variables :
545 * Result : size of target buffer
546 * Remark :
547 * Status : UNTESTED STUB
548 *
549 * Author : Patrick Haller [Mon, 1998/06/15 08:00]
550 *****************************************************************************/
551
552BOOL WIN32API VirtualProtectEx(HANDLE hProcess,
553 LPVOID lpvAddress,
554 DWORD cbSize,
555 DWORD fdwNewProtect,
556 LPDWORD pfdwOldProtect)
557{
558 dprintf(("KERNEL32: VirtualProtectEx(%08x,%08xh,%08xh,%08xh,%08xh) not implemented for different processes.\n",
559 hProcess,
560 lpvAddress,
561 cbSize,
562 fdwNewProtect,
563 pfdwOldProtect));
564
565 return VirtualProtect(lpvAddress, cbSize, fdwNewProtect, pfdwOldProtect);
566}
567
568
569/*****************************************************************************
570 * Name : DWORD VirtualQueryEx
571 * Purpose : The VirtualQueryEx function provides information about a range
572 * of pages within the virtual address space of a specified process.
573 * Parameters: HANDLE hProcess handle of process
574 * LPCVOID lpvAddress address of region
575 * LPMEMORY_BASIC_INFORMATION pmbiBuffer address of information buffer
576 * DWORD cbLength size of buffer
577 * Variables :
578 * Result : number of bytes returned in buffer
579 * Remark :
580 * Status : UNTESTED STUB
581 *
582 * Author : Patrick Haller [Mon, 1998/06/15 08:00]
583 *****************************************************************************/
584
585DWORD WIN32API VirtualQueryEx(HANDLE hProcess,
586 LPCVOID lpvAddress,
587 LPMEMORY_BASIC_INFORMATION pmbiBuffer,
588 DWORD cbLength)
589{
590 dprintf(("KERNEL32: VirtualQueryEx(%08x,%08xh,%08xh,%08xh) not implemented for different processes.\n",
591 hProcess,
592 lpvAddress,
593 pmbiBuffer,
594 cbLength));
595
596 return VirtualQuery(lpvAddress, pmbiBuffer, cbLength);
597}
598//******************************************************************************
599//******************************************************************************
Note: See TracBrowser for help on using the repository browser.