1/* setjmp/longjmp functions for Xtensa. 2 3 Copyright (c) 2001-2006 by Tensilica Inc. 4 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: 12 13 The above copyright notice and this permission notice shall be included 14 in all copies or substantial portions of the Software. 15 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. */ 23 24/* Windowed ABI: 25 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. 33 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. 50 51 52 Call0 ABI: 53 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. */ 56 57#include "xtensa-asm.h" 58 59#define SYS_nop 0 60 61 62#if XCHAL_HAVE_WINDOWED && !__XTENSA_CALL0_ABI__ 63 64/* int setjmp (jmp_buf env) */ 65 66 .text 67 .align 4 68 .literal_position 69 .global setjmp 70 .type setjmp, @function 71setjmp: 72 entry sp, 16 73 74 /* Flush registers. */ 75 mov a4, a2 // save a2 (jmp_buf) 76 movi a2, SYS_nop 77 syscall 78 mov a2, a4 // restore a2 79 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 90 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: 112 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 122 123 /* Save the return address, including the window size bits. */ 124 s32i a0, a2, 64 125 126 movi a2, 0 127 retw 128 .size setjmp, . - setjmp 129 130 131/* void longjmp (jmp_buf env, int val) */ 132 133 .align 4 134 .literal_position 135 .global longjmp 136 .type longjmp, @function 137longjmp: 138 entry sp, 16 139 /* a2 == &env, a3 == val */ 140 141#if XCHAL_MAYHAVE_ERRATUM_XEA1KWIN 142 /* Using this register triggers early any overflow that a kernel-mode 143 level-one interrupt might otherwise cause. */ 144# define AR_WB a15 145#else 146 /* Using this register is more efficient; it triggers less overflows. */ 147# define AR_WB a5 148#endif 149 /* Invalidate all but the current window; 150 set WindowStart to (1 << WindowBase). */ 151 rsr AR_WB, WINDOWBASE 152 movi a4, 1 153 ssl AR_WB 154 sll a4, a4 155 wsr a4, WINDOWSTART 156 rsync 157 158 /* Return to the return address of the setjmp, using the 159 window size bits from the setjmp call so that the caller 160 will be able to find the return value that we put in a2. */ 161 162 l32i a0, a2, 64 163 164 /* Copy the first 4 saved registers from jmp_buf into the save area 165 at the current sp so that the values will be restored to registers 166 when longjmp returns. */ 167 168 addi a7, a1, -16 169 l32i a4, a2, 0 170 l32i a5, a2, 4 171 s32i a4, a7, 0 172 s32i a5, a7, 4 173 l32i a4, a2, 8 174 l32i a5, a2, 12 175 s32i a4, a7, 8 176 s32i a5, a7, 12 177 178 /* Copy the remaining 0-8 saved registers. */ 179 extui a7, a0, 30, 2 180 blti a7, 2, .Lendlj 181 l32i a8, a2, 52 182 slli a4, a7, 4 183 sub a6, a8, a4 184 addi a5, a2, 16 185 addi a8, a8, -16 // a8 = end of register overflow area 186.Lljloop: 187 l32i a7, a5, 0 188 l32i a4, a5, 4 189 s32i a7, a6, 0 190 s32i a4, a6, 4 191 l32i a7, a5, 8 192 l32i a4, a5, 12 193 s32i a7, a6, 8 194 s32i a4, a6, 12 195 addi a5, a5, 16 196 addi a6, a6, 16 197 blt a6, a8, .Lljloop 198.Lendlj: 199 200 /* The 4 words saved from the register save area at the target's 201 sp are copied back to the target procedure's save area. The 202 only point of this is to prevent a catastrophic failure in 203 case the contents were moved by an alloca after calling 204 setjmp. This is a bit paranoid but it doesn't cost much. */ 205 206 l32i a7, a2, 4 // load the target stack pointer 207 addi a7, a7, -16 // find the destination save area 208 l32i a4, a2, 48 209 l32i a5, a2, 52 210 s32i a4, a7, 0 211 s32i a5, a7, 4 212 l32i a4, a2, 56 213 l32i a5, a2, 60 214 s32i a4, a7, 8 215 s32i a5, a7, 12 216 217 /* Return val ? val : 1. */ 218 movi a2, 1 219 movnez a2, a3, a3 220 221 retw 222 .size longjmp, . - longjmp 223 224#else /* CALL0 ABI */ 225 226 .text 227 .align 4 228 .literal_position 229 .global setjmp 230 .type setjmp, @function 231setjmp: 232 s32i a0, a2, 0 233 s32i a1, a2, 4 234 s32i a12, a2, 8 235 s32i a13, a2, 12 236 s32i a14, a2, 16 237 s32i a15, a2, 20 238 movi a2, 0 239 ret 240 .size setjmp, . - setjmp 241 242 .align 4 243 .literal_position 244 .global longjmp 245 .type longjmp, @function 246longjmp: 247 l32i a0, a2, 0 248 l32i a12, a2, 8 249 l32i a13, a2, 12 250 l32i a14, a2, 16 251 l32i a15, a2, 20 252 l32i a1, a2, 4 253 /* Return val ? val : 1. */ 254 movi a2, 1 255 movnez a2, a3, a3 256 257 ret 258 .size longjmp, .-longjmp 259 260#endif /* CALL0 ABI */ 261