From bc3e77b356e29d2f3bb41e6e09ee064016a76318 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Mon, 8 Apr 2024 17:35:50 -0700 Subject: [PATCH] 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 --- arch/xtensa/core/gen_zsr.py | 2 +- arch/xtensa/core/vector_handlers.c | 9 +++++---- arch/xtensa/core/xtensa_asm2_util.S | 9 +++++++++ arch/xtensa/include/xtensa_asm2_s.h | 26 ++++++++++++++++++++++++++ 4 files changed, 41 insertions(+), 5 deletions(-) diff --git a/arch/xtensa/core/gen_zsr.py b/arch/xtensa/core/gen_zsr.py index 4644daadae5..6d9a228303f 100755 --- a/arch/xtensa/core/gen_zsr.py +++ b/arch/xtensa/core/gen_zsr.py @@ -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"] diff --git a/arch/xtensa/core/vector_handlers.c b/arch/xtensa/core/vector_handlers.c index 466c5f36111..5bed4e6f4c6 100644 --- a/arch/xtensa/core/vector_handlers.c +++ b/arch/xtensa/core/vector_handlers.c @@ -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 */ diff --git a/arch/xtensa/core/xtensa_asm2_util.S b/arch/xtensa/core/xtensa_asm2_util.S index 58ca9b46eec..76aab766bc9 100644 --- a/arch/xtensa/core/xtensa_asm2_util.S +++ b/arch/xtensa/core/xtensa_asm2_util.S @@ -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 diff --git a/arch/xtensa/include/xtensa_asm2_s.h b/arch/xtensa/include/xtensa_asm2_s.h index 0af8c4cb51f..d07b69dcdba 100644 --- a/arch/xtensa/include/xtensa_asm2_s.h +++ b/arch/xtensa/include/xtensa_asm2_s.h @@ -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