8f8510141f436a2b144782e7323062573b0c5a2d
[projects/cmucl/cmucl.git] / src / lisp / Linux-os.c
1 /*
2  * Linux-os.c. 
3  * From FreeBSD-os.c
4  * From osf1-os.c,v 1.1 94/03/27 15:30:51 hallgren Exp $
5  *
6  * OS-dependent routines.  This file (along with os.h) exports an
7  * OS-independent interface to the operating system VM facilities.
8  * Suprisingly, this interface looks a lot like the Mach interface
9  * (but simpler in some places).  For some operating systems, a subset
10  * of these functions will have to be emulated.
11  *
12  * This is the OSF1 version.  By Sean Hallgren.
13  * Much hacked by Paul Werkowski
14  * Morfed from the FreeBSD file by Peter Van Eynde (July 1996)
15  * GENCGC support by Douglas Crosher, 1996, 1997.
16  * Alpha support by Julian Dolby, 1999.
17  *
18  * $Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/lisp/Linux-os.c,v 1.52 2011/09/01 05:18:26 rtoy Exp $
19  *
20  */
21
22 #include <stdio.h>
23 #include <sys/param.h>
24 #include <sys/file.h>
25 #include <errno.h>
26 #include "os.h"
27 #include "arch.h"
28 #include "globals.h"
29 #include "interrupt.h"
30 #include "lispregs.h"
31 #include "internals.h"
32 #include <sys/socket.h>
33 #include <sys/utsname.h>
34
35 #include <sys/types.h>
36 #include <signal.h>
37 /* #include <sys/sysinfo.h> */
38 #include <sys/time.h>
39 #include <sys/stat.h>
40 #include <unistd.h>
41 #include <sys/resource.h>
42 #include <sys/wait.h>
43 #include <link.h>
44 #include <dlfcn.h>
45 #include <assert.h>
46
47 #include "validate.h"
48 size_t os_vm_page_size;
49
50 #if defined GENCGC
51 #include "gencgc.h"
52 #endif
53 \f
54
55 #if defined(__i386) || defined(__x86_64)
56 /* Prototype for personality(2). Done inline here since the header file
57  * for this isn't available on old versions of glibc. */
58 int personality (unsigned long);
59
60 #if !defined(ADDR_NO_RANDOMIZE)
61 #define ADDR_NO_RANDOMIZE 0x40000
62 #endif
63 /* From personality(2) */
64 #define CURRENT_PERSONALITY 0xffffffffUL
65 #endif
66
67 void
68 check_personality(struct utsname *name, char *const *argv, char *const *envp)
69 {
70     /* KLUDGE: Disable memory randomization on new Linux kernels
71      * by setting a personality flag and re-executing. (We need
72      * to re-execute, since the memory maps that can conflict with
73      * the CMUCL spaces have already been done at this point).
74      *
75      * Since randomization is currently implemented only on x86 kernels,
76      * don't do this trick on other platforms.
77      */
78 #if defined(__i386) || defined(__x86_64)
79     int major_version, minor_version, patch_version;
80     char *p;
81     p = name->release;
82     major_version = atoi(p);
83     p = strchr(p,'.')+1;
84     minor_version = atoi(p);
85     p = strchr(p,'.')+1;
86     patch_version = atoi(p);
87
88     if ((major_version == 2
89          /* Some old kernels will apparently lose unsupported personality flags
90           * on exec() */
91          && ((minor_version == 6 && patch_version >= 11)
92              || (minor_version > 6)
93              /* This is what RHEL 3 reports */
94              || (minor_version == 4 && patch_version > 20)))
95         || major_version >= 3)
96         {
97             int pers = personality(CURRENT_PERSONALITY);
98             if (!(pers & ADDR_NO_RANDOMIZE)) {
99                 int retval = personality(pers | ADDR_NO_RANDOMIZE);
100                 /* Allegedly some Linux kernels (the reported case was
101                  * "hardened Linux 2.6.7") won't set the new personality,
102                  * but nor will they return -1 for an error. So as a
103                  * workaround query the new personality...
104                  */
105                 int newpers = personality(CURRENT_PERSONALITY);
106                 /* ... and don't re-execute if either the setting resulted
107                  * in an error or if the value didn't change. Otherwise
108                  * this might result in an infinite loop.
109                  */
110                 if (retval != -1 && newpers != pers) {
111                     /* Use /proc/self/exe instead of trying to figure out
112                      * the executable path from PATH and argv[0], since
113                      * that's unreliable. We follow the symlink instead of
114                      * executing the file directly in order to prevent top
115                      * from displaying the name of the process as "exe". */
116                     char runtime[PATH_MAX+1];
117                     int i = readlink("/proc/self/exe", runtime, PATH_MAX);
118                     if (i != -1) {
119                         runtime[i] = '\0';
120                         execve(runtime, argv, envp);
121                     }
122                 }
123                 /* Either changing the personality or execve() failed. Either
124                  * way we might as well continue, and hope that the random
125                  * memory maps are ok this time around.
126                  */
127                 fprintf(stderr, "WARNING: Couldn't re-execute CMUCL with the proper personality flags"
128                         "(maybe /proc isn't mounted?). Trying to continue anyway.\n");
129             }
130         }
131 #endif
132 }
133
134 /*
135  * Check personality here, before we start processing command line
136  * args.  (Previously it was done in os_init.)  check_personality
137  * can re-exec us, so we end up parsing the command line args
138  * twice.  Not usually a problem unless the processing causes
139  * output, which can be confusing.
140  */
141
142 void
143 os_init0(const char *argv[], const char *envp[])
144 {
145     struct utsname name;
146     uname(&name);
147         
148     check_personality(&name, (char *const *) argv, (char *const *) envp);
149 }
150
151 void
152 os_init(const char *argv[], const char *envp[])
153 {
154     struct utsname name;
155
156     uname(&name);
157
158     /* We need this for mmap */
159
160     if (name.release[0] < '2') {
161         printf("Linux version must be later then 2.0.0!\n");
162         exit(2);
163     }
164
165     os_vm_page_size = getpagesize();
166 }
167
168 #ifdef __i386
169 unsigned long *
170 os_sigcontext_reg(ucontext_t *scp, int offset)
171 {
172     switch (offset) {
173     case 0:
174         return (unsigned long *) &scp->uc_mcontext.gregs[REG_EAX];
175     case 2:
176         return (unsigned long *) &scp->uc_mcontext.gregs[REG_ECX];
177     case 4:
178         return (unsigned long *) &scp->uc_mcontext.gregs[REG_EDX];
179     case 6:
180         return (unsigned long *) &scp->uc_mcontext.gregs[REG_EBX];
181     case 8:
182         return (unsigned long *) &scp->uc_mcontext.gregs[REG_ESP];
183     case 10:
184         return (unsigned long *) &scp->uc_mcontext.gregs[REG_EBP];
185     case 12:
186         return (unsigned long *) &scp->uc_mcontext.gregs[REG_ESI];
187     case 14:
188         return (unsigned long *) &scp->uc_mcontext.gregs[REG_EDI];
189     }
190     return NULL;
191 }
192
193 unsigned long *
194 os_sigcontext_pc(ucontext_t *scp)
195 {
196     return (unsigned long *) &scp->uc_mcontext.gregs[REG_EIP];
197 }
198
199 unsigned char *
200 os_sigcontext_fpu_reg(ucontext_t *scp, int offset)
201 {
202     fpregset_t fpregs = scp->uc_mcontext.fpregs;
203     unsigned char *reg = NULL;
204     
205     if (fpregs) {
206         if (offset < 8) {
207             reg = (unsigned char *) &fpregs->_st[offset];
208         }
209 #ifdef FEATURE_SSE2
210         else {
211             struct _fpstate *fpstate;
212             fpstate = (struct _fpstate*) scp->uc_mcontext.fpregs;
213             if (fpstate->magic != 0xffff) {
214                 reg = (unsigned char *) &fpstate->_xmm[offset - 8];
215             }
216         }
217 #endif
218     }
219     return reg;
220 }
221
222 unsigned int
223 os_sigcontext_fpu_modes(ucontext_t *scp)
224 {
225     unsigned int modes;
226     unsigned short cw, sw;
227
228     if (scp->uc_mcontext.fpregs == NULL) {
229         cw = 0;
230         sw = 0x3f;
231     } else {
232         cw = scp->uc_mcontext.fpregs->cw & 0xffff;
233         sw = scp->uc_mcontext.fpregs->sw & 0xffff;
234     }
235
236     modes = ((cw & 0x3f) << 7) | (sw & 0x3f);
237
238 #ifdef FEATURE_SSE2
239     /*
240      * Add in the SSE2 part, if we're running the sse2 core.
241      */
242     if (fpu_mode == SSE2) {
243         struct _fpstate *fpstate;
244         unsigned long mxcsr;
245
246         fpstate = (struct _fpstate*) scp->uc_mcontext.fpregs;
247         if (fpstate->magic == 0xffff) {
248             mxcsr = 0;
249         } else {
250             mxcsr = fpstate->mxcsr;
251             DPRINTF(0, (stderr, "SSE2 modes = %08lx\n", mxcsr));
252         }
253
254         modes |= mxcsr;
255     }
256 #endif
257
258     modes ^= (0x3f << 7);
259     return modes;
260 }
261 #endif
262
263 #ifdef __x86_64
264 int *
265 sc_reg(ucontext_t *c, int offset)
266 {
267     switch (offset) {
268       case 0:
269           return &c->uc_mcontext.gregs[REG_RAX];
270       case 2:
271           return &c->uc_mcontext.gregs[REG_RCX];
272       case 4:
273           return &c->uc_mcontext.gregs[REG_RDX];
274       case 6:
275           return &c->uc_mcontext.gregs[REG_RBX];
276       case 8:
277           return &c->uc_mcontext.gregs[REG_RSP];
278       case 10:
279           return &c->uc_mcontext.gregs[REG_RBP];
280       case 12:
281           return &c->uc_mcontext.gregs[REG_RSI];
282       case 14:
283           return &c->uc_mcontext.gregs[REG_RDI];
284       case 16:
285           return &c->uc_mcontext.gregs[REG_R8];
286       case 18:
287           return &c->uc_mcontext.gregs[REG_R9];
288       case 20:
289           return &c->uc_mcontext.gregs[REG_R10];
290       case 22:
291           return &c->uc_mcontext.gregs[REG_R11];
292       case 24:
293           return &c->uc_mcontext.gregs[REG_R12];
294       case 26:
295           return &c->uc_mcontext.gregs[REG_R13];
296       case 28:
297           return &c->uc_mcontext.gregs[REG_R14];
298       case 30:
299           return &c->uc_mcontext.gregs[REG_R15];
300     }
301     return (int *) 0;
302 }
303 #endif
304
305 os_vm_address_t
306 os_validate(os_vm_address_t addr, os_vm_size_t len)
307 {
308     int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE;
309
310     if (addr)
311       flags |= MAP_FIXED;
312
313     addr = mmap(addr, len, OS_VM_PROT_ALL, flags, -1, 0);
314
315     if (addr == (os_vm_address_t) - 1) {
316         perror("mmap");
317         return NULL;
318     }
319
320     return addr;
321 }
322
323 void
324 os_invalidate(os_vm_address_t addr, os_vm_size_t len)
325 {
326     DPRINTF(0, (stderr, "os_invalidate %p %d\n", addr, len));
327
328     if (munmap(addr, len) == -1)
329         perror("munmap");
330 }
331
332 os_vm_address_t
333 os_map(int fd, int offset, os_vm_address_t addr, os_vm_size_t len)
334 {
335     addr = mmap(addr, len,
336                 OS_VM_PROT_ALL,
337                 MAP_PRIVATE | MAP_FILE | MAP_FIXED, fd, (off_t) offset);
338
339     if (addr == (os_vm_address_t) - 1)
340         perror("mmap");
341
342     return addr;
343 }
344
345 void
346 os_flush_icache(os_vm_address_t address, os_vm_size_t length)
347 {
348 }
349
350 void
351 os_protect(os_vm_address_t address, os_vm_size_t length, os_vm_prot_t prot)
352 {
353     if (mprotect(address, length, prot) == -1)
354         perror("mprotect");
355 }
356 \f
357
358
359 static boolean
360 in_range_p(os_vm_address_t a, lispobj sbeg, size_t slen)
361 {
362     char *beg = (char *) sbeg;
363     char *end = (char *) sbeg + slen;
364     char *adr = (char *) a;
365
366     return (adr >= beg && adr < end);
367 }
368
369 boolean
370 valid_addr(os_vm_address_t addr)
371 {
372     os_vm_address_t newaddr;
373
374     newaddr = os_trunc_to_page(addr);
375
376     if (in_range_p(addr, READ_ONLY_SPACE_START, read_only_space_size)
377         || in_range_p(addr, STATIC_SPACE_START, static_space_size)
378         || in_range_p(addr, DYNAMIC_0_SPACE_START, dynamic_space_size)
379         || in_range_p(addr, DYNAMIC_1_SPACE_START, dynamic_space_size)
380         || in_range_p(addr, CONTROL_STACK_START, control_stack_size)
381         || in_range_p(addr, BINDING_STACK_START, binding_stack_size))
382         return TRUE;
383     return FALSE;
384 }
385 \f
386
387 #if defined GENCGC
388
389 static void
390 sigsegv_handle_now(HANDLER_ARGS)
391 {
392     interrupt_handle_now(signal, code, context);
393 }
394
395 static int tramp_signal;
396 static siginfo_t tramp_code;
397 static ucontext_t tramp_context;
398
399 static void
400 sigsegv_handler_tramp(void)
401 {
402     sigsegv_handle_now(tramp_signal, &tramp_code, &tramp_context);
403     assert(0);
404 }
405
406 void
407 sigsegv_handler(HANDLER_ARGS)
408 {
409     os_context_t *os_context = (os_context_t *) context;
410     int fault_addr = os_context->uc_mcontext.cr2;
411
412 #ifdef RED_ZONE_HIT
413     if (os_control_stack_overflow((void *) fault_addr, os_context))
414         return;
415 #endif
416     if (gc_write_barrier(code->si_addr))
417         return;
418 #if defined(__x86_64)
419     DPRINTF(0, (stderr, "sigsegv: rip: %p\n", os_context->uc_mcontext.gregs[REG_RIP]));
420 #else
421     DPRINTF(0, (stderr, "sigsegv: eip: %x\n", os_context->uc_mcontext.gregs[REG_EIP]));
422 #endif
423
424 #ifdef RED_ZONE_HIT
425     {
426         /* Switch back to the normal stack and invoke the Lisp signal
427            handler there.  Global variables are used to pass the context
428            to the other stack. */
429         tramp_signal = signal;
430         tramp_code = *code;
431         tramp_context = *os_context;
432         SC_PC(os_context) = (unsigned long) sigsegv_handler_tramp;
433         return;
434     }
435 #endif
436
437     sigsegv_handle_now(signal, code, os_context);
438 }
439 #else
440 static void
441 sigsegv_handler(HANDLER_ARGS)
442 {
443     os_vm_address_t addr;
444
445     DPRINTF(0, (stderr, "sigsegv\n"));
446 #ifdef i386
447     interrupt_handle_now(signal, contextstruct);
448 #else
449 #define CONTROL_STACK_TOP (((char*) CONTROL_STACK_START) + control_stack_size)
450
451     addr = arch_get_bad_addr(signal, code, context);
452
453     if (addr != NULL && context->sc_regs[reg_ALLOC] & (1 << 63)) {
454         context->sc_regs[reg_ALLOC] -= (1 << 63);
455         interrupt_handle_pending(context);
456     } else if (addr > CONTROL_STACK_TOP && addr < BINDING_STACK_START) {
457         fprintf(stderr, "Possible stack overflow at 0x%08lX!\n", addr);
458         /* try to fix control frame pointer */
459         while (!(CONTROL_STACK_START <= *current_control_frame_pointer &&
460                  *current_control_frame_pointer <= CONTROL_STACK_TOP))
461             ((char *) current_control_frame_pointer) -= sizeof(lispobj);
462         ldb_monitor();
463     } else if (!interrupt_maybe_gc(signal, code, context))
464         interrupt_handle_now(signal, code, context);
465 #endif
466 }
467 #endif
468
469 static void
470 sigbus_handler(HANDLER_ARGS)
471 {
472     DPRINTF(1, (stderr, "sigbus:\n"));  /* there is no sigbus in linux??? */
473     interrupt_handle_now(signal, code, context);
474 }
475
476 void
477 os_install_interrupt_handlers(void)
478 {
479     interrupt_install_low_level_handler(SIGSEGV, sigsegv_handler);
480     interrupt_install_low_level_handler(SIGBUS, sigbus_handler);
481 }
482
483 /* Some symbols, most notably stat and lstat, don't appear at all in
484    the glibc .so files as a result of preprocessor and linker magic /
485    braindamage.  So, try falling back to a stub in linux-stubs.S that
486    will call the proper function if it's one of those. */
487
488 static void *
489 dlsym_fallback(void *handle, const char *name)
490 {
491     char newsym[1024];
492     void *sym_addr;
493
494     strcpy(newsym, "PVE_stub_");
495     strcat(newsym, name);
496     sym_addr = dlsym(handle, newsym);
497 #ifdef DEBUG
498     if (sym_addr == 0) {
499         fputs(dlerror(), stderr);
500     }
501 #endif
502     return sym_addr;
503 }
504
505 void *
506 os_dlsym(const char *sym_name, lispobj lib_list)
507 {
508     static void *program_handle;
509     void *sym_addr = 0;
510
511     if (!program_handle)
512         program_handle = dlopen((void *) 0, RTLD_LAZY | RTLD_GLOBAL);
513     if (lib_list != NIL) {
514         lispobj lib_list_head;
515
516         for (lib_list_head = lib_list;
517              lib_list_head != NIL; lib_list_head = (CONS(lib_list_head))->cdr) {
518             struct cons *lib_cons = CONS(CONS(lib_list_head)->car);
519             struct sap *dlhandle = (struct sap *) PTR(lib_cons->car);
520
521             sym_addr = dlsym((void *) dlhandle->pointer, sym_name);
522             if (sym_addr)
523                 return sym_addr;
524         }
525     }
526     sym_addr = dlsym(program_handle, sym_name);
527     if (!sym_addr && dlerror()) {
528         return dlsym_fallback(program_handle, sym_name);
529     } else {
530         return sym_addr;
531     }
532 }
533
534 void
535 restore_fpu(ucontext_t *context)
536 {
537     if (context->uc_mcontext.fpregs) {
538         short cw = context->uc_mcontext.fpregs->cw;
539         DPRINTF(0, (stderr, "restore_fpu:  cw = %08x\n", cw));
540         __asm__ __volatile__ ("fldcw %0" : : "m" (*&cw));
541 #ifdef FEATURE_SSE2
542         if (fpu_mode == SSE2) {
543             struct _fpstate *fpstate;
544             unsigned int mxcsr;
545             
546             fpstate = (struct _fpstate*) context->uc_mcontext.fpregs;
547             if (fpstate->magic != 0xffff) {
548                 mxcsr = fpstate->mxcsr;
549                 DPRINTF(0, (stderr, "restore_fpu:  mxcsr (raw) = %04x\n", mxcsr));
550                 __asm__ __volatile__ ("ldmxcsr %0" :: "m" (*&mxcsr));
551             }
552         }
553 #endif        
554     }
555 }
556
557 #ifdef i386
558 boolean
559 os_support_sse2()
560 {
561     return TRUE;
562 }
563 #endif