Clean up RCS ids
[projects/cmucl/cmucl.git] / src / lisp / x86-arch.c
1 /*
2
3  This code was written as part of the CMU Common Lisp project at
4  Carnegie Mellon University, and has been placed in the public domain.
5
6 */
7
8 #include <stdio.h>
9 #include <stdlib.h>
10
11 #include "lisp.h"
12 #include "globals.h"
13 #include "validate.h"
14 #include "os.h"
15 #include "internals.h"
16 #include "arch.h"
17 #include "lispregs.h"
18 #include "signal.h"
19 #include "alloc.h"
20 #include "interrupt.h"
21 #include "interr.h"
22 #include "breakpoint.h"
23
24 #define BREAKPOINT_INST 0xcc    /* INT3 */
25
26 unsigned long fast_random_state = 1;
27
28 #if defined(SOLARIS)
29 /*
30  * Use the /dev/cpu/self/cpuid interface on Solaris.  We could use the
31  * same method below, but the Sun C compiler miscompiles the inline
32  * assembly.
33  */
34
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <fcntl.h>
38 #include <unistd.h>
39 #include <string.h>
40 #include <errno.h>
41
42 void cpuid(int level, unsigned int* a, unsigned int* b,
43            unsigned int* c, unsigned int* d)
44 {
45     int device;
46     uint32_t regs[4];
47     static const char devname[] = "/dev/cpu/self/cpuid";
48
49         *a = *b = *c = *d = 0;
50     if ((device = open(devname, O_RDONLY)) == -1) {
51         perror(devname);
52         goto exit;
53     }
54
55     if (pread(device, regs, sizeof(regs), 1) != sizeof(regs)) {
56         perror(devname);
57         goto exit;
58     }
59
60     *a = regs[0];
61     *b = regs[1];
62     *c = regs[2];
63     *d = regs[3];
64
65   exit:
66     (void) close(device);
67
68     return;
69 }
70
71 #else
72 #define __cpuid(level, a, b, c, d)                      \
73   __asm__ ("xchgl\t%%ebx, %1\n\t"                       \
74            "cpuid\n\t"                                  \
75            "xchgl\t%%ebx, %1\n\t"                       \
76            : "=a" (a), "=r" (b), "=c" (c), "=d" (d)     \
77            : "0" (level))
78
79 void cpuid(int level, unsigned int* a, unsigned int* b,
80            unsigned int* c, unsigned int* d)
81 {
82     unsigned int eax, ebx, ecx, edx;
83     
84     __cpuid(level, eax, ebx, ecx, edx);
85
86     *a = eax;
87     *b = ebx;
88     *c = ecx;
89     *d = edx;
90 }
91 #endif
92
93 int
94 arch_support_sse2(void)
95 {
96     unsigned int eax, ebx, ecx, edx;
97
98     cpuid(1, &eax, &ebx, &ecx, &edx);
99
100     /* Return non-zero if SSE2 is supported */
101     return edx & 0x4000000;
102 }
103
104 char *
105 arch_init(fpu_mode_t mode)
106 {
107     int have_sse2;
108
109     have_sse2 = arch_support_sse2() && os_support_sse2();
110     
111     switch (mode) {
112       case AUTO:
113           if (have_sse2) {
114               return "lisp-sse2.core";
115           } else {
116               return "lisp-x87.core";
117           }
118           break;
119       case X87:
120           return "lisp-x87.core";
121           break;
122       case SSE2:
123           return "lisp-sse2.core";
124           break;
125       default:
126           abort();
127     }
128 }
129 \f
130
131
132 /*
133  * Assuming we get here via an INT3 xxx instruction, the PC now
134  * points to the interrupt code (lisp value) so we just move past
135  * it. Skip the code, then if the code is an error-trap or
136  * Cerror-trap then skip the data bytes that follow.
137  */
138
139 void
140 arch_skip_instruction(os_context_t * context)
141 {
142     int vlen, code;
143
144     DPRINTF(0, (stderr, "[arch_skip_inst at %lx>]\n", SC_PC(context)));
145
146     /* Get and skip the lisp error code. */
147     code = *(char *) SC_PC(context)++;
148     switch (code) {
149       case trap_Error:
150       case trap_Cerror:
151           /* Lisp error arg vector length */
152           vlen = *(char *) SC_PC(context)++;
153           /* Skip lisp error arg data bytes */
154           while (vlen-- > 0)
155               SC_PC(context)++;
156           break;
157
158       case trap_Breakpoint:
159       case trap_FunctionEndBreakpoint:
160           break;
161
162       case trap_PendingInterrupt:
163       case trap_Halt:
164           /* Only needed to skip the Code. */
165           break;
166
167       default:
168           fprintf(stderr, "[arch_skip_inst invalid code %d\n]\n", code);
169           break;
170     }
171
172     DPRINTF(0, (stderr, "[arch_skip_inst resuming at %lx>]\n", SC_PC(context)));
173 }
174
175 unsigned char *
176 arch_internal_error_arguments(os_context_t * context)
177 {
178     return (unsigned char *) (SC_PC(context) + 1);
179 }
180
181 boolean
182 arch_pseudo_atomic_atomic(os_context_t * context)
183 {
184     return SymbolValue(PSEUDO_ATOMIC_ATOMIC);
185 }
186
187 void
188 arch_set_pseudo_atomic_interrupted(os_context_t * context)
189 {
190     SetSymbolValue(PSEUDO_ATOMIC_INTERRUPTED, make_fixnum(1));
191 }
192 \f
193
194
195 unsigned long
196 arch_install_breakpoint(void *pc)
197 {
198     unsigned long result = *(unsigned long *) pc;
199
200     *(char *) pc = BREAKPOINT_INST;     /* x86 INT3       */
201     *((char *) pc + 1) = trap_Breakpoint;       /* Lisp trap code */
202
203     return result;
204 }
205
206 void
207 arch_remove_breakpoint(void *pc, unsigned long orig_inst)
208 {
209     *((char *) pc) = orig_inst & 0xff;
210     *((char *) pc + 1) = (orig_inst & 0xff00) >> 8;
211 }
212 \f
213
214
215 /*
216  * When single stepping single_stepping holds the original instruction
217  * pc location.
218  */
219
220 unsigned int *single_stepping = NULL;
221
222 #ifndef __linux__
223 unsigned int single_step_save1;
224 unsigned int single_step_save2;
225 unsigned int single_step_save3;
226 #endif
227
228 void
229 arch_do_displaced_inst(os_context_t * context, unsigned long orig_inst)
230 {
231     unsigned int *pc = (unsigned int *) SC_PC(context);
232
233     /*
234      * Put the original instruction back.
235      */
236
237     *((char *) pc) = orig_inst & 0xff;
238     *((char *) pc + 1) = (orig_inst & 0xff00) >> 8;
239
240 #ifdef SC_EFLAGS
241     /* Enable single-stepping */
242     SC_EFLAGS(context) |= 0x100;
243 #else
244
245     /*
246      * Install helper instructions for the single step:
247      *    nop; nop; nop; pushf; or [esp],0x100; popf.
248      *
249      * The or instruction enables the trap flag which enables
250      * single-stepping.  So when the popf instruction is run, we start
251      * single-stepping and stop on the next instruction.
252      */
253
254     DPRINTF(0, (stderr, "Installing helper instructions\n"));
255     
256     single_step_save1 = *(pc - 3);
257     single_step_save2 = *(pc - 2);
258     single_step_save3 = *(pc - 1);
259     *(pc - 3) = 0x9c909090;
260     *(pc - 2) = 0x00240c81;
261     *(pc - 1) = 0x9d000001;
262 #endif
263
264     single_stepping = (unsigned int *) pc;
265
266 #ifndef SC_EFLAGS
267     /*
268      * pc - 9 points to the pushf instruction that we installed for
269      * the helper.
270      */
271     
272     DPRINTF(0, (stderr, " Setting pc to pushf instruction at %p\n", (void*) ((char*) pc - 9)));
273     SC_PC(context) = (int)((char *) pc - 9);
274 #endif
275 }
276 \f
277
278 void
279 sigtrap_handler(HANDLER_ARGS)
280 {
281     unsigned int trap;
282     os_context_t* os_context = (os_context_t *) context;
283 #if 0
284     fprintf(stderr, "x86sigtrap: %8x %x\n",
285             SC_PC(os_os_context), *(unsigned char *) (SC_PC(os_context) - 1));
286     fprintf(stderr, "sigtrap(%d %d %x)\n", signal, CODE(code), os_context);
287 #endif
288
289     if (single_stepping && (signal == SIGTRAP)) {
290 #if 0
291         fprintf(stderr, "* Single step trap %p\n", single_stepping);
292 #endif
293
294 #ifdef SC_EFLAGS
295         /* Disable single-stepping */
296         SC_EFLAGS(os_context) ^= 0x100;
297 #else
298         /* Un-install single step helper instructions. */
299         *(single_stepping - 3) = single_step_save1;
300         *(single_stepping - 2) = single_step_save2;
301         *(single_stepping - 1) = single_step_save3;
302         DPRINTF(0, (stderr, "Uninstalling helper instructions\n"));
303 #endif
304
305         /*
306          * Re-install the breakpoint if possible.
307          */
308         if ((int) SC_PC(os_context) == (int) single_stepping + 1)
309             fprintf(stderr, "* Breakpoint not re-install\n");
310         else {
311             char *ptr = (char *) single_stepping;
312
313             ptr[0] = BREAKPOINT_INST;   /* x86 INT3 */
314             ptr[1] = trap_Breakpoint;
315         }
316
317         single_stepping = NULL;
318         return;
319     }
320
321     /* This is just for info in case monitor wants to print an approx */
322     current_control_stack_pointer = (unsigned long *) SC_SP(os_context);
323
324     RESTORE_FPU(os_context);
325
326     /*
327      * On entry %eip points just after the INT3 byte and aims at the
328      * 'kind' value (eg trap_Cerror). For error-trap and Cerror-trap a
329      * number of bytes will follow, the first is the length of the byte
330      * arguments to follow.
331      */
332
333     trap = *(unsigned char *) SC_PC(os_context);
334
335     switch (trap) {
336       case trap_PendingInterrupt:
337           DPRINTF(0, (stderr, "<trap Pending Interrupt.>\n"));
338           arch_skip_instruction(os_context);
339           interrupt_handle_pending(os_context);
340           break;
341
342       case trap_Halt:
343           {
344               FPU_STATE(fpu_state);
345               save_fpu_state(fpu_state);
346
347               fake_foreign_function_call(os_context);
348               lose("%%primitive halt called; the party is over.\n");
349               undo_fake_foreign_function_call(os_context);
350
351               restore_fpu_state(fpu_state);
352               arch_skip_instruction(os_context);
353               break;
354           }
355
356       case trap_Error:
357       case trap_Cerror:
358           DPRINTF(0, (stderr, "<trap Error %x>\n", CODE(code)));
359           interrupt_internal_error(signal, code, os_context, CODE(code) == trap_Cerror);
360           break;
361
362       case trap_Breakpoint:
363 #if 0
364           fprintf(stderr, "*C break\n");
365 #endif
366           SC_PC(os_context) -= 1;
367
368           handle_breakpoint(signal, CODE(code), os_context);
369 #if 0
370           fprintf(stderr, "*C break return\n");
371 #endif
372           break;
373
374       case trap_FunctionEndBreakpoint:
375           SC_PC(os_context) -= 1;
376           SC_PC(os_context) =
377               (int) handle_function_end_breakpoint(signal, CODE(code), os_context);
378           break;
379
380 #ifdef trap_DynamicSpaceOverflowWarning
381       case trap_DynamicSpaceOverflowWarning:
382           interrupt_handle_space_overflow(SymbolFunction
383                                           (DYNAMIC_SPACE_OVERFLOW_WARNING_HIT),
384                                           os_context);
385           break;
386 #endif
387 #ifdef trap_DynamicSpaceOverflowError
388       case trap_DynamicSpaceOverflowError:
389           interrupt_handle_space_overflow(SymbolFunction
390                                           (DYNAMIC_SPACE_OVERFLOW_ERROR_HIT),
391                                           os_context);
392           break;
393 #endif
394       default:
395           DPRINTF(0,
396                   (stderr, "[C--trap default %d %d %p]\n", signal, CODE(code),
397                    os_context));
398           interrupt_handle_now(signal, code, os_context);
399           break;
400     }
401 }
402
403 void
404 arch_install_interrupt_handlers(void)
405 {
406     interrupt_install_low_level_handler(SIGILL, sigtrap_handler);
407     interrupt_install_low_level_handler(SIGTRAP, sigtrap_handler);
408 }
409 \f
410
411 extern lispobj call_into_lisp(lispobj fun, lispobj * args, int nargs);
412
413 /* These next four functions are an interface to the 
414  * Lisp call-in facility. Since this is C we can know
415  * nothing about the calling environment. The control
416  * stack might be the C stack if called from the monitor
417  * or the Lisp stack if called as a result of an interrupt
418  * or maybe even a separate stack. The args are most likely
419  * on that stack but could be in registers depending on
420  * what the compiler likes. So I try to package up the
421  * args into a portable vector and let the assembly language
422  * call-in function figure it out.
423  */
424
425 lispobj
426 funcall0(lispobj function)
427 {
428     lispobj *args = NULL;
429
430     return call_into_lisp(function, args, 0);
431 }
432
433 lispobj
434 funcall1(lispobj function, lispobj arg0)
435 {
436     lispobj args[1];
437
438     args[0] = arg0;
439     return call_into_lisp(function, args, 1);
440 }
441
442 lispobj
443 funcall2(lispobj function, lispobj arg0, lispobj arg1)
444 {
445     lispobj args[2];
446
447     args[0] = arg0;
448     args[1] = arg1;
449     return call_into_lisp(function, args, 2);
450 }
451
452 lispobj
453 funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2)
454 {
455     lispobj args[3];
456
457     args[0] = arg0;
458     args[1] = arg1;
459     args[2] = arg2;
460     return call_into_lisp(function, args, 3);
461 }
462
463 #ifdef LINKAGE_TABLE
464
465 #ifndef LinkageEntrySize
466 #define LinkageEntrySize 8
467 #endif
468
469 void
470 arch_make_linkage_entry(long linkage_entry, void *target_addr, long type)
471 {
472     char *reloc_addr = (char *) (FOREIGN_LINKAGE_SPACE_START
473
474                                  + linkage_entry * LinkageEntrySize);
475
476     if (type == 1) {            /* code reference */
477         /* Make JMP to function entry. */
478         /* JMP offset is calculated from next instruction. */
479         long offset = (char *) target_addr - (reloc_addr + 5);
480         int i;
481
482         *reloc_addr++ = 0xe9;   /* opcode for JMP rel32 */
483         for (i = 0; i < 4; i++) {
484             *reloc_addr++ = offset & 0xff;
485             offset >>= 8;
486         }
487         /* write a nop for good measure. */
488         *reloc_addr = 0x90;
489     } else if (type == 2) {
490         *(unsigned long *) reloc_addr = (unsigned long) target_addr;
491     }
492 }
493
494 /* Make a call to the first function in the linkage table, which is
495    resolve_linkage_tramp. */
496 void
497 arch_make_lazy_linkage(long linkage_entry)
498 {
499     char *reloc_addr = (char *) (FOREIGN_LINKAGE_SPACE_START
500
501                                  + linkage_entry * LinkageEntrySize);
502     long offset = (char *) (FOREIGN_LINKAGE_SPACE_START) - (reloc_addr + 5);
503     int i;
504
505     *reloc_addr++ = 0xe8;       /* opcode for CALL rel32 */
506     for (i = 0; i < 4; i++) {
507         *reloc_addr++ = offset & 0xff;
508         offset >>= 8;
509     }
510     /* write a nop for good measure. */
511     *reloc_addr = 0x90;
512 }
513
514 /* Get linkage entry.  The initial instruction in the linkage
515    entry is a CALL; the return address we're passed points to the next
516    instruction. */
517
518 long
519 arch_linkage_entry(unsigned long retaddr)
520 {
521     return ((retaddr - 5) - FOREIGN_LINKAGE_SPACE_START) / LinkageEntrySize;
522 }
523 #endif /* LINKAGE_TABLE */
524
525 int ieee754_rem_pio2(double x, double *y0, double *y1)
526 {
527   extern int __ieee754_rem_pio2(double x, double *y);
528
529   double y[2];
530   int n;
531
532   n = __ieee754_rem_pio2(x, y);
533   *y0 = y[0];
534   *y1 = y[1];
535
536   return n;
537 }
538
539