Release 960623
[wine] / win32 / memory.c
1 /*
2  * Win32 kernel functions
3  *
4  * Copyright 1995 Martin von Loewis and Cameron Heide
5  */
6
7 #include <fcntl.h>
8 #include <malloc.h>
9 #include <stdio.h>
10 #include <string.h>
11 #include <sys/time.h>
12 #include <unistd.h>
13 #include <sys/mman.h>
14 #include <string.h>
15 #include <stdlib.h>
16 #include "windows.h"
17 #include "winerror.h"
18 #include "kernel32.h"
19 #include "winbase.h"
20 #include "handle32.h"
21 #include "stddebug.h"
22 #include "debug.h"
23
24 #ifndef PROT_NONE  /* FreeBSD doesn't define PROT_NONE */
25 #define PROT_NONE 0
26 #endif
27
28 typedef struct {
29     caddr_t     ptr;
30     long        size;
31 } virtual_mem_t;
32
33 virtual_mem_t *mem = 0;
34 int mem_count = 0;
35 int mem_used = 0;
36
37 /*******************************************************************
38  *                   VRANGE
39  * A VRANGE denotes a contiguous part of the address space. It is used
40  * for house keeping, and will be obtained by higher-level memory allocation
41  * functions (VirtualAlloc, MapViewOfFile)
42  * There can be at most one VRANGE object covering any address at any time.
43  * Currently, all VRANGE objects are stored in a sorted list. Wine does not
44  * attempt to give a complete list of in-use address ranges, only those
45  * allocated via Win32.
46  * An exception is IsVrangeFree, which should test the OS specific 
47  * mappings, too. As a default, an range not known to be allocated is 
48  * considered free.
49  *******************************************************************/
50
51 VRANGE_OBJECT *MEMORY_ranges=0;
52
53 VRANGE_OBJECT *MEMORY_FindVrange(DWORD start)
54 {
55         VRANGE_OBJECT *range;
56         for(range=MEMORY_ranges;range && range->start<start;range=range->next)
57         {
58                 if(range->start<start && start<range->start+range->size)
59                         return range;
60         }
61         return 0;
62 }
63
64 static int MEMORY_IsVrangeFree(DWORD start,DWORD size)
65 {
66         DWORD end;
67         VRANGE_OBJECT *range;
68         if(!size)
69                 return 1;
70         /* First, check our lists*/
71         end=start+size;
72         for(range=MEMORY_ranges;range && range->start<start;range=range->next)
73         {
74                 if((range->start<start && start<range->start+range->size) ||
75                         (range->start<end && end<range->start+range->size))
76                 return 0;
77         }
78         /* Now, check the maps that are not under our control */
79 #ifdef linux
80         {
81         FILE *f=fopen("/proc/self/maps","r");
82         char line[80];
83         int found=0;
84         while(1)
85         {
86                 char *it;
87                 int lower,upper;
88                 if(!fgets(line,sizeof(line),f))
89                         break;
90                 it=line;
91                 lower=strtoul(it,&it,16);
92                 if(*it++!='-')
93                         fprintf(stderr,"Format of /proc/self/maps changed\n");
94                 upper=strtoul(it,&it,16);
95                 if((lower<start && start<upper) || (lower<start+size && start+size<upper))
96                 {
97                         found=1;
98                         break;
99                 }
100         }
101         fclose(f);
102         return !found;
103         }
104 #else
105         {
106         static int warned=0;
107         if(!warned)
108         {
109                 fprintf(stdnimp, "Don't know how to perform MEMORY_IsVrangeFree on "
110                         "this system.\n Please fix\n");
111                 warned=0;
112         }
113         return 1;
114         }
115 #endif
116 }
117
118 /* FIXME: might need to consolidate ranges */
119 void MEMORY_InsertVrange(VRANGE_OBJECT *r)
120 {
121         VRANGE_OBJECT *it,*last;
122         if(!MEMORY_ranges || r->start<MEMORY_ranges->start)
123         {
124                 r->next=MEMORY_ranges;
125                 MEMORY_ranges=r;
126         }
127         for(it=MEMORY_ranges,last=0;it && it->start<r->start;it=it->next)
128                 last=it;
129         r->next=last->next;
130         last->next=r;
131 }
132         
133
134 VRANGE_OBJECT *MEMORY_AllocVrange(int start,int size)
135 {
136         VRANGE_OBJECT *ret=CreateKernelObject(sizeof(VRANGE_OBJECT));
137         ret->common.magic=KERNEL_OBJECT_VRANGE;
138         MEMORY_InsertVrange(ret);
139         return ret;
140 }
141
142 void MEMORY_ReleaseVrange(VRANGE_OBJECT *r)
143 {
144         VRANGE_OBJECT *it;
145         if(MEMORY_ranges==r)
146         {
147                 MEMORY_ranges=r->next;
148                 ReleaseKernelObject(r);
149                 return;
150         }
151         for(it=MEMORY_ranges;it;it=it->next)
152                 if(it->next==r)break;
153         if(!it)
154         {
155                 fprintf(stderr,"VRANGE not found\n");
156                 return;
157         }
158         it->next=r->next;
159         ReleaseKernelObject(r);
160 }
161
162 /***********************************************************************
163  *           VirtualAlloc             (KERNEL32.548)
164  */
165 int TranslateProtectionFlags(DWORD);
166 LPVOID VirtualAlloc(LPVOID lpvAddress, DWORD cbSize,
167                    DWORD fdwAllocationType, DWORD fdwProtect)
168 {
169     caddr_t     ptr;
170     int i;
171     virtual_mem_t *tmp_mem;
172     int prot;
173     static int fdzero = -1;
174
175     if (fdzero == -1)
176     {
177         if ((fdzero = open( "/dev/zero", O_RDONLY )) == -1)
178         {
179             perror( "/dev/zero: open" );
180             return (LPVOID)NULL;
181         }
182     }
183
184     dprintf_win32(stddeb, "VirtualAlloc: size = %ld, address=%p\n", cbSize, lpvAddress);
185     if (fdwAllocationType & MEM_RESERVE || !lpvAddress) {
186         ptr = mmap((void *)((((unsigned long)lpvAddress-1) & 0xFFFF0000L) 
187                         + 0x00010000L),
188                    cbSize, PROT_NONE, MAP_PRIVATE, fdzero, 0 );
189         if (ptr == (caddr_t) -1) {
190             dprintf_win32(stddeb, "VirtualAlloc: returning NULL");
191             return (LPVOID) NULL;
192         }
193         if (lpvAddress && ((unsigned long)ptr & 0xFFFF0000L)) {
194             munmap(ptr, cbSize);
195             cbSize += 65535;
196             ptr =  mmap(lpvAddress, cbSize, 
197                         PROT_NONE, MAP_PRIVATE, fdzero, 0 );
198             if (ptr == (caddr_t) -1) {
199                 dprintf_win32(stddeb, "VirtualAlloc: returning NULL");
200                 return (LPVOID) NULL;
201             }
202             ptr = (void *)((((unsigned long)ptr-1) & 0xFFFF0000L)+0x00010000L);
203         }
204         /* remember the size for VirtualFree since it's going to be handed
205            a zero len */
206         if (ptr) {
207             if (mem_count == mem_used) {
208                 tmp_mem = realloc(mem,(mem_count+10)*sizeof(virtual_mem_t));
209                 if (!tmp_mem) return 0;
210                 mem = tmp_mem;
211                 memset(mem+mem_count, 0, 10*sizeof(virtual_mem_t));
212                 mem_count += 10;
213             }
214             for (i=0; i<mem_count; i++) {
215                 if (!(mem+i)->ptr) {
216                     (mem+i)->ptr = ptr;
217                     (mem+i)->size = cbSize;
218                     mem_used++;
219                     break;
220                 }
221             }
222         }
223     } else {
224         ptr = lpvAddress;
225     }
226     if (fdwAllocationType & MEM_COMMIT) {
227         prot = TranslateProtectionFlags(fdwProtect & 
228                                           ~(PAGE_GUARD | PAGE_NOCACHE));
229         mprotect(ptr, cbSize, prot);
230     }
231 #if 0
232 /* kludge for gnu-win32 */
233     if (fdwAllocationType & MEM_RESERVE) return sbrk(0);
234     ptr = malloc(cbSize + 65536);
235     if(ptr)
236     {
237         /* Round it up to the next 64K boundary and zero it.
238          */
239         ptr = (void *)(((unsigned long)ptr & 0xFFFF0000L) + 0x00010000L);
240         memset(ptr, 0, cbSize);
241     }
242 #endif
243     dprintf_win32(stddeb, "VirtualAlloc: got pointer %p\n", ptr);
244     return ptr;
245 }
246
247 /***********************************************************************
248  *           VirtualFree               (KERNEL32.550)
249  */
250 BOOL VirtualFree(LPVOID lpvAddress, DWORD cbSize, DWORD fdwFreeType)
251 {
252     int i;
253
254     if (fdwFreeType & MEM_RELEASE) {
255         for (i=0; i<mem_count; i++) {
256             if ((mem+i)->ptr == lpvAddress) {
257                  munmap(lpvAddress, (mem+i)->size);
258                  (mem+i)->ptr = 0;
259                  mem_used--;
260                  break;
261             }
262         }
263     } else {
264         mprotect(lpvAddress, cbSize, PROT_NONE);
265     }
266 #if 0
267     if(lpvAddress)
268         free(lpvAddress);
269 #endif
270     return 1;
271 }
272
273 int TranslateProtectionFlags(DWORD protection_flags)
274 {
275     int prot;
276
277         switch(protection_flags) {
278             case PAGE_READONLY:
279                 prot=PROT_READ;
280                 break;
281             case PAGE_READWRITE:
282                 prot=PROT_READ|PROT_WRITE;
283                 break;
284             case PAGE_WRITECOPY:
285                 prot=PROT_WRITE;
286                 break;
287             case PAGE_EXECUTE:
288                 prot=PROT_EXEC;
289                 break;
290             case PAGE_EXECUTE_READ:
291                 prot=PROT_EXEC|PROT_READ;
292                 break;
293             case PAGE_EXECUTE_READWRITE:
294                 prot=PROT_EXEC|PROT_READ|PROT_WRITE;
295                 break;
296             case PAGE_EXECUTE_WRITECOPY:
297                 prot=PROT_EXEC|PROT_WRITE;
298                 break;
299             case PAGE_NOACCESS:
300             default:
301                 prot=PROT_NONE;
302                 break;
303         }
304    return prot;
305 }
306
307
308 /******************************************************************
309  *                   IsBadReadPtr
310  */
311 BOOL WIN32_IsBadReadPtr(void* ptr, unsigned int bytes)
312 {
313         dprintf_global(stddeb,"IsBadReadPtr(%x,%x)\n",ptr,bytes);
314         /* FIXME: Should make check based on actual mappings, here */
315         return FALSE;
316 }
317
318 /******************************************************************
319  *                   IsBadWritePtr
320  */
321 BOOL WIN32_IsBadWritePtr(void* ptr, unsigned int bytes)
322 {
323         dprintf_global(stddeb,"IsBadWritePtr(%x,%x)\n",ptr,bytes);
324         /* FIXME: Should make check based on actual mappings, here */
325         return FALSE;
326 }
327 /******************************************************************
328  *                   IsBadWritePtr
329  */
330 BOOL WIN32_IsBadCodePtr(void* ptr, unsigned int bytes)
331 {
332         dprintf_global(stddeb,"IsBadCodePtr(%x,%x)\n",ptr,bytes);
333         /* FIXME: Should make check based on actual mappings, here */
334         return FALSE;
335 }