From 418dc05aa2366dce1f57539a5edfed3901c53451 Mon Sep 17 00:00:00 2001
From: wlott <wlott>
Date: Tue, 18 Dec 1990 01:01:00 +0000
Subject: [PATCH] Lots of changes to facilitate the SPARC port.  In addition to
 finishing all the handlers needed for the sparc port, stuff has been moved
 around to localize the machine specific parts.

---
 ldb/interrupt.c | 419 ++++++++++++++++++++++++++++++++++--------------
 1 file changed, 301 insertions(+), 118 deletions(-)

diff --git a/ldb/interrupt.c b/ldb/interrupt.c
index efa8bbb15..bd05181d9 100644
--- a/ldb/interrupt.c
+++ b/ldb/interrupt.c
@@ -1,4 +1,4 @@
-/* $Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/ldb/Attic/interrupt.c,v 1.18 1990/12/01 22:48:11 wlott Exp $ */
+/* $Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/ldb/Attic/interrupt.c,v 1.19 1990/12/18 01:01:00 wlott Exp $ */
 
 /* Interrupt handing magic. */
 
@@ -6,6 +6,9 @@
 #ifdef mips
 #include <mips/cpu.h>
 #endif
+#ifdef sparc
+#include <machine/trap.h>
+#endif
 
 #include "lisp.h"
 #include "ldb.h"
@@ -16,6 +19,8 @@
 
 #define crap_out(msg) do { write(2, msg, sizeof(msg)); abort(); } while (0)
 
+#define FIXNUM_VALUE(lispobj) (((int)lispobj)>>2)
+
 boolean internal_errors_enabled = 0;
 
 struct sigcontext *lisp_interrupt_contexts[MAX_INTERRUPTS];
@@ -25,6 +30,11 @@ union interrupt_handler interrupt_handlers[NSIG];
 static int pending_signal = 0, pending_code = 0, pending_mask = 0;
 static boolean maybe_gc_pending = FALSE;
 
+
+/****************************************************************\
+* Utility routines used by various signal handlers.              *
+\****************************************************************/
+
 static void fake_foreign_function_call(context)
      struct sigcontext *context;
 {
@@ -111,6 +121,86 @@ static void undo_fake_foreign_function_call(context)
         (unsigned long) current_dynamic_space_free_pointer;
 }
 
+#define call_maybe_gc() \
+    call_into_lisp(MAYBE_GC, SymbolFunction(MAYBE_GC), \
+                   current_control_stack_pointer, 0)
+
+static void skip_instruction(context)
+     struct sigcontext *context;
+{
+#ifdef mips
+    /* Skip the offending instruction */
+    if (context->sc_cause & CAUSE_BD)
+        emulate_branch(context, *(unsigned long *)context->sc_pc);
+    else
+        context->sc_pc += 4;
+#endif
+#ifdef sparc
+    context->sc_pc = context->sc_npc;
+    context->sc_npc += 4;
+#endif
+}
+
+static void internal_error(signal, code, context, continuable)
+     struct sigcontext *context;
+     boolean continuable;
+{
+    lispobj *args;
+
+    sigsetmask(context->sc_mask);
+    fake_foreign_function_call(context);
+    args = current_control_stack_pointer;
+    current_control_stack_pointer += 2;
+    args[0] = alloc_sap(context);
+    if (continuable)
+	args[1] = T;
+    else
+	args[1] = NIL;
+    call_into_lisp(INTERNAL_ERROR, SymbolFunction(INTERNAL_ERROR),
+		   args, 2);
+    undo_fake_foreign_function_call(context);
+    if (continuable)
+	skip_instruction(context);
+}
+
+static void handle_pending_interrupt(context)
+     struct sigcontext *context;
+{
+    if (foreign_function_call_active)
+	crap_out("Oh no, got a PendingInterrupt while foreign function call was active.\n");
+
+#ifdef mips
+    context->sc_regs[FLAGS] &= ~(1<<flag_Interrupted);
+#else
+    SetSymbolValue(PSEUDO_ATOMIC_INTERRUPTED, 0);
+#endif
+    SetSymbolValue(INTERRUPT_PENDING, NIL);
+    if (maybe_gc_pending) {
+	maybe_gc_pending = FALSE;
+	fake_foreign_function_call(context);
+	call_maybe_gc();
+	undo_fake_foreign_function_call(context);
+    }
+    if (pending_signal) {
+	int signal, code;
+
+	signal = pending_signal;
+	code = pending_code;
+	pending_signal = 0;
+	pending_code = 0;
+	handle_now(signal, code, context);
+    }
+    context->sc_mask = pending_mask;
+    pending_mask = 0;
+    skip_instruction(context);
+}
+
+
+/****************************************************************\
+* handle_now, maybe_now_maybe_later                              *
+*    the two main signal handlers.                               *
+\****************************************************************/
+
 static handle_now(signal, code, context)
 int signal, code;
 struct sigcontext *context;
@@ -186,116 +276,34 @@ struct sigcontext *context;
         handle_now(signal, code, context);
 }
 
-static void skip_instruction(context)
-     struct sigcontext *context;
-{
-#ifdef mips
-    /* Skip the offending instruction */
-    if (context->sc_cause & CAUSE_BD)
-        emulate_branch(context, *(unsigned long *)context->sc_pc);
-    else
-        context->sc_pc += 4;
-#endif
-#ifdef sparc
-    context->sc_pc = context->sc_npc;
-    context->sc_npc += 4;
-#endif
-}
-
-#define call_maybe_gc() \
-    call_into_lisp(MAYBE_GC, SymbolFunction(MAYBE_GC), \
-                   current_control_stack_pointer, 0)
-
-static break_handler(signal, code, context)
-int signal, code;
-struct sigcontext *context;
-{
-    int trap;
-    lispobj *args;
+/****************************************************************\
+* PMAX specific signal handlers.                                 *
+\****************************************************************/
 
 #ifdef mips
-    trap = code;
-#endif
-#ifdef sparc
-    int badinst;
-
-    badinst = *(unsigned long *)(context->sc_pc);
-    if ((badinst & 0xc1c00000) == 0)
-	trap = 0x3fffff & badinst;
-    else
-	trap = 0;
-#endif
-
-    switch (trap) {
+static sigtrap_handler(signal, code, context)
+     int signal, code;
+     struct sigcontext *context;
+{
+    switch (code) {
       case trap_PendingInterrupt:
-        if (foreign_function_call_active)
-            crap_out("Oh no, got a PendingInterrupt while foreign function call was active.\n");
-
-#ifdef mips
-        context->sc_regs[FLAGS] &= ~(1<<flag_Interrupted);
-#endif
-        SetSymbolValue(INTERRUPT_PENDING, NIL);
-        if (maybe_gc_pending) {
-            maybe_gc_pending = FALSE;
-            fake_foreign_function_call(context);
-            call_maybe_gc();
-            undo_fake_foreign_function_call(context);
-        }
-        if (pending_signal) {
-            signal = pending_signal;
-            code = pending_code;
-            pending_signal = 0;
-            pending_code = 0;
-            handle_now(signal, code, context);
-        }
-        context->sc_mask = pending_mask;
-        pending_mask = 0;
-        skip_instruction(context);
+	handle_pending_interrupt(context);
 	break;
 
       case trap_Halt:
 	crap_out("%primitive halt called; the party is over.\n");
 
       case trap_Error:
-	if (internal_errors_enabled) {
-	    sigsetmask(context->sc_mask);
-	    fake_foreign_function_call(context);
-	    args = current_control_stack_pointer;
-	    current_control_stack_pointer += 2;
-	    args[0] = alloc_sap(context);
-	    args[1] = NIL;
-	    call_into_lisp(INTERNAL_ERROR, SymbolFunction(INTERNAL_ERROR),
-			   args, 2);
-	    undo_fake_foreign_function_call(context);
-	}
-	else
-	    handle_now(signal, code, context);
-	break;
-
       case trap_Cerror:
-	if (internal_errors_enabled) {
-	    sigsetmask(context->sc_mask);
-	    fake_foreign_function_call(context);
-	    args = current_control_stack_pointer;
-	    current_control_stack_pointer += 2;
-	    args[0] = alloc_sap(context);
-	    args[1] = T;
-	    call_into_lisp(INTERNAL_ERROR, SymbolFunction(INTERNAL_ERROR),
-			   args, 2);
-	    undo_fake_foreign_function_call(context);
-	    skip_instruction(context);
-	}
-	else
-	    handle_now(signal, code, context);
+	internal_error(signal, code, context, code==trap_Cerror);
 	break;
 
       default:
-        handle_now(signal, code, context);
+	handle_now(signal, code, context);
 	break;
     }
 }
 
-#ifdef mips
 static sigfpe_handler(signal, code, context)
 int signal, code;
 struct sigcontext *context;
@@ -317,8 +325,6 @@ struct sigcontext *context;
     funct = bad_inst & 0x3f;
     immed = (((int)(bad_inst & 0xffff)) << 16) >> 16;
 
-#define FIXNUM_VALUE(lispobj) (((int)lispobj)>>2)
-
     switch (op) {
         case 0x0: /* SPECIAL */
             switch (funct) {
@@ -364,39 +370,212 @@ struct sigcontext *context;
     else
         handle_now(signal, code, context);
 }
-#undef FIXNUM_VALUE
+#endif
 
+/****************************************************************\
+* SPARC specific signal handlers.                                *
+\****************************************************************/
 
-static sigbus_handler(signal, code, context)
+#ifdef sparc
+static sigill_handler(signal, code, context)
 int signal, code;
 struct sigcontext *context;
+{
+    int badinst;
+
+    if (code == T_UNIMP_INSTR) {
+	int trap;
+
+	trap = *(unsigned long *)(context->sc_pc) & 0x3fffff;
+
+	switch (trap) {
+	  case trap_PendingInterrupt:
+	    handle_pending_interrupt(context);
+	    break;
+
+	  case trap_Halt:
+	    crap_out("%primitive halt called; the party is over.\n");
+
+	  case trap_Error:
+	  case trap_Cerror:
+	    internal_error(signal, code, context, trap == trap_Cerror);
+	    break;
+
+	  default:
+	    handle_now(signal, code, context);
+	    break;
+	}
+    }
+    else if (code >= T_SOFTWARE_TRAP + 16 & code < T_SOFTWARE_TRAP + 32)
+	internal_error(signal, code, context, FALSE);
+    else
+	handle_now(signal, code, context);
+}
+
+static sigemt_handler(signal, code, context)
+     int signal, code;
+     struct sigcontext *context;
+{
+    unsigned long badinst;
+    boolean subtract, immed;
+    int rd, rs1, op1, rs2, op2, result;
+
+    badinst = *(unsigned long *)context->sc_pc;
+    if ((badinst >> 30) != 2 || ((badinst >> 20) & 0x1f) != 0x11) {
+	/* It wasn't a tagged add.  Pass the signal into lisp. */
+	handle_now(signal, code, context);
+	return;
+    }
+	
+    /* Extract the parts of the inst. */
+    subtract = badinst & (1<<19);
+    rs1 = (badinst>>14) & 0x1f;
+    op1 = context->sc_regs[rs1];
+    if ((op1 & 3) != 0) {
+	/* The first arg wan't a fixnum. */
+	internal_error(signal, code, context, FALSE);
+	return;
+    }
+
+    if (immed = badinst & (1<<13)) {
+	op2 = badinst & 0x1fff;
+	if (op2 & (1<<12))
+	    op2 |= -1<<13;
+    }
+    else {
+	rs2 = badinst & 0x1f;
+	op2 = context->sc_regs[rs2];
+    }
+
+    if ((op2 & 3) != 0) {
+	/* The second arg wan't a fixnum. */
+	internal_error(signal, code, context, FALSE);
+	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);
+
+        current_dynamic_space_free_pointer =
+            (lispobj *) context->sc_regs[ALLOC];
+
+	context->sc_regs[rd] = alloc_number(result);
+
+	context->sc_regs[ALLOC] =
+	    (unsigned long) current_dynamic_space_free_pointer;
+    }
+    skip_instruction(context);
+}
+#endif
+
+/****************************************************************\
+* Stuff to detect and handle hitting the gc trigger.             *
+\****************************************************************/
+
+static boolean gc_trigger_hit(context)
+     struct sigcontext *context;
 {
     lispobj *badaddr;
+#ifdef sparc
+    unsigned long badinst;
+    int rs1;
+#endif
+
+    if (current_auto_gc_trigger == NULL)
+	return FALSE;
 
+#ifdef mips
+    /* Finding the bad address on the mips is easy. */
     badaddr = (lispobj *)context->sc_badvaddr;
+#endif
 
-    if (!foreign_function_call_active && badaddr >= current_dynamic_space && badaddr < current_dynamic_space + DYNAMIC_SPACE_SIZE) {
-        set_global_pointer(saved_global_pointer);
-        clear_auto_gc_trigger();
+#ifdef sparc
+    /* On the sparc, we have to decode the instruction. */
 
-        if (context->sc_regs[FLAGS] & (1<<flag_Atomic)) {
-            maybe_gc_pending = TRUE;
-            if (pending_signal == 0) {
-                pending_mask = context->sc_mask;
-                context->sc_mask |= BLOCKABLE;
-            }
-            context->sc_regs[FLAGS] |= (1<<flag_Interrupted);
-        }
-        else {
-            fake_foreign_function_call(context);
-            call_maybe_gc();
-            undo_fake_foreign_function_call(context);
-        }
+    /* Make sure it's not the pc thats bogus, and that it was lisp code */
+    /* that caused the fault. */
+    if ((context->sc_pc & 3) != 0 ||
+	((context->sc_pc < READ_ONLY_SPACE_START ||
+	  context->sc_pc >= READ_ONLY_SPACE_START+READ_ONLY_SPACE_SIZE) &&
+	 ((lispobj *)context->sc_pc < current_dynamic_space &&
+	  (lispobj *)context->sc_pc >=
+	      current_dynamic_space + DYNAMIC_SPACE_SIZE)))
+	return FALSE;
+
+    badinst = *(unsigned long *)context->sc_pc;
+
+    if ((badinst >> 30) != 3)
+	/* All load/store instructions have op = 11 (binary) */
+	return FALSE;
+
+    rs1 = (badinst>>14)&0x1f;
+
+    if (badinst & (1<<13)) {
+	/* r[rs1] + simm(13) */
+	int simm13 = badinst & 0x1fff;
+
+	if (simm13 & (1<<12))
+	    simm13 |= -1<<13;
+
+	badaddr = (lispobj *)(context->sc_regs[rs1] + simm13);
     }
-    else
-        handle_now(signal, code, context);
+    else {
+	/* r[rs1] + r[rs2] */
+	int rs2 = badinst & 0x1f;
+
+	badaddr = (lispobj *)(context->sc_regs[rs1] + context->sc_regs[rs2]);
+    }
+#endif
+    return (badaddr >= current_auto_gc_trigger &&
+	    badaddr < current_dynamic_space + DYNAMIC_SPACE_SIZE);
 }
+
+static sigbus_handler(signal, code, context)
+int signal, code;
+struct sigcontext *context;
+{
+    if (!foreign_function_call_active && gc_trigger_hit(context)) {
+#ifdef MIPS
+	set_global_pointer(saved_global_pointer);
 #endif
+	clear_auto_gc_trigger();
+
+	if (
+#ifdef mips
+	    context->sc_regs[FLAGS] & (1<<flag_Atomic)
+#else
+	    SymbolValue(PSEUDO_ATOMIC_ATOMIC)
+#endif
+	    ) {
+	    maybe_gc_pending = TRUE;
+	    if (pending_signal == 0) {
+		pending_mask = context->sc_mask;
+		context->sc_mask |= BLOCKABLE;
+	    }
+#ifdef mips
+	    context->sc_regs[FLAGS] |= (1<<flag_Interrupted);
+#else
+	    SetSymbolValue(PSEUDO_ATOMIC_INTERRUPTED, T);
+#endif
+	}
+	else {
+	    fake_foreign_function_call(context);
+	    call_maybe_gc();
+	    undo_fake_foreign_function_call(context);
+	}
+    }
+    else
+	handle_now(signal, code, context);
+}
+
+/****************************************************************\
+* Noise to install handlers.                                     *
+\****************************************************************/
 
 unsigned long install_handler(signal, handler)
 int signal;
@@ -408,7 +587,7 @@ int (*handler)();
 
 #ifdef mips
     if (signal == SIGTRAP)
-        sv.sv_handler = break_handler;
+        sv.sv_handler = sigtrap_handler;
     else if (signal == SIGFPE)
         sv.sv_handler = sigfpe_handler;
     else if (signal == SIGBUS)
@@ -416,7 +595,11 @@ int (*handler)();
 #endif
 #ifdef sparc
     if (signal == SIGILL)
-	sv.sv_handler = break_handler;
+	sv.sv_handler = sigill_handler;
+    else if (signal == SIGEMT)
+	sv.sv_handler = sigemt_handler;
+    else if (signal == SIGBUS)
+        sv.sv_handler = sigbus_handler;
 #endif
     else if (handler == SIG_DFL || handler == SIG_IGN)
         sv.sv_handler = handler;
-- 
GitLab