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

Last change on this file since 9911 was 9911, checked in by sandervl, 22 years ago

cleanup/resync

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