Cygwin: Add new APIs tc[gs]etwinsize()
[newlib-cygwin.git] / newlib / libc / machine / xtensa / setjmp.S
blobc32d443f2c7f42457bf6af3876b8723a24d0c11c
1 /* setjmp/longjmp functions for Xtensa.
3    Copyright (c) 2001-2006 by Tensilica Inc.
5    Permission is hereby granted, free of charge, to any person obtaining
6    a copy of this software and associated documentation files (the
7    "Software"), to deal in the Software without restriction, including
8    without limitation the rights to use, copy, modify, merge, publish,
9    distribute, sublicense, and/or sell copies of the Software, and to
10    permit persons to whom the Software is furnished to do so, subject to
11    the following conditions:
13    The above copyright notice and this permission notice shall be included
14    in all copies or substantial portions of the Software.
16    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
24 /* Windowed ABI:
26    This implementation relies heavily on the Xtensa register window
27    mechanism.  Setjmp flushes all the windows except its own to the
28    stack and then copies registers from the save areas on the stack
29    into the jmp_buf structure, along with the return address of the call
30    to setjmp.  Longjmp invalidates all the windows except its own, and
31    then sets things up so that it will return to the right place,
32    using a window underflow to automatically restore the registers.
34    Note that it would probably be sufficient to only copy the
35    registers from setjmp's caller into jmp_buf.  However, we also copy
36    the save area located at the stack pointer of setjmp's caller.
37    This save area will typically remain intact until the longjmp call.
38    The one exception is when there is an intervening alloca in
39    setjmp's caller.  This is certainly an unusual situation and is
40    likely to cause problems in any case (the storage allocated on the
41    stack cannot be safely accessed following the longjmp).  As bad as
42    it is, on most systems this situation would not necessarily lead to
43    a catastrophic failure.  If we did not preserve the extra save area
44    on Xtensa, however, it would.  When setjmp's caller returns after a
45    longjmp, there will be a window underflow; an invalid return
46    address or stack pointer in the save area will almost certainly
47    lead to a crash.  Keeping a copy of the extra save area in the
48    jmp_buf avoids this with only a small additional cost.  If setjmp
49    and longjmp are ever time-critical, this could be removed.
52    Call0 ABI:
54    Much like other ABIs, this version just saves the necessary registers
55    to the stack and restores them later.  Much less needs to be done.  */
57 #include "xtensa-asm.h"
59 #define SYS_nop 0
62 #if XCHAL_HAVE_WINDOWED && !__XTENSA_CALL0_ABI__
64 /* int setjmp (jmp_buf env) */
66         .text
67         .align  4
68         .literal_position
69         .global setjmp
70         .type   setjmp, @function
71 setjmp:
72         entry   sp, 16
74         /* Flush registers.  */
75         mov     a4, a2                  // save a2 (jmp_buf)
76         movi    a2, SYS_nop
77         syscall
78         mov     a2, a4                  // restore a2
80         /* Copy the register save area at (sp - 16).  */
81         addi    a5, a1, -16
82         l32i    a3, a5, 0
83         l32i    a4, a5, 4
84         s32i    a3, a2, 0
85         s32i    a4, a2, 4
86         l32i    a3, a5, 8
87         l32i    a4, a5, 12
88         s32i    a3, a2, 8
89         s32i    a4, a2, 12
91         /* Copy 0-8 words from the register overflow area.  */
92         extui   a3, a0, 30, 2
93         blti    a3, 2, .Lendsj
94         l32i    a7, a1, 4
95         slli    a4, a3, 4
96         sub     a5, a7, a4
97         addi    a6, a2, 16
98         addi    a7, a7, -16             // a7 = end of register overflow area
99 .Lsjloop:
100         l32i    a3, a5, 0
101         l32i    a4, a5, 4
102         s32i    a3, a6, 0
103         s32i    a4, a6, 4
104         l32i    a3, a5, 8
105         l32i    a4, a5, 12
106         s32i    a3, a6, 8
107         s32i    a4, a6, 12
108         addi    a5, a5, 16
109         addi    a6, a6, 16
110         blt     a5, a7, .Lsjloop
111 .Lendsj:
113         /* Copy the register save area at sp.  */
114         l32i    a3, a1, 0
115         l32i    a4, a1, 4
116         s32i    a3, a2, 48
117         s32i    a4, a2, 52
118         l32i    a3, a1, 8
119         l32i    a4, a1, 12
120         s32i    a3, a2, 56
121         s32i    a4, a2, 60
123         /* Save the return address, including the window size bits.  */
124         s32i    a0, a2, 64
126         movi    a2, 0
127         retw
128         .size   setjmp, . - setjmp
131 /* void longjmp (jmp_buf env, int val) */
133         .align  4
134         .literal_position
135         .global longjmp
136         .type   longjmp, @function
137 longjmp:
138         entry   sp, 16
139         /*  a2 == &env, a3 == val  */
141         /* Invalidate all but the current window;
142            set WindowStart to (1 << WindowBase).  */
143         rsr     a5, WINDOWBASE
144         movi    a4, 1
145         ssl     a5
146         sll     a4, a4
147         wsr     a4, WINDOWSTART
148         rsync
150         /* Return to the return address of the setjmp, using the
151            window size bits from the setjmp call so that the caller
152            will be able to find the return value that we put in a2.  */
154         l32i    a0, a2, 64
156         /* Copy the first 4 saved registers from jmp_buf into the save area
157            at the current sp so that the values will be restored to registers
158            when longjmp returns.  */
160         addi    a7, a1, -16
161         l32i    a4, a2, 0
162         l32i    a5, a2, 4
163         s32i    a4, a7, 0
164         s32i    a5, a7, 4
165         l32i    a4, a2, 8
166         l32i    a5, a2, 12
167         s32i    a4, a7, 8
168         s32i    a5, a7, 12
170         /* Copy the remaining 0-8 saved registers.  */
171         extui   a7, a0, 30, 2
172         blti    a7, 2, .Lendlj
173         l32i    a8, a2, 52
174         slli    a4, a7, 4
175         sub     a6, a8, a4
176         addi    a5, a2, 16
177         addi    a8, a8, -16             // a8 = end of register overflow area
178 .Lljloop:
179         l32i    a7, a5, 0
180         l32i    a4, a5, 4
181         s32i    a7, a6, 0
182         s32i    a4, a6, 4
183         l32i    a7, a5, 8
184         l32i    a4, a5, 12
185         s32i    a7, a6, 8
186         s32i    a4, a6, 12
187         addi    a5, a5, 16
188         addi    a6, a6, 16
189         blt     a6, a8, .Lljloop
190 .Lendlj:
192         /* The 4 words saved from the register save area at the target's
193            sp are copied back to the target procedure's save area.  The
194            only point of this is to prevent a catastrophic failure in
195            case the contents were moved by an alloca after calling
196            setjmp.  This is a bit paranoid but it doesn't cost much.  */
198         l32i    a7, a2, 4               // load the target stack pointer
199         addi    a7, a7, -16             // find the destination save area
200         l32i    a4, a2, 48
201         l32i    a5, a2, 52
202         s32i    a4, a7, 0
203         s32i    a5, a7, 4
204         l32i    a4, a2, 56
205         l32i    a5, a2, 60
206         s32i    a4, a7, 8
207         s32i    a5, a7, 12
209         /* Return val ? val : 1.  */
210         movi    a2, 1
211         movnez  a2, a3, a3
213         retw
214         .size   longjmp, . - longjmp
216 #else /* CALL0 ABI */
218         .text
219         .align  4
220         .literal_position
221         .global setjmp
222         .type   setjmp, @function
223 setjmp:
224         s32i    a0, a2, 0
225         s32i    a1, a2, 4
226         s32i    a12, a2, 8
227         s32i    a13, a2, 12
228         s32i    a14, a2, 16
229         s32i    a15, a2, 20
230         movi    a2, 0
231         ret
232         .size   setjmp, . - setjmp
234         .align  4
235         .literal_position
236         .global longjmp
237         .type   longjmp, @function
238 longjmp:
239         l32i    a0, a2, 0
240         l32i    a12, a2, 8
241         l32i    a13, a2, 12
242         l32i    a14, a2, 16
243         l32i    a15, a2, 20
244         l32i    a1, a2, 4
245         /* Return val ? val : 1.  */
246         movi    a2, 1
247         movnez  a2, a3, a3
249         ret
250         .size   longjmp, .-longjmp
252 #endif /* CALL0 ABI */