source: trunk/src/kernel32/oslibmem.cpp@ 21302

Last change on this file since 21302 was 21302, checked in by ydario, 16 years ago

Kernel32 updates.

File size: 14.5 KB
Line 
1/* $Id: oslibmem.cpp,v 1.7 2003-03-27 14:00:53 sandervl Exp $ */
2/*
3 * Wrappers for OS/2 Dos* API
4 *
5 * Copyright 1998-2002 Sander van Leeuwen (sandervl@xs4all.nl)
6 * Copyright 2000 knut st. osmundsen (knut.stange.osmundsen@mynd.no)
7 *
8 * Project Odin Software License can be found in LICENSE.TXT
9 *
10 */
11
12
13
14/*******************************************************************************
15* Header Files *
16*******************************************************************************/
17#define INCL_BASE
18#define INCL_DOSEXCEPTIONS
19#define INCL_DOSMEMMGR
20#define INCL_DOSPROCESS
21#define INCL_DOSFILEMGR
22#define INCL_DOSERRORS
23#define INCL_DOSDEVIOCTL
24#define INCL_DOSDEVICES
25#define INCL_NPIPES
26#include <os2wrap.h> //Odin32 OS/2 api wrappers
27#include <stdlib.h>
28#include <stdio.h>
29#include <string.h>
30#include <ctype.h>
31#include <win32api.h>
32#include <winconst.h>
33#include <win\winioctl.h>
34#include <dbglog.h>
35#include <vmutex.h>
36#include "initterm.h"
37#include "oslibdos.h"
38#include "oslibmem.h"
39#include "dosqss.h"
40#include "win32k.h"
41#include "exceptstackdump.h"
42
43#define DBG_LOCALLOG DBG_oslibmem
44#include "dbglocal.h"
45
46#include <_ras.h>
47
48#ifdef RAS
49RAS_TRACK_HANDLE rthVirtual = 0;
50
51void rasInitVirtual (void)
52{
53 RasRegisterObjectTracking (&rthVirtual, "Virtual* memory allocation",
54 0, RAS_TRACK_FLAG_MEMORY | RAS_TRACK_FLAG_LOG_OBJECTS_AT_EXIT,
55 NULL, NULL);
56}
57#endif
58
59typedef struct _VirtAllocRec {
60 ULONG baseaddr;
61 ULONG size;
62 ULONG attr;
63
64 struct _VirtAllocRec *next;
65} VirtAllocRec;
66
67static VirtAllocRec *allocrecords = NULL;
68static CRITICAL_SECTION_OS2 alloccritsect = {0};
69
70//******************************************************************************
71//******************************************************************************
72void AddAllocRec(ULONG baseaddr, ULONG size, ULONG attr)
73{
74 VirtAllocRec *rec, *tmp;
75
76 rec = (VirtAllocRec *)malloc(sizeof(VirtAllocRec));
77 if(!rec) {
78 DebugInt3();
79 return;
80 }
81 rec->baseaddr = baseaddr;
82 rec->size = size;
83 rec->attr = attr;
84
85 DosEnterCriticalSection(&alloccritsect);
86 if(!allocrecords || allocrecords->baseaddr > baseaddr) {
87 rec->next = allocrecords;
88 allocrecords = rec;
89 }
90 else {
91 tmp = allocrecords;
92 while(tmp->next) {
93 if(tmp->next->baseaddr > baseaddr) {
94 break;
95 }
96 tmp = tmp->next;
97 }
98
99 rec->next = tmp->next;
100 tmp->next = rec;
101 }
102 DosLeaveCriticalSection(&alloccritsect);
103}
104//******************************************************************************
105//******************************************************************************
106void FreeAllocRec(ULONG baseaddr)
107{
108 VirtAllocRec *rec = NULL, *tmp;
109
110 if(!allocrecords) {
111 DebugInt3();
112 return;
113 }
114
115 DosEnterCriticalSection(&alloccritsect);
116 if(allocrecords->baseaddr == baseaddr) {
117 rec = allocrecords;
118 allocrecords = allocrecords->next;
119 }
120 else {
121 tmp = allocrecords;
122 while(tmp->next) {
123 if(tmp->next->baseaddr == baseaddr) {
124 break;
125 }
126 tmp = tmp->next;
127 }
128 if(tmp->next) {
129 rec = tmp->next;
130 tmp->next = tmp->next->next;
131 }
132 else dprintf(("ERROR: FreeAllocRec: allocation not found!! (%x)", baseaddr));
133 }
134 DosLeaveCriticalSection(&alloccritsect);
135 if(rec) free(rec);
136}
137//******************************************************************************
138//******************************************************************************
139BOOL FindAllocRec(ULONG addr, ULONG *lpBase, ULONG *lpSize, ULONG *lpAttr)
140{
141 VirtAllocRec *rec = NULL;
142
143 DosEnterCriticalSection(&alloccritsect);
144 rec = allocrecords;
145 while(rec) {
146 if(rec->baseaddr <= addr && rec->baseaddr + rec->size > addr) {
147 *lpBase = rec->baseaddr;
148 *lpSize = rec->size;
149 *lpAttr = rec->attr;
150 break; //found it
151 }
152 if(rec->baseaddr > addr) {
153 //sorted list, so no need to search any further
154 rec = NULL;
155 break;
156 }
157 rec = rec->next;
158 }
159 DosLeaveCriticalSection(&alloccritsect);
160 return (rec != NULL);
161}
162//******************************************************************************
163//TODO: Check if this works for code aliases...
164//NOTE: DosAliasMem fails if the address isn't page aligned
165//******************************************************************************
166DWORD OSLibDosAliasMem(LPVOID pb, ULONG cb, LPVOID *ppbAlias, ULONG fl)
167{
168 DWORD rc;
169 DWORD attr;
170 DWORD size = cb;
171
172 cb = (cb-1) & ~0xfff;
173 cb+= PAGE_SIZE;
174
175 rc = DosAliasMem(pb, cb, ppbAlias, 2);
176 if(rc) {
177 dprintf(("!ERROR!: OSLibDosAliasMem: DosAliasMem %x %x returned %d", pb, cb, rc));
178 return rc;
179 }
180 //Now try to change the protection flags of all pages in the aliased range
181 DWORD pAlias = (DWORD)*ppbAlias;
182
183 while(pAlias < (DWORD)*ppbAlias + cb)
184 {
185 rc = DosQueryMem((PVOID)pAlias, &size, &attr);
186 if(rc != NO_ERROR) {
187 dprintf(("!ERROR!: OSLibDosAliasMem: DosQueryMem %x returned %d", pAlias, rc));
188 DebugInt3();
189 return rc;
190 }
191 //Don't bother if the pages are not committed. DosSetMem will return
192 //ERROR_ACCESS_DENIED.
193 if(attr & PAG_COMMIT) {
194 rc = DosSetMem((PVOID)pAlias, size, fl);
195 if(rc) {
196 dprintf(("!ERROR!: OSLibDosAliasMem: DosSetMem %x %x return %d", *ppbAlias, size, rc));
197 DebugInt3();
198 return rc;
199 }
200 }
201 pAlias += size;
202 }
203 AddAllocRec((ULONG)*ppbAlias, cb, fl);
204 return 0;
205}
206//******************************************************************************
207//Allocate memory aligned at 64kb boundary
208//******************************************************************************
209DWORD OSLibDosAllocMem(LPVOID *lplpMemAddr, DWORD cbSize, DWORD flFlags, BOOL fLowMemory)
210{
211 PVOID pvMemAddr;
212 DWORD offset;
213 APIRET rc;
214 BOOL fMemFlags = flAllocMem;
215
216 //Override low/high memory flag if necessary
217 if(fLowMemory) {
218 fMemFlags = 0;
219 }
220
221 /*
222 * Let's try use the extended DosAllocMem API of Win32k.sys.
223 */
224 if (libWin32kInstalled())
225 {
226 rc = DosAllocMemEx(lplpMemAddr, cbSize, flFlags | fMemFlags | OBJ_ALIGN64K);
227#ifdef RAS
228 if (rc == NO_ERROR)
229 {
230 RasAddObject (rthVirtual, (ULONG)*lplpMemAddr, NULL, cbSize);
231 }
232#endif
233 if (rc != ERROR_NOT_SUPPORTED) /* This call was stubbed until recently. */
234 return rc;
235 }
236
237 /*
238 * If no or old Win32k fall back to old method.
239 */
240
241 rc = DosAllocMem(&pvMemAddr, cbSize, flFlags | fMemFlags);
242 if(rc) {
243 dprintf(("!ERROR!: DosAllocMem failed with rc %d", rc));
244 return rc;
245 }
246 // already 64k aligned ?
247 if((ULONG) pvMemAddr & 0xFFFF)
248 {
249 ULONG addr64kb;
250
251 //free misaligned allocated memory
252 DosFreeMem(pvMemAddr);
253
254 //Allocate 64kb more so we can round the address to a 64kb aligned value
255 rc = DosAllocMem((PPVOID)&addr64kb, cbSize + 64*1024, (flFlags & ~PAG_COMMIT) | fMemFlags);
256 if(rc) {
257 dprintf(("!ERROR!: DosAllocMem failed with rc %d", rc));
258 return rc;
259 }
260
261 PVOID baseAddr = (PVOID)addr64kb; // sunlover20040613: save returned address for a possible Free on failure
262
263 dprintf(("Allocate aligned memory %x -> %x", addr64kb, (addr64kb + 0xFFFF) & ~0xFFFF));
264
265 if(addr64kb & 0xFFFF) {
266 addr64kb = (addr64kb + 0xFFFF) & ~0xFFFF;
267 }
268 pvMemAddr = (PVOID)addr64kb;
269
270 //and set the correct page flags for the request range
271 if((flFlags & ~PAG_COMMIT) != flFlags) {
272 rc = DosSetMem(pvMemAddr, cbSize, flFlags);
273 if(rc) {
274 dprintf(("!ERROR!: DosSetMem failed with rc %d", rc));
275 DosFreeMem (baseAddr); // sunlover20040613: Free allocated memory
276 return rc;
277 }
278 }
279 }
280
281 if(!rc) {
282 *lplpMemAddr = pvMemAddr;
283 AddAllocRec((ULONG)pvMemAddr, cbSize, flFlags);
284 RasAddObject (rthVirtual, (ULONG)*lplpMemAddr, NULL, cbSize);
285 }
286 return rc;
287}
288//******************************************************************************
289//Locate the base page of a memory allocation (the page with the PAG_BASE attribute)
290//******************************************************************************
291PVOID OSLibDosFindMemBase(LPVOID lpMemAddr, DWORD *lpAttr)
292{
293 ULONG ulAttr, ulSize, ulAddr, ulBase;
294 APIRET rc;
295 VirtAllocRec *allocrec;
296
297 *lpAttr = 0;
298
299 if(FindAllocRec((ULONG)lpMemAddr, &ulBase, &ulSize, lpAttr) == TRUE) {
300 return (PVOID)ulBase;
301 }
302
303 ulSize = PAGE_SIZE;
304 rc = DosQueryMem(lpMemAddr, &ulSize, &ulAttr);
305 if(rc != NO_ERROR) {
306 dprintf(("!ERROR!: OSLibDosFindMemBase: DosQueryMem %x failed with rc %d", lpMemAddr, rc));
307 return lpMemAddr;
308 }
309 if(!(ulAttr & PAG_BASE)) {
310 //Not the base of the initial allocation (can happen due to alignment) or app
311 //passing address inside memory allocation range
312 ulAddr = (DWORD)lpMemAddr & ~0xFFF;
313 ulAddr -= PAGE_SIZE;
314
315 while(ulAddr > 0)
316 {
317 rc = DosQueryMem((PVOID)ulAddr, &ulSize, &ulAttr);
318 if(rc) {
319 dprintf(("!ERROR!: OSLibDosFindMemBase: DosQueryMem %x failed with rc %d", lpMemAddr, rc));
320 DebugInt3();
321 return NULL;
322 }
323 if(ulAttr & PAG_BASE) {
324 //Memory below the 512 MB boundary is always aligned at 64kb and VirtualAlloc only
325 //returns high memory (if OS/2 version supports it)
326 //If it is above the 512 MB boundary, then we must make sure the right base address
327 //is returned. VirtualAlloc allocates extra memory to make sure it can return addresses
328 //aligned at 64kb. If extra pages are needed, then the allocation base is inside
329 //the filler region. In that case we must return the next 64kb address as base.
330 if(ulAddr > MEM_TILED_CEILING) {
331 ulAddr = (ulAddr + 0xFFFF) & ~0xFFFF;
332 }
333 lpMemAddr = (PVOID)ulAddr;
334 break;
335 }
336 ulAddr -= PAGE_SIZE;
337 }
338 }
339 return lpMemAddr;
340}
341//******************************************************************************
342//******************************************************************************
343DWORD OSLibDosFreeMem(LPVOID lpMemAddr)
344{
345 ULONG ulAttr, ulSize, ulAddr;
346 APIRET rc;
347
348 ulAddr = (DWORD)lpMemAddr & ~0xFFF;
349 ulSize = 0x1000;
350
351 //Find base within previous 64kb (alignment can add filler pages)
352 for(int i=0;i<16;i++) {
353 rc = DosQueryMem((PVOID)ulAddr, &ulSize, &ulAttr);
354 if(rc != NO_ERROR) {
355 dprintf(("!ERROR!: OSLibDosFreeMem: DosQueryMem %x failed with rc %d", lpMemAddr, rc));
356 i = 16; //fail
357 break;
358 }
359 if(ulAttr & PAG_BASE) {
360 break;
361 }
362 ulAddr -= PAGE_SIZE;
363 }
364 if(i == 16) {
365 //oh, oh. didn't find base; shouldn't happen!!
366 dprintf(("!ERROR!: OSLibDosFreeMem: Unable to find base of %x", lpMemAddr));
367 DebugInt3();
368 return ERROR_INVALID_PARAMETER;
369 }
370 FreeAllocRec((ULONG)lpMemAddr);
371
372 RasRemoveObject (rthVirtual, (ULONG)lpMemAddr);
373
374 return DosFreeMem((PVOID)ulAddr);
375}
376//******************************************************************************
377//NOTE: If name == NULL, allocated gettable unnamed shared memory
378//OS/2 returns error 123 (invalid name) if the shared memory name includes
379//colons. We need to replace them with underscores.
380//******************************************************************************
381DWORD OSLibDosAllocSharedMem(LPVOID *lplpMemAddr, DWORD size, DWORD flags, LPSTR name)
382{
383 APIRET rc;
384 char *sharedmemname = NULL, *tmp;
385
386 if(name) {
387 sharedmemname = (char *)malloc(strlen(name) + 16);
388 strcpy(sharedmemname, "\\SHAREMEM\\");
389 strcat(sharedmemname, name);
390 }
391 else flags |= OBJ_GETTABLE;
392
393 //SvL: Colons are unacceptable in shared memory names (for whatever reason)
394 tmp = sharedmemname;
395 while(*tmp != 0) {
396 if(*tmp == ':') {
397 *tmp = '_';
398 }
399 tmp++;
400 }
401
402 rc = DosAllocSharedMem(lplpMemAddr, sharedmemname, size, flags);
403 if(name) {
404 free(sharedmemname);
405 }
406 return rc;
407}
408//******************************************************************************
409//NOTE: If name == NULL, assume gettable unnamed shared memory
410//******************************************************************************
411DWORD OSLibDosGetNamedSharedMem(LPVOID *lplpMemAddr, LPSTR name)
412{
413 APIRET rc;
414 char *sharedmemname = NULL, *tmp;
415
416 if(name) {
417 sharedmemname = (char *)malloc(strlen(name) + 16);
418 strcpy(sharedmemname, "\\SHAREMEM\\");
419 strcat(sharedmemname, name);
420
421 //SvL: Colons are unacceptable in shared memory names (for whatever reason)
422 tmp = sharedmemname;
423 while(*tmp != 0) {
424 if(*tmp == ':') {
425 *tmp = '_';
426 }
427 tmp++;
428 }
429 rc = DosGetNamedSharedMem(lplpMemAddr, sharedmemname, PAG_READ|PAG_WRITE);
430 if(name) {
431 free(sharedmemname);
432 }
433 }
434 else rc = DosGetSharedMem((LPVOID)*(DWORD *)lplpMemAddr, PAG_READ|PAG_WRITE);
435
436 return rc;
437}
438//******************************************************************************
439//******************************************************************************
440DWORD OSLibDosQueryMem(LPVOID lpMemAddr, DWORD *lpRangeSize, DWORD *lpAttr)
441{
442 return DosQueryMem(lpMemAddr, lpRangeSize, lpAttr);
443}
444//******************************************************************************
445//******************************************************************************
446DWORD OSLibDosSetMem(LPVOID lpMemAddr, DWORD size, DWORD flags)
447{
448 APIRET rc;
449
450 rc = DosSetMem(lpMemAddr, size, flags);
451 switch(rc) {
452 case ERROR_INVALID_ADDRESS:
453 return OSLIB_ERROR_INVALID_ADDRESS;
454 case ERROR_ACCESS_DENIED:
455 return OSLIB_ERROR_ACCESS_DENIED;
456 default:
457 return rc;
458 }
459}
460//******************************************************************************
461//******************************************************************************
Note: See TracBrowser for help on using the repository browser.