Fill in the alignment trap handler a bit: now it can fix unaligned

floating point loads and stores (to work around a gcc bug), but will
still cause a bus error on other sorts of unaligned accesses.
This commit is contained in:
danw 2000-01-19 03:30:12 +00:00
parent 83cfcdd15a
commit 6c14ba0dba
2 changed files with 75 additions and 4 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: trap.h,v 1.1 1996/09/30 16:34:35 ws Exp $ */
/* $NetBSD: trap.h,v 1.2 2000/01/19 03:30:12 danw Exp $ */
/*
* Copyright (C) 1995, 1996 Wolfgang Solfrank.
@ -64,4 +64,22 @@
/* Trap was in user mode */
#define EXC_USER 0x10000
/*
* EXC_ALI sets bits in the DSISR and DAR to provide enough
* information to recover from the unaligned access without needing to
* parse the offending instruction. This includes certain bits of the
* opcode, and information about what registers are used. The opcode
* indicator values below come from Appendix F of Book III of "The
* PowerPC Architecture".
*/
#define EXC_ALI_OPCODE_INDICATOR(dsisr) ((dsisr >> 10) & 0x7f)
#define EXC_ALI_LFD 0x09
#define EXC_ALI_STFD 0x0b
/* Macros to extract register information */
#define EXC_ALI_RST(dsisr) ((dsisr >> 5) & 0x1f) /* source or target */
#define EXC_ALI_RA(dsisr) (dsisr & 0x1f)
#endif /* _MACHINE_TRAP_H_ */

View File

@ -1,4 +1,4 @@
/* $NetBSD: trap.c,v 1.22 1999/05/03 10:02:20 tsubai Exp $ */
/* $NetBSD: trap.c,v 1.23 2000/01/19 03:30:13 danw Exp $ */
/*
* Copyright (C) 1995, 1996 Wolfgang Solfrank.
@ -62,6 +62,8 @@
volatile int astpending;
volatile int want_resched;
static int fix_unaligned __P((struct proc *p, struct trapframe *frame));
void
trap(frame)
struct trapframe *frame;
@ -262,8 +264,10 @@ syscall_bad:
break;
case EXC_ALI|EXC_USER:
/* XXX temporarily */
trapsignal(p, SIGBUS, EXC_ALI);
if (fix_unaligned(p, frame) != 0)
trapsignal(p, SIGBUS, EXC_ALI);
else
frame->srr0 += 4;
break;
case EXC_PGM|EXC_USER:
@ -531,3 +535,52 @@ badaddr_read(addr, size, rptr)
return 0;
}
/*
* For now, this only deals with the particular unaligned access case
* that gcc tends to generate. Eventually it should handle all of the
* possibilities that can happen on a 32-bit PowerPC in big-endian mode.
*/
static int
fix_unaligned(p, frame)
struct proc *p;
struct trapframe *frame;
{
int indicator = EXC_ALI_OPCODE_INDICATOR(frame->dsisr);
switch (indicator) {
case EXC_ALI_LFD:
case EXC_ALI_STFD:
{
int reg = EXC_ALI_RST(frame->dsisr);
double *fpr = &p->p_addr->u_pcb.pcb_fpu.fpr[reg];
/* Juggle the FPU to ensure that we've initialized
* the FPRs, and that their current state is in
* the PCB.
*/
if (fpuproc != p) {
if (fpuproc)
save_fpu(fpuproc);
enable_fpu(p);
}
save_fpu(p);
if (indicator == EXC_ALI_LFD) {
if (copyin((void *)frame->dar, fpr,
sizeof(double)) != 0)
return -1;
enable_fpu(p);
} else {
if (copyout(fpr, (void *)frame->dar,
sizeof(double)) != 0)
return -1;
}
return 0;
}
break;
}
return -1;
}