From fd4e66499cdcf4db30c42b53ec4ea076de253f50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20=C3=85berg?= Date: Tue, 17 Oct 2023 15:24:25 +0200 Subject: [PATCH] SPARC: Update the Flush windows software trap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit re-implements the SPARC V8 ABI "Flush windows" software trap. The trap is generated by C++ compilers for exceptions and also by the C standard library function longjmp(). There were two issues with the previous implementation: 1. It did reads and writes via the stack pointer of the trap window, which is not defined. 2. It executed with traps enabled but without the processor run-time state set to safely handle traps. In particular there was no valid stack for trap processing. Even though interrupt priority was set to highest level, the behavior at other traps was not deterministic. For example non-maskable interrupt (15) trap or bus error trap for instruction fetch. This new implementation does not store backup copies of CPU registers to the stack, and it executes with traps disabled. Fixes #63901 Signed-off-by: Martin Ã…berg --- arch/sparc/core/window_trap.S | 111 +++++++++++++++++++++------------- 1 file changed, 68 insertions(+), 43 deletions(-) diff --git a/arch/sparc/core/window_trap.S b/arch/sparc/core/window_trap.S index ea810e1d6dd..5a9edfd37c2 100644 --- a/arch/sparc/core/window_trap.S +++ b/arch/sparc/core/window_trap.S @@ -83,60 +83,85 @@ SECTION_FUNC(TEXT, __sparc_trap_window_underflow) * "By executing a type 3 trap, a process asks the system to flush all its * register windows to the stack." * - * This implementation uses the window overflow trap handler to perform the - * actual window flush. - * * On entry: * %l0: psr * %l1: pc * %l2: npc */ SECTION_FUNC(TEXT, __sparc_trap_flush_windows) - /* push a few registers which are needed later to the stack */ - sub %sp, 0x10, %sp - std %l0, [%sp + 0x40 + 0x00] - st %l2, [%sp + 0x40 + 0x08] - st %g2, [%sp + 0x40 + 0x0c] + /* Save global registers used by the routine */ + mov %g3, %l3 + mov %g4, %l4 + mov %g5, %l5 + mov %g1, %l6 + mov %g2, %l7 - restore - /* In window where we trapped from. This window will not be flushed. */ + /* Uses g3=psr, g4=1, g2=wim, g1,g5=scratch */ + mov %l0, %g3 + set 1, %g4 + rd %wim, %g2 - /* Set highest processor interrupt level and enable traps. */ - rd %psr, %g2 - or %g2, PSR_PIL, %g2 - wr %g2, PSR_ET, %psr - nop - nop + /* + * We can always restore the previous window. Check if we can restore + * the window after that. + */ + and %l0, PSR_CWP, %g1 + add %g1, 2, %g1 + ba .LcheckNextWindow + restore - /* Execute "save" NWINDOWS-1 times. */ - set CONFIG_SPARC_NWIN-2, %g2 -1: - save - cmp %g2, %g0 - bne 1b - sub %g2, 1, %g2 + /* Flush window to stack */ +.LflushWindow: + std %l0, [%sp + 0x00] + std %l2, [%sp + 0x08] + std %l4, [%sp + 0x10] + std %l6, [%sp + 0x18] + std %i0, [%sp + 0x20] + std %i2, [%sp + 0x28] + std %i4, [%sp + 0x30] + std %i6, [%sp + 0x38] - /* Execute "restore" NWINDOWS-1 times. */ - set CONFIG_SPARC_NWIN-2, %g2 -2: - restore - cmp %g2, %g0 - bne 2b - sub %g2, 1, %g2 + /* + * Check if next window is invalid by comparing + * (1 << ((cwp + 1) % NWIN)) with WIM + */ +.LcheckNextWindow: + set CONFIG_SPARC_NWIN, %g5 + cmp %g1, %g5 + bge,a .Lnowrap + sub %g1, %g5, %g1 +.Lnowrap: + sll %g4, %g1, %g5 + cmp %g5, %g2 + be .LflushWindowDone + inc %g1 - save - - /* pop registers from stack which are used for the trap return */ - ldd [%sp + 0x40 + 0x00], %l0 - ld [%sp + 0x40 + 0x08], %l2 - ld [%sp + 0x40 + 0x0c], %g2 - add %sp, 0x10, %sp - - /* Restore %psr as it was on trap entry. */ - wr %l0, %psr - nop - nop - nop + /* We need to flush the next window */ + ba .LflushWindow + restore + /* + * All used windows have been flushed. Set WIM to cause trap for CWP+2. + * When we return from this trap it will be CWP+1 that will trap, that + * is, the next restore or rett. + */ +.LflushWindowDone: + /* We can not restore %psr from %l0 because we may be in any window. */ + wr %g3, %psr + and %g3, PSR_CWP, %g1 + add %g1, 2, %g1 + set CONFIG_SPARC_NWIN, %g5 + /* We are now back in the trap window. */ + cmp %g1, %g5 + bge,a .Lnowrap2 + sub %g1, %g5, %g1 +.Lnowrap2: + sll %g4, %g1, %g1 + wr %g1, %wim + mov %l3, %g3 + mov %l4, %g4 + mov %l5, %g5 + mov %l6, %g1 + mov %l7, %g2 jmp %l2 rett %l2 + 4