Skip to content
sparc-arch.c 7.7 KiB
Newer Older
ram's avatar
ram committed
/*

 $Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/lisp/sparc-arch.c,v 1.5 1994/10/27 17:13:54 ram Exp $

 This code was written as part of the CMU Common Lisp project at
 Carnegie Mellon University, and has been placed in the public domain.

*/

wlott's avatar
wlott committed
#include <stdio.h>
ram's avatar
ram committed
#ifdef SOLARIS
#include <sys/trap.h>
#else
wlott's avatar
wlott committed
#include <machine/trap.h>
ram's avatar
ram committed
#endif
wlott's avatar
wlott committed

ram's avatar
ram committed
#include "arch.h"
wlott's avatar
wlott committed
#include "lisp.h"
#include "internals.h"
#include "globals.h"
#include "validate.h"
#include "os.h"
#include "lispregs.h"
#include "signal.h"
#include "interrupt.h"

char *arch_init()
{
ram's avatar
ram committed
    return 0;
wlott's avatar
wlott committed
}

ram's avatar
ram committed
os_vm_address_t arch_get_bad_addr(HANDLER_ARGS)
wlott's avatar
wlott committed
{
    unsigned long badinst;
    int rs1;

    /* On the sparc, we have to decode the instruction. */

    /* Make sure it's not the pc thats bogus, and that it was lisp code */
    /* that caused the fault. */
ram's avatar
ram committed
    if ((SC_PC(context) & 3) != 0 ||
	((SC_PC(context) < READ_ONLY_SPACE_START ||
	  SC_PC(context) >= READ_ONLY_SPACE_START+READ_ONLY_SPACE_SIZE) &&
	 ((lispobj *)SC_PC(context) < current_dynamic_space &&
	  (lispobj *)SC_PC(context) >=
wlott's avatar
wlott committed
	      current_dynamic_space + DYNAMIC_SPACE_SIZE)))
ram's avatar
ram committed
	return 0;
wlott's avatar
wlott committed

ram's avatar
ram committed
    badinst = *(unsigned long *)SC_PC(context);
wlott's avatar
wlott committed

    if ((badinst >> 30) != 3)
	/* All load/store instructions have op = 11 (binary) */
ram's avatar
ram committed
	return 0;
wlott's avatar
wlott committed

    rs1 = (badinst>>14)&0x1f;

    if (badinst & (1<<13)) {
	/* r[rs1] + simm(13) */
	int simm13 = badinst & 0x1fff;

	if (simm13 & (1<<12))
	    simm13 |= -1<<13;

	return (os_vm_address_t)(SC_REG(context, rs1) + simm13);
    }
    else {
	/* r[rs1] + r[rs2] */
	int rs2 = badinst & 0x1f;

	return (os_vm_address_t)(SC_REG(context, rs1) + SC_REG(context, rs2));
    }

}

void arch_skip_instruction(context)
struct sigcontext *context;
{
    /* Skip the offending instruction */
ram's avatar
ram committed
    SC_PC(context) = SC_NPC(context);
    SC_NPC(context) += 4;
wlott's avatar
wlott committed
}

unsigned char *arch_internal_error_arguments(struct sigcontext *scp)
{
ram's avatar
ram committed
    return (unsigned char *)(SC_PC(scp)+4);
wlott's avatar
wlott committed
}

boolean arch_pseudo_atomic_atomic(struct sigcontext *scp)
{
    return (SC_REG(scp, reg_ALLOC) & 4);
}

void arch_set_pseudo_atomic_interrupted(struct sigcontext *scp)
{
    SC_REG(scp, reg_ALLOC) |= 1;
}

unsigned long arch_install_breakpoint(void *pc)
{
    unsigned long *ptr = (unsigned long *)pc;
    unsigned long result = *ptr;
    *ptr = trap_Breakpoint;
    return result;
}

void arch_remove_breakpoint(void *pc, unsigned long orig_inst)
{
    *(unsigned long *)pc = orig_inst;
}

static unsigned long *skipped_break_addr, displaced_after_inst;
ram's avatar
ram committed
#ifdef POSIX_SIGS
static sigset_t orig_sigmask;
#else
wlott's avatar
wlott committed
static int orig_sigmask;
ram's avatar
ram committed
#endif
wlott's avatar
wlott committed

void arch_do_displaced_inst(struct sigcontext *scp,
				   unsigned long orig_inst)
{
ram's avatar
ram committed
    unsigned long *pc = (unsigned long *)SC_PC(scp);
    unsigned long *npc = (unsigned long *)SC_NPC(scp);

#ifdef POSIX_SIGS
    orig_sigmask = scp->uc_sigmask;
    sigemptyset(&scp->uc_sigmask);
    FILLBLOCKSET(&scp->uc_sigmask);
#else
wlott's avatar
wlott committed
    orig_sigmask = scp->sc_mask;
    scp->sc_mask = BLOCKABLE;
ram's avatar
ram committed
#endif
wlott's avatar
wlott committed

    *pc = orig_inst;
    skipped_break_addr = pc;
    displaced_after_inst = *npc;
    *npc = trap_AfterBreakpoint;

ram's avatar
ram committed
#ifdef SOLARIS
    /* XXX never tested */
    setcontext(scp);
#else
wlott's avatar
wlott committed
    sigreturn(scp);
ram's avatar
ram committed
#endif
wlott's avatar
wlott committed
}

ram's avatar
ram committed
static void sigill_handler(HANDLER_ARGS)
wlott's avatar
wlott committed
{
    int badinst;

ram's avatar
ram committed
    SAVE_CONTEXT();

#ifdef POSIX_SIGS
    sigprocmask(SIG_SETMASK, &context->uc_sigmask, 0);
#else
    sigsetmask(context->sc_mask);
#endif
wlott's avatar
wlott committed

ram's avatar
ram committed
#ifdef SOLARIS
    if (CODE(code) == ILL_ILLOPC)
#else
    if (CODE(code) == T_UNIMP_INSTR)
#endif
    {
wlott's avatar
wlott committed
	int trap;

ram's avatar
ram committed
	trap = *(unsigned long *)(SC_PC(context)) & 0x3fffff;
wlott's avatar
wlott committed

	switch (trap) {
	  case trap_PendingInterrupt:
ram's avatar
ram committed
	    arch_skip_instruction(context);
	    interrupt_handle_pending(context);
wlott's avatar
wlott committed
	    break;

	  case trap_Halt:
ram's avatar
ram committed
	    fake_foreign_function_call(context);
wlott's avatar
wlott committed
	    lose("%%primitive halt called; the party is over.\n");

	  case trap_Error:
	  case trap_Cerror:
ram's avatar
ram committed
	    interrupt_internal_error(signal, code, context, trap == trap_Cerror);
wlott's avatar
wlott committed
	    break;

	  case trap_Breakpoint:
ram's avatar
ram committed
	    handle_breakpoint(signal, code, context);
wlott's avatar
wlott committed
	    break;

	  case trap_FunctionEndBreakpoint:
ram's avatar
ram committed
	    SC_PC(context)=(int)handle_function_end_breakpoint(signal, code, context);
	    SC_NPC(context)=SC_PC(context) + 4;
wlott's avatar
wlott committed
	    break;

	  case trap_AfterBreakpoint:
	    *skipped_break_addr = trap_Breakpoint;
	    skipped_break_addr = NULL;
ram's avatar
ram committed
	    *(unsigned long *)SC_PC(context) = displaced_after_inst;
#ifdef POSIX_SIGS
	    context->uc_sigmask = orig_sigmask;
#else
	    context->sc_mask = orig_sigmask;
#endif
wlott's avatar
wlott committed
	    break;

	  default:
ram's avatar
ram committed
	    interrupt_handle_now(signal, code, context);
wlott's avatar
wlott committed
	    break;
	}
    }
ram's avatar
ram committed
#ifdef SOLARIS
    else if (CODE(code) == ILL_ILLTRP)
#else
    else if (CODE(code) >= T_SOFTWARE_TRAP + 16 & CODE(code) < T_SOFTWARE_TRAP + 32)
#endif
	interrupt_internal_error(signal, code, context, FALSE);
wlott's avatar
wlott committed
    else
ram's avatar
ram committed
	interrupt_handle_now(signal, code, context);
wlott's avatar
wlott committed
}

ram's avatar
ram committed
static void sigemt_handler(HANDLER_ARGS)
wlott's avatar
wlott committed
{
    unsigned long badinst;
    boolean subtract, immed;
    int rd, rs1, op1, rs2, op2, result;

ram's avatar
ram committed
    badinst = *(unsigned long *)SC_PC(context);
wlott's avatar
wlott committed
    if ((badinst >> 30) != 2 || ((badinst >> 20) & 0x1f) != 0x11) {
	/* It wasn't a tagged add.  Pass the signal into lisp. */
ram's avatar
ram committed
	interrupt_handle_now(signal, code, context);
wlott's avatar
wlott committed
	return;
    }
	
    /* Extract the parts of the inst. */
    subtract = badinst & (1<<19);
    rs1 = (badinst>>14) & 0x1f;
ram's avatar
ram committed
    op1 = SC_REG(context, rs1);
wlott's avatar
wlott committed

    /* 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;
ram's avatar
ram committed
	SC_REG(context, reg_ALLOC) = result & ~7;
	arch_skip_instruction(context);
	interrupt_handle_pending(context);
wlott's avatar
wlott committed
	return;
    }

    if ((op1 & 3) != 0) {
	/* The first arg wan't a fixnum. */
ram's avatar
ram committed
	interrupt_internal_error(signal, code, context, FALSE);
wlott's avatar
wlott committed
	return;
    }

    if (immed = badinst & (1<<13)) {
	op2 = badinst & 0x1fff;
	if (op2 & (1<<12))
	    op2 |= -1<<13;
    }
    else {
	rs2 = badinst & 0x1f;
ram's avatar
ram committed
	op2 = SC_REG(context, rs2);
wlott's avatar
wlott committed
    }

    if ((op2 & 3) != 0) {
	/* The second arg wan't a fixnum. */
ram's avatar
ram committed
	interrupt_internal_error(signal, code, context, FALSE);
wlott's avatar
wlott committed
	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 =
ram's avatar
ram committed
            (lispobj *) SC_REG(context, reg_ALLOC);
wlott's avatar
wlott committed

ram's avatar
ram committed
	SC_REG(context, rd) = alloc_number(result);
wlott's avatar
wlott committed

ram's avatar
ram committed
	SC_REG(context, reg_ALLOC) =
wlott's avatar
wlott committed
	    (unsigned long) current_dynamic_space_free_pointer;
    }

ram's avatar
ram committed
    arch_skip_instruction(context);
wlott's avatar
wlott committed
}

void arch_install_interrupt_handlers()
{
    interrupt_install_low_level_handler(SIGILL,sigill_handler);
    interrupt_install_low_level_handler(SIGEMT,sigemt_handler);
}


extern lispobj call_into_lisp(lispobj fun, lispobj *args, int nargs);

lispobj funcall0(lispobj function)
{
    lispobj *args = current_control_stack_pointer;

    return call_into_lisp(function, args, 0);
}

lispobj funcall1(lispobj function, lispobj arg0)
{
    lispobj *args = current_control_stack_pointer;

    current_control_stack_pointer += 1;
    args[0] = arg0;

    return call_into_lisp(function, args, 1);
}

lispobj funcall2(lispobj function, lispobj arg0, lispobj arg1)
{
    lispobj *args = current_control_stack_pointer;

    current_control_stack_pointer += 2;
    args[0] = arg0;
    args[1] = arg1;

    return call_into_lisp(function, args, 2);
}

lispobj funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2)
{
    lispobj *args = current_control_stack_pointer;

    current_control_stack_pointer += 3;
    args[0] = arg0;
    args[1] = arg1;
    args[2] = arg2;

    return call_into_lisp(function, args, 3);
}