summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiod Vallat <miod@cvs.openbsd.org>2007-12-02 21:27:03 +0000
committerMiod Vallat <miod@cvs.openbsd.org>2007-12-02 21:27:03 +0000
commitcf67d8fb8b98c12477963015fdd28c91a18f92be (patch)
treedb2cd431517468b5c53706d29ea52b8c1e02cfd2
parent5a2e47cb2f42a2980b166391aff5ac4fa72f9680 (diff)
Since the 88110 doesn't disable the FPU when handling an exception (and does
not need to), do not try to handle exceptions occuring when we re-enable shadowing as special - these are just nested exceptions. While there, add a workaround for the 88110 rte errata (#18).
-rw-r--r--sys/arch/m88k/m88k/eh_common.S171
1 files changed, 60 insertions, 111 deletions
diff --git a/sys/arch/m88k/m88k/eh_common.S b/sys/arch/m88k/m88k/eh_common.S
index d4e87ecc160..88dd1b194c5 100644
--- a/sys/arch/m88k/m88k/eh_common.S
+++ b/sys/arch/m88k/m88k/eh_common.S
@@ -1,4 +1,4 @@
-/* $OpenBSD: eh_common.S,v 1.38 2007/11/22 23:30:11 miod Exp $ */
+/* $OpenBSD: eh_common.S,v 1.39 2007/12/02 21:27:02 miod Exp $ */
/*
* Mach Operating System
* Copyright (c) 1993-1991 Carnegie Mellon University
@@ -30,7 +30,8 @@
/*
* NOTICE: This is not a standalone file. To use it, define the PFSR_SAVE
- * macro and #include this file in your port's eh.S:
+ * macro (if supporting 88100 processors) and #include this file in your
+ * port's eh.S:
* #include <m88k/m88k/eh_common.S>
*/
@@ -40,7 +41,7 @@
* (second edition). Reference in []s refer to section numbers.
*
* This discussion assumes that you are at least vaguely familiar with 88100
- * exception handling (chapter 6), the MACH kernel, and that you have a brain
+ * exception handling (chapter 6), the BSD kernel, and that you have a brain
* (and use it while reading this).
*
* I also assume (and hope) that you're not offended by frequent misspellings.
@@ -341,10 +342,10 @@
1: bsr _ASM_LABEL(m88110_setup_phase_one) ; \
/* TMP2 now free -- use to set EF_VECTOR */ ; \
or TMP2, r0, NUM ; \
- st TMP2, r31, REG_OFF(EF_VECTOR) ; \
- /* call setup_phase_two to restart the FPU */ ; \
- /* and to save all general registers. */ ; \
- bsr _ASM_LABEL(m88110_setup_phase_two)
+ /* call setup_phase_two to save all general */ ; \
+ /* registers. */ ; \
+ bsr.n _ASM_LABEL(m88110_setup_phase_two) ; \
+ st TMP2, r31, REG_OFF(EF_VECTOR)
#endif
/* Some defines for use with PREP88100() */
@@ -1317,7 +1318,7 @@ ASLOCAL(m88100_setup_phase_two)
*
* immediate goal:
* restore the system to the exception-time state (except
- * SR3 will be OUR stack pointer) so that we may resart the FPU.
+ * SR3 will be OUR stack pointer) so that we may restart the FPU.
*/
stcr TMP, SSBR /* done with SSBR, TMP now free */
@@ -1821,19 +1822,16 @@ ASLOCAL(m88110_setup_phase_one)
* Might be at the end of R31, SR3, or the process pcb.
*/
- /* Check if we are coming in from a FPU restart exception.
- If so, the pcb will be in SR3 */
NOP
xcr r1, r1, SR2
NOP
NOP
NOP
- bb1 FLAG_ENABLING_FPU, FLAGS, _ASM_LABEL(m88110_use_SR3_pcb)
/* are we coming in from user mode? If so, pick up process pcb */
bb0 FLAG_FROM_KERNEL, FLAGS, _ASM_LABEL(m88110_pickup_stack)
- /* Interrupt in kernel mode, not FPU restart */
+ /* Interrupt in kernel mode */
/*
* SR1: saved copy of exception-time register now holding FLAGS
* SR2: return address to the calling exception handler
@@ -1856,63 +1854,6 @@ ASLOCAL(m88110_setup_phase_one)
br.n _ASM_LABEL(m88110_have_pcb)
st r1, r31, GENREG_OFF(31)
-ASLOCAL(m88110_use_SR3_pcb)
- /*
- * SR1: saved copy of exception-time register now holding FLAGS
- * SR2: return address to the calling exception handler
- * SR3: must be preserved; exception-time stack pointer
- * FLAGS: CPU status flags
- *
- * immediate goal:
- * An exception occurred while enabling the FPU. Since r31 is the
- * user's r31 while enabling the FPU, we had put our pcb pointer
- * into SR3, so make room from there for our stack pointer.
- * We need to check if SR3 is the old stack pointer or the pointer
- * off to the user pcb. If it pointing to the user pcb, we need to
- * pick up the kernel stack. Otherwise we need to allocate a frame
- * upon it.
- * We look at the EPSR to see if it was from user mode
- * Unfortunately, we have no registers free at the moment, but we
- * know register 0 in the pcb frame will always be zero, so we can
- * use it as scratch storage.
- */
- xcr r30, r30, SR3 /* r30 = old exception frame */
- st r1, r30, GENREG_OFF(0) /* free up r1 */
- ld r1, r30, REG_OFF(EF_EPSR) /* get back the epsr */
- bb0.n PSR_SUPERVISOR_MODE_BIT, r1, 1f /* if user mode */
- ld r1, r30, GENREG_OFF(0) /* restore r1 */
- /* we were in kernel mode - dump frame upon the stack */
- st r0, r30, GENREG_OFF(0) /* repair old frame */
- subu r30, r30, SIZEOF_EF /* r30 now our E.F. */
- st FLAGS,r30, REG_OFF(EF_FLAGS) /* save flags */
- st r1, r30, GENREG_OFF(1) /* save prev. r1 (now free) */
-
- st r31, r30, GENREG_OFF(31) /* save previous r31 */
- or r31, r0, r30 /* make r31 our pointer. */
- addu r30, r30, SIZEOF_EF /* r30 now has previous SR3 */
- st r30, r31, REG_OFF(EF_SR3) /* save previous SR3 */
- br.n _ASM_LABEL(m88110_have_pcb)
- xcr r30, r30, SR3 /* restore r30 */
-1:
- /*
- * We took an exception while restarting the FPU from user space.
- * Consequently, we never picked up a stack. Do so now.
- * R1 is currently free (saved in the exception frame pointed at by
- * r30)
- */
- ldcr r1, CPU
- ld r1, r1, CI_CURPCB
- addu r1, r1, USIZE - SIZEOF_EF
- st FLAGS,r1, REG_OFF(EF_FLAGS) /* store flags */
- st r31, r1, GENREG_OFF(31) /* store r31 - now free */
- st r30, r1, REG_OFF(EF_SR3) /* store old SR3 (pcb) */
- or r31, r1, r0 /* make r31 our exception fp */
- ld r1, r30, GENREG_OFF(0) /* restore old r1 */
- st r0, r30, GENREG_OFF(0) /* repair that frame */
- st r1, r31, GENREG_OFF(1) /* store r1 */
- br.n _ASM_LABEL(m88110_have_pcb)
- xcr r30, r30, SR3 /* restore r30 */
-
ASLOCAL(m88110_pickup_stack)
/*
* SR1: saved copy of exception-time register now holding FLAGS
@@ -1935,8 +1876,7 @@ ASLOCAL(m88110_pickup_stack)
/*
* WARNING! Using pcb->user_state as the exception frame
* AND stack pointer, means we can not afford using the stack
- * until we have saved enough and can go back to the top of the u area,
- * after the FPU is enabled.
+ * until we have saved enough and can go back to the top of the u area.
*/
st FLAGS,r31, REG_OFF(EF_FLAGS) /* save flags */
@@ -1956,10 +1896,6 @@ ASLOCAL(m88110_have_pcb)
* Valid in the exception frame:
* Exception-time r1, r31, FLAGS.
* Exception SR3, if appropriate.
- *
- * immediate goal:
- * Save the shadow registers that need to be saved to
- * the exception frame.
*/
stcr TMP, SR3 /* free up TMP, TMP2, TMP3 */
SAVE_TMP2
@@ -2024,29 +1960,24 @@ ASLOCAL(m88110_setup_phase_two)
* Exception-time TMP2, TMP3.
* Exception-time espr, enip, exip.
* Exception number (EF_VECTOR).
- * Dmt0
- * Other data pipeline control registers, if appropriate.
- * FPU control registers, if appropriate.
* Exception SR3, if appropriate.
*
* immediate goal:
* restore the system to the exception-time state (except SR3 will
- * be OUR stack pointer) so that we may resart the FPU.
+ * be OUR stack pointer).
*/
RESTORE_TMP2 /* done with extra temp regs */
RESTORE_TMP3 /* done with extra temp regs */
ldcr TMP, PSR
- clr TMP, TMP, 1<PSR_FPU_DISABLE_BIT> /* enable the FPU */
clr TMP, TMP, 1<PSR_SHADOW_FREEZE_BIT> /* and shadowing */
stcr TMP, EPSR
- or.u TMP, r0, hi16(_ASM_LABEL(m88110_fpu_enable))
- or TMP, TMP, lo16(_ASM_LABEL(m88110_fpu_enable))
+ or.u TMP, r0, hi16(_ASM_LABEL(m88110_shadow_enable))
+ or TMP, TMP, lo16(_ASM_LABEL(m88110_shadow_enable))
stcr TMP, EXIP
- set FLAGS, FLAGS, 1<FLAG_ENABLING_FPU>
xcr FLAGS, FLAGS, SR1
st r1, r31, REG_OFF(EF_RET) /* save the return address */
ld r1, r31, GENREG_OFF(1) /* get original r1 */
@@ -2072,13 +2003,13 @@ ASLOCAL(m88110_setup_phase_two)
* Return address to the calling exception handler.
*
* immediate goal:
- * Do an RTE to restart the fpu and jump to "fpu_enable"
+ * Do an RTE to unfreeze the shadow registers.
* Another exception (or exceptions) may be raised in
- * this, which is why FLAG_ENABLING_FPU is set in SR1.
+ * this.
*/
- RTE /* jumps to "m88110_fpu_enable" to enable the FPU. */
+ RTE /* jumps to "m88110_shadow_enable" */
-ASLOCAL(m88110_fpu_enable)
+ASLOCAL(m88110_shadow_enable)
FLUSH_PIPELINE
xcr TMP, TMP, SR3 /* get E.F. pointer */
@@ -2086,13 +2017,7 @@ ASLOCAL(m88110_fpu_enable)
st r31, TMP, GENREG_OFF(31) /* save previous r30, r31 */
or r31, TMP, r0 /* transfer E.F. pointer */
ld TMP, r31, REG_OFF(EF_SR3) /* get previous SR3 */
-
- /* make sure that the FLAG_ENABLING_FPU bit is off */
- xcr FLAGS,FLAGS,SR1
- clr FLAGS,FLAGS,1<FLAG_ENABLING_FPU>
- xcr FLAGS,FLAGS,SR1
-
- xcr TMP, TMP, SR3 /* replace TMP, SR3 */
+ xcr TMP, TMP, SR3 /* replace TMP, SR3 */
/* now save all regs to the exception frame. */
st r0 , r31, GENREG_OFF(0)
@@ -2143,13 +2068,10 @@ ASLOCAL(m88110_fpu_enable)
* Exception-time FLAGS.
* Exception-time espr, enip, exip.
* Exception number (EF_VECTOR).
- * DSR
- * Other data pipeline control registers, if appropriate.
- * FPU control registers, if appropriate.
+ * DSR/ISR
* Exception SR3, if appropriate.
*
* immediate goal:
- * Pick up a stack if we came in from user mode.
* Put a copy of the exception frame pointer into r30
* Bump the stack a doubleword and write the exception frame pointer.
* If not an interrupt exception, turn on interrupts and service any
@@ -2351,23 +2273,16 @@ ASGLOBAL(ast_done)
FLUSH_PIPELINE
/* reload the control regs*/
-#ifdef M88110
-#ifdef M88100
+#if defined(M88100) && defined(M88110)
or.u r1, r0, hi16(_C_LABEL(cputyp))
ld r30, r1, lo16(_C_LABEL(cputyp))
cmp r1, r30, CPU_88110
- bb1 ne, r1, 1f
-#endif
- ld r30, r31, REG_OFF(EF_ENIP)
- ld r1, r31, REG_OFF(EF_EXIP)
- stcr r30, ENIP
- stcr r1, EXIP
-#ifdef M88100
- br 2f
-1:
-#endif
+ bb1 ne, r1, _ASM_LABEL(m88100_user_rte)
+ br _ASM_LABEL(m88110_user_rte)
#endif
+
#ifdef M88100
+ASGLOBAL(m88100_user_rte)
/*
* RTE will cause execution to continue first with the
* instruction pointed to by the NIP and then the FIP;
@@ -2378,8 +2293,25 @@ ASGLOBAL(ast_done)
ld r1, r31, REG_OFF(EF_SFIP)
stcr r30, SNIP
stcr r1, SFIP
-2:
+
+ ld r30, r31, REG_OFF(EF_EPSR)
+ stcr r30, EPSR
+
+ /* Now restore r1, r30, and r31 */
+ ld r1, r31, GENREG_OFF(1)
+ ld r30, r31, GENREG_OFF(30)
+ ld r31, r31, GENREG_OFF(31)
+
+ RTE
#endif
+
+#ifdef M88110
+ASGLOBAL(m88110_user_rte)
+ ld r30, r31, REG_OFF(EF_ENIP)
+ ld r1, r31, REG_OFF(EF_EXIP)
+ stcr r30, ENIP
+ stcr r1, EXIP
+
ld r30, r31, REG_OFF(EF_EPSR)
stcr r30, EPSR
@@ -2388,4 +2320,21 @@ ASGLOBAL(ast_done)
ld r30, r31, GENREG_OFF(30)
ld r31, r31, GENREG_OFF(31)
+ /*
+ * 88110 errata #18 (fixed in revision 5 cpus):
+ * ``An rte to user mode where the logical address of the rte
+ * instruction is within two cache lines of the logical address
+ * in the exip can cause the wrong instruction to be returned
+ * to if the rte instruction misses in the icache.''
+ *
+ * Since we run with interrupts disabled at this point, all we
+ * need is make sure that the rte will not appear as the first
+ * instruction of a cache line.
+ */
+ br 1f
+
+ align 64 /* 32 might not be enough */
+1:
+ NOP
RTE
+#endif