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