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_init_current_teb
72 void wine_pthread_init_current_teb( struct wine_pthread_thread_info
*info
)
76 /***********************************************************************
77 * wine_pthread_get_current_teb
79 void *wine_pthread_get_current_teb(void)
84 /***********************************************************************
85 * wine_pthread_exit_thread
87 void wine_pthread_exit_thread( struct wine_pthread_thread_info
*info
)
89 exit( info
->exit_status
);
92 /***********************************************************************
93 * wine_pthread_abort_thread
95 void wine_pthread_abort_thread( int status
)
101 /***********************************************************************
102 * wine_switch_to_stack
104 * Switch to the specified stack and call the function.
106 void DECLSPEC_NORETURN
wine_switch_to_stack( void (*func
)(void *), void *arg
, void *stack
);
107 #if defined(__i386__) && defined(__GNUC__)
108 __ASM_GLOBAL_FUNC( wine_switch_to_stack
,
109 "movl 4(%esp),%ecx\n\t" /* func */
110 "movl 8(%esp),%edx\n\t" /* arg */
111 "movl 12(%esp),%esp\n\t" /* stack */
115 "int $3" /* we never return here */ );
116 #elif defined(__i386__) && defined(_MSC_VER)
117 __declspec(naked
) void wine_switch_to_stack( void (*func
)(void *), void *arg
, void *stack
)
119 __asm mov ecx
, 4[esp
];
120 __asm mov edx
, 8[esp
];
121 __asm mov esp
, 12[esp
];
127 #elif defined(__sparc__) && defined(__GNUC__)
128 __ASM_GLOBAL_FUNC( wine_switch_to_stack
,
129 "mov %o0, %l0\n\t" /* store first argument */
130 "mov %o1, %l1\n\t" /* store second argument */
131 "mov %o2, %sp\n\t" /* store stack */
132 "call %l0, 0\n\t" /* call func */
133 "mov %l1, %o0\n\t" /* delay slot: arg for func */
134 "ta 0x01"); /* breakpoint - we never get here */
135 #elif defined(__powerpc__) && defined(__APPLE__)
136 __ASM_GLOBAL_FUNC( wine_switch_to_stack
,
137 "mtctr r3\n\t" /* func -> ctr */
138 "mr r3,r4\n\t" /* args -> function param 1 (r3) */
139 "mr r1,r5\n\t" /* stack */
140 "bctr\n" /* call ctr */
141 "1:\tb 1b"); /* loop */
142 #elif defined(__powerpc__) && defined(__GNUC__)
143 __ASM_GLOBAL_FUNC( wine_switch_to_stack
,
144 "mtctr 3\n\t" /* func -> ctr */
145 "mr 3,4\n\t" /* args -> function param 1 (r3) */
146 "mr 1,5\n\t" /* stack */
147 "bctr\n\t" /* call ctr */
148 "1:\tb 1b"); /* loop */
150 #error You must implement wine_switch_to_stack for your platform
154 static char *pe_area
;
155 static size_t pe_area_size
;
157 /***********************************************************************
158 * wine_set_pe_load_area
160 * Define the reserved area to use for loading the main PE binary.
162 void wine_set_pe_load_area( void *base
, size_t size
)
164 unsigned int page_mask
= getpagesize() - 1;
165 char *end
= (char *)base
+ size
;
167 pe_area
= (char *)(((unsigned long)base
+ page_mask
) & ~page_mask
);
168 pe_area_size
= (end
- pe_area
) & ~page_mask
;
172 /***********************************************************************
173 * wine_free_pe_load_area
175 * Free the reserved area to use for loading the main PE binary.
177 void wine_free_pe_load_area(void)
180 if (pe_area
) munmap( pe_area
, pe_area_size
);
186 #if (defined(__svr4__) || defined(__NetBSD__)) && !defined(MAP_TRYFIXED)
187 /***********************************************************************
190 * The purpose of this routine is to emulate the behaviour of
191 * the Linux mmap() routine if a non-NULL address is passed,
192 * but the MAP_FIXED flag is not set. Linux in this case tries
193 * to place the mapping at the specified address, *unless* the
194 * range is already in use. Solaris, however, completely ignores
195 * the address argument in this case.
197 * As Wine code occasionally relies on the Linux behaviour, e.g. to
198 * be able to map non-relocateable PE executables to their proper
199 * start addresses, or to map the DOS memory to 0, this routine
200 * emulates the Linux behaviour by checking whether the desired
201 * address range is still available, and placing the mapping there
202 * using MAP_FIXED if so.
204 static int try_mmap_fixed (void *addr
, size_t len
, int prot
, int flags
,
205 int fildes
, off_t off
)
207 char * volatile result
= NULL
;
208 int pagesize
= getpagesize();
211 /* We only try to map to a fixed address if
212 addr is non-NULL and properly aligned,
213 and MAP_FIXED isn't already specified. */
217 if ( (uintptr_t)addr
& (pagesize
-1) )
219 if ( flags
& MAP_FIXED
)
222 /* We use vfork() to freeze all threads of the
223 current process. This allows us to check without
224 race condition whether the desired memory range is
225 already in use. Note that because vfork() shares
226 the address spaces between parent and child, we
227 can actually perform the mapping in the child. */
229 if ( (pid
= vfork()) == -1 )
231 perror("try_mmap_fixed: vfork");
239 /* We call mincore() for every page in the desired range.
240 If any of these calls succeeds, the page is already
241 mapped and we must fail. */
242 for ( i
= 0; i
< len
; i
+= pagesize
)
243 if ( mincore( (caddr_t
)addr
+ i
, pagesize
, &vec
) != -1 )
246 /* Perform the mapping with MAP_FIXED set. This is safe
247 now, as none of the pages is currently in use. */
248 result
= mmap( addr
, len
, prot
, flags
| MAP_FIXED
, fildes
, off
);
249 if ( result
== addr
)
252 if ( result
!= (void *) -1 ) /* This should never happen ... */
253 munmap( result
, len
);
258 /* vfork() lets the parent continue only after the child
259 has exited. Furthermore, Wine sets SIGCHLD to SIG_IGN,
260 so we don't need to wait for the child. */
262 return result
== addr
;
264 #endif /* (__svr4__ || __NetBSD__) && !MAP_TRYFIXED */
267 /***********************************************************************
270 * Portable wrapper for anonymous mmaps
272 void *wine_anon_mmap( void *start
, size_t size
, int prot
, int flags
)
275 static int fdzero
= -1;
282 if ((fdzero
= open( "/dev/zero", O_RDONLY
)) == -1)
284 perror( "/dev/zero: open" );
288 #endif /* MAP_ANON */
291 flags
&= ~MAP_SHARED
;
294 /* Linux EINVAL's on us if we don't pass MAP_PRIVATE to an anon mmap */
296 flags
|= MAP_PRIVATE
;
299 if (pe_area
&& start
&&
300 (char *)start
>= pe_area
&&
301 (char *)start
+ size
<= pe_area
+ pe_area_size
)
303 wine_free_pe_load_area();
307 if (!(flags
& MAP_FIXED
))
310 /* If available, this will attempt a fixed mapping in-kernel */
311 flags
|= MAP_TRYFIXED
;
312 #elif defined(__svr4__) || defined(__NetBSD__)
313 if ( try_mmap_fixed( start
, size
, prot
, flags
, fdzero
, 0 ) )
317 return mmap( start
, size
, prot
, flags
, fdzero
, 0 );