Newer
Older
/*
$Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/lisp/hppa-arch.c,v 1.9 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.
*/
#include <stdio.h>
#include <machine/trap.h>
#include "lisp.h"
#include "globals.h"
#include "validate.h"
#include "os.h"
#include "arch.h"
#include "lispregs.h"
#include "signal.h"
#include "internals.h"
#include "breakpoint.h"
char *arch_init(void)
{
return NULL;
}
os_vm_address_t arch_get_bad_addr(int signal,
int code,
struct sigcontext *scp)
#ifdef hpux
struct save_state *state;
os_vm_address_t addr;
state = (struct save_state *)(&(scp->sc_sl.sl_ss));
if (state == NULL)
return NULL;
/* Check the instruction address first. */
addr = (os_vm_address_t)((unsigned long)scp->sc_pcoq_head & ~3);
if (addr < (os_vm_address_t)0x1000)
return addr;
/* Otherwise, it must have been a data fault. */
#else
struct hp800_thread_state *state;
os_vm_address_t addr;
state = (struct hp800_thread_state *)(scp->sc_ap);
if (state == NULL)
return NULL;
/* Check the instruction address first. */
addr = scp->sc_pcoqh & ~3;
if (addr < 0x1000)
return addr;
/* Otherwise, it must have been a data fault. */
return state->cr21;
#endif
}
unsigned char *arch_internal_error_arguments(struct sigcontext *scp)
{
#ifdef hpux
return (unsigned char *)((scp->sc_pcoq_head&~0x3)+4);
#else
#endif
}
boolean arch_pseudo_atomic_atomic(struct sigcontext *scp)
{
/* Pseudo-atomic-atomic is implemented by oring 0x4 into ALLOC. */
if (SC_REG(scp, reg_ALLOC) & 0x4)
return TRUE;
else
return FALSE;
}
void arch_set_pseudo_atomic_interrupted(struct sigcontext *scp)
{
/* Pseudo-atomic-atomic is implemented by oring 0x1 into ALLOC. */
SC_REG(scp, reg_ALLOC) |= 1;
}
void arch_skip_instruction(struct sigcontext *scp)
{
/* Skip the offending instruction */
#ifdef hpux
scp->sc_pcoq_head = scp->sc_pcoq_tail;
scp->sc_pcoq_tail += 4;
#else
#endif
}
unsigned long arch_install_breakpoint(void *pc)
{
unsigned long *ulpc = (unsigned long *)pc;
unsigned long orig_inst = *ulpc;
*ulpc = trap_Breakpoint;
return orig_inst;
}
void arch_remove_breakpoint(void *pc, unsigned long orig_inst)
{
unsigned long *ulpc = (unsigned long *)pc;
*ulpc = orig_inst;
#ifdef hpux
extern void SingleStepTraps();
static unsigned long *BreakpointAddr = NULL;
static unsigned long NextPc = NULL;
#endif
void arch_do_displaced_inst(struct sigcontext *scp, unsigned long orig_inst)
{
#ifdef hpux
/* We change the next-pc to point to a breakpoint instruction, restore */
/* the original instruction, and exit. We would like to be able to */
/* sigreturn, but we can't, because this is hpux. */
unsigned long *pc = (unsigned long *)(SC_PC(scp) & ~3);
NextPc = SC_NPC(scp);
SC_NPC(scp) = (unsigned)SingleStepTraps | (SC_NPC(scp)&3);
BreakpointAddr = pc;
*pc = orig_inst;
os_flush_icache((os_vm_address_t)pc, sizeof(unsigned long));
#else
/* We set the recovery counter to cover one instruction, put the */
/* original instruction back in, and then resume. We will then trap */
/* after executing that one instruction, at which time we can put */
/* the breakpoint back in. */
((struct hp800_thread_state *)scp->sc_ap)->cr0 = 1;
scp->sc_ps |= 0x10;
*(unsigned long *)SC_PC(scp) = orig_inst;
sigreturn(scp);
#endif
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
#ifdef hpux
static void restore_breakpoint(struct sigcontext *scp)
{
/* We just single-stepped over an instruction that we want to replace */
/* with a breakpoint. So we put the breakpoint back in, and tweek the */
/* state so that we will continue as if nothing happened. */
if (NextPc == NULL)
lose("SingleStepBreakpoint trap at strange time.");
if ((SC_PC(scp)&~3) == (unsigned long)SingleStepTraps) {
/* The next instruction was not nullified. */
SC_PC(scp) = NextPc;
if ((SC_NPC(scp)&~3) == (unsigned long)SingleStepTraps + 4) {
/* The instruction we just stepped over was not a branch, so */
/* we need to fix it up. If it was a branch, it will point to */
/* the correct place. */
SC_NPC(scp) = NextPc + 4;
}
}
else {
/* The next instruction was nullified, so we want to skip it. */
SC_PC(scp) = NextPc + 4;
SC_NPC(scp) = NextPc + 8;
}
NextPc = NULL;
if (BreakpointAddr) {
*BreakpointAddr = trap_Breakpoint;
os_flush_icache((os_vm_address_t)BreakpointAddr,
sizeof(unsigned long));
BreakpointAddr = NULL;
}
}
#endif
static void sigtrap_handler(int signal, int code, struct sigcontext *scp)
{
unsigned long bad_inst;
sigsetmask(scp->sc_mask);
#if 0
printf("sigtrap_handler, pc=0x%08x, alloc=0x%08x\n", scp->sc_pcoqh,
SC_REG(scp,reg_ALLOC));
#endif
#ifdef hpux
bad_inst = *(unsigned long *)(scp->sc_pcoq_head & ~3);
#else
#endif
if (bad_inst & 0xfc001fe0)
interrupt_handle_now(signal, code, scp);
else {
int im5 = bad_inst & 0x1f;
switch (im5) {
case trap_Halt:
fake_foreign_function_call(scp);
lose("%%primitive halt called; the party is over.\n");
case trap_PendingInterrupt:
arch_skip_instruction(scp);
interrupt_handle_pending(scp);
break;
case trap_Error:
case trap_Cerror:
interrupt_internal_error(signal, code, scp, im5==trap_Cerror);
break;
case trap_Breakpoint:
sigsetmask(scp->sc_mask);
handle_breakpoint(signal, code, scp);
break;
case trap_FunctionEndBreakpoint:
sigsetmask(scp->sc_mask);
{
unsigned long pc;
pc = (unsigned long)
handle_function_end_breakpoint(signal, code, scp);
#ifdef hpux
#else
#endif
break;
case trap_SingleStepBreakpoint:
restore_breakpoint(scp);
break;
default:
interrupt_handle_now(signal, code, scp);
break;
}
}
}
static void sigfpe_handler(int signal, int code, struct sigcontext *scp)
{
unsigned long badinst;
int opcode, r1, r2, t;
long op1, op2, res;
#if 0
printf("sigfpe_handler, pc=0x%08x, alloc=0x%08x\n", scp->sc_pcoqh,
SC_REG(scp,reg_ALLOC));
#endif
switch (code) {
case I_OVFLO:
badinst = *(unsigned long *)(SC_PC(scp)&~3);
opcode = badinst >> 26;
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
if (opcode == 2) {
/* reg/reg inst. */
r1 = (badinst >> 16) & 0x1f;
op1 = fixnum_value(SC_REG(scp, r1));
r2 = (badinst >> 21) & 0x1f;
op2 = fixnum_value(SC_REG(scp, r2));
t = badinst & 0x1f;
switch ((badinst >> 5) & 0x7f) {
case 0x70:
/* Add and trap on overflow. */
res = op1 + op2;
break;
case 0x60:
/* Subtract and trap on overflow. */
res = op1 - op2;
break;
default:
goto not_interesting;
}
}
else if ((opcode & 0x37) == 0x25 && (badinst & (1<<11))) {
/* Add or subtract immediate. */
op1 = ((badinst >> 3) & 0xff) | ((-badinst&1)<<8);
r2 = (badinst >> 16) & 0x1f;
op2 = fixnum_value(SC_REG(scp, r1));
t = (badinst >> 21) & 0x1f;
if (opcode == 0x2d)
res = op1 + op2;
else
res = op1 - op2;
}
else
goto not_interesting;
current_dynamic_space_free_pointer = (lispobj *)SC_REG(scp, reg_ALLOC);
SC_REG(scp, t) = alloc_number(res);
SC_REG(scp, reg_ALLOC)
= (unsigned long)current_dynamic_space_free_pointer;
arch_skip_instruction(scp);
break;
case I_COND:
badinst = *(unsigned long *)(SC_PC(scp)&~3);
if ((badinst&0xfffff800) == (0xb000e000|reg_ALLOC<<21|reg_ALLOC<<16)) {
/* It is an ADDIT,OD i,ALLOC,ALLOC instruction that trapped. */
/* That means that it is the end of a pseudo-atomic. So do the */
/* add stripping off the pseudo-atomic-interrupted bit, and then */
/* tell the machine-independent code to process the pseudo- */
/* atomic. */
int immed = (badinst>>1)&0x3ff;
if (badinst & 1)
immed |= -1<<10;
SC_REG(scp,reg_ALLOC) += (immed-1);
arch_skip_instruction(scp);
interrupt_handle_pending(scp);
break;
}
/* else drop-through. */
default:
#ifdef hpux
interrupt_install_low_level_handler(SIGILL,sigtrap_handler);
#endif
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
interrupt_install_low_level_handler(SIGTRAP,sigtrap_handler);
interrupt_install_low_level_handler(SIGFPE,sigfpe_handler);
}
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);
}