Porting fixes.
[wine] / libs / wine / port.c
1 /*
2  * Wine portability routines
3  *
4  * Copyright 2000 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <assert.h>
25 #include <ctype.h>
26 #include <fcntl.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <sys/types.h>
30 #ifdef HAVE_SYS_MMAN_H
31 #include <sys/mman.h>
32 #endif
33 #ifdef HAVE_UNISTD_H
34 # include <unistd.h>
35 #endif
36 #ifdef HAVE_STDINT_H
37 # include <stdint.h>
38 #endif
39
40 #include "wine/library.h"
41 #include "wine/pthread.h"
42
43 /* Note: the wine_pthread functions are just placeholders,
44  * they will be overridden by the pthread support code.
45  */
46
47 /***********************************************************************
48  *           wine_pthread_init_process
49  */
50 void wine_pthread_init_process( const struct wine_pthread_functions *functions )
51 {
52 }
53
54 /***********************************************************************
55  *           wine_pthread_init_thread
56  */
57 void wine_pthread_init_thread( struct wine_pthread_thread_info *info )
58 {
59 }
60
61 /***********************************************************************
62  *           wine_pthread_create_thread
63  */
64 int wine_pthread_create_thread( struct wine_pthread_thread_info *info )
65 {
66     return -1;
67 }
68
69 /***********************************************************************
70  *           wine_pthread_get_current_teb
71  */
72 void *wine_pthread_get_current_teb(void)
73 {
74     return NULL;
75 }
76
77 /***********************************************************************
78  *           wine_pthread_exit_thread
79  */
80 void wine_pthread_exit_thread( struct wine_pthread_thread_info *info )
81 {
82     exit( info->exit_status );
83 }
84
85 /***********************************************************************
86  *           wine_pthread_abort_thread
87  */
88 void wine_pthread_abort_thread( int status )
89 {
90     exit( status );
91 }
92
93
94 /***********************************************************************
95  *           wine_switch_to_stack
96  *
97  * Switch to the specified stack and call the function.
98  */
99 void DECLSPEC_NORETURN wine_switch_to_stack( void (*func)(void *), void *arg, void *stack );
100 #if defined(__i386__) && defined(__GNUC__)
101 __ASM_GLOBAL_FUNC( wine_switch_to_stack,
102                    "movl 4(%esp),%ecx\n\t"  /* func */
103                    "movl 8(%esp),%edx\n\t"  /* arg */
104                    "movl 12(%esp),%esp\n\t"  /* stack */
105                    "pushl %edx\n\t"
106                    "xorl %ebp,%ebp\n\t"
107                    "call *%ecx\n\t"
108                    "int $3" /* we never return here */ );
109 #elif defined(__i386__) && defined(_MSC_VER)
110 __declspec(naked) void wine_switch_to_stack( void (*func)(void *), void *arg, void *stack )
111 {
112   __asm mov ecx, 4[esp];
113   __asm mov edx, 8[esp];
114   __asm mov esp, 12[esp];
115   __asm push edx;
116   __asm xor ebp, ebp;
117   __asm call [ecx];
118   __asm int 3;
119 }
120 #elif defined(__sparc__) && defined(__GNUC__)
121 __ASM_GLOBAL_FUNC( wine_switch_to_stack,
122                    "mov %o0, %l0\n\t" /* store first argument */
123                    "mov %o1, %l1\n\t" /* store second argument */
124                    "mov %o2, %sp\n\t" /* store stack */
125                    "call %l0, 0\n\t" /* call func */
126                    "mov %l1, %o0\n\t" /* delay slot:  arg for func */
127                    "ta 0x01"); /* breakpoint - we never get here */
128 #elif defined(__powerpc__) && defined(__APPLE__)
129 __ASM_GLOBAL_FUNC( wine_switch_to_stack,
130                    "mtctr r3\n\t" /* func -> ctr */
131                    "mr r3,r4\n\t" /* args -> function param 1 (r3) */
132                    "mr r1,r5\n\t" /* stack */
133                    "bctr\n" /* call ctr */
134                    "1:\tb 1b"); /* loop */
135 #elif defined(__powerpc__) && defined(__GNUC__)
136 __ASM_GLOBAL_FUNC( wine_switch_to_stack,
137                    "mtctr 3\n\t" /* func -> ctr */
138                    "mr 3,4\n\t" /* args -> function param 1 (r3) */
139                    "mr 1,5\n\t" /* stack */
140                    "bctr\n\t" /* call ctr */
141                    "1:\tb 1b"); /* loop */
142 #else
143 #error You must implement wine_switch_to_stack for your platform
144 #endif
145
146
147 static char *pe_area;
148 static size_t pe_area_size;
149
150 /***********************************************************************
151  *              wine_set_pe_load_area
152  *
153  * Define the reserved area to use for loading the main PE binary.
154  */
155 void wine_set_pe_load_area( void *base, size_t size )
156 {
157     unsigned int page_mask = getpagesize() - 1;
158     char *end = (char *)base + size;
159
160     pe_area = (char *)(((unsigned long)base + page_mask) & ~page_mask);
161     pe_area_size = (end - pe_area) & ~page_mask;
162 }
163
164
165 /***********************************************************************
166  *              wine_free_pe_load_area
167  *
168  * Free the reserved area to use for loading the main PE binary.
169  */
170 void wine_free_pe_load_area(void)
171 {
172 #ifdef HAVE_MMAP
173     if (pe_area) munmap( pe_area, pe_area_size );
174 #endif
175     pe_area = NULL;
176 }
177
178
179 #if (defined(__svr4__) || defined(__NetBSD__)) && !defined(MAP_TRYFIXED)
180 /***********************************************************************
181  *             try_mmap_fixed
182  *
183  * The purpose of this routine is to emulate the behaviour of
184  * the Linux mmap() routine if a non-NULL address is passed,
185  * but the MAP_FIXED flag is not set.  Linux in this case tries
186  * to place the mapping at the specified address, *unless* the
187  * range is already in use.  Solaris, however, completely ignores
188  * the address argument in this case.
189  *
190  * As Wine code occasionally relies on the Linux behaviour, e.g. to
191  * be able to map non-relocateable PE executables to their proper
192  * start addresses, or to map the DOS memory to 0, this routine
193  * emulates the Linux behaviour by checking whether the desired
194  * address range is still available, and placing the mapping there
195  * using MAP_FIXED if so.
196  */
197 static int try_mmap_fixed (void *addr, size_t len, int prot, int flags,
198                            int fildes, off_t off)
199 {
200     char * volatile result = NULL;
201     int pagesize = getpagesize();
202     pid_t pid;
203
204     /* We only try to map to a fixed address if
205        addr is non-NULL and properly aligned,
206        and MAP_FIXED isn't already specified. */
207
208     if ( !addr )
209         return 0;
210     if ( (uintptr_t)addr & (pagesize-1) )
211         return 0;
212     if ( flags & MAP_FIXED )
213         return 0;
214
215     /* We use vfork() to freeze all threads of the
216        current process.  This allows us to check without
217        race condition whether the desired memory range is
218        already in use.  Note that because vfork() shares
219        the address spaces between parent and child, we
220        can actually perform the mapping in the child. */
221
222     if ( (pid = vfork()) == -1 )
223     {
224         perror("try_mmap_fixed: vfork");
225         exit(1);
226     }
227     if ( pid == 0 )
228     {
229         int i;
230         char vec;
231
232         /* We call mincore() for every page in the desired range.
233            If any of these calls succeeds, the page is already
234            mapped and we must fail. */
235         for ( i = 0; i < len; i += pagesize )
236             if ( mincore( (caddr_t)addr + i, pagesize, &vec ) != -1 )
237                _exit(1);
238
239         /* Perform the mapping with MAP_FIXED set.  This is safe
240            now, as none of the pages is currently in use. */
241         result = mmap( addr, len, prot, flags | MAP_FIXED, fildes, off );
242         if ( result == addr )
243             _exit(0);
244
245         if ( result != (void *) -1 ) /* This should never happen ... */
246             munmap( result, len );
247
248        _exit(1);
249     }
250
251     /* vfork() lets the parent continue only after the child
252        has exited.  Furthermore, Wine sets SIGCHLD to SIG_IGN,
253        so we don't need to wait for the child. */
254
255     return result == addr;
256 }
257 #endif  /* (__svr4__ || __NetBSD__) && !MAP_TRYFIXED */
258
259
260 /***********************************************************************
261  *              wine_anon_mmap
262  *
263  * Portable wrapper for anonymous mmaps
264  */
265 void *wine_anon_mmap( void *start, size_t size, int prot, int flags )
266 {
267 #ifdef HAVE_MMAP
268     static int fdzero = -1;
269
270 #ifdef MAP_ANON
271     flags |= MAP_ANON;
272 #else
273     if (fdzero == -1)
274     {
275         if ((fdzero = open( "/dev/zero", O_RDONLY )) == -1)
276         {
277             perror( "/dev/zero: open" );
278             exit(1);
279         }
280     }
281 #endif  /* MAP_ANON */
282
283 #ifdef MAP_SHARED
284     flags &= ~MAP_SHARED;
285 #endif
286
287     /* Linux EINVAL's on us if we don't pass MAP_PRIVATE to an anon mmap */
288 #ifdef MAP_PRIVATE
289     flags |= MAP_PRIVATE;
290 #endif
291
292     if (pe_area && start &&
293         (char *)start >= pe_area &&
294         (char *)start + size <= pe_area + pe_area_size)
295     {
296         wine_free_pe_load_area();
297         flags |= MAP_FIXED;
298     }
299
300     if (!(flags & MAP_FIXED))
301     {
302 #ifdef MAP_TRYFIXED
303         /* If available, this will attempt a fixed mapping in-kernel */
304         flags |= MAP_TRYFIXED;
305 #elif defined(__svr4__) || defined(__NetBSD__)
306         if ( try_mmap_fixed( start, size, prot, flags, fdzero, 0 ) )
307             return start;
308 #endif
309     }
310     return mmap( start, size, prot, flags, fdzero, 0 );
311 #else
312     return (void *)-1;
313 #endif
314 }