1 /* x86-arch.c -*- Mode: C; comment-column: 40 -*-
3 * $Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/lisp/x86-arch.c,v 1.43 2010/12/26 16:04:43 rswindells Exp $
14 #include "internals.h"
19 #include "interrupt.h"
21 #include "breakpoint.h"
23 #define BREAKPOINT_INST 0xcc /* INT3 */
25 unsigned long fast_random_state = 1;
29 * Use the /dev/cpu/self/cpuid interface on Solaris. We could use the
30 * same method below, but the Sun C compiler miscompiles the inline
34 #include <sys/types.h>
41 void cpuid(int level, unsigned int* a, unsigned int* b,
42 unsigned int* c, unsigned int* d)
46 static const char devname[] = "/dev/cpu/self/cpuid";
48 *a = *b = *c = *d = 0;
49 if ((device = open(devname, O_RDONLY)) == -1) {
54 if (pread(device, regs, sizeof(regs), 1) != sizeof(regs)) {
71 #define __cpuid(level, a, b, c, d) \
72 __asm__ ("xchgl\t%%ebx, %1\n\t" \
74 "xchgl\t%%ebx, %1\n\t" \
75 : "=a" (a), "=r" (b), "=c" (c), "=d" (d) \
78 void cpuid(int level, unsigned int* a, unsigned int* b,
79 unsigned int* c, unsigned int* d)
81 unsigned int eax, ebx, ecx, edx;
83 __cpuid(level, eax, ebx, ecx, edx);
93 arch_support_sse2(void)
95 unsigned int eax, ebx, ecx, edx;
97 cpuid(1, &eax, &ebx, &ecx, &edx);
99 /* Return non-zero if SSE2 is supported */
100 return edx & 0x4000000;
104 arch_init(fpu_mode_t mode)
108 have_sse2 = arch_support_sse2() && os_support_sse2();
113 return "lisp-sse2.core";
115 return "lisp-x87.core";
119 return "lisp-x87.core";
122 return "lisp-sse2.core";
132 * Assuming we get here via an INT3 xxx instruction, the PC now
133 * points to the interrupt code (lisp value) so we just move past
134 * it. Skip the code, then if the code is an error-trap or
135 * Cerror-trap then skip the data bytes that follow.
139 arch_skip_instruction(os_context_t * context)
143 DPRINTF(0, (stderr, "[arch_skip_inst at %lx>]\n", SC_PC(context)));
145 /* Get and skip the lisp error code. */
146 code = *(char *) SC_PC(context)++;
150 /* Lisp error arg vector length */
151 vlen = *(char *) SC_PC(context)++;
152 /* Skip lisp error arg data bytes */
157 case trap_Breakpoint:
158 case trap_FunctionEndBreakpoint:
161 case trap_PendingInterrupt:
163 /* Only needed to skip the Code. */
167 fprintf(stderr, "[arch_skip_inst invalid code %d\n]\n", code);
171 DPRINTF(0, (stderr, "[arch_skip_inst resuming at %lx>]\n", SC_PC(context)));
175 arch_internal_error_arguments(os_context_t * context)
177 return (unsigned char *) (SC_PC(context) + 1);
181 arch_pseudo_atomic_atomic(os_context_t * context)
183 return SymbolValue(PSEUDO_ATOMIC_ATOMIC);
187 arch_set_pseudo_atomic_interrupted(os_context_t * context)
189 SetSymbolValue(PSEUDO_ATOMIC_INTERRUPTED, make_fixnum(1));
195 arch_install_breakpoint(void *pc)
197 unsigned long result = *(unsigned long *) pc;
199 *(char *) pc = BREAKPOINT_INST; /* x86 INT3 */
200 *((char *) pc + 1) = trap_Breakpoint; /* Lisp trap code */
206 arch_remove_breakpoint(void *pc, unsigned long orig_inst)
208 *((char *) pc) = orig_inst & 0xff;
209 *((char *) pc + 1) = (orig_inst & 0xff00) >> 8;
215 * When single stepping single_stepping holds the original instruction
219 unsigned int *single_stepping = NULL;
222 unsigned int single_step_save1;
223 unsigned int single_step_save2;
224 unsigned int single_step_save3;
228 arch_do_displaced_inst(os_context_t * context, unsigned long orig_inst)
230 unsigned int *pc = (unsigned int *) SC_PC(context);
233 * Put the original instruction back.
236 *((char *) pc) = orig_inst & 0xff;
237 *((char *) pc + 1) = (orig_inst & 0xff00) >> 8;
240 /* Enable single-stepping */
241 SC_EFLAGS(context) |= 0x100;
245 * Install helper instructions for the single step:
246 * nop; nop; nop; pushf; or [esp],0x100; popf.
248 * The or instruction enables the trap flag which enables
249 * single-stepping. So when the popf instruction is run, we start
250 * single-stepping and stop on the next instruction.
253 DPRINTF(0, (stderr, "Installing helper instructions\n"));
255 single_step_save1 = *(pc - 3);
256 single_step_save2 = *(pc - 2);
257 single_step_save3 = *(pc - 1);
258 *(pc - 3) = 0x9c909090;
259 *(pc - 2) = 0x00240c81;
260 *(pc - 1) = 0x9d000001;
263 single_stepping = (unsigned int *) pc;
267 * pc - 9 points to the pushf instruction that we installed for
271 DPRINTF(0, (stderr, " Setting pc to pushf instruction at %p\n", (void*) ((char*) pc - 9)));
272 SC_PC(context) = (int)((char *) pc - 9);
278 sigtrap_handler(HANDLER_ARGS)
281 os_context_t* os_context = (os_context_t *) context;
283 fprintf(stderr, "x86sigtrap: %8x %x\n",
284 SC_PC(os_os_context), *(unsigned char *) (SC_PC(os_context) - 1));
285 fprintf(stderr, "sigtrap(%d %d %x)\n", signal, CODE(code), os_context);
288 if (single_stepping && (signal == SIGTRAP)) {
290 fprintf(stderr, "* Single step trap %p\n", single_stepping);
294 /* Disable single-stepping */
295 SC_EFLAGS(os_context) ^= 0x100;
297 /* Un-install single step helper instructions. */
298 *(single_stepping - 3) = single_step_save1;
299 *(single_stepping - 2) = single_step_save2;
300 *(single_stepping - 1) = single_step_save3;
301 DPRINTF(0, (stderr, "Uninstalling helper instructions\n"));
305 * Re-install the breakpoint if possible.
307 if ((int) SC_PC(os_context) == (int) single_stepping + 1)
308 fprintf(stderr, "* Breakpoint not re-install\n");
310 char *ptr = (char *) single_stepping;
312 ptr[0] = BREAKPOINT_INST; /* x86 INT3 */
313 ptr[1] = trap_Breakpoint;
316 single_stepping = NULL;
320 /* This is just for info in case monitor wants to print an approx */
321 current_control_stack_pointer = (unsigned long *) SC_SP(os_context);
323 RESTORE_FPU(os_context);
326 * On entry %eip points just after the INT3 byte and aims at the
327 * 'kind' value (eg trap_Cerror). For error-trap and Cerror-trap a
328 * number of bytes will follow, the first is the length of the byte
329 * arguments to follow.
332 trap = *(unsigned char *) SC_PC(os_context);
335 case trap_PendingInterrupt:
336 DPRINTF(0, (stderr, "<trap Pending Interrupt.>\n"));
337 arch_skip_instruction(os_context);
338 interrupt_handle_pending(os_context);
343 FPU_STATE(fpu_state);
344 save_fpu_state(fpu_state);
346 fake_foreign_function_call(os_context);
347 lose("%%primitive halt called; the party is over.\n");
348 undo_fake_foreign_function_call(os_context);
350 restore_fpu_state(fpu_state);
351 arch_skip_instruction(os_context);
357 DPRINTF(0, (stderr, "<trap Error %x>\n", CODE(code)));
358 interrupt_internal_error(signal, code, os_context, CODE(code) == trap_Cerror);
361 case trap_Breakpoint:
363 fprintf(stderr, "*C break\n");
365 SC_PC(os_context) -= 1;
367 handle_breakpoint(signal, CODE(code), os_context);
369 fprintf(stderr, "*C break return\n");
373 case trap_FunctionEndBreakpoint:
374 SC_PC(os_context) -= 1;
376 (int) handle_function_end_breakpoint(signal, CODE(code), os_context);
379 #ifdef trap_DynamicSpaceOverflowWarning
380 case trap_DynamicSpaceOverflowWarning:
381 interrupt_handle_space_overflow(SymbolFunction
382 (DYNAMIC_SPACE_OVERFLOW_WARNING_HIT),
386 #ifdef trap_DynamicSpaceOverflowError
387 case trap_DynamicSpaceOverflowError:
388 interrupt_handle_space_overflow(SymbolFunction
389 (DYNAMIC_SPACE_OVERFLOW_ERROR_HIT),
395 (stderr, "[C--trap default %d %d %p]\n", signal, CODE(code),
397 interrupt_handle_now(signal, code, os_context);
403 arch_install_interrupt_handlers(void)
405 interrupt_install_low_level_handler(SIGILL, sigtrap_handler);
406 interrupt_install_low_level_handler(SIGTRAP, sigtrap_handler);
410 extern lispobj call_into_lisp(lispobj fun, lispobj * args, int nargs);
412 /* These next four functions are an interface to the
413 * Lisp call-in facility. Since this is C we can know
414 * nothing about the calling environment. The control
415 * stack might be the C stack if called from the monitor
416 * or the Lisp stack if called as a result of an interrupt
417 * or maybe even a separate stack. The args are most likely
418 * on that stack but could be in registers depending on
419 * what the compiler likes. So I try to package up the
420 * args into a portable vector and let the assembly language
421 * call-in function figure it out.
425 funcall0(lispobj function)
427 lispobj *args = NULL;
429 return call_into_lisp(function, args, 0);
433 funcall1(lispobj function, lispobj arg0)
438 return call_into_lisp(function, args, 1);
442 funcall2(lispobj function, lispobj arg0, lispobj arg1)
448 return call_into_lisp(function, args, 2);
452 funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2)
459 return call_into_lisp(function, args, 3);
464 #ifndef LinkageEntrySize
465 #define LinkageEntrySize 8
469 arch_make_linkage_entry(long linkage_entry, void *target_addr, long type)
471 char *reloc_addr = (char *) (FOREIGN_LINKAGE_SPACE_START
473 + linkage_entry * LinkageEntrySize);
475 if (type == 1) { /* code reference */
476 /* Make JMP to function entry. */
477 /* JMP offset is calculated from next instruction. */
478 long offset = (char *) target_addr - (reloc_addr + 5);
481 *reloc_addr++ = 0xe9; /* opcode for JMP rel32 */
482 for (i = 0; i < 4; i++) {
483 *reloc_addr++ = offset & 0xff;
486 /* write a nop for good measure. */
488 } else if (type == 2) {
489 *(unsigned long *) reloc_addr = (unsigned long) target_addr;
493 /* Make a call to the first function in the linkage table, which is
494 resolve_linkage_tramp. */
496 arch_make_lazy_linkage(long linkage_entry)
498 char *reloc_addr = (char *) (FOREIGN_LINKAGE_SPACE_START
500 + linkage_entry * LinkageEntrySize);
501 long offset = (char *) (FOREIGN_LINKAGE_SPACE_START) - (reloc_addr + 5);
504 *reloc_addr++ = 0xe8; /* opcode for CALL rel32 */
505 for (i = 0; i < 4; i++) {
506 *reloc_addr++ = offset & 0xff;
509 /* write a nop for good measure. */
513 /* Get linkage entry. The initial instruction in the linkage
514 entry is a CALL; the return address we're passed points to the next
518 arch_linkage_entry(unsigned long retaddr)
520 return ((retaddr - 5) - FOREIGN_LINKAGE_SPACE_START) / LinkageEntrySize;
522 #endif /* LINKAGE_TABLE */
524 int ieee754_rem_pio2(double x, double *y0, double *y1)
526 extern int __ieee754_rem_pio2(double x, double *y);
531 n = __ieee754_rem_pio2(x, y);