0.7.5.13:
authorChristophe Rhodes <csr21@cam.ac.uk>
Tue, 16 Jul 2002 13:48:02 +0000 (13:48 +0000)
committerChristophe Rhodes <csr21@cam.ac.uk>
Tue, 16 Jul 2002 13:48:02 +0000 (13:48 +0000)
Linux floating point fixes
... define an os_restore_fp_control() function in the runtime, and
use it in signal handlers (protected by #ifdef
LISP_FEATURE_LINUX in non-Linux-specific code)
... write useful definitions of it
... for x86 (probably correct)
... for ppc (works, but could do with fixing)
... delete a SET_FPU_CONTROL_WORD from initialization
... dunno why it was there; no observable symptoms. Shout
if some early x86/Linux system no longer works.
... export to C (via sbcl.h) Lisp's view of the floating point
control word
... delete some floating-point-related stale symbols and comments
from package-data-list.lisp-expr
Now floating point stuff mostly works (I think) on x86/Linux and
ppc/Linux, as well as sparc/SunOS. Other platforms still
probably don't work.

19 files changed:
package-data-list.lisp-expr
src/code/x86-vm.lisp
src/compiler/generic/genesis.lisp
src/runtime/alpha-arch.c
src/runtime/alpha-linux-os.c
src/runtime/alpha-linux-os.h
src/runtime/interrupt.c
src/runtime/linux-os.c
src/runtime/linux-os.h
src/runtime/ppc-arch.c
src/runtime/ppc-linux-os.c
src/runtime/ppc-linux-os.h
src/runtime/sparc-arch.c
src/runtime/sparc-linux-os.c
src/runtime/sparc-linux-os.h
src/runtime/x86-arch.c
src/runtime/x86-linux-os.c
src/runtime/x86-linux-os.h
version.lisp-expr

index 7be4e32..f632013 100644 (file)
@@ -552,11 +552,6 @@ like *STACK-TOP-HINT* and unsupported stuff like *TRACED-FUN-LIST*."
              ;; WITH-STANDARD-IO-SYNTAX or something.)
              "*ERROR-PRINT-LENGTH*" "*ERROR-PRINT-LEVEL*" "*ERROR-PRINT-LINES*"
 
-             ;; KLUDGE: CMU CL had
-             ;; "*IGNORE-FLOATING-POINT-UNDERFLOW*", which seemed
-             ;; like a reasonable idea but doesn't seem to be supported
-             ;; now? -- WHN 19991206
-
              ;; extended declarations..
              "FREEZE-TYPE" "INHIBIT-WARNINGS"
              "MAYBE-INLINE"
@@ -586,7 +581,6 @@ like *STACK-TOP-HINT* and unsupported stuff like *TRACED-FUN-LIST*."
              ;; want to do this stuff.
              "FLOAT-DENORMALIZED-P"
              "FLOAT-NAN-P" "FLOAT-TRAPPING-NAN-P"
-             "FLOATING-POINT-INVALID"
              "FLOAT-INFINITY-P"
              "SHORT-FLOAT-NEGATIVE-INFINITY"
              "SHORT-FLOAT-POSITIVE-INFINITY"
index 2d68335..21c2f47 100644 (file)
 
 ;;; Given a signal context, return the floating point modes word in
 ;;; the same format as returned by FLOATING-POINT-MODES.
+#!-linux
 (defun context-floating-point-modes (context)
   ;; FIXME: As of sbcl-0.6.7 and the big rewrite of signal handling for
   ;; POSIXness and (at the Lisp level) opaque signal contexts,
     (logior (ash (logand sw #xffff) 16) (logxor (logand cw #xffff) #x3f)))
 
   0)
+
+#!+linux
+(define-alien-routine ("os_context_fp_control" context-floating-point-modes)
+    (sb!alien:unsigned 32)
+  (context (* os-context-t)))
 \f
 ;;;; INTERNAL-ERROR-ARGS
 
index fad92a9..8640884 100644 (file)
   ;; pseudo-atomic-trap-number or pseudo-atomic-magic-constant
   ;; [possibly applicable to other platforms])
 
+  (dolist (symbol '(sb!vm::float-traps-byte sb!vm::float-exceptions-byte sb!vm::float-sticky-bits sb!vm::float-rounding-mode))
+    (format t "#define ~A_POSITION ~A /* ~:*0x~X */~%"
+           (substitute #\_ #\- (symbol-name symbol))
+           (sb!xc:byte-position (symbol-value symbol)))
+    (format t "#define ~A_MASK 0x~X /* ~:*~A */~%"
+           (substitute #\_ #\- (symbol-name symbol))
+           (sb!xc:mask-field (symbol-value symbol) -1)))
+
   ;; writing primitive object layouts
   (let ((structs (sort (copy-list sb!vm:*primitive-objects*) #'string<
                       :key (lambda (obj)
index 27ea9ee..03cf3c7 100644 (file)
@@ -280,6 +280,10 @@ sigtrap_handler(int signal, siginfo_t *siginfo, os_context_t *context)
 {
     unsigned int code;
 
+#ifdef LISP_FEATURE_LINUX
+    os_restore_fp_control(context);
+#endif
+
     /* Don't disallow recursive breakpoint traps.  Otherwise, we can't */
     /* use debugger breakpoints anywhere in here. */
     sigset_t *mask=(os_context_sigmask_addr(context));
index 249136d..45c9ffb 100644 (file)
@@ -74,6 +74,22 @@ os_context_fp_control(os_context_t *context)
     return ieee_fpcr_to_swcr((context->uc_mcontext).sc_fpcr);
 }
 
+void
+os_restore_fp_control(os_context_t *context)
+{
+    /* FIXME (in two parts):
+       Firstly, what happens in alpha linux inside the signal handler?
+       Does the floating point control state get cleared as in other
+       Linuxes?
+    
+       Secondly, how do we put it back if so? It will probably involve
+       something to do with
+    
+       context->uc_mcontext.sc_fpcr
+
+       (maybe a simple assembly statement will be enough)
+    */ 
+}
 
 void os_flush_icache(os_vm_address_t address, os_vm_size_t length)
 {
index c270f2e..63858cf 100644 (file)
@@ -7,4 +7,6 @@ static inline os_context_t *arch_os_get_context(void **void_context) {
   return (os_context_t *) *void_context;
 }
 
+unsigned long os_context_fp_control(os_context_t *context);
+
 #endif /* _ALPHA_LINUX_OS_H */
index 5b20451..1eb49ca 100644 (file)
@@ -347,23 +347,12 @@ interrupt_handle_now(int signal, siginfo_t *info, void *void_context)
 #endif
     union interrupt_handler handler;
 
-    /* FIXME: The CMU CL we forked off of had this Linux-only
-     * operation here. Newer CMU CLs (e.g. 18c) have hairier
-     * Linux/i386-only logic here. SBCL seems to be more reliable
-     * without anything here. However, if we start supporting code
-     * which sets the rounding mode, then we may want to do something
-     * special to force the rounding mode back to some standard value
-     * here, so that ISRs can have a standard environment. (OTOH, if
-     * rounding modes are under user control, then perhaps we should
-     * leave this up to the user.)
-     *
-     * In the absence of a test case to show that this is really a
-     * problem, we just suppress this code completely (just like the
-     * parallel code in maybe_now_maybe_later).
-     * #ifdef __linux__
-     *    SET_FPU_CONTROL_WORD(context->__fpregs_mem.cw);
-     * #endif */
-
+#ifdef LISP_FEATURE_LINUX
+    /* Under Linux, we appear to have to restore the fpu control word
+       from the context, as after the signal is delivered we appear to
+       have a null fpu control word. */
+    os_restore_fp_control(context);
+#endif 
     handler = interrupt_handlers[signal];
 
     if (ARE_SAME_HANDLER(handler.c, SIG_IGN)) {
@@ -446,12 +435,12 @@ maybe_now_maybe_later(int signal, siginfo_t *info, void *void_context)
      * interrupt time which should be ported into SBCL. Also see the
      * analogous logic at the head of interrupt_handle_now for
      * more related FIXME stuff. 
-     *
-     * For now, we just suppress this code completely.
-     * #ifdef __linux__
-     *    SET_FPU_CONTROL_WORD(context->__fpregs_mem.cw);
-     * #endif */
-
+     */
+    
+#ifdef LISP_FEATURE_LINUX
+    os_restore_fp_control(context);
+#endif 
+    
     /* see comments at top of code/signal.lisp for what's going on here
      * with INTERRUPTS_ENABLED/INTERRUPT_HANDLE_NOW 
      */
index d44f19f..bef7006 100644 (file)
@@ -80,16 +80,17 @@ void os_init(void)
     }
 
     os_vm_page_size = getpagesize();
-   /* This could just as well be in arch_init(), but it's not. */
+    /* This could just as well be in arch_init(), but it's not. */
 #ifdef __i386__
-    SET_FPU_CONTROL_WORD(0x1372|4|8|16|32); /* no interrupts */
+    /* FIXME: This used to be here.  However, I have just removed it
+       with no apparent ill effects (it may be that earlier kernels
+       started up a process with a different set of traps, or
+       something?) Find out what this was meant to do, and reenable it
+       or delete it if possible. -- CSR, 2002-07-15 */
+    /* SET_FPU_CONTROL_WORD(0x1372|4|8|16|32); /* no interrupts */
 #endif
 }
 
-/* various os_context_*_addr accessors moved to {x86,alpha}-linux-os.c 
- * -dan 20010125
- */
-
 /* In Debian CMU CL ca. 2.4.9, it was possible to get an infinite
  * cascade of errors from do_mmap(..). This variable is a counter to
  * prevent that; when it counts down to zero, an error in do_mmap
index 267929f..ed8733d 100644 (file)
@@ -32,13 +32,9 @@ typedef size_t os_vm_size_t;
 typedef off_t os_vm_offset_t;
 typedef int os_vm_prot_t;
 
-/* typedef struct ucontext os_context_t;*/
-
 #define OS_VM_PROT_READ    PROT_READ
 #define OS_VM_PROT_WRITE   PROT_WRITE
 #define OS_VM_PROT_EXECUTE PROT_EXEC
 
-#define SET_FPU_CONTROL_WORD(cw) asm("fldcw %0" : : "m" (cw))
-
 /* /usr/include/asm/sigcontext.h  */
 typedef long os_context_register_t ;
index eac4013..2d62424 100644 (file)
@@ -137,6 +137,9 @@ sigtrap_handler(int signal, siginfo_t *siginfo, os_context_t *context)
     int badinst;
     u32 code;
     sigset_t *mask;
+#ifdef LISP_FEATURE_LINUX
+    os_restore_fp_control(context);
+#endif
     mask=(os_context_sigmask_addr(context));
     sigsetmask(mask); 
     code=*((u32 *)(*os_context_pc_addr(context)));
index 1d0ae66..14411f6 100644 (file)
@@ -75,10 +75,41 @@ os_context_fp_control(os_context_t *context)
        registers, and PT_FPSCR is an offset that is larger than 32
        (the number of ppc registers), but that happens to get the
        right answer. -- CSR, 2002-07-11 */
-    return &((context->uc_mcontext.regs)->gpr[PT_FPSCR]); 
+    return context->uc_mcontext.regs->gpr[PT_FPSCR]; 
 }
 
-void os_flush_icache(os_vm_address_t address, os_vm_size_t length)
+void 
+os_restore_fp_control(os_context_t *context)
+{
+    unsigned long control;
+    
+    control = os_context_fp_control(context) & 
+      /* FIXME: Should we preserve the user's requested rounding mode?
+
+         Note that doing 
+
+        ~(FLOAT_STICKY_BITS_MASK | FLOAT_EXCEPTIONS_BYTE_MASK)
+
+        here leads to infinite SIGFPE for invalid operations, as
+        there are bits in the control register that need to be
+        cleared that are let through by that mask. -- CSR, 2002-07-16 */
+      FLOAT_TRAPS_BYTE_MASK;
+    
+    /* FIXME: Shoot me now.
+       
+       Hardcoded nastiness: the "0"s below refer to the first floating
+       point registers -- we should let gcc deal with that. The 8(31)
+       refers to the position on the stack, less one, of control (we
+       need for control to be the high word of the double loaded by
+       lfd; how do I know that r31 contains the stack? I don't, I'm
+       just guessing. The 255, on the other hand, is a valid constant
+       -- it says "move everything in the upper word into the floating
+       point control register. -- CSR, 2002-07-16 */
+    asm ("stw %0, 12(31); lfd 0, 8(31); mtfsf 255, 0" : : "r" (control) : "r31");
+}
+
+void 
+os_flush_icache(os_vm_address_t address, os_vm_size_t length)
 {
     /* see ppc-arch.c */
     ppc_flush_icache(address,length);
index e057ad3..28dad76 100644 (file)
@@ -7,4 +7,7 @@ static inline os_context_t *arch_os_get_context(void **void_context) {
   return (os_context_t *) *void_context;
 }
 
+unsigned long os_context_fp_control(os_context_t *context);
+void os_restore_fp_control(os_context_t *context);
+
 #endif /* _PPC_LINUX_OS_H */
index c2bfd22..6a79854 100644 (file)
@@ -62,7 +62,7 @@ os_vm_address_t arch_get_bad_addr(int sig, siginfo_t *code, os_context_t *contex
        return 0;
 
     rs1 = (badinst>>14)&0x1f;
-
+    
     if (badinst & (1<<13)) {
        /* r[rs1] + simm(13) */
        int simm13 = badinst & 0x1fff;
@@ -71,54 +71,54 @@ os_vm_address_t arch_get_bad_addr(int sig, siginfo_t *code, os_context_t *contex
            simm13 |= -1<<13;
 
        return (os_vm_address_t)
-         (*os_context_register_addr(context, rs1)+simm13);
+           (*os_context_register_addr(context, rs1)+simm13);
     }
     else {
        /* r[rs1] + r[rs2] */
        int rs2 = badinst & 0x1f;
 
        return (os_vm_address_t)
-         (*os_context_register_addr(context, rs1) + 
-          *os_context_register_addr(context, rs2));
+           (*os_context_register_addr(context, rs1) + 
+            *os_context_register_addr(context, rs2));
     }
 }
 
 void arch_skip_instruction(os_context_t *context)
 {
-  ((char *) *os_context_pc_addr(context)) = ((char *) *os_context_npc_addr(context));
-  ((char *) *os_context_npc_addr(context)) += 4;
+    ((char *) *os_context_pc_addr(context)) = ((char *) *os_context_npc_addr(context));
+    ((char *) *os_context_npc_addr(context)) += 4;
 }
 
 unsigned char *arch_internal_error_arguments(os_context_t *context)
 {
-  return (unsigned char *)(*os_context_pc_addr(context) + 4);
+    return (unsigned char *)(*os_context_pc_addr(context) + 4);
 }
 
 boolean arch_pseudo_atomic_atomic(os_context_t *context)
 {
-  return ((*os_context_register_addr(context,reg_ALLOC)) & 4);
+    return ((*os_context_register_addr(context,reg_ALLOC)) & 4);
 }
 
 void arch_set_pseudo_atomic_interrupted(os_context_t *context)
 {
-  *os_context_register_addr(context,reg_ALLOC) |=  1;
+    *os_context_register_addr(context,reg_ALLOC) |=  1;
 }
 
 unsigned long arch_install_breakpoint(void *pc)
 {
-  unsigned long *ptr = (unsigned long *)pc;
-  unsigned long result = *ptr;
-  *ptr = trap_Breakpoint;
-  
-  os_flush_icache((os_vm_address_t) pc, sizeof(unsigned long));
+    unsigned long *ptr = (unsigned long *)pc;
+    unsigned long result = *ptr;
+    *ptr = trap_Breakpoint;
   
-  return result;
+    os_flush_icache((os_vm_address_t) pc, sizeof(unsigned long));
+    
+    return result;
 }
 
 void arch_remove_breakpoint(void *pc, unsigned long orig_inst)
 {
-  *(unsigned long *)pc = orig_inst;
-  os_flush_icache((os_vm_address_t) pc, sizeof(unsigned long));
+    *(unsigned long *)pc = orig_inst;
+    os_flush_icache((os_vm_address_t) pc, sizeof(unsigned long));
 }
 
 static unsigned long *skipped_break_addr, displaced_after_inst;
@@ -126,223 +126,228 @@ static sigset_t orig_sigmask;
 
 void arch_do_displaced_inst(os_context_t *context, unsigned int orig_inst)
 {
-  unsigned long *pc = (unsigned long *)(*os_context_pc_addr(context));
-  /* FIXME */
-  unsigned long *npc = (unsigned long *)(*os_context_npc_addr(context));
+    unsigned long *pc = (unsigned long *)(*os_context_pc_addr(context));
+    unsigned long *npc = (unsigned long *)(*os_context_npc_addr(context));
 
   /*  orig_sigmask = context->sigmask;
       sigemptyset(&context->sigmask); */
   /* FIXME!!! */
   /* FILLBLOCKSET(&context->uc_sigmask);*/
 
-  *pc = orig_inst;
-  os_flush_icache((os_vm_address_t) pc, sizeof(unsigned long));
-  skipped_break_addr = pc;
-  displaced_after_inst = *npc;
-  *npc = trap_AfterBreakpoint;
-  os_flush_icache((os_vm_address_t) npc, sizeof(unsigned long));
-
+    *pc = orig_inst;
+    os_flush_icache((os_vm_address_t) pc, sizeof(unsigned long));
+    skipped_break_addr = pc;
+    displaced_after_inst = *npc;
+    *npc = trap_AfterBreakpoint;
+    os_flush_icache((os_vm_address_t) npc, sizeof(unsigned long));
+    
 }
 
 static int pseudo_atomic_trap_p(os_context_t *context)
 {
-  unsigned int* pc;
-  unsigned int badinst;
-  int result;
-  
-  
-  pc = (unsigned int*) *os_context_pc_addr(context);
-  badinst = *pc;
-  result = 0;
-
-  /* Check to see if the current instruction is a pseudo-atomic-trap */
-  if (((badinst >> 30) == 2) && (((badinst >> 19) & 0x3f) == 0x3a)
-      && (((badinst >> 13) & 1) == 1) && ((badinst & 0x7f) == PSEUDO_ATOMIC_TRAP))
-    {
-      unsigned int previnst;
-      previnst = pc[-1];
-      /*
-       * Check to see if the previous instruction was an andcc alloc-tn,
-       * 3, zero-tn instruction.
-       */
-      if (((previnst >> 30) == 2) && (((previnst >> 19) & 0x3f) == 0x11)
-          && (((previnst >> 14) & 0x1f) == reg_ALLOC)
-          && (((previnst >> 25) & 0x1f) == reg_ZERO)
-          && (((previnst >> 13) & 1) == 1)
-          && ((previnst & 0x1fff) == 3))
-        {
-          result = 1;
-        }
-      else
-        {
-          fprintf(stderr, "Oops!  Got a PSEUDO-ATOMIC-TRAP without a preceeding andcc!\n");
-        }
-    }
-  return result;
+    unsigned int* pc;
+    unsigned int badinst;
+    int result;
+    
+    
+    pc = (unsigned int*) *os_context_pc_addr(context);
+    badinst = *pc;
+    result = 0;
+    
+    /* Check to see if the current instruction is a pseudo-atomic-trap */
+    if (((badinst >> 30) == 2) && (((badinst >> 19) & 0x3f) == 0x3a)
+       && (((badinst >> 13) & 1) == 1) && ((badinst & 0x7f) == PSEUDO_ATOMIC_TRAP))
+       {
+           unsigned int previnst;
+           previnst = pc[-1];
+           /*
+            * Check to see if the previous instruction was an andcc alloc-tn,
+            * 3, zero-tn instruction.
+            */
+           if (((previnst >> 30) == 2) && (((previnst >> 19) & 0x3f) == 0x11)
+               && (((previnst >> 14) & 0x1f) == reg_ALLOC)
+               && (((previnst >> 25) & 0x1f) == reg_ZERO)
+               && (((previnst >> 13) & 1) == 1)
+               && ((previnst & 0x1fff) == 3))
+               {
+                   result = 1;
+               }
+           else
+               {
+                   fprintf(stderr, "Oops!  Got a PSEUDO-ATOMIC-TRAP without a preceeding andcc!\n");
+               }
+       }
+    return result;
 }
 
 static void sigill_handler(int signal, siginfo_t *siginfo, void *void_context)
 {
-  os_context_t *context = arch_os_get_context(&void_context);
-
-  sigprocmask(SIG_SETMASK, os_context_sigmask_addr(context), 0);
-
-  if ((siginfo->si_code) == ILL_ILLOPC
+    os_context_t *context = arch_os_get_context(&void_context);
 #ifdef LISP_FEATURE_LINUX
-      || (early_kernel && (siginfo->si_code == 2))
+    /* FIXME: Check that this is necessary -- CSR, 2002-07-15 */
+    os_restore_fp_control(context);
 #endif
-      ) {
-    int trap;
-    unsigned int inst;
-    unsigned int* pc = (unsigned int*) siginfo->si_addr;
-
-    inst = *pc;
-    trap = inst & 0x3fffff;
+    sigprocmask(SIG_SETMASK, os_context_sigmask_addr(context), 0);
     
-    switch (trap) {
-    case trap_PendingInterrupt:
-      arch_skip_instruction(context);
-      interrupt_handle_pending(context);
-      break;
-
-    case trap_Halt:
-      fake_foreign_function_call(context);
-      lose("%%primitive halt called; the party is over.\n");
-      
-    case trap_Error:
-    case trap_Cerror:
-      interrupt_internal_error(signal, siginfo, context, trap == trap_Cerror);
-      break;
-
-    case trap_Breakpoint:
-      handle_breakpoint(signal, siginfo, context);
-      break;
-
-    case trap_FunEndBreakpoint:
-      *os_context_pc_addr(context) = (int) handle_fun_end_breakpoint(signal, siginfo, context);
-      *os_context_npc_addr(context) = *os_context_pc_addr(context) + 4;
-      break;
-
-    case trap_AfterBreakpoint:
-      *skipped_break_addr = trap_Breakpoint;
-      skipped_break_addr = NULL;
-      *(unsigned long *) os_context_pc_addr(context) = displaced_after_inst;
-      /* context->sigmask = orig_sigmask; */
-      os_flush_icache((os_vm_address_t) os_context_pc_addr(context), sizeof(unsigned long));
-      break;
-      
-    default:
-      interrupt_handle_now(signal, siginfo, context);
-      break;
+    if ((siginfo->si_code) == ILL_ILLOPC
+#ifdef LISP_FEATURE_LINUX
+       || (early_kernel && (siginfo->si_code == 2))
+#endif
+       ) {
+       int trap;
+       unsigned int inst;
+       unsigned int* pc = (unsigned int*) siginfo->si_addr;
+
+       inst = *pc;
+       trap = inst & 0x3fffff;
+       
+       switch (trap) {
+       case trap_PendingInterrupt:
+           arch_skip_instruction(context);
+           interrupt_handle_pending(context);
+           break;
+           
+       case trap_Halt:
+           fake_foreign_function_call(context);
+           lose("%%primitive halt called; the party is over.\n");
+           
+       case trap_Error:
+       case trap_Cerror:
+           interrupt_internal_error(signal, siginfo, context, trap == trap_Cerror);
+           break;
+           
+       case trap_Breakpoint:
+           handle_breakpoint(signal, siginfo, context);
+           break;
+           
+       case trap_FunEndBreakpoint:
+           *os_context_pc_addr(context) = (int) handle_fun_end_breakpoint(signal, siginfo, context);
+           *os_context_npc_addr(context) = *os_context_pc_addr(context) + 4;
+           break;
+           
+       case trap_AfterBreakpoint:
+           *skipped_break_addr = trap_Breakpoint;
+           skipped_break_addr = NULL;
+           *(unsigned long *) os_context_pc_addr(context) = displaced_after_inst;
+           /* context->sigmask = orig_sigmask; */
+           os_flush_icache((os_vm_address_t) os_context_pc_addr(context), sizeof(unsigned long));
+           break;
+           
+       default:
+           interrupt_handle_now(signal, siginfo, context);
+           break;
+       }
     }
-  }
-  else if ((siginfo->si_code) == ILL_ILLTRP
+    else if ((siginfo->si_code) == ILL_ILLTRP
 #ifdef LISP_FEATURE_LINUX
-          || (early_kernel && (siginfo->si_code) == 192)
+            || (early_kernel && (siginfo->si_code) == 192)
 #endif
-          ) {
-    if (pseudo_atomic_trap_p(context)) {
-      /* A trap instruction from a pseudo-atomic.  We just need
-        to fixup up alloc-tn to remove the interrupted flag,
-        skip over the trap instruction, and then handle the
-        pending interrupt(s). */
-      *os_context_register_addr(context, reg_ALLOC) &= ~7;
-      arch_skip_instruction(context);
-      interrupt_handle_pending(context);
+            ) {
+       if (pseudo_atomic_trap_p(context)) {
+           /* A trap instruction from a pseudo-atomic.  We just need
+              to fixup up alloc-tn to remove the interrupted flag,
+              skip over the trap instruction, and then handle the
+              pending interrupt(s). */
+           *os_context_register_addr(context, reg_ALLOC) &= ~7;
+           arch_skip_instruction(context);
+           interrupt_handle_pending(context);
+       }
+       else {
+           interrupt_internal_error(signal, siginfo, context, 0);
+       }
     }
     else {
-      interrupt_internal_error(signal, siginfo, context, 0);
+       interrupt_handle_now(signal, siginfo, context);
     }
-  }
-  else {
-    interrupt_handle_now(signal, siginfo, context);
-  }
 }
 
 static void sigemt_handler(int signal, siginfo_t *siginfo, void *void_context)
 {
-  unsigned long badinst;
-  boolean subtract, immed;
-  int rd, rs1, op1, rs2, op2, result;
-  os_context_t *context = arch_os_get_context(&void_context);
-
-  badinst = *(unsigned long *)os_context_pc_addr(context);
-  if ((badinst >> 30) != 2 || ((badinst >> 20) & 0x1f) != 0x11) {
-    /* It wasn't a tagged add.  Pass the signal into lisp. */
-    interrupt_handle_now(signal, siginfo, context);
-    return;
-  }
-
-  fprintf(stderr, "SIGEMT trap handler with tagged op instruction!\n");
-  
-  /* Extract the parts of the inst. */
-  subtract = badinst & (1<<19);
-  rs1 = (badinst>>14) & 0x1f;
-  op1 = *os_context_register_addr(context, rs1);
-  
-  /* If the first arg is $ALLOC then it is really a signal-pending note */
-  /* for the pseudo-atomic noise. */
-  if (rs1 == reg_ALLOC) {
-    /* Perform the op anyway. */
-    op2 = badinst & 0x1fff;
-    if (op2 & (1<<12))
-      op2 |= -1<<13;
-    if (subtract)
-      result = op1 - op2;
-    else
-      result = op1 + op2;
-    *os_context_register_addr(context, reg_ALLOC) = result & ~7;
-    arch_skip_instruction(context);
-    interrupt_handle_pending(context);
-    return;
-  }
-
-  if ((op1 & 3) != 0) {
-    /* The first arg wan't a fixnum. */
-    interrupt_internal_error(signal, siginfo, context, 0);
-    return;
-  }
-
-  if (immed = badinst & (1<<13)) {
-    op2 = badinst & 0x1fff;
-    if (op2 & (1<<12))
-      op2 |= -1<<13;
-  }
-  else {
-    rs2 = badinst & 0x1f;
-    op2 = *os_context_register_addr(context, rs2);
-  }
-
-  if ((op2 & 3) != 0) {
-    /* The second arg wan't a fixnum. */
-    interrupt_internal_error(signal, siginfo, context, 0);
-    return;
-  }
-
-  rd = (badinst>>25) & 0x1f;
-  if (rd != 0) {
-    /* Don't bother computing the result unless we are going to use it. */
-    if (subtract)
-      result = (op1>>2) - (op2>>2);
-    else
-      result = (op1>>2) + (op2>>2);
+    unsigned long badinst;
+    boolean subtract, immed;
+    int rd, rs1, op1, rs2, op2, result;
+    os_context_t *context = arch_os_get_context(&void_context);
+#ifdef LISP_FEATURE_LINUX
+    os_restore_fp_control(context);
+#endif
     
-    dynamic_space_free_pointer =
-      (lispobj *) *os_context_register_addr(context, reg_ALLOC);
-
-    *os_context_register_addr(context, rd) = alloc_number(result);
+    badinst = *(unsigned long *)os_context_pc_addr(context);
+    if ((badinst >> 30) != 2 || ((badinst >> 20) & 0x1f) != 0x11) {
+       /* It wasn't a tagged add.  Pass the signal into lisp. */
+       interrupt_handle_now(signal, siginfo, context);
+       return;
+    }
     
-    *os_context_register_addr(context, reg_ALLOC) =
-      (unsigned long) dynamic_space_free_pointer;
-  }
-
-  arch_skip_instruction(context);
+    fprintf(stderr, "SIGEMT trap handler with tagged op instruction!\n");
+    
+    /* Extract the parts of the inst. */
+    subtract = badinst & (1<<19);
+    rs1 = (badinst>>14) & 0x1f;
+    op1 = *os_context_register_addr(context, rs1);
+    
+    /* If the first arg is $ALLOC then it is really a signal-pending note */
+    /* for the pseudo-atomic noise. */
+    if (rs1 == reg_ALLOC) {
+       /* Perform the op anyway. */
+       op2 = badinst & 0x1fff;
+       if (op2 & (1<<12))
+           op2 |= -1<<13;
+       if (subtract)
+           result = op1 - op2;
+       else
+           result = op1 + op2;
+       *os_context_register_addr(context, reg_ALLOC) = result & ~7;
+       arch_skip_instruction(context);
+       interrupt_handle_pending(context);
+       return;
+    }
+    
+    if ((op1 & 3) != 0) {
+       /* The first arg wan't a fixnum. */
+       interrupt_internal_error(signal, siginfo, context, 0);
+       return;
+    }
+    
+    if (immed = badinst & (1<<13)) {
+       op2 = badinst & 0x1fff;
+       if (op2 & (1<<12))
+           op2 |= -1<<13;
+    }
+    else {
+       rs2 = badinst & 0x1f;
+       op2 = *os_context_register_addr(context, rs2);
+    }
+    
+    if ((op2 & 3) != 0) {
+       /* The second arg wan't a fixnum. */
+       interrupt_internal_error(signal, siginfo, context, 0);
+       return;
+    }
+    
+    rd = (badinst>>25) & 0x1f;
+    if (rd != 0) {
+       /* Don't bother computing the result unless we are going to use it. */
+       if (subtract)
+           result = (op1>>2) - (op2>>2);
+       else
+           result = (op1>>2) + (op2>>2);
+       
+       dynamic_space_free_pointer =
+           (lispobj *) *os_context_register_addr(context, reg_ALLOC);
+       
+       *os_context_register_addr(context, rd) = alloc_number(result);
+       
+       *os_context_register_addr(context, reg_ALLOC) =
+           (unsigned long) dynamic_space_free_pointer;
+    }
+    
+    arch_skip_instruction(context);
 }
 
 void arch_install_interrupt_handlers()
 {
-  undoably_install_low_level_interrupt_handler(SIGILL , sigill_handler);
-  undoably_install_low_level_interrupt_handler(SIGEMT, sigemt_handler);
+    undoably_install_low_level_interrupt_handler(SIGILL , sigill_handler);
+    undoably_install_low_level_interrupt_handler(SIGEMT, sigemt_handler);
 }
 
 \f
index 60c1bc5..9d4d683 100644 (file)
@@ -75,7 +75,22 @@ os_context_sigmask_addr(os_context_t *context)
     return &(context->si_mask);
 }
 
-void os_flush_icache(os_vm_address_t address, os_vm_size_t length)
+void 
+os_restore_fp_control(os_context_t *context)
+{
+    /* Included here, for reference, is an attempt at the PPC
+       variant. If it weren't the case that SPARC/Linux gave a Bus
+       Error on floating point exceptions, something like this would
+       have to be done. -- CSR, 2002-07-13
+
+    asm ("msfsf $255, %0" : : "m" 
+        (os_context_fp_control(context) & 
+         ~ (FLOAT_STICKY_BITS_MASK | FLOAT_EXCEPTIONS_BYTE_MASK)));
+    */
+}
+
+void 
+os_flush_icache(os_vm_address_t address, os_vm_size_t length)
 {
     /* This is the same for linux and solaris, so see sparc-assem.S */
     sparc_flush_icache(address,length);
index a8305f3..98413e8 100644 (file)
@@ -8,4 +8,7 @@ static inline os_context_t *arch_os_get_context(void **void_context) {
   return (os_context_t *) (void_context + 37);
 }
 
+unsigned long os_context_fp_control(os_context_t *context);
+void os_restore_fp_control(os_context_t *context);
+
 #endif /* _SPARC_LINUX_OS_H */
index 96d3bcd..5063c98 100644 (file)
@@ -217,6 +217,16 @@ sigtrap_handler(int signal, siginfo_t *info, void *void_context)
     current_control_stack_pointer =
        (lispobj *)*os_context_sp_addr(context);
 
+    /* FIXME: CMUCL puts the float control restoration code here.
+       Thus, it seems to me that single-stepping won't restore the
+       float control.  Since SBCL currently doesn't support
+       single-stepping (as far as I can tell) this is somewhat moot,
+       but it might be worth either moving this code up or deleting
+       the single-stepping code entirely.  -- CSR, 2002-07-15 */
+#ifdef LISP_FEATURE_LINUX
+    os_restore_fp_control(context);
+#endif
+
     /* On entry %eip points just after the INT3 byte and aims at the
      * 'kind' value (eg trap_Cerror). For error-trap and Cerror-trap a
      * number of bytes will follow, the first is the length of the byte
index 560babb..3d6e8a3 100644 (file)
@@ -79,18 +79,8 @@ os_context_sp_addr(os_context_t *context)
 unsigned long
 os_context_fp_control(os_context_t *context)
 {
-    /* probably the code snippet
-     * #ifdef __linux__
-     *    SET_FPU_CONTROL_WORD(context->__fpregs_mem.cw);
-     * #endif 
-     * is relevant to implementing this correctly */
-
-    /* Note that currently this is not called, as there is an analogous
-     * stub in lisp-land (x86-vm.lisp), also returning 0, with the old
-     * lisp fp-control code. This is here more as a signpost of a possible
-     * way of restoring functionality, and if it is the way to go would
-     * need to be included for other architectures as well. */
-    return 0;
+    return ((((context->uc_mcontext.fpregs->cw) & 0xffff) ^ 0x3f) |
+           (((context->uc_mcontext.fpregs->sw) & 0xffff) << 16));
 }
 
 sigset_t *
@@ -100,6 +90,12 @@ os_context_sigmask_addr(os_context_t *context)
 }
 
 void
+os_restore_fp_control(os_context_t *context)
+{
+    asm ("fldcw %0" : : "m" (context->uc_mcontext.fpregs->cw));
+}
+
+void
 os_flush_icache(os_vm_address_t address, os_vm_size_t length)
 {
 }
index 02cdfc1..8db9207 100644 (file)
@@ -7,4 +7,7 @@ static inline os_context_t *arch_os_get_context(void **void_context) {
   return (os_context_t *) *void_context;
 }
 
+unsigned long os_context_fp_control(os_context_t *context);
+void os_restore_fp_control(os_context_t *context);
+
 #endif /* _X86_LINUX_OS_H */
index e70fd5b..51c2d9d 100644 (file)
@@ -18,4 +18,4 @@
 ;;; for internal versions, especially for internal versions off the
 ;;; main CVS branch, it gets hairier, e.g. "0.pre7.14.flaky4.13".)
 
-"0.7.5.12"
+"0.7.5.13"