026923ae15d81c4d2d21b8a32a99dbfd995d62fa
[sbcl.git] / src / runtime / linux-os.c
1 /*
2  * the Linux incarnation of OS-dependent routines.  See also
3  * $(sbcl_arch)-linux-os.c
4  *
5  * This file (along with os.h) exports an OS-independent interface to
6  * the operating system VM facilities. Surprise surprise, this
7  * interface looks a lot like the Mach interface (but simpler in some
8  * places). For some operating systems, a subset of these functions
9  * will have to be emulated.
10  */
11
12 /*
13  * This software is part of the SBCL system. See the README file for
14  * more information.
15  *
16  * This software is derived from the CMU CL system, which was
17  * written at Carnegie Mellon University and released into the
18  * public domain. The software is in the public domain and is
19  * provided with absolutely no warranty. See the COPYING and CREDITS
20  * files for more information.
21  */
22
23 #include <stdio.h>
24 #include <sys/param.h>
25 #include <sys/file.h>
26 #include "sbcl.h"
27 #include "./signal.h"
28 #include "os.h"
29 #include "arch.h"
30 #include "globals.h"
31 #include "interrupt.h"
32 #include "interr.h"
33 #include "lispregs.h"
34 #include "runtime.h"
35 #include "genesis/static-symbols.h"
36 #include "genesis/fdefn.h"
37 #include <sys/socket.h>
38 #include <sys/utsname.h>
39 #include <errno.h>
40
41 #include <sys/types.h>
42 #include <signal.h>
43 /* #include <sys/sysinfo.h> */
44 #include <sys/time.h>
45 #include <sys/stat.h>
46 #include <unistd.h>
47 #include <linux/version.h>
48
49 #include "validate.h"
50 #include "thread.h"
51 #include "gc.h"
52 #if defined LISP_FEATURE_GENCGC
53 #include "gencgc-internal.h"
54 #endif
55
56 #ifdef LISP_FEATURE_X86
57 /* Prototype for personality(2). Done inline here since the header file
58  * for this isn't available on old versions of glibc. */
59 int personality (unsigned long);
60 #endif
61
62 size_t os_vm_page_size;
63
64 #ifdef LISP_FEATURE_SB_THREAD
65 #include <sys/syscall.h>
66 #include <unistd.h>
67 #include <errno.h>
68
69 /* values taken from the kernel's linux/futex.h.  This header file
70    doesn't exist in userspace, which is our excuse for not grovelling
71    them automatically */
72 #define FUTEX_WAIT (0)
73 #define FUTEX_WAKE (1)
74 #define FUTEX_FD (2)
75 #define FUTEX_REQUEUE (3)
76
77 #define sys_futex sbcl_sys_futex
78 static inline int sys_futex (void *futex, int op, int val, struct timespec *rel)
79 {
80     return syscall (SYS_futex, futex, op, val, rel);
81 }
82
83 int
84 futex_wait(int *lock_word, int oldval)
85 {
86     int t= sys_futex(lock_word,FUTEX_WAIT,oldval, 0);
87     return t;
88 }
89
90 int
91 futex_wake(int *lock_word, int n)
92 {
93     return sys_futex(lock_word,FUTEX_WAKE,n,0);
94 }
95 #endif
96
97 \f
98 int linux_sparc_siginfo_bug = 0;
99 int linux_no_threads_p = 0;
100
101 #ifdef LISP_FEATURE_SB_THREAD
102 int
103 isnptl (void)
104 {
105   size_t n = confstr (_CS_GNU_LIBPTHREAD_VERSION, NULL, 0);
106   if (n > 0) {
107       char *buf = alloca (n);
108       confstr (_CS_GNU_LIBPTHREAD_VERSION, buf, n);
109       if (strstr (buf, "NPTL")) {
110           return 1;
111       }
112   }
113   return 0;
114 }
115 #endif
116
117 void
118 os_init(char *argv[], char *envp[])
119 {
120     /* Conduct various version checks: do we have enough mmap(), is
121      * this a sparc running 2.2, can we do threads? */
122 #ifdef LISP_FEATURE_SB_THREAD
123     int *futex=0;
124 #endif
125     struct utsname name;
126     int major_version;
127     int minor_version;
128     int patch_version;
129     char *p;
130     uname(&name);
131     p=name.release;
132     major_version = atoi(p);
133     p=strchr(p,'.')+1;
134     minor_version = atoi(p);
135     p=strchr(p,'.')+1;
136     patch_version = atoi(p);
137     if (major_version<2) {
138         lose("linux kernel version too old: major version=%d (can't run in version < 2.0.0)\n",
139              major_version);
140     }
141     if (!(major_version>2 || minor_version >= 4)) {
142 #ifdef LISP_FEATURE_SPARC
143         FSHOW((stderr,"linux kernel %d.%d predates 2.4;\n enabling workarounds for SPARC kernel bugs in signal handling.\n", major_version,minor_version));
144         linux_sparc_siginfo_bug = 1;
145 #endif
146     }
147 #ifdef LISP_FEATURE_SB_THREAD
148     futex_wait(futex,-1);
149     if(errno==ENOSYS) {
150        lose("This version of SBCL is compiled with threading support, but your kernel\n"
151             "is too old to support this. Please use a more recent kernel or\n"
152             "a version of SBCL without threading support.\n");
153     }
154     if(! isnptl()) {
155        lose("This version of SBCL only works correctly with the NPTL threading\n"
156             "library. Please use a newer glibc, use an older SBCL, or stop using\n"
157             "LD_ASSUME_KERNEL\n");
158     }
159 #endif
160     os_vm_page_size = getpagesize();
161
162     /* KLUDGE: Disable memory randomization on new Linux kernels
163      * by setting a personality flag and re-executing. (We need
164      * to re-execute, since the memory maps that can conflict with
165      * the SBCL spaces have already been done at this point).
166      *
167      * Since randomization is currently implemented only on x86 kernels,
168      * don't do this trick on other platforms.
169      */
170 #ifdef LISP_FEATURE_X86
171     if ((major_version == 2
172          /* Some old kernels will apparently lose unsupported personality flags
173           * on exec() */
174          && ((minor_version == 6 && patch_version >= 11)
175              || (minor_version > 6)))
176         || major_version >= 3)
177     {
178         int pers = personality(0xffffffffUL);
179         /* 0x40000 aka. ADDR_NO_RANDOMIZE */
180         if (!(pers & 0x40000)) {
181             int retval = personality(pers | 0x40000);
182             /* Allegedly some Linux kernels (the reported case was
183              * "hardened Linux 2.6.7") won't set the new personality,
184              * but nor will they return -1 for an error. So as a
185              * workaround query the new personality...
186              */
187             int newpers = personality(0xffffffffUL);
188             /* ... and don't re-execute if either the setting resulted
189              * in an error or if the value didn't change. Otherwise
190              * this might result in an infinite loop.
191              */
192             if (retval != -1 && newpers != pers) {
193                 /* Use /proc/self/exe instead of trying to figure out
194                  * the executable path from PATH and argv[0], since
195                  * that's unreliable. We follow the symlink instead of
196                  * executing the file directly in order to prevent top
197                  * from displaying the name of the process as "exe". */
198                 char runtime[PATH_MAX+1];
199                 int i = readlink("/proc/self/exe", runtime, PATH_MAX);
200                 if (i != -1) {
201                     runtime[i] = '\0';
202                     execve(runtime, argv, envp);
203                 }
204             }
205             /* Either changing the personality or execve() failed. Either
206              * way we might as well continue, and hope that the random
207              * memory maps are ok this time around.
208              */
209             fprintf(stderr, "WARNING: Couldn't re-execute SBCL with the proper personality flags (maybe /proc isn't mounted?). Trying to continue anyway.\n");
210         }
211     }
212     /* Use SSE detector.  Recent versions of Linux enable SSE support
213      * on SSE capable CPUs.  */
214     /* FIXME: Are there any old versions that does not support SSE?  */
215     fast_bzero_pointer = fast_bzero_detect;
216 #endif
217 }
218
219
220 #ifdef LISP_FEATURE_ALPHA
221 /* The Alpha is a 64 bit CPU.  SBCL is a 32 bit application.  Due to all
222  * the places that assume we can get a pointer into a fixnum with no
223  * information loss, we have to make sure it allocates all its ram in the
224  * 0-2Gb region.  */
225
226 static void * under_2gb_free_pointer=DYNAMIC_1_SPACE_END;
227 #endif
228
229 os_vm_address_t
230 os_validate(os_vm_address_t addr, os_vm_size_t len)
231 {
232     int flags =  MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE;
233     os_vm_address_t actual;
234
235 #ifdef LISP_FEATURE_ALPHA
236     if (!addr) {
237         addr=under_2gb_free_pointer;
238     }
239 #endif
240     actual = mmap(addr, len, OS_VM_PROT_ALL, flags, -1, 0);
241     if (actual == MAP_FAILED) {
242         perror("mmap");
243         return 0;               /* caller should check this */
244     }
245
246     if (addr && (addr!=actual)) {
247         fprintf(stderr, "mmap: wanted %lu bytes at %p, actually mapped at %p\n",
248                 (unsigned long) len, addr, actual);
249         return 0;
250     }
251
252 #ifdef LISP_FEATURE_ALPHA
253
254     len=(len+(os_vm_page_size-1))&(~(os_vm_page_size-1));
255     under_2gb_free_pointer+=len;
256 #endif
257
258     return actual;
259 }
260
261 void
262 os_invalidate(os_vm_address_t addr, os_vm_size_t len)
263 {
264     if (munmap(addr,len) == -1) {
265         perror("munmap");
266     }
267 }
268
269 os_vm_address_t
270 os_map(int fd, int offset, os_vm_address_t addr, os_vm_size_t len)
271 {
272     os_vm_address_t actual;
273
274     actual = mmap(addr, len, OS_VM_PROT_ALL, MAP_PRIVATE | MAP_FIXED,
275                   fd, (off_t) offset);
276     if (actual == MAP_FAILED || (addr && (addr != actual))) {
277         perror("mmap");
278         lose("unexpected mmap(..) failure\n");
279     }
280
281     return actual;
282 }
283
284 void
285 os_protect(os_vm_address_t address, os_vm_size_t length, os_vm_prot_t prot)
286 {
287     if (mprotect(address, length, prot) == -1) {
288         if (errno == ENOMEM) {
289             lose("An mprotect call failed with ENOMEM. This probably means that the maximum amount\n"
290                  "of separate memory mappings was exceeded. To fix the problem, either increase\n"
291                  "the maximum with e.g. 'echo 262144 > /proc/sys/vm/max_map_count' or recompile\n"
292                  "SBCL with a larger value for GENCGC-PAGE-SIZE in 'src/target/parms.lisp'.");
293         } else {
294             perror("mprotect");
295         }
296     }
297 }
298 \f
299 boolean
300 is_valid_lisp_addr(os_vm_address_t addr)
301 {
302     struct thread *th;
303     size_t ad = (size_t) addr;
304
305     if ((READ_ONLY_SPACE_START <= ad && ad < READ_ONLY_SPACE_END)
306         || (STATIC_SPACE_START <= ad && ad < STATIC_SPACE_END)
307 #if defined LISP_FEATURE_GENCGC
308         || (DYNAMIC_SPACE_START <= ad && ad < DYNAMIC_SPACE_END)
309 #else
310         || (DYNAMIC_0_SPACE_START <= ad && ad < DYNAMIC_0_SPACE_END)
311         || (DYNAMIC_1_SPACE_START <= ad && ad < DYNAMIC_1_SPACE_END)
312 #endif
313         )
314         return 1;
315     for_each_thread(th) {
316         if((size_t)(th->control_stack_start) <= ad
317            && ad < (size_t)(th->control_stack_end))
318             return 1;
319         if((size_t)(th->binding_stack_start) <= ad
320            && ad < (size_t)(th->binding_stack_start + BINDING_STACK_SIZE))
321             return 1;
322     }
323     return 0;
324 }
325 \f
326 /*
327  * any OS-dependent special low-level handling for signals
328  */
329
330 /*
331  * The GC needs to be hooked into whatever signal is raised for
332  * page fault on this OS.
333  */
334 static void
335 sigsegv_handler(int signal, siginfo_t *info, void* void_context)
336 {
337     os_context_t *context = arch_os_get_context(&void_context);
338     os_vm_address_t addr = arch_get_bad_addr(signal, info, context);
339
340 #ifdef LISP_FEATURE_ALPHA
341     /* Alpha stuff: This is the end of a pseudo-atomic section during
342        which a signal was received.  We must deal with the pending
343        interrupt (see also interrupt.c, ../code/interrupt.lisp)
344
345        (how we got here: when interrupting, we set bit 63 in reg_ALLOC.
346        At the end of the atomic section we tried to write to reg_ALLOC,
347        got a SIGSEGV (there's nothing mapped there) so ended up here. */
348     if (addr != NULL &&
349         *os_context_register_addr(context, reg_ALLOC) & (1L<<63)) {
350         *os_context_register_addr(context, reg_ALLOC) -= (1L<<63);
351         interrupt_handle_pending(context);
352         return;
353     }
354 #endif
355
356 #ifdef LISP_FEATURE_GENCGC
357     if (!gencgc_handle_wp_violation(addr))
358 #else
359     if (!interrupt_maybe_gc(signal, info, context))
360 #endif
361         if (!handle_guard_page_triggered(context, addr))
362 #ifdef LISP_FEATURE_C_STACK_IS_CONTROL_STACK
363             arrange_return_to_lisp_function(context, SymbolFunction(MEMORY_FAULT_ERROR));
364 #else
365             interrupt_handle_now(signal, info, context);
366 #endif
367 }
368
369 void
370 os_install_interrupt_handlers(void)
371 {
372     undoably_install_low_level_interrupt_handler(SIG_MEMORY_FAULT,
373                                                  sigsegv_handler);
374 #ifdef LISP_FEATURE_SB_THREAD
375     undoably_install_low_level_interrupt_handler(SIG_INTERRUPT_THREAD,
376                                                  interrupt_thread_handler);
377     undoably_install_low_level_interrupt_handler(SIG_STOP_FOR_GC,
378                                                  sig_stop_for_gc_handler);
379 #endif
380 }
381
382 char *
383 os_get_runtime_executable_path()
384 {
385     char path[PATH_MAX + 1];
386     int size;
387
388     size = readlink("/proc/self/exe", path, sizeof(path)-1);
389     if (size < 0)
390         return NULL;
391     else
392         path[size] = '\0';
393
394     return copied_string(path);
395 }