d4dd4c7d916322aa3cc021ab11273e9a655b7678
[vpp.git] / vppinfra / vppinfra / longjmp.S
1 /*
2  * Copyright (c) 2015 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 /*
16   Copyright (c) 2005 Eliot Dresselhaus
17
18   Permission is hereby granted, free of charge, to any person obtaining
19   a copy of this software and associated documentation files (the
20   "Software"), to deal in the Software without restriction, including
21   without limitation the rights to use, copy, modify, merge, publish,
22   distribute, sublicense, and/or sell copies of the Software, and to
23   permit persons to whom the Software is furnished to do so, subject to
24   the following conditions:
25
26   The above copyright notice and this permission notice shall be
27   included in all copies or substantial portions of the Software.
28
29   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
32   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
33   LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
34   OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
35   WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 */
37         
38 #if defined(__x86_64__)
39         .global clib_setjmp
40         .align 4
41         .type clib_setjmp, @function
42 clib_setjmp:
43         movq %rbx, 8*0(%rdi)
44         movq %rbp, 8*1(%rdi)
45         movq %r12, 8*2(%rdi)
46         movq %r13, 8*3(%rdi)
47         movq %r14, 8*4(%rdi)
48         movq %r15, 8*5(%rdi)
49
50         /* Save SP after return. */
51         leaq 8(%rsp), %rdx
52         movq %rdx, 8*6(%rdi)
53         
54         /* Save PC we are returning to from stack frame. */
55         movq 0(%rsp), %rax
56         movq %rax, 8*7(%rdi)
57         
58         /* Give back user's return value. */
59         movq %rsi, %rax
60         ret
61         
62         .global clib_longjmp
63         .align 4
64         .type clib_longjmp, @function
65 clib_longjmp:   
66         /* Restore regs. */
67         movq 8*0(%rdi), %rbx
68         movq 8*1(%rdi), %rbp
69         movq 8*2(%rdi), %r12
70         movq 8*3(%rdi), %r13
71         movq 8*4(%rdi), %r14
72         movq 8*5(%rdi), %r15
73         movq 8*6(%rdi), %rsp
74         movq 8*7(%rdi), %rdx
75         
76         /* Give back user's return value. */
77         movq %rsi, %rax
78         
79         /* Away we go. */
80         jmpq *%rdx      
81         
82         .global clib_calljmp
83         .align 4
84         .type clib_calljmp, @function
85 clib_calljmp:
86         /* Make sure stack is 16-byte aligned. */
87         movq %rdx, %rax
88         andq $0xf, %rax
89         subq %rax, %rdx
90         
91         /* Get return address. */
92         pop %rax
93         
94         /* Switch to new stack. */
95         xchgq %rsp, %rdx
96         
97         /* Save return address on new stack. */
98         push %rax
99         
100         /* Save old stack pointer on new stack. */
101         push %rdx
102         
103         /* Get function. */
104         movq %rdi, %rdx
105         
106         /* Move argument into place. */
107         movq %rsi, %rdi
108         
109         /* Away we go. */
110         callq *%rdx
111         
112         /* Switch back to old stack. */
113         movq 8(%rsp), %rdx
114         movq 0(%rsp), %rcx
115         xchgq %rcx, %rsp
116         
117         /* Return to caller. */
118         jmpq *%rdx
119
120 #elif defined(i386)
121         .global clib_setjmp
122         .align 4
123         .type clib_setjmp, @function
124 clib_setjmp:
125         movl 4(%esp), %ecx
126         
127         movl %ebp, 4*0(%ecx)
128         movl %ebx, 4*1(%ecx)
129         movl %edi, 4*2(%ecx)
130         movl %esi, 4*3(%ecx)
131
132         /* Save SP after return. */
133         leal 4(%esp), %edx
134         movl %edx, 4*4(%ecx)
135         
136         /* Save PC we are returning to from stack frame. */
137         movl 0(%esp), %eax
138         movl %eax, 4*5(%ecx)
139         
140         /* Give back user's return value. */
141         movl 8(%esp), %eax
142         ret
143         
144         .global clib_longjmp
145         .align 4
146         .type clib_longjmp, @function
147 clib_longjmp:   
148         movl 4(%esp), %ecx
149         
150         /* Give back user's return value. */
151         movl 8(%esp), %eax
152         
153         /* Restore regs. */
154         movl 4*0(%ecx), %ebp
155         movl 4*1(%ecx), %ebx
156         movl 4*2(%ecx), %edi
157         movl 4*3(%ecx), %esi
158         movl 4*4(%ecx), %esp
159         movl 4*5(%ecx), %edx
160         
161         /* Away we go. */
162         jmp *%edx       
163         
164         .global clib_calljmp
165         .align 4
166         .type clib_calljmp, @function
167 clib_calljmp:   
168         /* Get new stack pointer. */
169         movl 12(%esp), %edx
170         
171         /* Switch stacks. */
172         xchgl %esp, %edx
173         
174         /* Save old stack pointer on new stack. */
175         sub $8, %esp
176         movl %edx, 4(%esp)
177         
178         /* Put function argument in stack frame. */
179         movl 8(%edx), %eax
180         movl %eax, 0(%esp)
181         
182         /* Get function. */
183         movl 4(%edx), %eax
184         
185         /* Away we go. */
186         call *%eax
187         
188         /* Switch back to old stack. */
189         movl 4(%esp), %edx
190         xchgl %edx, %esp
191         
192         /* Return to caller. */
193         ret
194         
195 #elif defined(__SPU__)
196         
197 #elif defined(__powerpc64__)
198         
199         .text
200
201 #define _prologue(n)                            \
202     .align 2 ;                                  \
203     .globl n, .##n ;                            \
204     .section ".opd", "aw" ;                     \
205     .align 3 ;                                  \
206 n:  .quad .##n, .TOC.@tocbase, 0 ;              \
207     .previous ;                                 \
208     .size n, 24 ;                               \
209     .type .##n, @function ;                     \
210 .##n:
211
212 #define _foreach_14_31                                                  \
213 _ (14, 0)  _ (15, 1)  _ (16, 2)  _ (17, 3)  _ (18, 4)  _ (19, 5)        \
214 _ (20, 6)  _ (21, 7)  _ (22, 8)  _ (23, 9)  _ (24, 10) _ (25, 11)       \
215 _ (26, 12) _ (27, 13) _ (28, 14) _ (29, 15) _ (30, 16) _ (31, 17)
216
217 #define _foreach_20_31                                          \
218 _ (20, 0) _ (21, 1) _ (22, 2) _ (23, 3) _ (24, 4)  _ (25, 5)    \
219 _ (26, 6) _ (27, 7) _ (28, 8) _ (29, 9) _ (30, 10) _ (31, 11)
220         
221 #ifdef __ALTIVEC__
222 #define CLIB_POWERPC_ALTIVEC_N_REGS 12
223 #else
224 #define CLIB_POWERPC_ALTIVEC_N_REGS 0
225 #endif
226
227 _prologue (clib_setjmp)
228         mflr 0
229         std 0, 8*0(3)
230         std 1, 8*1(3)
231         std 2, 8*2(3)
232         mfcr 0
233         std 0, 8*3(3)
234         mfspr 0, 256
235         stw 0, 8*4(3)
236         
237         /* gprs 14 - 31 */
238 #define _(a,b) std a, 8*((b) + 4 + 18*0)(3) ; 
239         _foreach_14_31
240 #undef _
241         
242         /* fprs 14 - 31 */
243 #define _(a,b) stfd a, 8*((b) + 4 + 18*1)(3) ; 
244         _foreach_14_31
245 #undef _
246
247 #if CLIB_POWERPC_ALTIVEC_N_REGS > 0
248         /* vrs 20 - 31 */
249         li 5, 8*(4 + 18*2)
250 #define _(a,b) stvx a, 5, 3 ; addi 5, 5, 16 ;
251         _foreach_20_31
252 #undef _
253 #endif /* CLIB_POWERPC_ALTIVEC_N_REGS > 0 */
254         
255         /* Return value. */
256         mr 3, 4
257         
258         blr
259         
260 _prologue (clib_longjmp)
261         ld 0, 8*0(3)
262         mtlr 0
263         ld 1, 8*1(3)
264         ld 2, 8*2(3)
265         ld 0, 8*3(3)
266         mtcrf 0xff, 0
267         lwz 0, 8*3(3)
268         mtspr 256, 0
269         
270         /* gprs 14 - 31 */
271 #define _(a,b) ld a, 8*((b) + 4 + 18*0)(3) ; 
272         _foreach_14_31
273 #undef _
274         
275         /* fprs 14 - 31 */
276 #define _(a,b) lfd a, 8*((b) + 4 + 18*1)(3) ; 
277         _foreach_14_31
278 #undef _
279         
280 #if CLIB_POWERPC_ALTIVEC_N_REGS > 0
281         /* vrs 20 - 31 */
282         li 5, 8*(4 + 18*2)
283 #define _(a,b) lvx a, 5, 3 ; addi 5, 5, 16 ;
284         _foreach_20_31
285 #undef _
286 #endif /* CLIB_POWERPC_ALTIVEC_N_REGS > 0 */
287         
288         /* Return value. */
289         mr 3, 4
290         
291         blr
292
293         .globl clib_calljmp
294         .section        ".opd","aw"
295         .align 3
296 clib_calljmp:
297         .quad   .L.clib_calljmp,.TOC.@tocbase,0
298         .previous
299         .type   clib_calljmp, @function
300 .L.clib_calljmp:
301         mflr 0
302         mr 9,3
303         std 0,16(1)
304         stdu 1,-112(1)
305 #APP
306         std 1,-8(5)
307         addi 5,5,-256
308         mr 1,5
309 #NO_APP
310         ld 10,0(9)
311         std 2,40(1)
312         mr 3,4
313         mtctr 10
314         ld 11,16(9)
315         ld 2,8(9)
316         bctrl
317         ld 2,40(1)
318 #APP
319         addi 1,1,256
320         ld 1,-8(1)
321 #NO_APP
322         addi 1,1,112
323         ld 0,16(1)
324         mtlr 0
325         blr
326         .long 0
327         .byte 0,0,0,1,128,0,0,0
328         .size   clib_calljmp,.-.L.clib_calljmp
329         
330 #elif defined(__powerpc__)
331         
332 #define _foreach_14_31                                                  \
333 _ (14, 0)  _ (15, 1)  _ (16, 2)  _ (17, 3)  _ (18, 4)  _ (19, 5)        \
334 _ (20, 6)  _ (21, 7)  _ (22, 8)  _ (23, 9)  _ (24, 10) _ (25, 11)       \
335 _ (26, 12) _ (27, 13) _ (28, 14) _ (29, 15) _ (30, 16) _ (31, 17)
336
337 #define _foreach_20_31                                          \
338 _ (20, 0) _ (21, 1) _ (22, 2) _ (23, 3) _ (24, 4)  _ (25, 5)    \
339 _ (26, 6) _ (27, 7) _ (28, 8) _ (29, 9) _ (30, 10) _ (31, 11)
340         
341 #ifdef __ALTIVEC__
342 #define CLIB_POWERPC_ALTIVEC_N_REGS 12
343 #else
344 #define CLIB_POWERPC_ALTIVEC_N_REGS 0
345 #endif
346
347         .global clib_setjmp
348         .align 4
349         .type clib_setjmp, @function
350 clib_setjmp:
351         mflr 0
352         stw 0, 4*0(3)
353         stw 1, 4*1(3)
354         mfcr 0
355         stw 0, 4*2(3)
356 #if CLIB_POWERPC_ALTIVEC_N_REGS > 0
357         mfspr 0, 256
358 #endif
359         stw 0, 4*3(3)
360         
361 #if CLIB_POWERPC_ALTIVEC_N_REGS > 0
362         li 5, 4*4
363 #define _(a,b) stvx a, 3, 5 ; addi 5, 5, 16 ;
364         _foreach_20_31
365 #undef _
366 #endif /* CLIB_POWERPC_ALTIVEC_N_REGS > 0 */
367         
368         /* gp 14 - 31 */
369 #define _(a,b) stw a,  4*(1*(b) + 4 + 4*CLIB_POWERPC_ALTIVEC_N_REGS + 0*18)(3) ; 
370         _foreach_14_31
371 #undef _
372         
373         /* fp 14 - 31 */
374 #define _(a,b) stfd a, 4*(2*(b) + 4 + 4*CLIB_POWERPC_ALTIVEC_N_REGS + 1*18)(3) ;
375         _foreach_14_31
376 #undef _
377
378         /* Return value. */
379         mr 3, 4
380         
381         blr
382         
383         .global clib_longjmp
384         .align 4
385         .type clib_longjmp, @function
386 clib_longjmp:   
387         
388         lwz 0, 4*0(3)
389         mtlr 0
390         lwz 1, 4*1(3)
391         lwz 0, 4*2(3)
392         mtcr 0
393         lwz 0, 4*3(3)
394 #if CLIB_POWERPC_ALTIVEC_N_REGS > 0
395         mtspr 256, 0
396 #endif
397         
398 #if CLIB_POWERPC_ALTIVEC_N_REGS > 0
399         li 5, 4*4
400 #define _(a,b) lvx a, 3, 5 ; addi 5, 5, 16 ;
401         _foreach_20_31
402 #undef _
403 #endif /* CLIB_POWERPC_ALTIVEC_N_REGS > 0 */
404         
405         /* gp 14 - 31 */
406 #define _(a,b) lwz a, 4*(1*(b) + 4 + 4*CLIB_POWERPC_ALTIVEC_N_REGS + 0*18)(3) ;
407         _foreach_14_31
408 #undef _
409         
410         /* fp 14 - 31 */
411 #define _(a,b) lfd a, 4*(2*(b) + 4 + 4*CLIB_POWERPC_ALTIVEC_N_REGS + 1*18)(3) ;
412         _foreach_14_31
413 #undef _
414
415         /* Return value. */
416         mr 3, 4
417         
418         blr
419
420         .global clib_calljmp
421         .align 4
422         .type clib_calljmp, @function
423 clib_calljmp:   
424         /* Make sure stack is 16 byte aligned. */
425         andi. 0, 5, 0xf
426         sub  5, 5, 0
427         addi 5, 5, -16
428         
429         /* Save old stack/link pointer on new stack. */
430         stw 1, 0(5)
431         mflr 0
432         stw 0, 4(5)
433         
434         /* account for (sp, lr) tuple, and keep aligned */
435         addi 5, 5, -16
436         
437         /* Switch stacks. */
438         mr 1, 5
439         
440         /* Move argument into place. */
441         mtctr 3
442         mr 3, 4
443         
444         /* Away we go. */
445         bctrl
446         
447         /* back to our synthetic frame */
448         addi 1,1,16
449         
450         /* Switch back to old stack. */
451         lwz 0, 4(1)
452         mtlr 0
453         lwz 0, 0(1)
454         mr 1, 0
455         
456         /* Return to caller. */
457         blr
458         
459 #elif defined(__arm__)
460         
461         .global clib_setjmp
462         .align 4
463         .type clib_setjmp, %function
464 clib_setjmp:
465         mov ip, r0              /* jmp buffer */
466
467         /* Save integer registers */
468         stmia ip!, {v1-v6, sl, fp, sp, lr}
469         
470 #ifdef __IWMMXT__
471         /* Save the call-preserved iWMMXt registers.  */
472         wstrd wr10, [ip], #8
473         wstrd wr11, [ip], #8
474         wstrd wr12, [ip], #8
475         wstrd wr13, [ip], #8
476         wstrd wr14, [ip], #8
477         wstrd wr15, [ip], #8
478 #endif
479
480         /* Give back user's return value. */
481         mov r0, r1
482         bx lr
483         
484         .global clib_longjmp
485         .align 4
486         .type clib_longjmp, %function
487 clib_longjmp:   
488         mov ip, r0              /* jmp buffer */
489
490         /* Restore integer registers. */
491         ldmia     ip!,  {v1-v6, sl, fp, sp, lr}
492         
493 #ifdef __IWMMXT__
494         /* Save the call-preserved iWMMXt registers.  */
495         wldrd wr10, [ip], #8
496         wldrd wr11, [ip], #8
497         wldrd wr12, [ip], #8
498         wldrd wr13, [ip], #8
499         wldrd wr14, [ip], #8
500         wldrd wr15, [ip], #8
501 #endif
502         
503         /* Give back user's return value. */
504         mov r0, r1
505         bx lr
506
507         .global clib_calljmp
508         .align 4
509         .type clib_calljmp, %function
510 clib_calljmp:   
511         /* Make sure stack is 8 byte aligned. */
512         bic r2, r2, #7
513         
514         /* Allocate space for stack/link pointer on new stack. */
515         sub r2, r2, #8  
516         
517         /* Save old stack/link pointer on new stack. */
518         str sp, [r2, #0]
519         str lr, [r2, #4]
520         
521         /* Switch stacks. */
522         mov sp, r2
523         
524         /* Save function to call. */
525         mov ip, r0
526         
527         /* Move argument into place. */
528         mov r0, r1
529         
530         /* Away we go. */
531         bx ip
532         
533         /* Switch back to old stack. */
534         ldr lr, [sp, #4]
535         ldr ip, [sp, #0]
536         mov sp, ip
537         
538         /* Return to caller. */
539         bx lr
540         
541 #elif defined(__xtensa__)
542         
543         /* FIXME implement if needed. */
544         .global clib_setjmp
545         .align 4
546         .type clib_setjmp, %function
547 clib_setjmp:
548 1:      j 1b
549
550         .global clib_longjmp
551         .align 4
552         .type clib_longjmp, @function
553 clib_longjmp:   
554 1:      j 1b
555         
556         .global clib_calljmp
557         .align 4
558         .type clib_calljmp, %function
559 clib_calljmp:   
560 1:      j 1b
561         
562 #elif defined(__TMS320C6X__)
563         
564         /* FIXME implement if needed. */
565         .global clib_setjmp
566         .align 4
567         .type clib_setjmp, %function
568 clib_setjmp:
569 1:      B       .S1     1b
570
571         .global clib_longjmp
572         .align 4
573         .type clib_longjmp, @function
574 clib_longjmp:   
575 1:      B       .S1     1b
576         
577         .global clib_calljmp
578         .align 4
579         .type clib_calljmp, %function
580 clib_calljmp:   
581 1:      B       .S1     1b
582         
583 #elif defined (__aarch64__)
584 /*
585    Copyright (c) 2011, 2012 ARM Ltd
586    All rights reserved.
587    Redistribution and use in source and binary forms, with or without
588    modification, are permitted provided that the following conditions
589    are met:
590    1. Redistributions of source code must retain the above copyright
591       notice, this list of conditions and the following disclaimer.
592    2. Redistributions in binary form must reproduce the above copyright
593       notice, this list of conditions and the following disclaimer in the
594       documentation and/or other materials provided with the distribution.
595    3. The name of the company may not be used to endorse or promote
596       products derived from this software without specific prior written
597       permission.
598    THIS SOFTWARE IS PROVIDED BY ARM LTD ``AS IS'' AND ANY EXPRESS OR IMPLIED
599    WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
600    MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
601    IN NO EVENT SHALL ARM LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
602    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
603    TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
604    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
605    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
606    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
607    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
608  */
609 #define GPR_LAYOUT                      \
610         REG_PAIR (x19, x20,  0);        \
611         REG_PAIR (x21, x22, 16);        \
612         REG_PAIR (x23, x24, 32);        \
613         REG_PAIR (x25, x26, 48);        \
614         REG_PAIR (x27, x28, 64);        \
615         REG_PAIR (x29, x30, 80);        \
616         REG_ONE (x16,      96)
617 #define FPR_LAYOUT                      \
618         REG_PAIR ( d8,  d9, 112);       \
619         REG_PAIR (d10, d11, 128);       \
620         REG_PAIR (d12, d13, 144);       \
621         REG_PAIR (d14, d15, 160);
622 // int clib_setjmp (jmp_buf)
623         .global clib_setjmp
624         .type   clib_setjmp, %function
625 clib_setjmp:
626         mov     x16, sp
627 #define REG_PAIR(REG1, REG2, OFFS)      stp REG1, REG2, [x0, OFFS]
628 #define REG_ONE(REG1, OFFS)             str REG1, [x0, OFFS]
629         GPR_LAYOUT
630         FPR_LAYOUT
631 #undef REG_PAIR
632 #undef REG_ONE
633         mov     x0, x1
634         ret
635         .size   clib_setjmp, .-clib_setjmp
636 // void clib_longjmp (jmp_buf, int) __attribute__ ((noreturn))
637         .global clib_longjmp
638         .type   clib_longjmp, %function
639 clib_longjmp:
640 #define REG_PAIR(REG1, REG2, OFFS)      ldp REG1, REG2, [x0, OFFS]
641 #define REG_ONE(REG1, OFFS)             ldr REG1, [x0, OFFS]
642         GPR_LAYOUT
643         FPR_LAYOUT
644 #undef REG_PAIR
645 #undef REG_ONE
646         mov     sp, x16
647         mov     x0, x1
648         // cmp  w1, #0
649         // cinc w0, w1, eq
650         // use br not ret, as ret is guaranteed to mispredict
651         br      x30
652         .size   clib_longjmp, .-clib_longjmp
653
654
655 // void clib_calljmp (x0=function, x1=arg, x2=new_stack)
656         .global clib_calljmp
657         .type   clib_calljmp, %function
658 clib_calljmp:
659         // save fn ptr
660         mov     x3, x0
661         // set up fn arg
662         mov     x0, x1
663         // switch stacks
664         mov     x4, sp
665         
666         // space for saved sp, lr on new stack
667         sub     x2, x2, #16
668         mov     sp, x2
669         
670         // save old sp and link register on new stack
671         str     x4, [sp]
672         str     x30,[sp,#8]
673         mov     x4, sp
674
675         // go there
676         blr     x3
677         
678         // restore old sp and link register
679         mov     x4, sp
680         
681         ldr     x3, [x4]
682         ldr     x30,[x4, #8]
683         mov     sp, x3
684         ret
685         .size   clib_calljmp, .-clib_calljmp
686 #else
687 #error "unknown machine"
688 #endif  
689
690 .section .note.GNU-stack,"",%progbits