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

Last change on this file since 9292 was 9292, checked in by sandervl, 23 years ago

VT: Fix for OSLibDosFreeMem

File size: 10.7 KB
Line 
1/* $Id: oslibmem.cpp,v 1.5 2002-09-24 15:15:27 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 <misc.h>
35#include "initterm.h"
36#include "oslibdos.h"
37#include "oslibmem.h"
38#include "dosqss.h"
39#include "win32k.h"
40
41#define DBG_LOCALLOG DBG_oslibmem
42#include "dbglocal.h"
43
44//******************************************************************************
45//TODO: Assumes entire memory range has the same protection flags!
46//TODO: Check if this works for code aliases...
47//******************************************************************************
48DWORD OSLibDosAliasMem(LPVOID pb, ULONG cb, LPVOID *ppbAlias, ULONG fl)
49{
50 DWORD rc;
51 DWORD attr;
52 DWORD size = cb;
53
54 cb = (cb-1) & ~0xfff;
55 cb+= PAGE_SIZE;
56
57 rc = DosQueryMem(pb, &size, &attr);
58 if(rc) {
59 dprintf(("!ERROR!: OSLibDosAliasMem: DosQueryMem %x %x return %d", pb, size, rc));
60 return rc;
61 }
62 size = (size-1) & ~0xfff;
63 size+= PAGE_SIZE;
64 if(size != cb) {
65 dprintf(("!WARNING!: OSLibDosAliasMem: size != cb (%x!=%x)!!!!!!!!", size, cb));
66 //ignore this and continue return 5;
67 attr = fl; //just use original protection flags (NOT CORRECT)
68 }
69 attr &= (PAG_READ|PAG_WRITE|PAG_EXECUTE|PAG_GUARD|PAG_DEFAULT);
70 if(attr != fl) {
71 rc = DosSetMem(pb, size, fl);
72 if(rc) {
73 dprintf(("!ERROR!: OSLibDosAliasMem: DosSetMem %x %x return %d", pb, size, rc));
74 attr = fl;
75 //just continue for now
76 //return rc;
77 }
78 }
79 rc = DosAliasMem(pb, cb, ppbAlias, 2);
80 if(rc) {
81 dprintf(("!ERROR!: OSLibDosAliasMem: DosAliasMem %x %x returned %d", pb, cb, rc));
82 return rc;
83 }
84 if(attr != fl) {
85 rc = DosSetMem(pb, size, attr);
86 if(rc) {
87 dprintf(("!ERROR!: OSLibDosAliasMem: DosSetMem (2) %x %x return %d", pb, size, rc));
88 return rc;
89 }
90 }
91 return 0;
92}
93//******************************************************************************
94//Allocate memory aligned at 64kb boundary
95//******************************************************************************
96DWORD OSLibDosAllocMem(LPVOID *lplpMemAddr, DWORD cbSize, DWORD flFlags, BOOL fLowMemory)
97{
98 PVOID pvMemAddr;
99 DWORD offset;
100 APIRET rc;
101 BOOL fMemFlags = flAllocMem;
102
103 //Override low/high memory flag if necessary
104 if(fLowMemory) {
105 fMemFlags = 0;
106 }
107 /*
108 * Let's try use the extended DosAllocMem API of Win32k.sys.
109 */
110 if (libWin32kInstalled())
111 {
112 rc = DosAllocMemEx(lplpMemAddr, cbSize, flFlags | fMemFlags | OBJ_ALIGN64K);
113 if (rc != ERROR_NOT_SUPPORTED) /* This call was stubbed until recently. */
114 return rc;
115 }
116
117 /*
118 * If no or old Win32k fall back to old method.
119 */
120
121 rc = DosAllocMem(&pvMemAddr, cbSize, flFlags | fMemFlags);
122 if(rc) {
123 dprintf(("!ERROR!: DosAllocMem failed with rc %d", rc));
124 return rc;
125 }
126 // already 64k aligned ?
127 if((ULONG) pvMemAddr & 0xFFFF)
128 {
129 ULONG addr64kb;
130
131 //free misaligned allocated memory
132 DosFreeMem(pvMemAddr);
133
134 //Allocate 64kb more so we can round the address to a 64kb aligned value
135 rc = DosAllocMem((PPVOID)&addr64kb, cbSize + 64*1024, (flFlags & ~PAG_COMMIT) | fMemFlags);
136 if(rc) {
137 dprintf(("!ERROR!: DosAllocMem failed with rc %d", rc));
138 return rc;
139 }
140 dprintf(("Allocate aligned memory %x -> %x", addr64kb, (addr64kb + 0xFFFF) & ~0xFFFF));
141
142 if(addr64kb & 0xFFFF) {
143 addr64kb = (addr64kb + 0xFFFF) & ~0xFFFF;
144 }
145 pvMemAddr = (PVOID)addr64kb;
146
147 //and set the correct page flags for the request range
148 if((flFlags & ~PAG_COMMIT) != flFlags) {
149 rc = DosSetMem(pvMemAddr, cbSize, flFlags);
150 if(rc) {
151 dprintf(("!ERROR!: DosSetMem failed with rc %d", rc));
152 return rc;
153 }
154 }
155 }
156
157 if(!rc)
158 *lplpMemAddr = pvMemAddr;
159
160 return rc;
161}
162//******************************************************************************
163//Locate the base page of a memory allocation (the page with the PAG_BASE attribute)
164//******************************************************************************
165PVOID OSLibDosFindMemBase(LPVOID lpMemAddr)
166{
167 ULONG ulAttr, ulSize, ulAddr;
168 APIRET rc;
169
170 rc = DosQueryMem(lpMemAddr, &ulSize, &ulAttr);
171 if(rc != NO_ERROR) {
172 dprintf(("!ERROR!: OSLibDosFindMemBase: DosQueryMem %x failed with rc %d", lpMemAddr, rc));
173 return lpMemAddr;
174 }
175 if(!(ulAttr & PAG_BASE)) {
176 //Not the base of the initial allocation (can happen due to alignment) or app
177 //passing address inside memory allocation range
178 ulAddr = (DWORD)lpMemAddr & ~0xFFF;
179 ulAddr -= PAGE_SIZE;
180
181 while(ulAddr > 0)
182 {
183 rc = DosQueryMem((PVOID)ulAddr, &ulSize, &ulAttr);
184 if(rc) {
185 dprintf(("!ERROR!: OSLibDosFindMemBase: DosQueryMem %x failed with rc %d", lpMemAddr, rc));
186 DebugInt3();
187 return NULL;
188 }
189 if(ulAttr & PAG_BASE) {
190 //Memory below the 512 MB boundary is always aligned at 64kb and VirtualAlloc only
191 //returns high memory (if OS/2 version supports it)
192 //If it is above the 512 MB boundary, then we must make sure the right base address
193 //is returned. VirtualAlloc allocates extra memory to make sure it can return addresses
194 //aligned at 64kb. If extra pages are needed, then the allocation base is inside
195 //the filler region. In that case we must return the next 64kb address as base.
196 if(ulAddr > MEM_TILED_CEILING) {
197 ulAddr = (ulAddr + 0xFFFF) & ~0xFFFF;
198 }
199 lpMemAddr = (PVOID)ulAddr;
200 break;
201 }
202 ulAddr -= PAGE_SIZE;
203 }
204 }
205 return lpMemAddr;
206}
207//******************************************************************************
208//******************************************************************************
209DWORD OSLibDosFreeMem(LPVOID lpMemAddr)
210{
211 ULONG ulAttr, ulSize, ulAddr;
212 APIRET rc;
213
214 ulAddr = (DWORD)lpMemAddr & ~0xFFF;
215 ulSize = 0x1000;
216
217 //Find base within previous 64kb (alignment can add filler pages)
218 for(int i=0;i<16;i++) {
219 rc = DosQueryMem((PVOID)ulAddr, &ulSize, &ulAttr);
220 if(rc != NO_ERROR) {
221 dprintf(("!ERROR!: OSLibDosFreeMem: DosQueryMem %x failed with rc %d", lpMemAddr, rc));
222 i = 16; //fail
223 break;
224 }
225 if(ulAttr & PAG_BASE) {
226 break;
227 }
228 ulAddr -= PAGE_SIZE;
229 }
230 if(i == 16) {
231 //oh, oh. didn't find base; shouldn't happen!!
232 dprintf(("!ERROR!: OSLibDosFreeMem: Unable to find base of %x", lpMemAddr));
233 DebugInt3();
234 }
235 else {
236 lpMemAddr = (PVOID)ulAddr;
237 }
238 return DosFreeMem(lpMemAddr);
239}
240//******************************************************************************
241//NOTE: If name == NULL, allocated gettable unnamed shared memory
242//OS/2 returns error 123 (invalid name) if the shared memory name includes
243//colons. We need to replace them with underscores.
244//******************************************************************************
245DWORD OSLibDosAllocSharedMem(LPVOID *lplpMemAddr, DWORD size, DWORD flags, LPSTR name)
246{
247 APIRET rc;
248 char *sharedmemname = NULL, *tmp;
249
250 if(name) {
251 sharedmemname = (char *)malloc(strlen(name) + 16);
252 strcpy(sharedmemname, "\\SHAREMEM\\");
253 strcat(sharedmemname, name);
254 }
255 else flags |= OBJ_GETTABLE;
256
257 //SvL: Colons are unacceptable in shared memory names (for whatever reason)
258 tmp = sharedmemname;
259 while(*tmp != 0) {
260 if(*tmp == ':') {
261 *tmp = '_';
262 }
263 tmp++;
264 }
265
266 rc = DosAllocSharedMem(lplpMemAddr, sharedmemname, size, flags);
267 if(name) {
268 free(sharedmemname);
269 }
270 return rc;
271}
272//******************************************************************************
273//NOTE: If name == NULL, assume gettable unnamed shared memory
274//******************************************************************************
275DWORD OSLibDosGetNamedSharedMem(LPVOID *lplpMemAddr, LPSTR name)
276{
277 APIRET rc;
278 char *sharedmemname = NULL, *tmp;
279
280 if(name) {
281 sharedmemname = (char *)malloc(strlen(name) + 16);
282 strcpy(sharedmemname, "\\SHAREMEM\\");
283 strcat(sharedmemname, name);
284
285 //SvL: Colons are unacceptable in shared memory names (for whatever reason)
286 tmp = sharedmemname;
287 while(*tmp != 0) {
288 if(*tmp == ':') {
289 *tmp = '_';
290 }
291 tmp++;
292 }
293 rc = DosGetNamedSharedMem(lplpMemAddr, sharedmemname, PAG_READ|PAG_WRITE);
294 if(name) {
295 free(sharedmemname);
296 }
297 }
298 else rc = DosGetSharedMem((LPVOID)*(DWORD *)lplpMemAddr, PAG_READ|PAG_WRITE);
299
300 return rc;
301}
302//******************************************************************************
303//******************************************************************************
304DWORD OSLibDosQueryMem(LPVOID lpMemAddr, DWORD *lpRangeSize, DWORD *lpAttr)
305{
306 return DosQueryMem(lpMemAddr, lpRangeSize, lpAttr);
307}
308//******************************************************************************
309//******************************************************************************
310DWORD OSLibDosSetMem(LPVOID lpMemAddr, DWORD size, DWORD flags)
311{
312 APIRET rc;
313
314 rc = DosSetMem(lpMemAddr, size, flags);
315 switch(rc) {
316 case ERROR_INVALID_ADDRESS:
317 return OSLIB_ERROR_INVALID_ADDRESS;
318 case ERROR_ACCESS_DENIED:
319 return OSLIB_ERROR_ACCESS_DENIED;
320 default:
321 return rc;
322 }
323}
324//******************************************************************************
325//******************************************************************************
Note: See TracBrowser for help on using the repository browser.