/* This is a simple version of setjmp and longjmp for the PowerPC. Ian Lance Taylor, Cygnus Support, 9 Feb 1994. Modified by Jeff Johnston, Red Hat Inc. 2 Oct 2001. Modified by Sebastian Huber, embedded brains GmbH. 22 Sep 2022. */ #include "ppc-asm.h" FUNC_START(setjmp) #ifdef __ALTIVEC__ addi 3,3,15 # align Altivec to 16 byte boundary #if __powerpc64__ clrrdi 3,3,4 #else rlwinm 3,3,0,0,27 #endif #else addi 3,3,7 # align to 8 byte boundary #if __powerpc64__ clrrdi 3,3,3 #else rlwinm 3,3,0,0,28 #endif #endif #if __SPE__ /* If we are E500, then save 64-bit registers. */ evstdd 1,0(3) # offset 0 evstdd 2,8(3) # offset 8 evstdd 13,16(3) # offset 16 evstdd 14,24(3) # offset 24 evstdd 15,32(3) # offset 32 evstdd 16,40(3) # offset 40 evstdd 17,48(3) # offset 48 evstdd 18,56(3) # offset 56 evstdd 19,64(3) # offset 64 evstdd 20,72(3) # offset 72 evstdd 21,80(3) # offset 80 evstdd 22,88(3) # offset 88 evstdd 23,96(3) # offset 96 evstdd 24,104(3) # offset 104 evstdd 25,112(3) # offset 112 evstdd 26,120(3) # offset 120 evstdd 27,128(3) # offset 128 evstdd 28,136(3) # offset 136 evstdd 29,144(3) # offset 144 evstdd 30,152(3) # offset 152 evstdd 31,160(3) # offset 160 /* Add 164 to r3 to account for the amount of data we just stored. Note that we are not adding 168 because the next store instruction uses an offset of 4. */ addi 3,3,164 #elif __powerpc64__ /* In the first store, add 8 to r3 so that the subsequent floating point stores are aligned on an 8 byte boundary and the Altivec stores are aligned on a 16 byte boundary. */ stdu 1,8(3) # offset 8 stdu 2,8(3) # offset 16 stdu 13,8(3) # offset 24 stdu 14,8(3) # offset 32 stdu 15,8(3) # offset 40 stdu 16,8(3) # offset 48 stdu 17,8(3) # offset 56 stdu 18,8(3) # offset 64 stdu 19,8(3) # offset 72 stdu 20,8(3) # offset 80 stdu 21,8(3) # offset 88 stdu 22,8(3) # offset 96 stdu 23,8(3) # offset 104 stdu 24,8(3) # offset 112 stdu 25,8(3) # offset 120 stdu 26,8(3) # offset 128 stdu 27,8(3) # offset 136 stdu 28,8(3) # offset 144 stdu 29,8(3) # offset 152 stdu 30,8(3) # offset 160 stdu 31,8(3) # offset 168 mflr 4 stdu 4,8(3) # offset 176 mfcr 4 stwu 4,8(3) # offset 184 #else stw 1,0(3) # offset 0 stwu 2,4(3) # offset 4 stwu 13,4(3) # offset 8 stwu 14,4(3) # offset 12 stwu 15,4(3) # offset 16 stwu 16,4(3) # offset 20 stwu 17,4(3) # offset 24 stwu 18,4(3) # offset 28 stwu 19,4(3) # offset 32 stwu 20,4(3) # offset 36 stwu 21,4(3) # offset 40 stwu 22,4(3) # offset 44 stwu 23,4(3) # offset 48 stwu 24,4(3) # offset 52 stwu 25,4(3) # offset 56 stwu 26,4(3) # offset 60 stwu 27,4(3) # offset 64 stwu 28,4(3) # offset 68 stwu 29,4(3) # offset 72 stwu 30,4(3) # offset 76 stwu 31,4(3) # offset 80 #endif #if !__powerpc64__ /* If __SPE__, then add 84 to the offset shown from this point on until the end of this function. This difference comes from the fact that we save 21 64-bit registers instead of 21 32-bit registers above. */ mflr 4 stwu 4,4(3) # offset 84 mfcr 4 stwu 4,4(3) # offset 88 # one word pad to get floating point aligned on 8 byte boundary #endif /* Check whether we need to save FPRs. Checking __NO_FPRS__ on its own would be enough for GCC 4.1 and above, but older compilers only define _SOFT_FLOAT, so check both. */ #if !defined (__NO_FPRS__) && !defined (_SOFT_FLOAT) #if defined (__rtems__) && !defined (__PPC_CPU_E6500__) /* For some RTEMS multilibs, the FPU and Altivec units are disabled during interrupt handling. Do not save and restore the corresponding registers in this case. */ mfmsr 5 andi. 5,5,0x2000 beq 1f #endif /* If __powerpc64__, then add 96 to the offset shown from this point on until the end of this function. This difference comes from the fact that we save 23 64-bit registers instead of 23 32-bit registers above and we take alignement requirements of floating point and Altivec stores into account. */ stfdu 14,8(3) # offset 96 stfdu 15,8(3) # offset 104 stfdu 16,8(3) # offset 112 stfdu 17,8(3) # offset 120 stfdu 18,8(3) # offset 128 stfdu 19,8(3) # offset 136 stfdu 20,8(3) # offset 144 stfdu 21,8(3) # offset 152 stfdu 22,8(3) # offset 160 stfdu 23,8(3) # offset 168 stfdu 24,8(3) # offset 176 stfdu 25,8(3) # offset 184 stfdu 26,8(3) # offset 192 stfdu 27,8(3) # offset 200 stfdu 28,8(3) # offset 208 stfdu 29,8(3) # offset 216 stfdu 30,8(3) # offset 224 stfdu 31,8(3) # offset 232 1: #endif /* This requires a total of 21 * 4 + 18 * 8 + 4 + 4 + 4 bytes == 60 * 4 bytes == 240 bytes. */ #ifdef __ALTIVEC__ #if defined (__rtems__) && !defined (__PPC_CPU_E6500__) mfmsr 5 andis. 5,5,0x200 beq 1f #endif /* save Altivec vrsave and vr20-vr31 registers */ mfspr 4,256 # vrsave register stwu 4,16(3) # offset 248 addi 3,3,8 stvx 20,0,3 # offset 256 addi 3,3,16 stvx 21,0,3 # offset 272 addi 3,3,16 stvx 22,0,3 # offset 288 addi 3,3,16 stvx 23,0,3 # offset 304 addi 3,3,16 stvx 24,0,3 # offset 320 addi 3,3,16 stvx 25,0,3 # offset 336 addi 3,3,16 stvx 26,0,3 # offset 352 addi 3,3,16 stvx 27,0,3 # offset 368 addi 3,3,16 stvx 28,0,3 # offset 384 addi 3,3,16 stvx 29,0,3 # offset 400 addi 3,3,16 stvx 30,0,3 # offset 416 addi 3,3,16 stvx 31,0,3 # offset 432 1: /* This requires a total of 240 + 8 + 8 + 12 * 16 == 448 bytes. */ #endif li 3,0 blr FUNC_END(setjmp) FUNC_START(longjmp) #ifdef __ALTIVEC__ addi 3,3,15 # align Altivec to 16 byte boundary #if __powerpc64__ clrrdi 3,3,4 #else rlwinm 3,3,0,0,27 #endif #else addi 3,3,7 # align to 8 byte boundary #if __powerpc64__ clrrdi 3,3,3 #else rlwinm 3,3,0,0,28 #endif #endif #if __SPE__ /* If we are E500, then restore 64-bit registers. */ evldd 1,0(3) # offset 0 evldd 2,8(3) # offset 8 evldd 13,16(3) # offset 16 evldd 14,24(3) # offset 24 evldd 15,32(3) # offset 32 evldd 16,40(3) # offset 40 evldd 17,48(3) # offset 48 evldd 18,56(3) # offset 56 evldd 19,64(3) # offset 64 evldd 20,72(3) # offset 72 evldd 21,80(3) # offset 80 evldd 22,88(3) # offset 88 evldd 23,96(3) # offset 96 evldd 24,104(3) # offset 104 evldd 25,112(3) # offset 112 evldd 26,120(3) # offset 120 evldd 27,128(3) # offset 128 evldd 28,136(3) # offset 136 evldd 29,144(3) # offset 144 evldd 30,152(3) # offset 152 evldd 31,160(3) # offset 160 /* Add 164 to r3 to account for the amount of data we just loaded. Note that we are not adding 168 because the next load instruction uses an offset of 4. */ addi 3,3,164 #elif __powerpc64__ /* In the first load, add 8 to r3 so that the subsequent floating point loades are aligned on an 8 byte boundary and the Altivec loads are aligned on a 16 byte boundary. */ ldu 1,8(3) # offset 8 ldu 2,8(3) # offset 16 ldu 13,8(3) # offset 24 ldu 14,8(3) # offset 32 ldu 15,8(3) # offset 40 ldu 16,8(3) # offset 48 ldu 17,8(3) # offset 56 ldu 18,8(3) # offset 64 ldu 19,8(3) # offset 72 ldu 20,8(3) # offset 80 ldu 21,8(3) # offset 88 ldu 22,8(3) # offset 96 ldu 23,8(3) # offset 104 ldu 24,8(3) # offset 112 ldu 25,8(3) # offset 120 ldu 26,8(3) # offset 128 ldu 27,8(3) # offset 136 ldu 28,8(3) # offset 144 ldu 29,8(3) # offset 152 ldu 30,8(3) # offset 160 ldu 31,8(3) # offset 168 ldu 5,8(3) # offset 176 mtlr 5 lwzu 5,8(3) # offset 184 mtcrf 255,5 #else lwz 1,0(3) # offset 0 lwzu 2,4(3) # offset 4 lwzu 13,4(3) # offset 8 lwzu 14,4(3) # offset 12 lwzu 15,4(3) # offset 16 lwzu 16,4(3) # offset 20 lwzu 17,4(3) # offset 24 lwzu 18,4(3) # offset 28 lwzu 19,4(3) # offset 32 lwzu 20,4(3) # offset 36 lwzu 21,4(3) # offset 40 lwzu 22,4(3) # offset 44 lwzu 23,4(3) # offset 48 lwzu 24,4(3) # offset 52 lwzu 25,4(3) # offset 56 lwzu 26,4(3) # offset 60 lwzu 27,4(3) # offset 64 lwzu 28,4(3) # offset 68 lwzu 29,4(3) # offset 72 lwzu 30,4(3) # offset 76 lwzu 31,4(3) # offset 80 #endif /* If __SPE__, then add 84 to the offset shown from this point on until the end of this function. This difference comes from the fact that we restore 22 64-bit registers instead of 22 32-bit registers above. */ #if !__powerpc64__ lwzu 5,4(3) # offset 84 mtlr 5 lwzu 5,4(3) # offset 88 mtcrf 255,5 # one word pad to get floating point aligned on 8 byte boundary #endif /* Check whether we need to restore FPRs. Checking __NO_FPRS__ on its own would be enough for GCC 4.1 and above, but older compilers only define _SOFT_FLOAT, so check both. */ #if !defined (__NO_FPRS__) && !defined (_SOFT_FLOAT) #if defined (__rtems__) && !defined (__PPC_CPU_E6500__) mfmsr 5 andi. 5,5,0x2000 beq 1f #endif /* If __powerpc64__, then add 96 to the offset shown from this point on until the end of this function. This difference comes from the fact that we restore 23 64-bit registers instead of 23 32-bit registers above and we take alignement requirements of floating point and Altivec loads into account. */ lfdu 14,8(3) # offset 96 lfdu 15,8(3) # offset 104 lfdu 16,8(3) # offset 112 lfdu 17,8(3) # offset 120 lfdu 18,8(3) # offset 128 lfdu 19,8(3) # offset 136 lfdu 20,8(3) # offset 144 lfdu 21,8(3) # offset 152 lfdu 22,8(3) # offset 160 lfdu 23,8(3) # offset 168 lfdu 24,8(3) # offset 176 lfdu 25,8(3) # offset 184 lfdu 26,8(3) # offset 192 lfdu 27,8(3) # offset 200 lfdu 28,8(3) # offset 208 lfdu 29,8(3) # offset 216 lfdu 30,8(3) # offset 224 lfdu 31,8(3) # offset 232 1: #endif #ifdef __ALTIVEC__ #if defined (__rtems__) && !defined (__PPC_CPU_E6500__) mfmsr 5 andis. 5,5,0x200 beq 1f #endif /* restore Altivec vrsave and v20-v31 registers */ lwzu 5,16(3) # offset 248 mtspr 256,5 # vrsave addi 3,3,8 lvx 20,0,3 # offset 256 addi 3,3,16 lvx 21,0,3 # offset 272 addi 3,3,16 lvx 22,0,3 # offset 288 addi 3,3,16 lvx 23,0,3 # offset 304 addi 3,3,16 lvx 24,0,3 # offset 320 addi 3,3,16 lvx 25,0,3 # offset 336 addi 3,3,16 lvx 26,0,3 # offset 352 addi 3,3,16 lvx 27,0,3 # offset 368 addi 3,3,16 lvx 28,0,3 # offset 384 addi 3,3,16 lvx 29,0,3 # offset 400 addi 3,3,16 lvx 30,0,3 # offset 416 addi 3,3,16 lvx 31,0,3 # offset 432 1: #endif mr. 3,4 bclr+ 4,2 li 3,1 blr FUNC_END(longjmp)