1 /* -----------------------------------------------------------------------
2 sysv.S - Copyright (c) 2013 Imagination Technologies Ltd.
4 Meta Foreign Function Interface
6 Permission is hereby granted, free of charge, to any person obtaining
7 a copy of this software and associated documentation files (the
8 ``Software''), to deal in the Software without restriction, including
9 without limitation the rights to use, copy, modify, merge, publish,
10 distribute, sublicense, and/or sell copies of the Software, and to
11 permit persons to whom the Software is furnished to do so, subject to
12 the following conditions:
14 The above copyright notice and this permission notice shall be included
15 in all copies or substantial portions of the Software.
18 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
19 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 DEALINGS IN THE SOFTWARE.
26 ----------------------------------------------------------------------- */
29 #include <fficonfig.h>
31 #ifdef HAVE_MACHINE_ASM_H
32 #include <machine/asm.h>
34 #ifdef __USER_LABEL_PREFIX__
35 #define CONCAT1(a, b) CONCAT2(a, b)
36 #define CONCAT2(a, b) a ## b
38 /* Use the right prefix for global labels. */
39 #define CNAME(x) CONCAT1 (__USER_LABEL_PREFIX__, x)
43 #define ENTRY(x) .globl CNAME(x); .type CNAME(x), %function; CNAME(x):
59 ! Save register arguments
63 setl [A0StP++], D0Ar6, D1Ar5
64 setl [A0StP++], D0Ar4, D1Ar3
65 setl [A0StP++], D0Ar2, D1Ar1
68 ! Save retrun, frame pointer and other regs
69 .macro SAVE_REGS regs=
72 setl [A0StP++], D0FrT, D1RtP
73 ! Needs to be a pair of regs
79 ! Declare a global function
80 .macro METAG_FUNC_START name
86 ! Return registers from the stack. Reverse SAVE_REGS operation
87 .macro RET_REGS regs=, cond=
91 getl D0FrT, D1RtP, [--A0StP]
96 getl D0Ar2, D1Ar1, [--A0StP]
97 getl D0Ar4, D1Ar3, [--A0StP]
98 getl D0Ar6, D1Ar5, [--A0StP]
108 ! This assumes we are using GNU as
109 METAG_FUNC_START ffi_call_SYSV
110 ! Save argument registers
118 ! Preserve the old frame pointer
119 SAVE_REGS "D1.5, D0.5"
121 ! Make room for new args. cifs->bytes is the total space for input
122 ! and return arguments
124 add A0StP, A0StP, D1Ar3
126 ! Preserve cifs->bytes & fn
130 ! Place all of the ffi_prep_args in position
133 ! Call ffi_prep_args(stack, &ecif)
135 callr D1RtP, CNAME(ffi_prep_args@PLT)
137 callr D1RtP, CNAME(ffi_prep_args)
142 ! The foreign stack should look like this
143 ! XXXXX XXXXXX <--- stack pointer
150 ! A0StP now points to the first (or return) argument + 4
152 ! Preserve cif->bytes
153 getl D0Ar2, D1Ar1, [--A0StP]
154 getl D0Ar4, D1Ar3, [--A0StP]
155 getl D0Ar6, D1Ar5, [--A0StP]
157 ! Place A0StP to the first argument again
158 add A0StP, A0StP, #24 ! That's because we loaded 6 regs x 4 byte each
160 ! A0FrP points to the initial stack without the reserved space for the
161 ! cifs->bytes, whilst A0StP points to the stack after the space allocation
163 ! fn was the first argument of ffi_call_SYSV.
164 ! The stack at this point looks like this:
166 ! A0StP(on entry to _SYSV) -> Arg6 Arg5 | low
169 ! A0FrP ----> D0FrtP D1RtP |
171 ! A0StP(bf prep_args) -> FnArgn FnArgn-1 |
173 ! ................ | <= cifs->bytes
175 ! A0StP (prv_A0StP+cifs->bytes) FnArg2 FnArg1 | high
177 ! fn was in Arg1 so it's located in in A0FrP+#-0xC
180 ! D0Re0 contains the size of arguments stored in registers
181 sub A0StP, A0StP, D0Re0
183 ! Arg1 is the function pointer for the foreign call. This has been
186 ! Time to call (fn). Arguments should be like this:
187 ! Arg1-Arg6 are loaded to regs
188 ! The rest of the arguments are stored in stack pointed by A0StP
196 ! Load Arg1 with the pointer to storage for the return type
197 ! This was stored in Arg5
199 getd D1Ar1, [A0FrP+#-20]
201 ! Load D0Ar2 with the return type code. This was stored in Arg4 (flags)
203 getd D0Ar2, [A0FrP+#-16]
205 ! We are ready to start processing the return value
206 ! D0Re0 (and D1Re0) hold the return value
208 ! If the return value is NULL, assume no return value
213 cmp D0Ar2, #FFI_TYPE_INT
214 ! Sadly, there is no setd{cc} instruction so we need to workaround that
221 cmp D0Ar2, #FFI_TYPE_SINT64
222 setleq [D1Ar1], D0Re0, D1Re0
225 cmp D0Ar2, #FFI_TYPE_DOUBLE
226 setl [D1AR1++], D0Re0, D1Re0
229 ! At this point, the stack pointer points right after the argument
230 ! saved area. We need to restore 4 regs, therefore we need to move
232 add A0StP, A0StP, #16
233 RET_REGS "D1.5, D0.5"
240 .size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV)
244 (called by ffi_metag_trampoline)
245 void ffi_closure_SYSV (ffi_closure*)
247 (called by ffi_closure_SYSV)
248 unsigned int FFI_HIDDEN
249 ffi_closure_SYSV_inner (closure,respp, args)
250 ffi_closure *closure;
255 METAG_FUNC_START ffi_closure_SYSV
256 ! We assume that D1Ar1 holds the address of the
257 ! ffi_closure struct. We will use that to fetch the
258 ! arguments. The stack pointer points to an empty space
259 ! and it is ready to store more data.
262 ! Allocate stack space for return value
269 ! D1Ar3 contains the address of the original D1Ar1 argument
270 ! We need to subtract #4 later on
276 callr D1RtP, CNAME(ffi_closure_SYSV_inner@PLT)
278 callr D1RtP, CNAME(ffi_closure_SYSV_inner)
281 ! Check the return value and store it to D0.5
282 cmp D0Re0, #FFI_TYPE_INT
284 cmp D0Re0, #FFI_TYPE_DOUBLE
288 RET_REGS "D1.5, D0.5"
296 setl [D0.5++], D0Re0, D1Re0
298 .ffi_closure_SYSV_end:
299 .size CNAME(ffi_closure_SYSV),.ffi_closure_SYSV_end-CNAME(ffi_closure_SYSV)
302 ENTRY(ffi_metag_trampoline)
306 SAVE_REGS "D1.5, D0.5"
308 ! Load D1Ar1 the value of ffi_metag_trampoline
309 getd D1Ar1, [D0.5 + #8]
310 ! Jump to ffi_closure_SYSV
311 getd PC, [D0.5 + #12]