Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch/powerpc Fill in the alignment trap handler a bit: n...



details:   https://anonhg.NetBSD.org/src/rev/056503363286
branches:  trunk
changeset: 480747:056503363286
user:      danw <danw%NetBSD.org@localhost>
date:      Wed Jan 19 03:30:12 2000 +0000

description:
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.

diffstat:

 sys/arch/powerpc/include/trap.h |  20 +++++++++++++-
 sys/arch/powerpc/powerpc/trap.c |  59 ++++++++++++++++++++++++++++++++++++++--
 2 files changed, 75 insertions(+), 4 deletions(-)

diffs (116 lines):

diff -r da5f81ec11db -r 056503363286 sys/arch/powerpc/include/trap.h
--- a/sys/arch/powerpc/include/trap.h   Wed Jan 19 03:28:21 2000 +0000
+++ b/sys/arch/powerpc/include/trap.h   Wed Jan 19 03:30:12 2000 +0000
@@ -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_ */
diff -r da5f81ec11db -r 056503363286 sys/arch/powerpc/powerpc/trap.c
--- a/sys/arch/powerpc/powerpc/trap.c   Wed Jan 19 03:28:21 2000 +0000
+++ b/sys/arch/powerpc/powerpc/trap.c   Wed Jan 19 03:30:12 2000 +0000
@@ -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 @@
                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 @@
 
        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;
+}



Home | Main Index | Thread Index | Old Index