4 * From osf1-os.c,v 1.1 94/03/27 15:30:51 hallgren Exp $
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.
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.
18 * $Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/lisp/Linux-os.c,v 1.52 2011/09/01 05:18:26 rtoy Exp $
23 #include <sys/param.h>
29 #include "interrupt.h"
31 #include "internals.h"
32 #include <sys/socket.h>
33 #include <sys/utsname.h>
35 #include <sys/types.h>
37 /* #include <sys/sysinfo.h> */
41 #include <sys/resource.h>
48 size_t os_vm_page_size;
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);
60 #if !defined(ADDR_NO_RANDOMIZE)
61 #define ADDR_NO_RANDOMIZE 0x40000
63 /* From personality(2) */
64 #define CURRENT_PERSONALITY 0xffffffffUL
68 check_personality(struct utsname *name, char *const *argv, char *const *envp)
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).
75 * Since randomization is currently implemented only on x86 kernels,
76 * don't do this trick on other platforms.
78 #if defined(__i386) || defined(__x86_64)
79 int major_version, minor_version, patch_version;
82 major_version = atoi(p);
84 minor_version = atoi(p);
86 patch_version = atoi(p);
88 if ((major_version == 2
89 /* Some old kernels will apparently lose unsupported personality flags
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)
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...
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.
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);
120 execve(runtime, argv, envp);
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.
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");
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.
143 os_init0(const char *argv[], const char *envp[])
148 check_personality(&name, (char *const *) argv, (char *const *) envp);
152 os_init(const char *argv[], const char *envp[])
158 /* We need this for mmap */
160 if (name.release[0] < '2') {
161 printf("Linux version must be later then 2.0.0!\n");
165 os_vm_page_size = getpagesize();
170 os_sigcontext_reg(ucontext_t *scp, int offset)
174 return (unsigned long *) &scp->uc_mcontext.gregs[REG_EAX];
176 return (unsigned long *) &scp->uc_mcontext.gregs[REG_ECX];
178 return (unsigned long *) &scp->uc_mcontext.gregs[REG_EDX];
180 return (unsigned long *) &scp->uc_mcontext.gregs[REG_EBX];
182 return (unsigned long *) &scp->uc_mcontext.gregs[REG_ESP];
184 return (unsigned long *) &scp->uc_mcontext.gregs[REG_EBP];
186 return (unsigned long *) &scp->uc_mcontext.gregs[REG_ESI];
188 return (unsigned long *) &scp->uc_mcontext.gregs[REG_EDI];
194 os_sigcontext_pc(ucontext_t *scp)
196 return (unsigned long *) &scp->uc_mcontext.gregs[REG_EIP];
200 os_sigcontext_fpu_reg(ucontext_t *scp, int offset)
202 fpregset_t fpregs = scp->uc_mcontext.fpregs;
203 unsigned char *reg = NULL;
207 reg = (unsigned char *) &fpregs->_st[offset];
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];
223 os_sigcontext_fpu_modes(ucontext_t *scp)
226 unsigned short cw, sw;
228 if (scp->uc_mcontext.fpregs == NULL) {
232 cw = scp->uc_mcontext.fpregs->cw & 0xffff;
233 sw = scp->uc_mcontext.fpregs->sw & 0xffff;
236 modes = ((cw & 0x3f) << 7) | (sw & 0x3f);
240 * Add in the SSE2 part, if we're running the sse2 core.
242 if (fpu_mode == SSE2) {
243 struct _fpstate *fpstate;
246 fpstate = (struct _fpstate*) scp->uc_mcontext.fpregs;
247 if (fpstate->magic == 0xffff) {
250 mxcsr = fpstate->mxcsr;
251 DPRINTF(0, (stderr, "SSE2 modes = %08lx\n", mxcsr));
258 modes ^= (0x3f << 7);
265 sc_reg(ucontext_t *c, int offset)
269 return &c->uc_mcontext.gregs[REG_RAX];
271 return &c->uc_mcontext.gregs[REG_RCX];
273 return &c->uc_mcontext.gregs[REG_RDX];
275 return &c->uc_mcontext.gregs[REG_RBX];
277 return &c->uc_mcontext.gregs[REG_RSP];
279 return &c->uc_mcontext.gregs[REG_RBP];
281 return &c->uc_mcontext.gregs[REG_RSI];
283 return &c->uc_mcontext.gregs[REG_RDI];
285 return &c->uc_mcontext.gregs[REG_R8];
287 return &c->uc_mcontext.gregs[REG_R9];
289 return &c->uc_mcontext.gregs[REG_R10];
291 return &c->uc_mcontext.gregs[REG_R11];
293 return &c->uc_mcontext.gregs[REG_R12];
295 return &c->uc_mcontext.gregs[REG_R13];
297 return &c->uc_mcontext.gregs[REG_R14];
299 return &c->uc_mcontext.gregs[REG_R15];
306 os_validate(os_vm_address_t addr, os_vm_size_t len)
308 int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE;
313 addr = mmap(addr, len, OS_VM_PROT_ALL, flags, -1, 0);
315 if (addr == (os_vm_address_t) - 1) {
324 os_invalidate(os_vm_address_t addr, os_vm_size_t len)
326 DPRINTF(0, (stderr, "os_invalidate %p %d\n", addr, len));
328 if (munmap(addr, len) == -1)
333 os_map(int fd, int offset, os_vm_address_t addr, os_vm_size_t len)
335 addr = mmap(addr, len,
337 MAP_PRIVATE | MAP_FILE | MAP_FIXED, fd, (off_t) offset);
339 if (addr == (os_vm_address_t) - 1)
346 os_flush_icache(os_vm_address_t address, os_vm_size_t length)
351 os_protect(os_vm_address_t address, os_vm_size_t length, os_vm_prot_t prot)
353 if (mprotect(address, length, prot) == -1)
360 in_range_p(os_vm_address_t a, lispobj sbeg, size_t slen)
362 char *beg = (char *) sbeg;
363 char *end = (char *) sbeg + slen;
364 char *adr = (char *) a;
366 return (adr >= beg && adr < end);
370 valid_addr(os_vm_address_t addr)
372 os_vm_address_t newaddr;
374 newaddr = os_trunc_to_page(addr);
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))
390 sigsegv_handle_now(HANDLER_ARGS)
392 interrupt_handle_now(signal, code, context);
395 static int tramp_signal;
396 static siginfo_t tramp_code;
397 static ucontext_t tramp_context;
400 sigsegv_handler_tramp(void)
402 sigsegv_handle_now(tramp_signal, &tramp_code, &tramp_context);
407 sigsegv_handler(HANDLER_ARGS)
409 os_context_t *os_context = (os_context_t *) context;
410 int fault_addr = os_context->uc_mcontext.cr2;
413 if (os_control_stack_overflow((void *) fault_addr, os_context))
416 if (gc_write_barrier(code->si_addr))
418 #if defined(__x86_64)
419 DPRINTF(0, (stderr, "sigsegv: rip: %p\n", os_context->uc_mcontext.gregs[REG_RIP]));
421 DPRINTF(0, (stderr, "sigsegv: eip: %x\n", os_context->uc_mcontext.gregs[REG_EIP]));
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;
431 tramp_context = *os_context;
432 SC_PC(os_context) = (unsigned long) sigsegv_handler_tramp;
437 sigsegv_handle_now(signal, code, os_context);
441 sigsegv_handler(HANDLER_ARGS)
443 os_vm_address_t addr;
445 DPRINTF(0, (stderr, "sigsegv\n"));
447 interrupt_handle_now(signal, contextstruct);
449 #define CONTROL_STACK_TOP (((char*) CONTROL_STACK_START) + control_stack_size)
451 addr = arch_get_bad_addr(signal, code, context);
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);
463 } else if (!interrupt_maybe_gc(signal, code, context))
464 interrupt_handle_now(signal, code, context);
470 sigbus_handler(HANDLER_ARGS)
472 DPRINTF(1, (stderr, "sigbus:\n")); /* there is no sigbus in linux??? */
473 interrupt_handle_now(signal, code, context);
477 os_install_interrupt_handlers(void)
479 interrupt_install_low_level_handler(SIGSEGV, sigsegv_handler);
480 interrupt_install_low_level_handler(SIGBUS, sigbus_handler);
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. */
489 dlsym_fallback(void *handle, const char *name)
494 strcpy(newsym, "PVE_stub_");
495 strcat(newsym, name);
496 sym_addr = dlsym(handle, newsym);
499 fputs(dlerror(), stderr);
506 os_dlsym(const char *sym_name, lispobj lib_list)
508 static void *program_handle;
512 program_handle = dlopen((void *) 0, RTLD_LAZY | RTLD_GLOBAL);
513 if (lib_list != NIL) {
514 lispobj lib_list_head;
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);
521 sym_addr = dlsym((void *) dlhandle->pointer, sym_name);
526 sym_addr = dlsym(program_handle, sym_name);
527 if (!sym_addr && dlerror()) {
528 return dlsym_fallback(program_handle, sym_name);
535 restore_fpu(ucontext_t *context)
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));
542 if (fpu_mode == SSE2) {
543 struct _fpstate *fpstate;
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));