1/* -----------------------------------------------------------------------
2   ffi.c - Copyright (c) 2015 Michael Knyszek <mknyszek@berkeley.edu>
3                         2015 Andrew Waterman <waterman@cs.berkeley.edu>
4                         2018 Stef O'Rear <sorear2@gmail.com>
5
6   RISC-V Foreign Function Interface
7
8   Permission is hereby granted, free of charge, to any person obtaining
9   a copy of this software and associated documentation files (the
10   ``Software''), to deal in the Software without restriction, including
11   without limitation the rights to use, copy, modify, merge, publish,
12   distribute, sublicense, and/or sell copies of the Software, and to
13   permit persons to whom the Software is furnished to do so, subject to
14   the following conditions:
15
16   The above copyright notice and this permission notice shall be included
17   in all copies or substantial portions of the Software.
18
19   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
20   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22   NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
23   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26   DEALINGS IN THE SOFTWARE.
27   ----------------------------------------------------------------------- */
28
29#define LIBFFI_ASM
30#include <fficonfig.h>
31#include <ffi.h>
32
33/* Define aliases so that we can handle all ABIs uniformly */
34
35#if __SIZEOF_POINTER__ == 8
36#define PTRS 8
37#define LARG ld
38#define SARG sd
39#else
40#define PTRS 4
41#define LARG lw
42#define SARG sw
43#endif
44
45#if __riscv_float_abi_double
46#define FLTS 8
47#define FLARG fld
48#define FSARG fsd
49#elif __riscv_float_abi_single
50#define FLTS 4
51#define FLARG flw
52#define FSARG fsw
53#else
54#define FLTS 0
55#endif
56
57#define fp s0
58
59    .text
60    .globl  ffi_call_asm
61    .type   ffi_call_asm, @function
62    .hidden ffi_call_asm
63/*
64  struct call_context {
65      floatreg fa[8];
66      intreg a[8];
67      intreg pad[rv32 ? 2 : 0];
68      intreg save_fp, save_ra;
69  }
70  void ffi_call_asm (size_t *stackargs, struct call_context *regargs,
71                     void (*fn) (void), void *closure);
72*/
73
74#define FRAME_LEN (8 * FLTS + 8 * PTRS + 16)
75
76ffi_call_asm:
77    .cfi_startproc
78
79    /*
80      We are NOT going to set up an ordinary stack frame.  In order to pass
81      the stacked args to the called function, we adjust our stack pointer to
82      a0, which is in the _caller's_ alloca area.  We establish our own stack
83      frame at the end of the call_context.
84
85      Anything below the arguments will be freed at this point, although we
86      preserve the call_context so that it can be read back in the caller.
87    */
88
89    .cfi_def_cfa 11, FRAME_LEN # interim CFA based on a1
90    SARG    fp, FRAME_LEN - 2*PTRS(a1)
91    .cfi_offset 8, -2*PTRS
92    SARG    ra, FRAME_LEN - 1*PTRS(a1)
93    .cfi_offset 1, -1*PTRS
94
95    addi    fp, a1, FRAME_LEN
96    mv      sp, a0
97    .cfi_def_cfa 8, 0 # our frame is fully set up
98
99    # Load arguments
100    mv      t1, a2
101    mv      t2, a3
102
103#if FLTS
104    FLARG   fa0, -FRAME_LEN+0*FLTS(fp)
105    FLARG   fa1, -FRAME_LEN+1*FLTS(fp)
106    FLARG   fa2, -FRAME_LEN+2*FLTS(fp)
107    FLARG   fa3, -FRAME_LEN+3*FLTS(fp)
108    FLARG   fa4, -FRAME_LEN+4*FLTS(fp)
109    FLARG   fa5, -FRAME_LEN+5*FLTS(fp)
110    FLARG   fa6, -FRAME_LEN+6*FLTS(fp)
111    FLARG   fa7, -FRAME_LEN+7*FLTS(fp)
112#endif
113
114    LARG    a0, -FRAME_LEN+8*FLTS+0*PTRS(fp)
115    LARG    a1, -FRAME_LEN+8*FLTS+1*PTRS(fp)
116    LARG    a2, -FRAME_LEN+8*FLTS+2*PTRS(fp)
117    LARG    a3, -FRAME_LEN+8*FLTS+3*PTRS(fp)
118    LARG    a4, -FRAME_LEN+8*FLTS+4*PTRS(fp)
119    LARG    a5, -FRAME_LEN+8*FLTS+5*PTRS(fp)
120    LARG    a6, -FRAME_LEN+8*FLTS+6*PTRS(fp)
121    LARG    a7, -FRAME_LEN+8*FLTS+7*PTRS(fp)
122
123    /* Call */
124    jalr    t1
125
126    /* Save return values - only a0/a1 (fa0/fa1) are used */
127#if FLTS
128    FSARG   fa0, -FRAME_LEN+0*FLTS(fp)
129    FSARG   fa1, -FRAME_LEN+1*FLTS(fp)
130#endif
131
132    SARG    a0, -FRAME_LEN+8*FLTS+0*PTRS(fp)
133    SARG    a1, -FRAME_LEN+8*FLTS+1*PTRS(fp)
134
135    /* Restore and return */
136    addi    sp, fp, -FRAME_LEN
137    .cfi_def_cfa 2, FRAME_LEN
138    LARG    ra, -1*PTRS(fp)
139    .cfi_restore 1
140    LARG    fp, -2*PTRS(fp)
141    .cfi_restore 8
142    ret
143    .cfi_endproc
144    .size   ffi_call_asm, .-ffi_call_asm
145
146
147/*
148  ffi_closure_asm. Expects address of the passed-in ffi_closure in t1.
149  void ffi_closure_inner (ffi_cif *cif,
150		          void (*fun) (ffi_cif *, void *, void **, void *),
151		          void *user_data,
152		          size_t *stackargs, struct call_context *regargs)
153*/
154
155    .globl ffi_closure_asm
156    .hidden ffi_closure_asm
157    .type ffi_closure_asm, @function
158ffi_closure_asm:
159    .cfi_startproc
160
161    addi    sp,  sp, -FRAME_LEN
162    .cfi_def_cfa_offset FRAME_LEN
163
164    /* make a frame */
165    SARG    fp, FRAME_LEN - 2*PTRS(sp)
166    .cfi_offset 8, -2*PTRS
167    SARG    ra, FRAME_LEN - 1*PTRS(sp)
168    .cfi_offset 1, -1*PTRS
169    addi    fp, sp, FRAME_LEN
170
171    /* save arguments */
172#if FLTS
173    FSARG   fa0, 0*FLTS(sp)
174    FSARG   fa1, 1*FLTS(sp)
175    FSARG   fa2, 2*FLTS(sp)
176    FSARG   fa3, 3*FLTS(sp)
177    FSARG   fa4, 4*FLTS(sp)
178    FSARG   fa5, 5*FLTS(sp)
179    FSARG   fa6, 6*FLTS(sp)
180    FSARG   fa7, 7*FLTS(sp)
181#endif
182
183    SARG    a0, 8*FLTS+0*PTRS(sp)
184    SARG    a1, 8*FLTS+1*PTRS(sp)
185    SARG    a2, 8*FLTS+2*PTRS(sp)
186    SARG    a3, 8*FLTS+3*PTRS(sp)
187    SARG    a4, 8*FLTS+4*PTRS(sp)
188    SARG    a5, 8*FLTS+5*PTRS(sp)
189    SARG    a6, 8*FLTS+6*PTRS(sp)
190    SARG    a7, 8*FLTS+7*PTRS(sp)
191
192    /* enter C */
193    LARG    a0, FFI_TRAMPOLINE_SIZE+0*PTRS(t1)
194    LARG    a1, FFI_TRAMPOLINE_SIZE+1*PTRS(t1)
195    LARG    a2, FFI_TRAMPOLINE_SIZE+2*PTRS(t1)
196    addi    a3, sp, FRAME_LEN
197    mv      a4, sp
198
199    call    ffi_closure_inner
200
201    /* return values */
202#if FLTS
203    FLARG   fa0, 0*FLTS(sp)
204    FLARG   fa1, 1*FLTS(sp)
205#endif
206
207    LARG    a0, 8*FLTS+0*PTRS(sp)
208    LARG    a1, 8*FLTS+1*PTRS(sp)
209
210    /* restore and return */
211    LARG    ra, FRAME_LEN-1*PTRS(sp)
212    .cfi_restore 1
213    LARG    fp, FRAME_LEN-2*PTRS(sp)
214    .cfi_restore 8
215    addi    sp, sp, FRAME_LEN
216    .cfi_def_cfa_offset 0
217    ret
218    .cfi_endproc
219    .size ffi_closure_asm, .-ffi_closure_asm
220
221/*
222  ffi_go_closure_asm.  Expects address of the passed-in ffi_go_closure in t2.
223  void ffi_closure_inner (ffi_cif *cif,
224		          void (*fun) (ffi_cif *, void *, void **, void *),
225		          void *user_data,
226		          size_t *stackargs, struct call_context *regargs)
227*/
228
229    .globl ffi_go_closure_asm
230    .hidden ffi_go_closure_asm
231    .type ffi_go_closure_asm, @function
232ffi_go_closure_asm:
233    .cfi_startproc
234
235    addi    sp,  sp, -FRAME_LEN
236    .cfi_def_cfa_offset FRAME_LEN
237
238    /* make a frame */
239    SARG    fp, FRAME_LEN - 2*PTRS(sp)
240    .cfi_offset 8, -2*PTRS
241    SARG    ra, FRAME_LEN - 1*PTRS(sp)
242    .cfi_offset 1, -1*PTRS
243    addi    fp, sp, FRAME_LEN
244
245    /* save arguments */
246#if FLTS
247    FSARG   fa0, 0*FLTS(sp)
248    FSARG   fa1, 1*FLTS(sp)
249    FSARG   fa2, 2*FLTS(sp)
250    FSARG   fa3, 3*FLTS(sp)
251    FSARG   fa4, 4*FLTS(sp)
252    FSARG   fa5, 5*FLTS(sp)
253    FSARG   fa6, 6*FLTS(sp)
254    FSARG   fa7, 7*FLTS(sp)
255#endif
256
257    SARG    a0, 8*FLTS+0*PTRS(sp)
258    SARG    a1, 8*FLTS+1*PTRS(sp)
259    SARG    a2, 8*FLTS+2*PTRS(sp)
260    SARG    a3, 8*FLTS+3*PTRS(sp)
261    SARG    a4, 8*FLTS+4*PTRS(sp)
262    SARG    a5, 8*FLTS+5*PTRS(sp)
263    SARG    a6, 8*FLTS+6*PTRS(sp)
264    SARG    a7, 8*FLTS+7*PTRS(sp)
265
266    /* enter C */
267    LARG    a0, 1*PTRS(t2)
268    LARG    a1, 2*PTRS(t2)
269    mv      a2, t2
270    addi    a3, sp, FRAME_LEN
271    mv      a4, sp
272
273    call    ffi_closure_inner
274
275    /* return values */
276#if FLTS
277    FLARG   fa0, 0*FLTS(sp)
278    FLARG   fa1, 1*FLTS(sp)
279#endif
280
281    LARG    a0, 8*FLTS+0*PTRS(sp)
282    LARG    a1, 8*FLTS+1*PTRS(sp)
283
284    /* restore and return */
285    LARG    ra, FRAME_LEN-1*PTRS(sp)
286    .cfi_restore 1
287    LARG    fp, FRAME_LEN-2*PTRS(sp)
288    .cfi_restore 8
289    addi    sp, sp, FRAME_LEN
290    .cfi_def_cfa_offset 0
291    ret
292    .cfi_endproc
293    .size ffi_go_closure_asm, .-ffi_go_closure_asm
294