1/* 2Copyright (c) 1990 The Regents of the University of California. 3All rights reserved. 4 5Redistribution and use in source and binary forms are permitted 6provided that the above copyright notice and this paragraph are 7duplicated in all such forms and that any documentation, 8and/or other materials related to such 9distribution and use acknowledge that the software was developed 10by the University of California, Berkeley. The name of the 11University may not be used to endorse or promote products derived 12from this software without specific prior written permission. 13THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 */ 17/* This is a simple version of setjmp and longjmp for the PowerPC. 18 Ian Lance Taylor, Cygnus Support, 9 Feb 1994. 19 Modified by Jeff Johnston, Red Hat Inc. 2 Oct 2001. 20 Modified by Sebastian Huber, embedded brains GmbH. 22 Sep 2022. */ 21 22#include "ppc-asm.h" 23 24FUNC_START(setjmp) 25#ifdef __ALTIVEC__ 26 addi 3,3,15 # align Altivec to 16 byte boundary 27#if __powerpc64__ 28 clrrdi 3,3,4 29#else 30 rlwinm 3,3,0,0,27 31#endif 32#else 33 addi 3,3,7 # align to 8 byte boundary 34#if __powerpc64__ 35 clrrdi 3,3,3 36#else 37 rlwinm 3,3,0,0,28 38#endif 39#endif 40#if __SPE__ 41 /* If we are E500, then save 64-bit registers. */ 42 evstdd 1,0(3) # offset 0 43 evstdd 2,8(3) # offset 8 44 evstdd 13,16(3) # offset 16 45 evstdd 14,24(3) # offset 24 46 evstdd 15,32(3) # offset 32 47 evstdd 16,40(3) # offset 40 48 evstdd 17,48(3) # offset 48 49 evstdd 18,56(3) # offset 56 50 evstdd 19,64(3) # offset 64 51 evstdd 20,72(3) # offset 72 52 evstdd 21,80(3) # offset 80 53 evstdd 22,88(3) # offset 88 54 evstdd 23,96(3) # offset 96 55 evstdd 24,104(3) # offset 104 56 evstdd 25,112(3) # offset 112 57 evstdd 26,120(3) # offset 120 58 evstdd 27,128(3) # offset 128 59 evstdd 28,136(3) # offset 136 60 evstdd 29,144(3) # offset 144 61 evstdd 30,152(3) # offset 152 62 evstdd 31,160(3) # offset 160 63 64 /* Add 164 to r3 to account for the amount of data we just 65 stored. Note that we are not adding 168 because the next 66 store instruction uses an offset of 4. */ 67 addi 3,3,164 68#elif __powerpc64__ 69 /* In the first store, add 8 to r3 so that the subsequent floating 70 point stores are aligned on an 8 byte boundary and the Altivec 71 stores are aligned on a 16 byte boundary. */ 72 stdu 1,8(3) # offset 8 73 stdu 2,8(3) # offset 16 74 stdu 13,8(3) # offset 24 75 stdu 14,8(3) # offset 32 76 stdu 15,8(3) # offset 40 77 stdu 16,8(3) # offset 48 78 stdu 17,8(3) # offset 56 79 stdu 18,8(3) # offset 64 80 stdu 19,8(3) # offset 72 81 stdu 20,8(3) # offset 80 82 stdu 21,8(3) # offset 88 83 stdu 22,8(3) # offset 96 84 stdu 23,8(3) # offset 104 85 stdu 24,8(3) # offset 112 86 stdu 25,8(3) # offset 120 87 stdu 26,8(3) # offset 128 88 stdu 27,8(3) # offset 136 89 stdu 28,8(3) # offset 144 90 stdu 29,8(3) # offset 152 91 stdu 30,8(3) # offset 160 92 stdu 31,8(3) # offset 168 93 mflr 4 94 stdu 4,8(3) # offset 176 95 mfcr 4 96 stwu 4,8(3) # offset 184 97#else 98 stw 1,0(3) # offset 0 99 stwu 2,4(3) # offset 4 100 stwu 13,4(3) # offset 8 101 stwu 14,4(3) # offset 12 102 stwu 15,4(3) # offset 16 103 stwu 16,4(3) # offset 20 104 stwu 17,4(3) # offset 24 105 stwu 18,4(3) # offset 28 106 stwu 19,4(3) # offset 32 107 stwu 20,4(3) # offset 36 108 stwu 21,4(3) # offset 40 109 stwu 22,4(3) # offset 44 110 stwu 23,4(3) # offset 48 111 stwu 24,4(3) # offset 52 112 stwu 25,4(3) # offset 56 113 stwu 26,4(3) # offset 60 114 stwu 27,4(3) # offset 64 115 stwu 28,4(3) # offset 68 116 stwu 29,4(3) # offset 72 117 stwu 30,4(3) # offset 76 118 stwu 31,4(3) # offset 80 119#endif 120 121#if !__powerpc64__ 122 /* If __SPE__, then add 84 to the offset shown from this point on until 123 the end of this function. This difference comes from the fact that 124 we save 21 64-bit registers instead of 21 32-bit registers above. */ 125 mflr 4 126 stwu 4,4(3) # offset 84 127 mfcr 4 128 stwu 4,4(3) # offset 88 129 # one word pad to get floating point aligned on 8 byte boundary 130#endif 131 132 /* Check whether we need to save FPRs. Checking __NO_FPRS__ 133 on its own would be enough for GCC 4.1 and above, but older 134 compilers only define _SOFT_FLOAT, so check both. */ 135#if !defined (__NO_FPRS__) && !defined (_SOFT_FLOAT) 136#if defined (__rtems__) && !defined (__PPC_CPU_E6500__) 137 /* For some RTEMS multilibs, the FPU and Altivec units are disabled 138 during interrupt handling. Do not save and restore the 139 corresponding registers in this case. */ 140 mfmsr 5 141 andi. 5,5,0x2000 142 beq 1f 143#endif 144 145 /* If __powerpc64__, then add 96 to the offset shown from this point on until 146 the end of this function. This difference comes from the fact that 147 we save 23 64-bit registers instead of 23 32-bit registers above and 148 we take alignement requirements of floating point and Altivec stores 149 into account. */ 150 151 stfdu 14,8(3) # offset 96 152 stfdu 15,8(3) # offset 104 153 stfdu 16,8(3) # offset 112 154 stfdu 17,8(3) # offset 120 155 stfdu 18,8(3) # offset 128 156 stfdu 19,8(3) # offset 136 157 stfdu 20,8(3) # offset 144 158 stfdu 21,8(3) # offset 152 159 stfdu 22,8(3) # offset 160 160 stfdu 23,8(3) # offset 168 161 stfdu 24,8(3) # offset 176 162 stfdu 25,8(3) # offset 184 163 stfdu 26,8(3) # offset 192 164 stfdu 27,8(3) # offset 200 165 stfdu 28,8(3) # offset 208 166 stfdu 29,8(3) # offset 216 167 stfdu 30,8(3) # offset 224 168 stfdu 31,8(3) # offset 232 1691: 170#endif 171 172 /* This requires a total of 21 * 4 + 18 * 8 + 4 + 4 + 4 173 bytes == 60 * 4 bytes == 240 bytes. */ 174 175#ifdef __ALTIVEC__ 176#if defined (__rtems__) && !defined (__PPC_CPU_E6500__) 177 mfmsr 5 178 andis. 5,5,0x200 179 beq 1f 180#endif 181 /* save Altivec vrsave and vr20-vr31 registers */ 182 mfspr 4,256 # vrsave register 183 stwu 4,16(3) # offset 248 184 addi 3,3,8 185 stvx 20,0,3 # offset 256 186 addi 3,3,16 187 stvx 21,0,3 # offset 272 188 addi 3,3,16 189 stvx 22,0,3 # offset 288 190 addi 3,3,16 191 stvx 23,0,3 # offset 304 192 addi 3,3,16 193 stvx 24,0,3 # offset 320 194 addi 3,3,16 195 stvx 25,0,3 # offset 336 196 addi 3,3,16 197 stvx 26,0,3 # offset 352 198 addi 3,3,16 199 stvx 27,0,3 # offset 368 200 addi 3,3,16 201 stvx 28,0,3 # offset 384 202 addi 3,3,16 203 stvx 29,0,3 # offset 400 204 addi 3,3,16 205 stvx 30,0,3 # offset 416 206 addi 3,3,16 207 stvx 31,0,3 # offset 432 2081: 209 210 /* This requires a total of 240 + 8 + 8 + 12 * 16 == 448 bytes. */ 211#endif 212 li 3,0 213 blr 214FUNC_END(setjmp) 215 216 217FUNC_START(longjmp) 218#ifdef __ALTIVEC__ 219 addi 3,3,15 # align Altivec to 16 byte boundary 220#if __powerpc64__ 221 clrrdi 3,3,4 222#else 223 rlwinm 3,3,0,0,27 224#endif 225#else 226 addi 3,3,7 # align to 8 byte boundary 227#if __powerpc64__ 228 clrrdi 3,3,3 229#else 230 rlwinm 3,3,0,0,28 231#endif 232#endif 233#if __SPE__ 234 /* If we are E500, then restore 64-bit registers. */ 235 evldd 1,0(3) # offset 0 236 evldd 2,8(3) # offset 8 237 evldd 13,16(3) # offset 16 238 evldd 14,24(3) # offset 24 239 evldd 15,32(3) # offset 32 240 evldd 16,40(3) # offset 40 241 evldd 17,48(3) # offset 48 242 evldd 18,56(3) # offset 56 243 evldd 19,64(3) # offset 64 244 evldd 20,72(3) # offset 72 245 evldd 21,80(3) # offset 80 246 evldd 22,88(3) # offset 88 247 evldd 23,96(3) # offset 96 248 evldd 24,104(3) # offset 104 249 evldd 25,112(3) # offset 112 250 evldd 26,120(3) # offset 120 251 evldd 27,128(3) # offset 128 252 evldd 28,136(3) # offset 136 253 evldd 29,144(3) # offset 144 254 evldd 30,152(3) # offset 152 255 evldd 31,160(3) # offset 160 256 257 /* Add 164 to r3 to account for the amount of data we just 258 loaded. Note that we are not adding 168 because the next 259 load instruction uses an offset of 4. */ 260 addi 3,3,164 261#elif __powerpc64__ 262 /* In the first load, add 8 to r3 so that the subsequent floating 263 point loades are aligned on an 8 byte boundary and the Altivec 264 loads are aligned on a 16 byte boundary. */ 265 ldu 1,8(3) # offset 8 266 ldu 2,8(3) # offset 16 267 ldu 13,8(3) # offset 24 268 ldu 14,8(3) # offset 32 269 ldu 15,8(3) # offset 40 270 ldu 16,8(3) # offset 48 271 ldu 17,8(3) # offset 56 272 ldu 18,8(3) # offset 64 273 ldu 19,8(3) # offset 72 274 ldu 20,8(3) # offset 80 275 ldu 21,8(3) # offset 88 276 ldu 22,8(3) # offset 96 277 ldu 23,8(3) # offset 104 278 ldu 24,8(3) # offset 112 279 ldu 25,8(3) # offset 120 280 ldu 26,8(3) # offset 128 281 ldu 27,8(3) # offset 136 282 ldu 28,8(3) # offset 144 283 ldu 29,8(3) # offset 152 284 ldu 30,8(3) # offset 160 285 ldu 31,8(3) # offset 168 286 ldu 5,8(3) # offset 176 287 mtlr 5 288 lwzu 5,8(3) # offset 184 289 mtcrf 255,5 290#else 291 lwz 1,0(3) # offset 0 292 lwzu 2,4(3) # offset 4 293 lwzu 13,4(3) # offset 8 294 lwzu 14,4(3) # offset 12 295 lwzu 15,4(3) # offset 16 296 lwzu 16,4(3) # offset 20 297 lwzu 17,4(3) # offset 24 298 lwzu 18,4(3) # offset 28 299 lwzu 19,4(3) # offset 32 300 lwzu 20,4(3) # offset 36 301 lwzu 21,4(3) # offset 40 302 lwzu 22,4(3) # offset 44 303 lwzu 23,4(3) # offset 48 304 lwzu 24,4(3) # offset 52 305 lwzu 25,4(3) # offset 56 306 lwzu 26,4(3) # offset 60 307 lwzu 27,4(3) # offset 64 308 lwzu 28,4(3) # offset 68 309 lwzu 29,4(3) # offset 72 310 lwzu 30,4(3) # offset 76 311 lwzu 31,4(3) # offset 80 312#endif 313 /* If __SPE__, then add 84 to the offset shown from this point on until 314 the end of this function. This difference comes from the fact that 315 we restore 22 64-bit registers instead of 22 32-bit registers above. */ 316 317#if !__powerpc64__ 318 lwzu 5,4(3) # offset 84 319 mtlr 5 320 lwzu 5,4(3) # offset 88 321 mtcrf 255,5 322 # one word pad to get floating point aligned on 8 byte boundary 323#endif 324 325 /* Check whether we need to restore FPRs. Checking 326 __NO_FPRS__ on its own would be enough for GCC 4.1 and 327 above, but older compilers only define _SOFT_FLOAT, so 328 check both. */ 329#if !defined (__NO_FPRS__) && !defined (_SOFT_FLOAT) 330#if defined (__rtems__) && !defined (__PPC_CPU_E6500__) 331 mfmsr 5 332 andi. 5,5,0x2000 333 beq 1f 334#endif 335 336 /* If __powerpc64__, then add 96 to the offset shown from this point on until 337 the end of this function. This difference comes from the fact that 338 we restore 23 64-bit registers instead of 23 32-bit registers above and 339 we take alignement requirements of floating point and Altivec loads 340 into account. */ 341 342 lfdu 14,8(3) # offset 96 343 lfdu 15,8(3) # offset 104 344 lfdu 16,8(3) # offset 112 345 lfdu 17,8(3) # offset 120 346 lfdu 18,8(3) # offset 128 347 lfdu 19,8(3) # offset 136 348 lfdu 20,8(3) # offset 144 349 lfdu 21,8(3) # offset 152 350 lfdu 22,8(3) # offset 160 351 lfdu 23,8(3) # offset 168 352 lfdu 24,8(3) # offset 176 353 lfdu 25,8(3) # offset 184 354 lfdu 26,8(3) # offset 192 355 lfdu 27,8(3) # offset 200 356 lfdu 28,8(3) # offset 208 357 lfdu 29,8(3) # offset 216 358 lfdu 30,8(3) # offset 224 359 lfdu 31,8(3) # offset 232 3601: 361#endif 362 363#ifdef __ALTIVEC__ 364#if defined (__rtems__) && !defined (__PPC_CPU_E6500__) 365 mfmsr 5 366 andis. 5,5,0x200 367 beq 1f 368#endif 369 /* restore Altivec vrsave and v20-v31 registers */ 370 lwzu 5,16(3) # offset 248 371 mtspr 256,5 # vrsave 372 addi 3,3,8 373 lvx 20,0,3 # offset 256 374 addi 3,3,16 375 lvx 21,0,3 # offset 272 376 addi 3,3,16 377 lvx 22,0,3 # offset 288 378 addi 3,3,16 379 lvx 23,0,3 # offset 304 380 addi 3,3,16 381 lvx 24,0,3 # offset 320 382 addi 3,3,16 383 lvx 25,0,3 # offset 336 384 addi 3,3,16 385 lvx 26,0,3 # offset 352 386 addi 3,3,16 387 lvx 27,0,3 # offset 368 388 addi 3,3,16 389 lvx 28,0,3 # offset 384 390 addi 3,3,16 391 lvx 29,0,3 # offset 400 392 addi 3,3,16 393 lvx 30,0,3 # offset 416 394 addi 3,3,16 395 lvx 31,0,3 # offset 432 3961: 397#endif 398 399 mr. 3,4 400 bclr+ 4,2 401 li 3,1 402 blr 403FUNC_END(longjmp) 404