vppinfra: initial RISC-V support
[vpp.git] / src / 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(__APPLE__)
39 # define cdecl(s) _##s
40 #else
41 # define cdecl(s) s
42 #endif
43
44 #if defined(__x86_64__)
45         .global cdecl(clib_setjmp)
46         .align 4
47 #ifndef __APPLE__
48         .type cdecl(clib_setjmp), @function
49 #endif
50
51 cdecl(clib_setjmp):
52         movq %rbx, 8*0(%rdi)
53         movq %rbp, 8*1(%rdi)
54         movq %r12, 8*2(%rdi)
55         movq %r13, 8*3(%rdi)
56         movq %r14, 8*4(%rdi)
57         movq %r15, 8*5(%rdi)
58
59         /* Save SP after return. */
60         leaq 8(%rsp), %rdx
61         movq %rdx, 8*6(%rdi)
62
63         /* Save PC we are returning to from stack frame. */
64         movq 0(%rsp), %rax
65         movq %rax, 8*7(%rdi)
66
67         /* Give back user's return value. */
68         movq %rsi, %rax
69         ret
70
71         .global cdecl(clib_longjmp)
72         .align 4
73 #ifndef __APPLE__
74         .type cdecl(clib_longjmp), @function
75 #endif
76 cdecl(clib_longjmp):
77         /* Restore regs. */
78         movq 8*0(%rdi), %rbx
79         movq 8*1(%rdi), %rbp
80         movq 8*2(%rdi), %r12
81         movq 8*3(%rdi), %r13
82         movq 8*4(%rdi), %r14
83         movq 8*5(%rdi), %r15
84         movq 8*6(%rdi), %rsp
85         movq 8*7(%rdi), %rdx
86
87         /* Give back user's return value. */
88         movq %rsi, %rax
89
90         /* Away we go. */
91         jmpq *%rdx
92
93         .global cdecl(clib_calljmp)
94         .align 4
95 #ifndef __APPLE__
96         .type cdecl(clib_calljmp), @function
97 #endif
98 cdecl(clib_calljmp):
99         /* Make sure stack is 16-byte aligned. */
100         movq %rdx, %rax
101         andq $0xf, %rax
102         subq %rax, %rdx
103
104         /* Get return address. */
105         pop %rax
106
107         /* Switch to new stack. */
108         xchgq %rsp, %rdx
109
110         /* Save return address on new stack. */
111         push %rax
112
113         /* Save old stack pointer on new stack. */
114         push %rdx
115
116         /* Get function. */
117         movq %rdi, %rdx
118
119         /* Move argument into place. */
120         movq %rsi, %rdi
121
122         /* Away we go. */
123         callq *%rdx
124
125         /* Switch back to old stack. */
126         movq 8(%rsp), %rdx
127         movq 0(%rsp), %rcx
128         xchgq %rcx, %rsp
129
130         /* Return to caller. */
131         jmpq *%rdx
132
133 #elif defined(i386)
134         .global cdecl(clib_setjmp)
135         .align 4
136         .type cdecl(clib_setjmp), @function
137 cdecl(clib_setjmp):
138         movl 4(%esp), %ecx
139
140         movl %ebp, 4*0(%ecx)
141         movl %ebx, 4*1(%ecx)
142         movl %edi, 4*2(%ecx)
143         movl %esi, 4*3(%ecx)
144
145         /* Save SP after return. */
146         leal 4(%esp), %edx
147         movl %edx, 4*4(%ecx)
148
149         /* Save PC we are returning to from stack frame. */
150         movl 0(%esp), %eax
151         movl %eax, 4*5(%ecx)
152
153         /* Give back user's return value. */
154         movl 8(%esp), %eax
155         ret
156
157         .global cdecl(clib_longjmp)
158         .align 4
159         .type cdecl(clib_longjmp), @function
160 cdecl(clib_longjmp):
161         movl 4(%esp), %ecx
162
163         /* Give back user's return value. */
164         movl 8(%esp), %eax
165
166         /* Restore regs. */
167         movl 4*0(%ecx), %ebp
168         movl 4*1(%ecx), %ebx
169         movl 4*2(%ecx), %edi
170         movl 4*3(%ecx), %esi
171         movl 4*4(%ecx), %esp
172         movl 4*5(%ecx), %edx
173
174         /* Away we go. */
175         jmp *%edx
176
177         .global cdecl(clib_calljmp)
178         .align 4
179         .type cdecl(clib_calljmp), @function
180 cdecl(clib_calljmp):
181         /* Get new stack pointer. */
182         movl 12(%esp), %edx
183
184         /* Switch stacks. */
185         xchgl %esp, %edx
186
187         /* Save old stack pointer on new stack. */
188         sub $8, %esp
189         movl %edx, 4(%esp)
190
191         /* Put function argument in stack frame. */
192         movl 8(%edx), %eax
193         movl %eax, 0(%esp)
194
195         /* Get function. */
196         movl 4(%edx), %eax
197
198         /* Away we go. */
199         call *%eax
200
201         /* Switch back to old stack. */
202         movl 4(%esp), %edx
203         xchgl %edx, %esp
204
205         /* Return to caller. */
206         ret
207
208 #elif defined(__SPU__)
209
210 #elif defined(__powerpc64__)
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 #if _CALL_ELF == 2
228
229 #define _prologue(n)                            \
230         .globl n ;                              \
231         .p2align 4 ;                            \
232         .type n, @function ;                    \
233 n: ;                                            \
234 .L##n##_begin: ;
235
236 #define _gep_lep(n)                             \
237 .L##n##_gep: ;                                  \
238         addis 2, 12, .TOC.-.L##n##_gep@ha ;     \
239         addi 2, 2, .TOC.-.L##n##_gep@l ;        \
240 .L##n##_lep: ;                                  \
241         .localentry n, .L##n##_lep-.L##n##_gep
242
243 #else /* _CALL_ELF == 1 */
244
245 #define _prologue(n)                            \
246     .globl n ;                                  \
247     .p2align 4 ;                                \
248     .type .##n, @function ;                     \
249     .section ".opd", "aw" ,@progbits ;          \
250 n: ;                                            \
251     .p2align 3 ;                                \
252     .quad .L##n##_begin ;                       \
253     .quad .TOC.@tocbase ;                       \
254     .quad 0 ;                                   \
255     .text ;                                     \
256 .L##n##_begin: ;
257
258 #endif
259
260 #define _epilogue(n)                            \
261         .long   0 ;                             \
262         .quad   0 ;                             \
263 .L##n##_end: ;                                  \
264         .size   n, .L##n##_end-.L##n##_begin
265
266 #if _CALL_ELF == 2
267         .abiversion 2
268         .section        ".text"
269 #else
270         .text
271 #endif
272
273 _prologue(clib_setjmp)
274         mflr 0
275         std 0, 8*0(3)
276         std 1, 8*1(3)
277         std 2, 8*2(3)
278         mfcr 0
279         std 0, 8*3(3)
280         mfspr 0, 256
281         stw 0, 8*4(3)
282
283         /* gprs 14 - 31 */
284 #define _(a,b) std a, 8*((b) + 4 + 18*0)(3) ;
285         _foreach_14_31
286 #undef _
287
288         /* fprs 14 - 31 */
289 #define _(a,b) stfd a, 8*((b) + 4 + 18*1)(3) ;
290         _foreach_14_31
291 #undef _
292
293 #if CLIB_POWERPC_ALTIVEC_N_REGS > 0
294         /* vrs 20 - 31 */
295         li 5, 8*(4 + 18*2)
296 #define _(a,b) stvx a, 5, 3 ; addi 5, 5, 16 ;
297         _foreach_20_31
298 #undef _
299 #endif /* CLIB_POWERPC_ALTIVEC_N_REGS > 0 */
300
301         /* Return value. */
302         mr 3, 4
303         blr
304 _epilogue(clib_setjmp)
305
306 _prologue(clib_longjmp)
307         ld 0, 8*0(3)
308         mtlr 0
309         ld 1, 8*1(3)
310         ld 2, 8*2(3)
311         ld 0, 8*3(3)
312         mtcrf 0xff, 0
313         lwz 0, 8*3(3)
314         mtspr 256, 0
315
316         /* gprs 14 - 31 */
317 #define _(a,b) ld a, 8*((b) + 4 + 18*0)(3) ;
318         _foreach_14_31
319 #undef _
320
321         /* fprs 14 - 31 */
322 #define _(a,b) lfd a, 8*((b) + 4 + 18*1)(3) ;
323         _foreach_14_31
324 #undef _
325
326 #if CLIB_POWERPC_ALTIVEC_N_REGS > 0
327         /* vrs 20 - 31 */
328         li 5, 8*(4 + 18*2)
329 #define _(a,b) lvx a, 5, 3 ; addi 5, 5, 16 ;
330         _foreach_20_31
331 #undef _
332 #endif /* CLIB_POWERPC_ALTIVEC_N_REGS > 0 */
333
334         /* Return value. */
335         mr 3, 4
336         blr
337 _epilogue(clib_longjmp)
338
339 #if _CALL_ELF == 2
340 _prologue(clib_calljmp)
341 _gep_lep(clib_calljmp)
342         mflr 0                  /* get link register into r0 */
343         std 0,16(1)             /* store r0 into the stack frame */
344         stdu 1,-32(1)           /* move sp down for one frame */
345         mr 12,3                 /* move func pointer to r12 */
346         mr 3,4                  /* pass func_arg as first arg */
347         std 1,-8(5)             /* store old sp into the top of the new stack */
348         addi 5,5,-256           /* stack_addr =- 256 */
349         mr 1,5                  /* set new sp */
350         mtctr 12                /* put function pointer into CTR register */
351         std 2,24(1)             /* store TOC pointer into stack frame */
352         bctrl                   /* unconditional branch to counter register */
353         ld 2,24(1)              /* load TOC pointer from stack frame */
354         addi 1,1,256            /* go back to the start of the new stack */
355         ld 1,-8(1)              /* load old sp */
356         addi 1,1,32             /* move sp back to previous frame */
357         ld 0,16(1)              /* get old link reg value from the stack */
358         mtlr 0                  /* restore link reg value */
359         blr
360 _epilogue(clib_calljmp)
361
362 #else /* v1 ABI */
363
364 _prologue(clib_calljmp)
365         mflr 0                  /* get link register into r0 */
366         mr 9,3                  /* store function pointer into the r9 */
367         std 0,16(1)             /* store r0 into the stack frame */
368         stdu 1,-112(1)          /* move sp down for one frame */
369         std 1,-8(5)             /* store old sp into the top of the new stack */
370         addi 5,5,-256           /* stack_addr =- 256 */
371         mr 1,5                  /* set new sp */
372         ld 10,0(9)
373         std 2,40(1)             /* store TOC pointer into the stack */
374         mr 3,4
375         mtctr 10
376         ld 11,16(9)
377         ld 2,8(9)
378         bctrl                   /* unconditional branch to counter register */
379         ld 2,40(1)              /* load TOC pointer from the stack */
380         addi 1,1,256            /* go back to the start of the new stack */
381         ld 1,-8(1)              /* load the old sp */
382         addi 1,1,112            /* move sp back to previous frame */
383         ld 0,16(1)              /* restore link register from the stack frame */
384         mtlr 0
385         blr
386 _epilogue(clib_calljmp)
387
388 #endif
389 #elif defined(__powerpc__)
390
391 #define _foreach_14_31                                                  \
392 _ (14, 0)  _ (15, 1)  _ (16, 2)  _ (17, 3)  _ (18, 4)  _ (19, 5)        \
393 _ (20, 6)  _ (21, 7)  _ (22, 8)  _ (23, 9)  _ (24, 10) _ (25, 11)       \
394 _ (26, 12) _ (27, 13) _ (28, 14) _ (29, 15) _ (30, 16) _ (31, 17)
395
396 #define _foreach_20_31                                          \
397 _ (20, 0) _ (21, 1) _ (22, 2) _ (23, 3) _ (24, 4)  _ (25, 5)    \
398 _ (26, 6) _ (27, 7) _ (28, 8) _ (29, 9) _ (30, 10) _ (31, 11)
399
400 #ifdef __ALTIVEC__
401 #define CLIB_POWERPC_ALTIVEC_N_REGS 12
402 #else
403 #define CLIB_POWERPC_ALTIVEC_N_REGS 0
404 #endif
405
406         .global cdecl(clib_setjmp)
407         .align 4
408         .type cdecl(clib_setjmp), @function
409 cdecl(clib_setjmp):
410         mflr 0
411         stw 0, 4*0(3)
412         stw 1, 4*1(3)
413         mfcr 0
414         stw 0, 4*2(3)
415 #if CLIB_POWERPC_ALTIVEC_N_REGS > 0
416         mfspr 0, 256
417 #endif
418         stw 0, 4*3(3)
419
420 #if CLIB_POWERPC_ALTIVEC_N_REGS > 0
421         li 5, 4*4
422 #define _(a,b) stvx a, 3, 5 ; addi 5, 5, 16 ;
423         _foreach_20_31
424 #undef _
425 #endif /* CLIB_POWERPC_ALTIVEC_N_REGS > 0 */
426
427         /* gp 14 - 31 */
428 #define _(a,b) stw a,  4*(1*(b) + 4 + 4*CLIB_POWERPC_ALTIVEC_N_REGS + 0*18)(3) ;
429         _foreach_14_31
430 #undef _
431
432         /* fp 14 - 31 */
433 #define _(a,b) stfd a, 4*(2*(b) + 4 + 4*CLIB_POWERPC_ALTIVEC_N_REGS + 1*18)(3) ;
434         _foreach_14_31
435 #undef _
436
437         /* Return value. */
438         mr 3, 4
439
440         blr
441
442         .global cdecl(clib_longjmp)
443         .align 4
444         .type cdecl(clib_longjmp), @function
445 cdecl(clib_longjmp):
446
447         lwz 0, 4*0(3)
448         mtlr 0
449         lwz 1, 4*1(3)
450         lwz 0, 4*2(3)
451         mtcr 0
452         lwz 0, 4*3(3)
453 #if CLIB_POWERPC_ALTIVEC_N_REGS > 0
454         mtspr 256, 0
455 #endif
456
457 #if CLIB_POWERPC_ALTIVEC_N_REGS > 0
458         li 5, 4*4
459 #define _(a,b) lvx a, 3, 5 ; addi 5, 5, 16 ;
460         _foreach_20_31
461 #undef _
462 #endif /* CLIB_POWERPC_ALTIVEC_N_REGS > 0 */
463
464         /* gp 14 - 31 */
465 #define _(a,b) lwz a, 4*(1*(b) + 4 + 4*CLIB_POWERPC_ALTIVEC_N_REGS + 0*18)(3) ;
466         _foreach_14_31
467 #undef _
468
469         /* fp 14 - 31 */
470 #define _(a,b) lfd a, 4*(2*(b) + 4 + 4*CLIB_POWERPC_ALTIVEC_N_REGS + 1*18)(3) ;
471         _foreach_14_31
472 #undef _
473
474         /* Return value. */
475         mr 3, 4
476
477         blr
478
479         .global cdecl(clib_calljmp)
480         .align 4
481         .type cdecl(clib_calljmp), @function
482 cdecl(clib_calljmp):
483         /* Make sure stack is 16 byte aligned. */
484         andi. 0, 5, 0xf
485         sub  5, 5, 0
486         addi 5, 5, -16
487
488         /* Save old stack/link pointer on new stack. */
489         stw 1, 0(5)
490         mflr 0
491         stw 0, 4(5)
492
493         /* account for (sp, lr) tuple, and keep aligned */
494         addi 5, 5, -16
495
496         /* Switch stacks. */
497         mr 1, 5
498
499         /* Move argument into place. */
500         mtctr 3
501         mr 3, 4
502
503         /* Away we go. */
504         bctrl
505
506         /* back to our synthetic frame */
507         addi 1,1,16
508
509         /* Switch back to old stack. */
510         lwz 0, 4(1)
511         mtlr 0
512         lwz 0, 0(1)
513         mr 1, 0
514
515         /* Return to caller. */
516         blr
517
518 #elif defined(__arm__)
519
520         .global cdecl(clib_setjmp)
521         .align 4
522         .type cdecl(clib_setjmp), %function
523 cdecl(clib_setjmp):
524         mov ip, r0              /* jmp buffer */
525
526         /* Save integer registers */
527         stmia ip!, {v1-v6, sl, fp, sp, lr}
528
529 #ifdef __IWMMXT__
530         /* Save the call-preserved iWMMXt registers.  */
531         wstrd wr10, [ip], #8
532         wstrd wr11, [ip], #8
533         wstrd wr12, [ip], #8
534         wstrd wr13, [ip], #8
535         wstrd wr14, [ip], #8
536         wstrd wr15, [ip], #8
537 #endif
538
539         /* Give back user's return value. */
540         mov r0, r1
541         bx lr
542
543         .global cdecl(clib_longjmp)
544         .align 4
545         .type cdecl(clib_longjmp), %function
546 cdecl(clib_longjmp):
547         mov ip, r0              /* jmp buffer */
548
549         /* Restore integer registers. */
550         ldmia     ip!,  {v1-v6, sl, fp, sp, lr}
551
552 #ifdef __IWMMXT__
553         /* Save the call-preserved iWMMXt registers.  */
554         wldrd wr10, [ip], #8
555         wldrd wr11, [ip], #8
556         wldrd wr12, [ip], #8
557         wldrd wr13, [ip], #8
558         wldrd wr14, [ip], #8
559         wldrd wr15, [ip], #8
560 #endif
561
562         /* Give back user's return value. */
563         mov r0, r1
564         bx lr
565
566         .global cdecl(clib_calljmp)
567         .align 4
568         .type cdecl(clib_calljmp), %function
569 cdecl(clib_calljmp):
570         /* Make sure stack is 8 byte aligned. */
571         bic r2, r2, #7
572
573         /* Allocate space for stack/link pointer on new stack. */
574         sub r2, r2, #8
575
576         /* Save old stack/link pointer on new stack. */
577         str sp, [r2, #0]
578         str lr, [r2, #4]
579
580         /* Switch stacks. */
581         mov sp, r2
582
583         /* Save function to call. */
584         mov ip, r0
585
586         /* Move argument into place. */
587         mov r0, r1
588
589         /* Away we go. */
590         bx ip
591
592         /* Switch back to old stack. */
593         ldr lr, [sp, #4]
594         ldr ip, [sp, #0]
595         mov sp, ip
596
597         /* Return to caller. */
598         bx lr
599
600 #elif defined(__xtensa__)
601
602         /* FIXME implement if needed. */
603         .global cdecl(clib_setjmp)
604         .align 4
605         .type cdecl(clib_setjmp), %function
606 cdecl(clib_setjmp):
607 1:      j 1b
608
609         .global cdecl(clib_longjmp)
610         .align 4
611         .type cdecl(clib_longjmp), @function
612 cdecl(clib_longjmp):
613 1:      j 1b
614
615         .global cdecl(clib_calljmp)
616         .align 4
617         .type cdecl(clib_calljmp), %function
618 cdecl(clib_calljmp):
619 1:      j 1b
620
621 #elif defined(__TMS320C6X__)
622
623         /* FIXME implement if needed. */
624         .global cdecl(clib_setjmp)
625         .align 4
626         .type cdecl(clib_setjmp), %function
627 cdecl(clib_setjmp):
628 1:      B       .S1     1b
629
630         .global cdecl(clib_longjmp)
631         .align 4
632         .type cdecl(clib_longjmp), @function
633 cdecl(clib_longjmp):
634 1:      B       .S1     1b
635
636         .global cdecl(clib_calljmp)
637         .align 4
638         .type cdecl(clib_calljmp), %function
639 cdecl(clib_calljmp):
640 1:      B       .S1     1b
641
642 #elif defined(_mips) && __mips == 64
643
644         .global cdecl(clib_setjmp)
645         .align 8
646         .type cdecl(clib_setjmp), %function
647 cdecl(clib_setjmp):
648         sd $ra, 0($a0)
649         sd $sp, 8($a0)
650         sd $gp, 16($a0)
651         sd $16, 24($a0)
652         sd $17, 32($a0)
653         sd $18, 40($a0)
654         sd $19, 48($a0)
655         sd $20, 56($a0)
656         sd $21, 64($a0)
657         sd $22, 72($a0)
658         sd $23, 80($a0)
659         sd $30, 88($a0)
660         move $v0, $a1
661         jr $ra
662         nop
663
664         .global cdecl(clib_longjmp)
665         .align 8
666         .type cdecl(clib_longjmp), @function
667 cdecl(clib_longjmp):
668         move $v0, $a1
669         bne $v0, $0, 1f
670         nop
671         daddu $v0, $v0, 1
672 1:
673         ld $ra, 0($a0)
674         ld $sp, 8($a0)
675         ld $gp, 16($a0)
676         ld $16, 24($a0)
677         ld $17, 32($a0)
678         ld $18, 40($a0)
679         ld $19, 48($a0)
680         ld $20, 56($a0)
681         ld $21, 64($a0)
682         ld $22, 72($a0)
683         ld $23, 80($a0)
684         ld $30, 88($a0)
685         jr $ra
686         nop
687
688         .global cdecl(clib_calljmp)
689         .align 8
690         .type cdecl(clib_calljmp), %function
691 cdecl(clib_calljmp):
692         /* Force 16 byte alignment of the new stack */
693         li $t1, -16
694         and $t0, $a2, $t1
695         /* Save old ra/gp/sp on new stack */
696         daddiu $t0, $t0, (-24)
697         sd $ra, 0($t0)
698         sd $gp, 8($t0)
699         sd $sp, 16($t0)
700         /* Switch stacks */
701         move $sp, $t0
702         /* Away we go */
703         move $t9, $a0
704         move $a0, $a1
705         jalr $t9
706         nop
707         /* Switch back to old ra/gp/sp */
708         move $t0, $sp
709         ld $ra, 0($t0)
710         ld $gp, 8($t0)
711         ld $sp, 16($t0)
712         /* Return to caller */
713         jr $ra
714         nop
715
716 #elif defined (__aarch64__)
717 /*
718    Copyright (c) 2011, 2012 ARM Ltd
719    All rights reserved.
720    Redistribution and use in source and binary forms, with or without
721    modification, are permitted provided that the following conditions
722    are met:
723    1. Redistributions of source code must retain the above copyright
724       notice, this list of conditions and the following disclaimer.
725    2. Redistributions in binary form must reproduce the above copyright
726       notice, this list of conditions and the following disclaimer in the
727       documentation and/or other materials provided with the distribution.
728    3. The name of the company may not be used to endorse or promote
729       products derived from this software without specific prior written
730       permission.
731    THIS SOFTWARE IS PROVIDED BY ARM LTD ``AS IS'' AND ANY EXPRESS OR IMPLIED
732    WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
733    MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
734    IN NO EVENT SHALL ARM LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
735    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
736    TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
737    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
738    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
739    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
740    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
741  */
742 #define GPR_LAYOUT                      \
743         REG_PAIR (x19, x20,  0);        \
744         REG_PAIR (x21, x22, 16);        \
745         REG_PAIR (x23, x24, 32);        \
746         REG_PAIR (x25, x26, 48);        \
747         REG_PAIR (x27, x28, 64);        \
748         REG_PAIR (x29, x30, 80);        \
749         REG_ONE (x16,      96)
750 #define FPR_LAYOUT                      \
751         REG_PAIR ( d8,  d9, 112);       \
752         REG_PAIR (d10, d11, 128);       \
753         REG_PAIR (d12, d13, 144);       \
754         REG_PAIR (d14, d15, 160);
755 // int cdecl(clib_setjmp) (jmp_buf)
756         .global cdecl(clib_setjmp)
757         .type   cdecl(clib_setjmp), %function
758 cdecl(clib_setjmp):
759         mov     x16, sp
760 #define REG_PAIR(REG1, REG2, OFFS)      stp REG1, REG2, [x0, OFFS]
761 #define REG_ONE(REG1, OFFS)             str REG1, [x0, OFFS]
762         GPR_LAYOUT
763         FPR_LAYOUT
764 #undef REG_PAIR
765 #undef REG_ONE
766         mov     x0, x1
767         ret
768         .size   cdecl(clib_setjmp), .-cdecl(clib_setjmp)
769 // void cdecl(clib_longjmp) (jmp_buf, int) __attribute__ ((noreturn))
770         .global cdecl(clib_longjmp)
771         .type   cdecl(clib_longjmp), %function
772 cdecl(clib_longjmp):
773 #define REG_PAIR(REG1, REG2, OFFS)      ldp REG1, REG2, [x0, OFFS]
774 #define REG_ONE(REG1, OFFS)             ldr REG1, [x0, OFFS]
775         GPR_LAYOUT
776         FPR_LAYOUT
777 #undef REG_PAIR
778 #undef REG_ONE
779         mov     sp, x16
780         mov     x0, x1
781         // cmp  w1, #0
782         // cinc w0, w1, eq
783         // use br not ret, as ret is guaranteed to mispredict
784         br      x30
785         .size   cdecl(clib_longjmp), .-cdecl(clib_longjmp)
786
787
788 // void cdecl(clib_calljmp) (x0=function, x1=arg, x2=new_stack)
789         .global cdecl(clib_calljmp)
790         .type   cdecl(clib_calljmp), %function
791 cdecl(clib_calljmp):
792         // save fn ptr
793         mov     x3, x0
794         // set up fn arg
795         mov     x0, x1
796         // switch stacks
797         mov     x4, sp
798
799         // space for saved sp, lr on new stack
800         sub     x2, x2, #16
801         mov     sp, x2
802
803         // save old sp and link register on new stack
804         str     x4, [sp]
805         str     x30,[sp,#8]
806         mov     x4, sp
807
808         // go there
809         blr     x3
810
811         // restore old sp and link register
812         mov     x4, sp
813
814         ldr     x3, [x4]
815         ldr     x30,[x4, #8]
816         mov     sp, x3
817         ret
818         .size   cdecl(clib_calljmp), .-cdecl(clib_calljmp)
819 #elif defined(__riscv)
820 #define foreach_0_to_11 _(0) _(1) _(2) _(3) _(4) _(5) _(6) _(7) _(8) _(9) _(10) _(11)
821         .global cdecl(clib_setjmp)
822         .align 1
823         .type cdecl(clib_setjmp), @function
824 cdecl(clib_setjmp):
825         sd      ra, 0*8(a0)
826         sd      sp, 1*8(a0)
827 #define _(x)  sd        s##x, (x + 2)*8(a0);
828         foreach_0_to_11
829 #undef _
830 #define _(x)  fsd       fs##x, (x + 14)*8(a0);
831         foreach_0_to_11
832 #undef _
833         mv      a0,a1
834         ret
835         .size   cdecl(clib_setjmp), .-cdecl(clib_setjmp)
836
837         .global cdecl(clib_longjmp)
838         .align 1
839         .type cdecl(clib_longjmp), @function
840 cdecl(clib_longjmp):
841         ld      ra, 0*8(a0)
842         ld      sp, 1*8(a0)
843 #define _(x)  ld        s##x, (x + 2)*8(a0);
844         foreach_0_to_11
845 #undef _
846 #define _(x)  fld       fs##x, (x + 14)*8(a0);
847         foreach_0_to_11
848 #undef _
849         mv      a0,a1
850         ret
851         .size   cdecl(clib_longjmp), .-cdecl(clib_longjmp)
852
853         .global cdecl(clib_calljmp)
854         .align 1
855         .type cdecl(clib_calljmp), @function
856 cdecl(clib_calljmp):
857         andi    a2,a2, -16      /* Make sure stack is 16-byte aligned. */
858         addi    a2, a2, -16     /* allocate space on the new stack */
859         sd      ra, 8(a2)       /* store return address */
860         sd      sp, 0(a2)       /* store existing stack pointer */
861         mv      sp, a2          /* change stack */
862         mv      a2, a0          /* functon pointer to a2 */
863         mv      a0, a1          /* 2nd argument becomes 1st one  */
864         jalr    a2              /* function call */
865         ld      ra, 8(sp)       /* restore old return address */
866         ld      sp, 0(sp)       /* restore old stack pointer */
867         ret
868         .size   cdecl(clib_calljmp), .-cdecl(clib_calljmp)
869 #else
870 #error "unknown machine"
871 #endif
872
873 #ifndef __APPLE__
874 .section .note.GNU-stack,"",%progbits
875 #endif