AArch64 port
[platform/upstream/libffi.git] / src / aarch64 / sysv.S
1 /* Copyright (c) 2009, 2010, 2011, 2012 ARM Ltd.
2
3 Permission is hereby granted, free of charge, to any person obtaining
4 a copy of this software and associated documentation files (the
5 ``Software''), to deal in the Software without restriction, including
6 without limitation the rights to use, copy, modify, merge, publish,
7 distribute, sublicense, and/or sell copies of the Software, and to
8 permit persons to whom the Software is furnished to do so, subject to
9 the following conditions:
10
11 The above copyright notice and this permission notice shall be
12 included in all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
15 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
21
22 #define LIBFFI_ASM
23 #include <fficonfig.h>
24 #include <ffi.h>
25
26 #define cfi_adjust_cfa_offset(off)      .cfi_adjust_cfa_offset off
27 #define cfi_rel_offset(reg, off)        .cfi_rel_offset reg, off
28 #define cfi_restore(reg)                .cfi_restore reg
29 #define cfi_def_cfa_register(reg)       .cfi_def_cfa_register reg
30
31         .text
32         .globl ffi_call_SYSV
33         .type ffi_call_SYSV, #function
34
35 /* ffi_call_SYSV()
36
37    Create a stack frame, setup an argument context, call the callee
38    and extract the result.
39
40    The maximum required argument stack size is provided,
41    ffi_call_SYSV() allocates that stack space then calls the
42    prepare_fn to populate register context and stack.  The
43    argument passing registers are loaded from the register
44    context and the callee called, on return the register passing
45    register are saved back to the context.  Our caller will
46    extract the return value from the final state of the saved
47    register context.
48
49    Prototype:
50
51    extern unsigned
52    ffi_call_SYSV (void (*)(struct call_context *context, unsigned char *,
53                            extended_cif *),
54                   struct call_context *context,
55                   extended_cif *,
56                   unsigned required_stack_size,
57                   void (*fn)(void));
58
59    Therefore on entry we have:
60
61    x0 prepare_fn
62    x1 &context
63    x2 &ecif
64    x3 bytes
65    x4 fn
66
67    This function uses the following stack frame layout:
68
69    ==
70                 saved x30(lr)
71    x29(fp)->    saved x29(fp)
72                 saved x24
73                 saved x23
74                 saved x22
75    sp'    ->    saved x21
76                 ...
77    sp     ->    (constructed callee stack arguments)
78    ==
79
80    Voila! */
81
82 #define ffi_call_SYSV_FS (8 * 4)
83
84         .cfi_startproc
85 ffi_call_SYSV:
86         stp     x29, x30, [sp, #-16]!
87         cfi_adjust_cfa_offset (16)
88         cfi_rel_offset (x29, 0)
89         cfi_rel_offset (x30, 8)
90
91         mov     x29, sp
92         cfi_def_cfa_register (x29)
93         sub     sp, sp, #ffi_call_SYSV_FS
94
95         stp     x21, x22, [sp, 0]
96         cfi_rel_offset (x21, 0 - ffi_call_SYSV_FS)
97         cfi_rel_offset (x22, 8 - ffi_call_SYSV_FS)
98
99         stp     x23, x24, [sp, 16]
100         cfi_rel_offset (x23, 16 - ffi_call_SYSV_FS)
101         cfi_rel_offset (x24, 24 - ffi_call_SYSV_FS)
102
103         mov     x21, x1
104         mov     x22, x2
105         mov     x24, x4
106
107         /* Allocate the stack space for the actual arguments, many
108            arguments will be passed in registers, but we assume
109            worst case and allocate sufficient stack for ALL of
110            the arguments.  */
111         sub     sp, sp, x3
112
113         /* unsigned (*prepare_fn) (struct call_context *context,
114                                    unsigned char *stack, extended_cif *ecif);
115          */
116         mov     x23, x0
117         mov     x0, x1
118         mov     x1, sp
119         /* x2 already in place */
120         blr     x23
121
122         /* Preserve the flags returned.  */
123         mov     x23, x0
124
125         /* Figure out if we should touch the vector registers.  */
126         tbz     x23, #AARCH64_FFI_WITH_V_BIT, 1f
127
128         /* Load the vector argument passing registers.  */
129         ldp     q0, q1, [x21, #8*32 +  0]
130         ldp     q2, q3, [x21, #8*32 + 32]
131         ldp     q4, q5, [x21, #8*32 + 64]
132         ldp     q6, q7, [x21, #8*32 + 96]
133 1:
134         /* Load the core argument passing registers.  */
135         ldp     x0, x1, [x21,  #0]
136         ldp     x2, x3, [x21, #16]
137         ldp     x4, x5, [x21, #32]
138         ldp     x6, x7, [x21, #48]
139
140         /* Don't forget x8 which may be holding the address of a return buffer.
141          */
142         ldr     x8,     [x21, #8*8]
143
144         blr     x24
145
146         /* Save the core argument passing registers.  */
147         stp     x0, x1, [x21,  #0]
148         stp     x2, x3, [x21, #16]
149         stp     x4, x5, [x21, #32]
150         stp     x6, x7, [x21, #48]
151
152         /* Note nothing useful ever comes back in x8!  */
153
154         /* Figure out if we should touch the vector registers.  */
155         tbz     x23, #AARCH64_FFI_WITH_V_BIT, 1f
156
157         /* Save the vector argument passing registers.  */
158         stp     q0, q1, [x21, #8*32 + 0]
159         stp     q2, q3, [x21, #8*32 + 32]
160         stp     q4, q5, [x21, #8*32 + 64]
161         stp     q6, q7, [x21, #8*32 + 96]
162 1:
163         /* All done, unwind our stack frame.  */
164         ldp     x21, x22, [x29,  # - ffi_call_SYSV_FS]
165         cfi_restore (x21)
166         cfi_restore (x22)
167
168         ldp     x23, x24, [x29,  # - ffi_call_SYSV_FS + 16]
169         cfi_restore (x23)
170         cfi_restore (x24)
171
172         mov     sp, x29
173         cfi_def_cfa_register (sp)
174
175         ldp     x29, x30, [sp], #16
176         cfi_adjust_cfa_offset (-16)
177         cfi_restore (x29)
178         cfi_restore (x30)
179
180         ret
181
182         .cfi_endproc
183         .size ffi_call_SYSV, .-ffi_call_SYSV
184
185 #define ffi_closure_SYSV_FS (8 * 2 + AARCH64_CALL_CONTEXT_SIZE)
186
187 /* ffi_closure_SYSV
188
189    Closure invocation glue. This is the low level code invoked directly by
190    the closure trampoline to setup and call a closure.
191
192    On entry x17 points to a struct trampoline_data, x16 has been clobbered
193    all other registers are preserved.
194
195    We allocate a call context and save the argument passing registers,
196    then invoked the generic C ffi_closure_SYSV_inner() function to do all
197    the real work, on return we load the result passing registers back from
198    the call context.
199
200    On entry
201
202    extern void
203    ffi_closure_SYSV (struct trampoline_data *);
204
205    struct trampoline_data
206    {
207         UINT64 *ffi_closure;
208         UINT64 flags;
209    };
210
211    This function uses the following stack frame layout:
212
213    ==
214                 saved x30(lr)
215    x29(fp)->    saved x29(fp)
216                 saved x22
217                 saved x21
218                 ...
219    sp     ->    call_context
220    ==
221
222    Voila!  */
223
224         .text
225         .globl ffi_closure_SYSV
226         .cfi_startproc
227 ffi_closure_SYSV:
228         stp     x29, x30, [sp, #-16]!
229         cfi_adjust_cfa_offset (16)
230         cfi_rel_offset (x29, 0)
231         cfi_rel_offset (x30, 8)
232
233         mov     x29, sp
234
235         sub     sp, sp, #ffi_closure_SYSV_FS
236         cfi_adjust_cfa_offset (ffi_closure_SYSV_FS)
237
238         stp     x21, x22, [x29, #-16]
239         cfi_rel_offset (x21, 0)
240         cfi_rel_offset (x22, 8)
241
242         /* Load x21 with &call_context.  */
243         mov     x21, sp
244         /* Preserve our struct trampoline_data *  */
245         mov     x22, x17
246
247         /* Save the rest of the argument passing registers.  */
248         stp     x0, x1, [x21, #0]
249         stp     x2, x3, [x21, #16]
250         stp     x4, x5, [x21, #32]
251         stp     x6, x7, [x21, #48]
252         /* Don't forget we may have been given a result scratch pad address.
253          */
254         str     x8,     [x21, #64]
255
256         /* Figure out if we should touch the vector registers.  */
257         ldr     x0, [x22, #8]
258         tbz     x0, #AARCH64_FFI_WITH_V_BIT, 1f
259
260         /* Save the argument passing vector registers.  */
261         stp     q0, q1, [x21, #8*32 + 0]
262         stp     q2, q3, [x21, #8*32 + 32]
263         stp     q4, q5, [x21, #8*32 + 64]
264         stp     q6, q7, [x21, #8*32 + 96]
265 1:
266         /* Load &ffi_closure..  */
267         ldr     x0, [x22, #0]
268         mov     x1, x21
269         /* Compute the location of the stack at the point that the
270            trampoline was called.  */
271         add     x2, x29, #16
272
273         bl      ffi_closure_SYSV_inner
274
275         /* Figure out if we should touch the vector registers.  */
276         ldr     x0, [x22, #8]
277         tbz     x0, #AARCH64_FFI_WITH_V_BIT, 1f
278
279         /* Load the result passing vector registers.  */
280         ldp     q0, q1, [x21, #8*32 + 0]
281         ldp     q2, q3, [x21, #8*32 + 32]
282         ldp     q4, q5, [x21, #8*32 + 64]
283         ldp     q6, q7, [x21, #8*32 + 96]
284 1:
285         /* Load the result passing core registers.  */
286         ldp     x0, x1, [x21,  #0]
287         ldp     x2, x3, [x21, #16]
288         ldp     x4, x5, [x21, #32]
289         ldp     x6, x7, [x21, #48]
290         /* Note nothing usefull is returned in x8.  */
291
292         /* We are done, unwind our frame.  */
293         ldp     x21, x22, [x29,  #-16]
294         cfi_restore (x21)
295         cfi_restore (x22)
296
297         mov     sp, x29
298         cfi_adjust_cfa_offset (-ffi_closure_SYSV_FS)
299
300         ldp     x29, x30, [sp], #16
301         cfi_adjust_cfa_offset (-16)
302         cfi_restore (x29)
303         cfi_restore (x30)
304
305         ret
306         .cfi_endproc
307         .size ffi_closure_SYSV, .-ffi_closure_SYSV