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

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

Rewrote algorithm for 64kb alignment in VirtualAlloc'ed memory; allocation changes for heap (in 64kb chunks) & PE image (align at 64kb)

File size: 10.5 KB
Line 
1/* $Id: oslibmem.cpp,v 1.3 2002-07-15 14:28:52 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)
97{
98 PVOID pvMemAddr;
99 DWORD offset;
100 APIRET rc;
101
102 /*
103 * Let's try use the extended DosAllocMem API of Win32k.sys.
104 */
105 if (libWin32kInstalled())
106 {
107 rc = DosAllocMemEx(lplpMemAddr, cbSize, flFlags | flAllocMem | OBJ_ALIGN64K);
108 if (rc != ERROR_NOT_SUPPORTED) /* This call was stubbed until recently. */
109 return rc;
110 }
111
112 /*
113 * If no or old Win32k fall back to old method.
114 */
115
116 rc = DosAllocMem(&pvMemAddr, cbSize, flFlags | flAllocMem);
117 if(rc) {
118 dprintf(("!ERROR!: DosAllocMem failed with rc %d", rc));
119 return rc;
120 }
121 // already 64k aligned ?
122 if((ULONG) pvMemAddr & 0xFFFF)
123 {
124 ULONG addr64kb;
125
126 //free misaligned allocated memory
127 DosFreeMem(pvMemAddr);
128
129 //Allocate 64kb more so we can round the address to a 64kb aligned value
130 rc = DosAllocMem((PPVOID)&addr64kb, cbSize + 64*1024, (flFlags & ~PAG_COMMIT) | flAllocMem);
131 if(rc) {
132 dprintf(("!ERROR!: DosAllocMem failed with rc %d", rc));
133 return rc;
134 }
135 dprintf(("Allocate aligned memory %x -> %x", addr64kb, (addr64kb + 0xFFFF) & ~0xFFFF));
136
137 if(addr64kb & 0xFFFF) {
138 addr64kb = (addr64kb + 0xFFFF) & ~0xFFFF;
139 }
140 pvMemAddr = (PVOID)addr64kb;
141
142 //and set the correct page flags for the request range
143 if((flFlags & ~PAG_COMMIT) != flFlags) {
144 rc = DosSetMem(pvMemAddr, cbSize, flFlags);
145 if(rc) {
146 dprintf(("!ERROR!: DosSetMem failed with rc %d", rc));
147 return rc;
148 }
149 }
150 }
151
152 if(!rc)
153 *lplpMemAddr = pvMemAddr;
154
155 return rc;
156}
157//******************************************************************************
158//Locate the base page of a memory allocation (the page with the PAG_BASE attribute)
159//******************************************************************************
160PVOID OSLibDosFindMemBase(LPVOID lpMemAddr)
161{
162 ULONG ulAttr, ulSize, ulAddr;
163 APIRET rc;
164
165 rc = DosQueryMem(lpMemAddr, &ulSize, &ulAttr);
166 if(rc != NO_ERROR) {
167 dprintf(("!ERROR!: OSLibDosFindMemBase: DosQueryMem %x failed with rc %d", lpMemAddr, rc));
168 return lpMemAddr;
169 }
170 if(!(ulAttr & PAG_BASE)) {
171 //Not the base of the initial allocation (can happen due to alignment) or app
172 //passing address inside memory allocation range
173 ulAddr = (DWORD)lpMemAddr & ~0xFFF;
174 ulAddr -= PAGE_SIZE;
175
176 while(ulAddr > 0)
177 {
178 rc = DosQueryMem((PVOID)ulAddr, &ulSize, &ulAttr);
179 if(rc) {
180 dprintf(("!ERROR!: OSLibDosFindMemBase: DosQueryMem %x failed with rc %d", lpMemAddr, rc));
181 DebugInt3();
182 return NULL;
183 }
184 if(ulAttr & PAG_BASE) {
185 //Memory below the 512 MB boundary is always aligned at 64kb and VirtualAlloc only
186 //returns high memory (if OS/2 version supports it)
187 //If it is above the 512 MB boundary, then we must make sure the right base address
188 //is returned. VirtualAlloc allocates extra memory to make sure it can return addresses
189 //aligned at 64kb. If extra pages are needed, then the allocation base is inside
190 //the filler region. In that case we must return the next 64kb address as base.
191 if(ulAddr > MEM_TILED_CEILING) {
192 ulAddr = (ulAddr + 0xFFFF) & ~0xFFFF;
193 }
194 lpMemAddr = (PVOID)ulAddr;
195 break;
196 }
197 ulAddr -= PAGE_SIZE;
198 }
199 }
200 return lpMemAddr;
201}
202//******************************************************************************
203//******************************************************************************
204DWORD OSLibDosFreeMem(LPVOID lpMemAddr)
205{
206 ULONG ulAttr, ulSize, ulAddr;
207 APIRET rc;
208
209 ulAddr = (DWORD)lpMemAddr & ~0xFFF;
210
211 //Find base within previous 64kb (alignment can add filler pages)
212 for(int i=0;i<16;i++) {
213 rc = DosQueryMem((PVOID)ulAddr, &ulSize, &ulAttr);
214 if(rc != NO_ERROR) {
215 dprintf(("!ERROR!: OSLibDosFreeMem: DosQueryMem %x failed with rc %d", lpMemAddr, rc));
216 i = 16; //fail
217 break;
218 }
219 if(ulAttr & PAG_BASE) {
220 break;
221 }
222 ulAddr -= PAGE_SIZE;
223 }
224 if(i == 16) {
225 //oh, oh. didn't find base; shouldn't happen!!
226 dprintf(("!ERROR!: OSLibDosFreeMem: Unable to find base of %x", lpMemAddr));
227 DebugInt3();
228 }
229 else {
230 lpMemAddr = (PVOID)ulAddr;
231 }
232 return DosFreeMem(lpMemAddr);
233}
234//******************************************************************************
235//NOTE: If name == NULL, allocated gettable unnamed shared memory
236//OS/2 returns error 123 (invalid name) if the shared memory name includes
237//colons. We need to replace them with underscores.
238//******************************************************************************
239DWORD OSLibDosAllocSharedMem(LPVOID *lplpMemAddr, DWORD size, DWORD flags, LPSTR name)
240{
241 APIRET rc;
242 char *sharedmemname = NULL, *tmp;
243
244 if(name) {
245 sharedmemname = (char *)malloc(strlen(name) + 16);
246 strcpy(sharedmemname, "\\SHAREMEM\\");
247 strcat(sharedmemname, name);
248 }
249 else flags |= OBJ_GETTABLE;
250
251 //SvL: Colons are unacceptable in shared memory names (for whatever reason)
252 tmp = sharedmemname;
253 while(*tmp != 0) {
254 if(*tmp == ':') {
255 *tmp = '_';
256 }
257 tmp++;
258 }
259
260 rc = DosAllocSharedMem(lplpMemAddr, sharedmemname, size, flags);
261 if(name) {
262 free(sharedmemname);
263 }
264 return rc;
265}
266//******************************************************************************
267//NOTE: If name == NULL, assume gettable unnamed shared memory
268//******************************************************************************
269DWORD OSLibDosGetNamedSharedMem(LPVOID *lplpMemAddr, LPSTR name)
270{
271 APIRET rc;
272 char *sharedmemname = NULL, *tmp;
273
274 if(name) {
275 sharedmemname = (char *)malloc(strlen(name) + 16);
276 strcpy(sharedmemname, "\\SHAREMEM\\");
277 strcat(sharedmemname, name);
278
279 //SvL: Colons are unacceptable in shared memory names (for whatever reason)
280 tmp = sharedmemname;
281 while(*tmp != 0) {
282 if(*tmp == ':') {
283 *tmp = '_';
284 }
285 tmp++;
286 }
287 rc = DosGetNamedSharedMem(lplpMemAddr, sharedmemname, PAG_READ|PAG_WRITE);
288 if(name) {
289 free(sharedmemname);
290 }
291 }
292 else rc = DosGetSharedMem((LPVOID)*(DWORD *)lplpMemAddr, PAG_READ|PAG_WRITE);
293
294 return rc;
295}
296//******************************************************************************
297//******************************************************************************
298DWORD OSLibDosQueryMem(LPVOID lpMemAddr, DWORD *lpRangeSize, DWORD *lpAttr)
299{
300 return DosQueryMem(lpMemAddr, lpRangeSize, lpAttr);
301}
302//******************************************************************************
303//******************************************************************************
304DWORD OSLibDosSetMem(LPVOID lpMemAddr, DWORD size, DWORD flags)
305{
306 APIRET rc;
307
308 rc = DosSetMem(lpMemAddr, size, flags);
309 switch(rc) {
310 case ERROR_INVALID_ADDRESS:
311 return OSLIB_ERROR_INVALID_ADDRESS;
312 case ERROR_ACCESS_DENIED:
313 return OSLIB_ERROR_ACCESS_DENIED;
314 default:
315 return rc;
316 }
317}
318//******************************************************************************
319//******************************************************************************
Note: See TracBrowser for help on using the repository browser.