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:
Daniel Leung 2024-04-08 17:35:50 -07:00 committed by Anas Nashif
parent 371ad016f8
commit bc3e77b356
4 changed files with 41 additions and 5 deletions

View File

@ -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"]

View File

@ -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 */

View File

@ -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

View File

@ -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