summaryrefslogtreecommitdiff
path: root/libc/sysdeps/linux/xtensa/setjmp.S
diff options
context:
space:
mode:
Diffstat (limited to 'libc/sysdeps/linux/xtensa/setjmp.S')
-rw-r--r--libc/sysdeps/linux/xtensa/setjmp.S131
1 files changed, 131 insertions, 0 deletions
diff --git a/libc/sysdeps/linux/xtensa/setjmp.S b/libc/sysdeps/linux/xtensa/setjmp.S
new file mode 100644
index 000000000..5e81460c7
--- /dev/null
+++ b/libc/sysdeps/linux/xtensa/setjmp.S
@@ -0,0 +1,131 @@
+/* setjmp for Xtensa Processors.
+ Copyright (C) 2001, 2007 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+/* This implementation relies heavily on the Xtensa register window
+ mechanism. Setjmp flushes all the windows except its own to the
+ stack and then copies registers from the save areas on the stack
+ into the jmp_buf structure, along with the return address of the call
+ to setjmp. Longjmp invalidates all the windows except its own, and
+ then sets things up so that it will return to the right place,
+ using a window underflow to automatically restore the registers.
+
+ Note that it would probably be sufficient to only copy the
+ registers from setjmp's caller into jmp_buf. However, we also copy
+ the save area located at the stack pointer of setjmp's caller.
+ This save area will typically remain intact until the longjmp call.
+ The one exception is when there is an intervening alloca in
+ setjmp's caller. This is certainly an unusual situation and is
+ likely to cause problems in any case (the storage allocated on the
+ stack cannot be safely accessed following the longjmp). As bad as
+ it is, on most systems this situation would not necessarily lead to
+ a catastrophic failure. If we did not preserve the extra save area
+ on Xtensa, however, it would. When setjmp's caller returns after a
+ longjmp, there will be a window underflow; an invalid return
+ address or stack pointer in the save area will almost certainly
+ lead to a crash. Keeping a copy of the extra save area in the
+ jmp_buf avoids this with only a small additional cost. If setjmp
+ and longjmp are ever time-critical, this could be removed. */
+
+#include "sysdep.h"
+
+/* int setjmp (a2 = jmp_buf env) */
+
+ENTRY (_setjmp)
+ movi a3, 0
+ j 1f
+END (_setjmp)
+libc_hidden_def (_setjmp)
+
+ENTRY (setjmp)
+ movi a3, 1
+ j 1f
+END (setjmp)
+
+/* int __sigsetjmp (a2 = jmp_buf env,
+ a3 = int savemask) */
+
+ENTRY (__sigsetjmp)
+1:
+ /* Flush registers. */
+ movi a4, __window_spill
+ callx4 a4
+
+ /* Preserve the second argument (savemask) in a15. The selection
+ of a15 is arbitrary, except it's otherwise unused. There is no
+ risk of triggering a window overflow since we just returned
+ from __window_spill(). */
+ mov a15, a3
+
+ /* Copy the register save area at (sp - 16). */
+ addi a5, a1, -16
+ l32i a3, a5, 0
+ l32i a4, a5, 4
+ s32i a3, a2, 0
+ s32i a4, a2, 4
+ l32i a3, a5, 8
+ l32i a4, a5, 12
+ s32i a3, a2, 8
+ s32i a4, a2, 12
+
+ /* Copy 0-8 words from the register overflow area. */
+ extui a3, a0, 30, 2
+ blti a3, 2, .Lendsj
+ l32i a7, a1, 4
+ slli a4, a3, 4
+ sub a5, a7, a4
+ addi a6, a2, 16
+ addi a7, a7, -16 // a7 = end of register overflow area
+.Lsjloop:
+ l32i a3, a5, 0
+ l32i a4, a5, 4
+ s32i a3, a6, 0
+ s32i a4, a6, 4
+ l32i a3, a5, 8
+ l32i a4, a5, 12
+ s32i a3, a6, 8
+ s32i a4, a6, 12
+ addi a5, a5, 16
+ addi a6, a6, 16
+ blt a5, a7, .Lsjloop
+.Lendsj:
+
+ /* Copy the register save area at sp. */
+ l32i a3, a1, 0
+ l32i a4, a1, 4
+ s32i a3, a2, 48
+ s32i a4, a2, 52
+ l32i a3, a1, 8
+ l32i a4, a1, 12
+ s32i a3, a2, 56
+ s32i a4, a2, 60
+
+ /* Save the return address, including the window size bits. */
+ s32i a0, a2, 64
+
+ /* a2 still addresses jmp_buf. a15 contains savemask. */
+ mov a6, a2
+ mov a7, a15
+ movi a3, __sigjmp_save
+ callx4 a3
+ mov a2, a6
+ retw
+END(__sigsetjmp)
+
+weak_extern(_setjmp)
+weak_extern(setjmp)