- Remove the RESVEC vector table (panic/debug traps). It's now in

machine-specific code.

 - Re-work the code which detects a nested critical section event.
   We can now determine who is the owner of the critical section, and
   what event occurred while it was owned.

 - Work-around a silicon bug which can cause a nested critical event.
   In the _EXCEPTION_ENTRY() macro (which sets up the critical section),
   if there is a pending hardware interrupt which has a higher priority
   than the current IMASK, then the "putcon" which supposedly clears SR.BL
   and sets SR.IMASK to 0xf is not atomic. The pending hardware interrupt
   will be taken, causing a nested critical section event. The work-around
   is to update SR.BL and SR.IMASK separately using two "putcon" insns.
This commit is contained in:
scw 2002-09-10 12:27:21 +00:00
parent cd4797ccfa
commit 1a8208566d

View File

@ -1,4 +1,4 @@
/* $NetBSD: exception.S,v 1.12 2002/09/04 14:37:53 scw Exp $ */
/* $NetBSD: exception.S,v 1.13 2002/09/10 12:27:21 scw Exp $ */
/*
* Copyright 2002 Wasabi Systems, Inc.
@ -128,6 +128,15 @@
* And there you have it. Exceptions from hell.
*/
#define CHECK_CRITICAL(base) \
pta/l 50f, tr0 /* Assume critical section is free */ ;\
ld.q base, ES(ES_CRITICAL), r0 /* Fetch owner */ ;\
beq/l r0, r63, tr0 /* Jump if it's free */ ;\
pta/l Lsh5_critical_fault, tr0 ;\
blink tr0, r0 /* Otherwise, we're toast. */ ;\
50:
/*
* The following three macros allow the _EXCEPTION_*, _INTR_FRAME_*
* and _TRAP_FRAME_* macros to work with the two different exception
@ -144,17 +153,16 @@
* DO NOT add any more instructions without first checking there is space
* for them in the exception handlers.
*/
#define _EXCEPTION_ENTRY(sz) \
#define _EXCEPTION_ENTRY(sz,id) \
getcon usr, r24 /* Stash USR somewhere safe for now */;\
putcon r24, kcr1 ;\
getcon kcr0, r24 ;\
st.q r24, ES(ES_R0), r0 /* Save r0 and tr0 temporarily */ ;\
gettr tr0, r0 ;\
st.q r24, ES(ES_TR0), r0 ;\
pta/u Lsh5_critical_fault, tr0 ;\
ld.q r24, ES(ES_CRITICAL), r0 ;\
bne/u r0, r63, tr0 ;\
st.q r24, ES(ES_CRITICAL), r24 ;\
CHECK_CRITICAL(r24) ;\
movi id, r0 /* Identify who owns critical sect */ ;\
st.q r24, ES(ES_CRITICAL), r0 ;\
st.q r24, ES(ES_R1), r1 ;\
st.q r24, ES(ES_R2), r2 ;\
st.q r24, ES(ES_R15), r15 ;\
@ -181,11 +189,13 @@
movi sz, r0 ;\
sub r15, r0, r15 /* Make space for trapframe */ ;\
getcon sr, r1 /* Fetch current status register */ ;\
LDC32(SH5_CONREG_SR_BL, r0) /* Unblock exceptions. This allows */ ;\
andc r1, r0, r1 /* us to take a TLB miss exception */ ;\
ori r1, SH5_CONREG_SR_IMASK_ALL, r0 /* But don't allow IRQs */ ;\
or r24, r63, r2 /* Drop use of r24 now */ ;\
ori r1, SH5_CONREG_SR_IMASK_ALL, r0 ;\
putcon r0, sr ;\
LDC32(SH5_CONREG_SR_BL, r2) /* Unblock exceptions. This allows */ ;\
andc r0, r2, r0 /* us to take a TLB miss exception */ ;\
andc r1, r2, r1 ;\
putcon r0, sr /* Now safe to touch kernel stack */ ;\
or r24, r63, r2 /* Drop use of r24 now */ ;\
ld.q r2, ES(ES_R0), r0 ;\
st.q r15, IFO(IF_R0,sz), r0 /* Save original r0 */ ;\
ld.q r2, ES(ES_SSR), r0 ;\
@ -210,12 +220,14 @@
* Note that we can't block synchronous exceptions here in case touching
* the kernel stack causes a DLTB miss.
*/
#define _EXCEPTION_EXIT(sz) \
#define _EXCEPTION_EXIT(sz,id) \
getcon sr, r0 ;\
ori r0, SH5_CONREG_SR_IMASK_ALL, r2 /* No IRQs please */ ;\
putcon r2, sr ;\
getcon kcr0, r1 ;\
st.q r1, ES(ES_CRITICAL), r1 /* Entering critical section */ ;\
CHECK_CRITICAL(r1) ;\
movi (id) | CRIT_EXIT, r0 ;\
st.q r1, ES(ES_CRITICAL), r0 /* Entering critical section */ ;\
ld.q r15, SFO(SF_SSR,sz), r0 ;\
LDC32(SH5_CONREG_SR_ASID_MASK << SH5_CONREG_SR_ASID_SHIFT, r24) ;\
and r2, r24, r2 /* Get current ASID into r2 */ ;\
@ -464,46 +476,11 @@
.balign 0x100
GLOBAL(sh5_vector_table)
/******************************************************************************
* Reset/Panic Exception Vector.
*
* VBR Offset: 0x0
* Length: 0x100
*/
Lsh5_vector_panic:
getcon usr, r24 /* Stash USR somewhere safe for now */
putcon r15, kcr1
getcon kcr0, r15
LDPTR r15, CI_PANICSTKPHYS, r15 /* Get on panic stack */
st.q r15, IFO(IF_R0,SZ_TRAPFRAME), r0 /* Save r0 */
st.q r15, IFO(IF_R1,SZ_TRAPFRAME), r1 /* Save r1 */
st.q r15, IFO(IF_R2,SZ_TRAPFRAME), r2 /* Save r2 */
getcon kcr1, r0
st.q r15, IFO(IF_R15,SZ_TRAPFRAME), r0 /* Save r15 */
gettr tr0, r0
st.q r15, IFO(IF_TR0,SZ_TRAPFRAME), r0 /* Save tr0 */
getcon ssr, r0
st.q r15, SFO(SF_SSR,SZ_TRAPFRAME), r0 /* Save SSR */
getcon spc, r0
st.q r15, SFO(SF_SPC,SZ_TRAPFRAME), r0 /* Save SPC */
st.q r15, SFO(SF_USR,SZ_TRAPFRAME), r24 /* Save USR */
getcon expevt, r0
st.q r15, SFO(SF_EXPEVT, SZ_TRAPFRAME), r0 /* Save EXPEVT */
getcon intevt, r0
st.q r15, SFO(SF_INTEVT, SZ_TRAPFRAME), r0 /* Save INTEVT */
getcon tea, r0
st.q r15, SFO(SF_TEA, SZ_TRAPFRAME), r0 /* Save TEA */
getcon tra, r0
st.q r15, SFO(SF_TRA, SZ_TRAPFRAME), r0 /* Save TRA */
pta/l Lsh5_event_panic, tr0
blink tr0, r63
.balign 0x100
.space (0x100 - (. - _C_LABEL(sh5_vector_table)))
/******************************************************************************
* Non-TLB Miss/Debug Synchronous Exception Handler
* Non-TLB Miss Synchronous Exception Handler
*
* VBR Offset: 0x100
* Length: 0x100
@ -511,34 +488,16 @@ Lsh5_vector_panic:
* XXX: This handler very nearly fills the 0x100 byte exception slot :XXX
*/
Lsh5_vector_general:
_EXCEPTION_ENTRY(SZ_TRAPFRAME)
_EXCEPTION_ENTRY(SZ_TRAPFRAME, CRIT_SYNC_EXCEPTION)
pta/l Lsh5_event_sync, tr0
blink tr0, r63
nop
nop
nop
nop
nop
.balign 0x100
/******************************************************************************
* Debug Interrupt Handler.
*
* VBR Offset: 0x200
* Length: 0x200
*
* XXX: This isn't actually used...
*/
Lsh5_vector_debugint:
_EXCEPTION_ENTRY(SZ_INTRFRAME)
ld.q r2, ES(ES_INTEVT), r0 /* Fetch interrupt vector */
st.q r15, SFO(SF_INTEVT, SZ_INTRFRAME), r0 /* Save in stateframe */
st.q r2, ES(ES_CRITICAL), r63 /* Left the critical section */
ld.l r2, CI_INTR_DEPTH, r0 /* Update interrupt nesting level */
addi r0, 1, r0
st.l r2, CI_INTR_DEPTH, r0
putcon r1, sr /* Can safely take interrupts now */
pta/l Lsh5_event_interrupt, tr0
blink tr0, r63
.balign 0x200
.space (0x300 - (. - Lsh5_vector_general))
/******************************************************************************
@ -689,8 +648,13 @@ Ltlbmiss_updaterm:
putcon r24, usr
synco
rte /* #174: Return to previous context */
nop
nop
nop
nop
nop
.balign 0x200
.space (0x200 - (. - Lsh5_vector_tlbmiss))
/******************************************************************************
@ -702,7 +666,7 @@ Ltlbmiss_updaterm:
* Asynchronous Exception Handler (Hardware interrupts to you and me)
*/
Lsh5_vector_interrupt:
_EXCEPTION_ENTRY(SZ_INTRFRAME)
_EXCEPTION_ENTRY(SZ_INTRFRAME, CRIT_ASYNC_EXCEPTION)
ld.q r2, ES(ES_INTEVT), r0 /* Fetch interrupt vector */
st.q r15, SFO(SF_INTEVT, SZ_INTRFRAME), r0 /* Save in stateframe */
st.q r2, ES(ES_CRITICAL), r63 /* Left the critical section */
@ -713,40 +677,9 @@ Lsh5_vector_interrupt:
pta/l Lsh5_event_interrupt, tr0
blink tr0, r63
.balign 0x100
.balign 0x10
/*========================== End of Vector Table =============================*/
/******************************************************************************
* Continuation of Panic Event.
*
* Save the remainder of the machine state, re-enable the MMU and head off
* into C code to report the problem on the console (if possible), never
* to return.
*/
Lsh5_event_panic:
_INTR_FRAME_SAVE(SZ_TRAPFRAME)
_TRAP_FRAME_SAVE(SZ_TRAPFRAME)
getcon pssr, r4
getcon pspc, r5
LEAF(1f, r0)
putcon r0, spc
LDUC32(SH5_CONREG_SR_BL|SH5_CONREG_SR_MD|SH5_CONREG_SR_MMU, r0)
putcon r0, ssr
getcon kcr0, r2
LEA(_C_LABEL(sh5_panic_stack), r15)
movi (USPACE - SZ_TRAPFRAME), r0
add r15, r0, r15
synco
rte
1: LEAF(_C_LABEL(panic_trap), r0)
ptabs/l r0, tr0
or r15, r63, r3
blink tr0, r63
/*NOTREACHED*/
.comm _C_LABEL(sh5_panic_stack),USPACE,16
/*======================== End of VBR Vector Table ===========================*/
/******************************************************************************
@ -850,7 +783,7 @@ Ltrapexit:
#endif
_TRAP_FRAME_RESTORE(SZ_TRAPFRAME)
_INTR_FRAME_RESTORE(SZ_TRAPFRAME)
_EXCEPTION_EXIT(SZ_TRAPFRAME)
_EXCEPTION_EXIT(SZ_TRAPFRAME, CRIT_SYNC_EXCEPTION)
/* NOTREACHED */
/******************************************************************************
@ -941,7 +874,7 @@ Lsh5_event_interrupt:
Lintrexit:
_INTR_FRAME_RESTORE(SZ_INTRFRAME)
_EXCEPTION_EXIT(SZ_INTRFRAME)
_EXCEPTION_EXIT(SZ_INTRFRAME, CRIT_ASYNC_EXCEPTION)
/* NOTREACHED */
@ -1202,7 +1135,7 @@ Ltlbmiss_dotrap:
* because that would trash the contents of tr0 ...
*/
_EXCEPTION_ENTRY(SZ_TRAPFRAME)
_EXCEPTION_ENTRY(SZ_TRAPFRAME, CRIT_TLBMISS_TRAP)
/* Handle it using the normal exception code. */
@ -1227,9 +1160,12 @@ Ltlbmiss_dotrap:
* saved. R0 is likely to be lost, and USR is definately lost..
*/
Lsh5_critical_fault:
getcon kcr0, r24
st.q r24, ES(ES_R1), r1 /* We need another register */
or r0, r63, r1 /* r1 == where we just came from */
putcon r15, kcr1 /* Save original (faulty?) stack ptr */
LEA(_C_LABEL(sh5_panic_stack), r15)
movi USPACE - SZ_TRAPFRAME, r0
movi (USPACE - SZ_TRAPFRAME), r0
add r15, r0, r15
getcon expevt, r0
st.q r15, SFO(SF_EXPEVT, SZ_TRAPFRAME), r0
@ -1245,7 +1181,8 @@ Lsh5_critical_fault:
st.q r15, SFO(SF_SSR, SZ_TRAPFRAME), r0
ld.q r24, ES(ES_R0), r0
st.q r15, IFO(IF_R0, SZ_TRAPFRAME), r0
st.q r15, IFO(IF_R1, SZ_TRAPFRAME), r1
ld.q r24, ES(ES_R1), r0
st.q r15, IFO(IF_R1, SZ_TRAPFRAME), r0
st.q r15, IFO(IF_R2, SZ_TRAPFRAME), r2
getcon kcr1, r0
st.q r15, IFO(IF_R15, SZ_TRAPFRAME), r0
@ -1254,13 +1191,33 @@ Lsh5_critical_fault:
_INTR_FRAME_SAVE(SZ_TRAPFRAME)
_TRAP_FRAME_SAVE(SZ_TRAPFRAME)
/*
* Unblock exceptions.
* We need the TLB miss handler to be available so device
* registers are accessable (think console output).
*/
getcon sr, r0
ori r0, SH5_CONREG_SR_IMASK_ALL, r0
putcon r0, sr
movi SH5_CONREG_SR_IMASK_ALL, r0
putcon r0, sr
/*
* Fetch the ID of the current owner of the critical section, and
* clear the flag so that we may take further exceptions in the
* debugger.
*/
ld.q r24, ES(ES_CRITICAL), r5
st.q r24, ES(ES_CRITICAL), r63
/*
* Call panic_critical_fault(trapframe, exc_scratch_frame)
*/
LEAF(_C_LABEL(panic_critical_fault), r0)
ptabs/l r0, tr0
or r15, r63, r2
or r24, r63, r3
or r15, r63, r2 /* Pointer to trap frame */
addi r24, CI_ESCRATCH, r3 /* Pointer to scratch frame */
or r1, r63, r4 /* Where the error was detected */
blink tr0, r63
/*NOTREACHED*/
@ -1365,18 +1322,19 @@ ENTRY_NOPROFILE(proc_trampoline)
ENTRY(sh5_setasid)
getcon sr, r1
LDC32(SH5_CONREG_SR_ASID_MASK << SH5_CONREG_SR_ASID_SHIFT, r0)
shlli r2, SH5_CONREG_SR_ASID_SHIFT, r2
ori r1, SH5_CONREG_SR_IMASK_ALL, r3
and r2, r0, r2
andc r1, r0, r1
shlli r2, SH5_CONREG_SR_ASID_SHIFT, r2 /* shift "asid" up */
LDC32(SH5_CONREG_SR_BL | SH5_CONREG_SR_IMASK_ALL, r3)
or r1, r3, r3 /* SR.BL=1, IMASK=0xf */
and r2, r0, r2 /* keep only valid asid bits */
andc r1, r0, r1 /* Clear current asid bits */
putcon r3, sr /* Disable interrupts */
or r1, r2, r1
pta/l 1f, tr0
or r1, r2, r1 /* r1 == required SR */
pta/u 1f, tr0
putcon r1, ssr /* Desired status register */
gettr tr0, r0
ptabs/l r18, tr1
putcon r0, spc /* Continuation point */
synci
synco
rte
1: blink tr1, r63
1: ptabs/l r18, tr0
blink tr0, r63