6d7046ccb0d8fdf2978ab9c8cd6111fed3e492b0
[sbcl.git] / src / runtime / x86-64-arch.c
1 /*
2  * This software is part of the SBCL system. See the README file for
3  * more information.
4  *
5  * This software is derived from the CMU CL system, which was
6  * written at Carnegie Mellon University and released into the
7  * public domain. The software is in the public domain and is
8  * provided with absolutely no warranty. See the COPYING and CREDITS
9  * files for more information.
10  */
11
12 #include <stdio.h>
13
14 #include "sbcl.h"
15 #include "runtime.h"
16 #include "globals.h"
17 #include "validate.h"
18 #include "os.h"
19 #include "sbcl.h"
20 #include "arch.h"
21 #include "lispregs.h"
22 #include "signal.h"
23 #include "alloc.h"
24 #include "interrupt.h"
25 #include "interr.h"
26 #include "breakpoint.h"
27 #include "thread.h"
28
29 #include "genesis/static-symbols.h"
30 #include "genesis/symbol.h"
31
32 #define BREAKPOINT_INST 0xcc    /* INT3 */
33
34 unsigned long fast_random_state = 1;
35
36 void arch_init(void)
37 {}
38
39 os_vm_address_t
40 arch_get_bad_addr(int sig, siginfo_t *code, os_context_t *context)
41 {
42     return (os_vm_address_t)code->si_addr;
43 }
44
45 \f
46 /*
47  * hacking signal contexts
48  *
49  * (This depends both on architecture, which determines what we might
50  * want to get to, and on OS, which determines how we get to it.)
51  */
52
53 int *
54 context_eflags_addr(os_context_t *context)
55 {
56 #if defined __linux__
57     /* KLUDGE: As of kernel 2.2.14 on Red Hat 6.2, there's code in the
58      * <sys/ucontext.h> file to define symbolic names for offsets into
59      * gregs[], but it's conditional on __USE_GNU and not defined, so
60      * we need to do this nasty absolute index magic number thing
61      * instead. */
62     return &context->uc_mcontext.gregs[17];
63 #elif defined __FreeBSD__
64     return &context->uc_mcontext.mc_eflags;
65 #elif defined __OpenBSD__
66     return &context->sc_eflags;
67 #else
68 #error unsupported OS
69 #endif
70 }
71 \f
72 void arch_skip_instruction(os_context_t *context)
73 {
74     /* Assuming we get here via an INT3 xxx instruction, the PC now
75      * points to the interrupt code (a Lisp value) so we just move
76      * past it. Skip the code; after that, if the code is an
77      * error-trap or cerror-trap then skip the data bytes that follow. */
78
79     int vlen;
80     long code;
81
82
83     /* Get and skip the Lisp interrupt code. */
84     code = *(char*)(*os_context_pc_addr(context))++;
85     switch (code)
86         {
87         case trap_Error:
88         case trap_Cerror:
89             /* Lisp error arg vector length */
90             vlen = *(char*)(*os_context_pc_addr(context))++;
91             /* Skip Lisp error arg data bytes. */
92             while (vlen-- > 0) {
93                 ++*os_context_pc_addr(context);
94             }
95             break;
96
97         case trap_Breakpoint:           /* not tested */
98         case trap_FunEndBreakpoint: /* not tested */
99             break;
100
101         case trap_PendingInterrupt:
102         case trap_Halt:
103         case trap_SingleStepAround:
104         case trap_SingleStepBefore:
105             /* only needed to skip the Code */
106             break;
107
108         default:
109             fprintf(stderr,"[arch_skip_inst invalid code %d\n]\n",code);
110             break;
111         }
112
113     FSHOW((stderr,
114            "/[arch_skip_inst resuming at %x]\n",
115            *os_context_pc_addr(context)));
116 }
117
118 unsigned char *
119 arch_internal_error_arguments(os_context_t *context)
120 {
121     return 1 + (unsigned char *)(*os_context_pc_addr(context));
122 }
123
124 boolean
125 arch_pseudo_atomic_atomic(os_context_t *context)
126 {
127     return get_pseudo_atomic_atomic(arch_os_get_current_thread());
128 }
129
130 void
131 arch_set_pseudo_atomic_interrupted(os_context_t *context)
132 {
133     struct thread *thread = arch_os_get_current_thread();
134     set_pseudo_atomic_interrupted(thread);
135 }
136
137 void
138 arch_clear_pseudo_atomic_interrupted(os_context_t *context)
139 {
140     struct thread *thread = arch_os_get_current_thread();
141     clear_pseudo_atomic_interrupted(thread);
142 }
143 \f
144 /*
145  * This stuff seems to get called for TRACE and debug activity.
146  */
147
148 unsigned int
149 arch_install_breakpoint(void *pc)
150 {
151     unsigned int result = *(unsigned int*)pc;
152
153     *(char*)pc = BREAKPOINT_INST;               /* x86 INT3       */
154     *((char*)pc+1) = trap_Breakpoint;           /* Lisp trap code */
155
156     return result;
157 }
158
159 void
160 arch_remove_breakpoint(void *pc, unsigned int orig_inst)
161 {
162     *((char *)pc) = orig_inst & 0xff;
163     *((char *)pc + 1) = (orig_inst & 0xff00) >> 8;
164 }
165 \f
166 /* When single stepping, single_stepping holds the original instruction
167  * PC location. */
168 unsigned int *single_stepping = NULL;
169
170 void
171 arch_do_displaced_inst(os_context_t *context, unsigned int orig_inst)
172 {
173     unsigned int *pc = (unsigned int*)(*os_context_pc_addr(context));
174
175     /* Put the original instruction back. */
176     *((char *)pc) = orig_inst & 0xff;
177     *((char *)pc + 1) = (orig_inst & 0xff00) >> 8;
178
179     *context_eflags_addr(context) |= 0x100;
180
181     single_stepping = pc;
182 }
183
184 \f
185 void
186 sigtrap_handler(int signal, siginfo_t *info, void *void_context)
187 {
188     int code = info->si_code;
189     os_context_t *context = (os_context_t*)void_context;
190     unsigned int trap;
191
192     if (single_stepping && (signal==SIGTRAP))
193     {
194         *context_eflags_addr(context) ^= 0x100;
195
196         /* Re-install the breakpoint if possible. */
197         if (*os_context_pc_addr(context) == (int)single_stepping + 1) {
198             fprintf(stderr, "warning: couldn't reinstall breakpoint\n");
199         } else {
200             *((char *)single_stepping) = BREAKPOINT_INST;       /* x86 INT3 */
201             *((char *)single_stepping+1) = trap_Breakpoint;
202         }
203
204         single_stepping = NULL;
205         return;
206     }
207
208     /* This is just for info in case the monitor wants to print an
209      * approximation. */
210     current_control_stack_pointer =
211         (lispobj *)*os_context_sp_addr(context);
212
213     /* FIXME: CMUCL puts the float control restoration code here.
214        Thus, it seems to me that single-stepping won't restore the
215        float control.  Since SBCL currently doesn't support
216        single-stepping (as far as I can tell) this is somewhat moot,
217        but it might be worth either moving this code up or deleting
218        the single-stepping code entirely.  -- CSR, 2002-07-15 */
219 #ifdef LISP_FEATURE_LINUX
220     os_restore_fp_control(context);
221 #endif
222
223     /* On entry %eip points just after the INT3 byte and aims at the
224      * 'kind' value (eg trap_Cerror). For error-trap and Cerror-trap a
225      * number of bytes will follow, the first is the length of the byte
226      * arguments to follow. */
227     trap = *(unsigned char *)(*os_context_pc_addr(context));
228     switch (trap) {
229
230     case trap_PendingInterrupt:
231         FSHOW((stderr, "/<trap pending interrupt>\n"));
232         arch_skip_instruction(context);
233         interrupt_handle_pending(context);
234         break;
235
236     case trap_Halt:
237         /* Note: the old CMU CL code tried to save FPU state
238          * here, and restore it after we do our thing, but there
239          * seems to be no point in doing that, since we're just
240          * going to lose(..) anyway. */
241         fake_foreign_function_call(context);
242         lose("%%PRIMITIVE HALT called; the party is over.\n");
243
244     case trap_Error:
245     case trap_Cerror:
246         FSHOW((stderr, "<trap error/cerror %d>\n", code));
247         interrupt_internal_error(signal, info, context, code==trap_Cerror);
248         break;
249
250     case trap_Breakpoint:
251         --*os_context_pc_addr(context);
252         handle_breakpoint(signal, info, context);
253         break;
254
255     case trap_FunEndBreakpoint:
256         --*os_context_pc_addr(context);
257         *os_context_pc_addr(context) =
258             (unsigned long)handle_fun_end_breakpoint(signal, info, context);
259         break;
260
261     case trap_SingleStepAround:
262     case trap_SingleStepBefore:
263         arch_skip_instruction(context);
264         /* On x86-64 the fdefn / function is always in RAX, so we pass
265          * 0 as the register_offset. */
266         handle_single_step_trap(context, trap, 0);
267         break;
268
269     default:
270         FSHOW((stderr,"/[C--trap default %d %d %x]\n",
271                signal, code, context));
272         interrupt_handle_now(signal, info, context);
273         break;
274     }
275 }
276
277 static void
278 sigill_handler(int signal, siginfo_t *siginfo, void *void_context) {
279     os_context_t *context = (os_context_t*)void_context;
280     fake_foreign_function_call(context);
281     lose("fake_foreign_function_call fell through");
282 }
283
284 void
285 arch_install_interrupt_handlers()
286 {
287     SHOW("entering arch_install_interrupt_handlers()");
288
289     /* Note: The old CMU CL code here used sigtrap_handler() to handle
290      * SIGILL as well as SIGTRAP. I couldn't see any reason to do
291      * things that way. So, I changed to separate handlers when
292      * debugging a problem on OpenBSD, where SBCL wasn't catching
293      * SIGILL properly, but was instead letting the process be
294      * terminated with an "Illegal instruction" output. If this change
295      * turns out to break something (maybe breakpoint handling on some
296      * OS I haven't tested on?) and we have to go back to the old CMU
297      * CL way, I hope there will at least be a comment to explain
298      * why.. -- WHN 2001-06-07 */
299     undoably_install_low_level_interrupt_handler(SIGILL , sigill_handler);
300     undoably_install_low_level_interrupt_handler(SIGTRAP, sigtrap_handler);
301
302     SHOW("returning from arch_install_interrupt_handlers()");
303 }
304 \f
305 /* This is implemented in assembly language and called from C: */
306 extern lispobj
307 call_into_lisp(lispobj fun, lispobj *args, int nargs);
308
309 /* These functions are an interface to the Lisp call-in facility.
310  * Since this is C we can know nothing about the calling environment.
311  * The control stack might be the C stack if called from the monitor
312  * or the Lisp stack if called as a result of an interrupt or maybe
313  * even a separate stack. The args are most likely on that stack but
314  * could be in registers depending on what the compiler likes. So we
315  * copy the args into a portable vector and let the assembly language
316  * call-in function figure it out. */
317
318 lispobj
319 funcall0(lispobj function)
320 {
321     lispobj *args = NULL;
322
323     FSHOW((stderr, "/entering funcall0(0x%lx)\n", (long)function));
324     return call_into_lisp(function, args, 0);
325 }
326 lispobj
327 funcall1(lispobj function, lispobj arg0)
328 {
329     lispobj args[1];
330     args[0] = arg0;
331     return call_into_lisp(function, args, 1);
332 }
333 lispobj
334 funcall2(lispobj function, lispobj arg0, lispobj arg1)
335 {
336     lispobj args[2];
337     args[0] = arg0;
338     args[1] = arg1;
339     return call_into_lisp(function, args, 2);
340 }
341 lispobj
342 funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2)
343 {
344     lispobj args[3];
345     args[0] = arg0;
346     args[1] = arg1;
347     args[2] = arg2;
348     return call_into_lisp(function, args, 3);
349 }
350
351
352 #ifdef LISP_FEATURE_LINKAGE_TABLE
353 /* FIXME: It might be cleaner to generate these from the lisp side of
354  * things.
355  */
356
357 void
358 arch_write_linkage_table_jmp(char * reloc, void * fun)
359 {
360     unsigned long addr = (unsigned long) fun;
361     int i;
362
363     *reloc++ = 0xFF; /* Opcode for near jump to absolute reg/mem64. */
364     *reloc++ = 0x25; /* ModRM #b00 100 101, i.e. RIP-relative. */
365     *reloc++ = 0x00; /* 32-bit displacement field = 0 */
366     *reloc++ = 0x00; /* ... */
367     *reloc++ = 0x00; /* ... */
368     *reloc++ = 0x00; /* ... */
369
370     for (i = 0; i < 8; i++) {
371         *reloc++ = addr & 0xff;
372         addr >>= 8;
373     }
374
375     /* write a nop for good measure. */
376     *reloc = 0x90;
377 }
378
379 void
380 arch_write_linkage_table_ref(void * reloc, void * data)
381 {
382     *(unsigned long *)reloc = (unsigned long)data;
383 }
384
385 #endif
386
387 /* These setup and check *both* the sse2 and x87 FPUs. While lisp code
388    only uses the sse2 FPU, other code (such as libc) may use the x87 FPU.
389  */
390
391 unsigned int
392 arch_get_fp_modes()
393 {
394     unsigned int temp;
395     unsigned int result;
396     /* return the x87 exception flags ored in with the sse2
397      * control+status flags */
398     asm ("fnstsw %0" : "=m" (temp));
399     result = temp;
400     result &= 0x3F;
401     asm ("stmxcsr %0" : "=m" (temp));
402     result |= temp;
403     /* flip exception mask bits */
404     return result ^ (0x3F << 7);
405 }
406
407 struct fpenv
408 {
409     unsigned short cw;
410     unsigned short unused1;
411     unsigned short sw;
412     unsigned short unused2;
413     unsigned int other_regs[5];
414 };
415
416 void
417 arch_set_fp_modes(unsigned int mxcsr)
418 {
419     struct fpenv f_env;
420     unsigned int temp;
421
422     /* turn trap enable bits into exception mask */
423     mxcsr ^= 0x3F << 7;
424
425     /* set x87 modes */
426     asm ("fnstenv %0" : "=m" (f_env));
427     /* set control word: always long double precision
428      * get traps and rounding from mxcsr word */
429     f_env.cw = 0x300 | ((mxcsr >> 7) & 0x3F) | (((mxcsr >> 13) & 0x3) << 10);
430     /* set status word: only override exception flags, from mxcsr */
431     f_env.sw &= ~0x3F;
432     f_env.sw |= (mxcsr & 0x3F);
433
434     asm ("fldenv %0" : : "m" (f_env));
435
436     /* now, simply, load up the mxcsr register */
437     temp = mxcsr;
438     asm ("ldmxcsr %0" : : "m" (temp));
439 }