xtensa: make it work with TLB misses during interrupt handling
If there are any TLB misses during interrupt handling, the user, kernel and double exception vector will be triggered for the miss and the DEPC and EXCCAUSE overwritten as the TLB missse are be handled in the assembly code and execution returned to the original vector code. Because of this, both DEPC and EXCCAUSE being read in the C handler are not the ones that triggered the original exception (for example, level-1 interrupt). So stash both DEPC and EXCCAUSE such that the original cause of exception is visible in the C handler. Signed-off-by: Daniel Leung <daniel.leung@intel.com>
This commit is contained in:
parent
371ad016f8
commit
bc3e77b356
|
@ -31,7 +31,7 @@ args = parse_args()
|
|||
|
||||
NEEDED = ["A0SAVE", "CPU"]
|
||||
if args.mmu:
|
||||
NEEDED += ["DBLEXC"]
|
||||
NEEDED += ["DBLEXC", "DEPC_SAVE", "EXCCAUSE_SAVE"]
|
||||
if args.coherence:
|
||||
NEEDED += ["FLUSH"]
|
||||
|
||||
|
|
|
@ -229,12 +229,13 @@ void *xtensa_excint1_c(void *esf)
|
|||
void *pc, *print_stack = (void *)interrupted_stack;
|
||||
uint32_t depc = 0;
|
||||
|
||||
__asm__ volatile("rsr.exccause %0" : "=r"(cause));
|
||||
|
||||
#ifdef CONFIG_XTENSA_MMU
|
||||
__asm__ volatile("rsr.depc %0" : "=r"(depc));
|
||||
depc = XTENSA_RSR(ZSR_DEPC_SAVE_STR);
|
||||
cause = XTENSA_RSR(ZSR_EXCCAUSE_SAVE_STR);
|
||||
|
||||
is_dblexc = (depc != 0U);
|
||||
#else /* CONFIG_XTENSA_MMU */
|
||||
__asm__ volatile("rsr.exccause %0" : "=r"(cause));
|
||||
#endif /* CONFIG_XTENSA_MMU */
|
||||
|
||||
switch (cause) {
|
||||
|
@ -375,7 +376,7 @@ fixup_out:
|
|||
#endif
|
||||
#if defined(CONFIG_XTENSA_MMU)
|
||||
if (is_dblexc) {
|
||||
__asm__ volatile("wsr.depc %0" : : "r"(0));
|
||||
XTENSA_WSR(ZSR_DEPC_SAVE_STR, 0);
|
||||
}
|
||||
#endif /* CONFIG_XTENSA_MMU */
|
||||
|
||||
|
|
|
@ -489,6 +489,15 @@ _DoubleExceptionVector:
|
|||
addi a0, a0, -EXCCAUSE_DTLB_MISS
|
||||
beqz a0, _handle_tlb_miss_dblexc
|
||||
|
||||
/* Need to stash the DEPC for used by the C handler.
|
||||
* If we encounter any DTLB misses when PS.EXCM is set,
|
||||
* this vector will be used and the DEPC register will
|
||||
* have the new address instead of the one resulted in
|
||||
* double exception.
|
||||
*/
|
||||
rsr.depc a0
|
||||
wsr a0, ZSR_DEPC_SAVE
|
||||
|
||||
rsr a0, ZSR_DBLEXC
|
||||
|
||||
j _Level1Vector
|
||||
|
|
|
@ -604,6 +604,32 @@ _Level\LVL\()VectorHelper :
|
|||
.global _Level\LVL\()Vector
|
||||
_Level\LVL\()Vector:
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_XTENSA_MMU
|
||||
.if \LVL == 1
|
||||
/* If there are any TLB misses during interrupt handling,
|
||||
* the user/kernel/double exception vector will be triggered
|
||||
* to handle these misses. This results in DEPC and EXCCAUSE
|
||||
* being overwritten, and then execution returned back to
|
||||
* this site of TLB misses. When it gets to the C handler,
|
||||
* it will not see the original cause. So stash
|
||||
* the EXCCAUSE here so C handler can see the original cause.
|
||||
*
|
||||
* For double exception, DEPC in saved in earlier vector
|
||||
* code.
|
||||
*/
|
||||
wsr a0, ZSR_EXCCAUSE_SAVE
|
||||
|
||||
esync
|
||||
|
||||
rsr.exccause a0
|
||||
|
||||
xsr a0, ZSR_EXCCAUSE_SAVE
|
||||
|
||||
esync
|
||||
.endif
|
||||
#endif
|
||||
|
||||
addi a1, a1, -___xtensa_irq_bsa_t_SIZEOF
|
||||
s32i a0, a1, ___xtensa_irq_bsa_t_a0_OFFSET
|
||||
s32i a2, a1, ___xtensa_irq_bsa_t_a2_OFFSET
|
||||
|
|
Loading…
Reference in New Issue