2 * Wine portability routines
4 * Copyright 2000 Alexandre Julliard
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.
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.
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
22 #include "wine/port.h"
29 #include <sys/types.h>
30 #ifdef HAVE_SYS_MMAN_H
40 #include "wine/library.h"
41 #include "wine/pthread.h"
43 /* Note: the wine_pthread functions are just placeholders,
44 * they will be overridden by the pthread support code.
47 /***********************************************************************
48 * wine_pthread_init_process
50 void wine_pthread_init_process( const struct wine_pthread_functions *functions )
54 /***********************************************************************
55 * wine_pthread_init_thread
57 void wine_pthread_init_thread( struct wine_pthread_thread_info *info )
61 /***********************************************************************
62 * wine_pthread_create_thread
64 int wine_pthread_create_thread( struct wine_pthread_thread_info *info )
69 /***********************************************************************
70 * wine_pthread_get_current_teb
72 void *wine_pthread_get_current_teb(void)
77 /***********************************************************************
78 * wine_pthread_exit_thread
80 void wine_pthread_exit_thread( struct wine_pthread_thread_info *info )
82 exit( info->exit_status );
85 /***********************************************************************
86 * wine_pthread_abort_thread
88 void wine_pthread_abort_thread( int status )
94 /***********************************************************************
95 * wine_switch_to_stack
97 * Switch to the specified stack and call the function.
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 */
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 )
112 __asm mov ecx, 4[esp];
113 __asm mov edx, 8[esp];
114 __asm mov esp, 12[esp];
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 */
143 #error You must implement wine_switch_to_stack for your platform
147 static char *pe_area;
148 static size_t pe_area_size;
150 /***********************************************************************
151 * wine_set_pe_load_area
153 * Define the reserved area to use for loading the main PE binary.
155 void wine_set_pe_load_area( void *base, size_t size )
157 unsigned int page_mask = getpagesize() - 1;
158 char *end = (char *)base + size;
160 pe_area = (char *)(((unsigned long)base + page_mask) & ~page_mask);
161 pe_area_size = (end - pe_area) & ~page_mask;
165 /***********************************************************************
166 * wine_free_pe_load_area
168 * Free the reserved area to use for loading the main PE binary.
170 void wine_free_pe_load_area(void)
173 if (pe_area) munmap( pe_area, pe_area_size );
179 #if (defined(__svr4__) || defined(__NetBSD__)) && !defined(MAP_TRYFIXED)
180 /***********************************************************************
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.
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.
197 static int try_mmap_fixed (void *addr, size_t len, int prot, int flags,
198 int fildes, off_t off)
200 char * volatile result = NULL;
201 int pagesize = getpagesize();
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. */
210 if ( (uintptr_t)addr & (pagesize-1) )
212 if ( flags & MAP_FIXED )
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. */
222 if ( (pid = vfork()) == -1 )
224 perror("try_mmap_fixed: vfork");
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 )
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 )
245 if ( result != (void *) -1 ) /* This should never happen ... */
246 munmap( result, len );
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. */
255 return result == addr;
257 #endif /* (__svr4__ || __NetBSD__) && !MAP_TRYFIXED */
260 /***********************************************************************
263 * Portable wrapper for anonymous mmaps
265 void *wine_anon_mmap( void *start, size_t size, int prot, int flags )
268 static int fdzero = -1;
275 if ((fdzero = open( "/dev/zero", O_RDONLY )) == -1)
277 perror( "/dev/zero: open" );
281 #endif /* MAP_ANON */
284 flags &= ~MAP_SHARED;
287 /* Linux EINVAL's on us if we don't pass MAP_PRIVATE to an anon mmap */
289 flags |= MAP_PRIVATE;
292 if (pe_area && start &&
293 (char *)start >= pe_area &&
294 (char *)start + size <= pe_area + pe_area_size)
296 wine_free_pe_load_area();
300 if (!(flags & MAP_FIXED))
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 ) )
310 return mmap( start, size, prot, flags, fdzero, 0 );