/* * Copyright (c) 2019-2020 Cobham Gaisler AB * * SPDX-License-Identifier: Apache-2.0 */ /* * This file contains standard handlers for the SPARC V8 window overflow and * underflow traps. It also implements the handler for SPARC-ABI * "Flush windows" which is used for example by longjmp() and C++ exceptions. */ #include #include #include GTEXT(__sparc_trap_window_overflow) GTEXT(__sparc_trap_window_underflow) GTEXT(__sparc_trap_flush_windows) SECTION_FUNC(TEXT, __sparc_trap_window_overflow) /* Enter the window to be stored. */ save /* Save local register set. */ std %l0, [%sp + 0x00] std %l2, [%sp + 0x08] std %l4, [%sp + 0x10] rd %wim, %l3 std %l6, [%sp + 0x18] /* l2 := WIM << (NWIN-1) */ sll %l3, (CONFIG_SPARC_NWIN-1), %l2 /* Save input register set. */ std %i0, [%sp + 0x20] /* l3 := WIM >> 1 */ srl %l3, 1, %l3 std %i2, [%sp + 0x28] /* WIM := (WIM >> 1) ^ (WIM << (NWIN-1)) */ wr %l3, %l2, %wim /* NOTE: 3 instruction before restore (delayed write instruction) */ std %i4, [%sp + 0x30] nop std %i6, [%sp + 0x38] /* Go back to trap window. */ restore /* Re-execute save. */ jmp %l1 rett %l2 SECTION_FUNC(TEXT, __sparc_trap_window_underflow) rd %wim, %l3 /* l4 := WIM << 1 */ sll %l3, 1, %l4 /* l5 := WIM >> (NWIN-1) */ srl %l3, (CONFIG_SPARC_NWIN-1), %l5 /* WIM := (WIM << 1) ^ (WIM >> (NWIN-1)) */ wr %l4, %l5, %wim /* WIM is implicitly read so nops are needed. */ nop nop nop /* Enter the window to restore requires two restore instructions. */ restore restore ldd [%sp + 0x00], %l0 ldd [%sp + 0x08], %l2 ldd [%sp + 0x10], %l4 ldd [%sp + 0x18], %l6 ldd [%sp + 0x20], %i0 ldd [%sp + 0x28], %i2 ldd [%sp + 0x30], %i4 ldd [%sp + 0x38], %i6 /* Go back to the trap window. */ save save /* Re-execute restore. */ jmp %l1 rett %l2 /* * Handler for SPARC trap 0x83: trap_instruction, defined as "Flush windows" by * SPARC-ABI: * "By executing a type 3 trap, a process asks the system to flush all its * register windows to the stack." * * On entry: * %l0: psr * %l1: pc * %l2: npc */ SECTION_FUNC(TEXT, __sparc_trap_flush_windows) /* Save global registers used by the routine */ mov %g3, %l3 mov %g4, %l4 mov %g5, %l5 mov %g1, %l6 mov %g2, %l7 /* Uses g3=psr, g4=1, g2=wim, g1,g5=scratch */ mov %l0, %g3 set 1, %g4 rd %wim, %g2 /* * 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 /* 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] /* * 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 /* 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