Home | History | Annotate | Download | only in aarch64
      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 #ifdef HAVE_MACHINE_ASM_H
     27 #include <machine/asm.h>
     28 #else
     29 #ifdef __USER_LABEL_PREFIX__
     30 #define CONCAT1(a, b) CONCAT2(a, b)
     31 #define CONCAT2(a, b) a ## b
     32 
     33 /* Use the right prefix for global labels.  */
     34 #define CNAME(x) CONCAT1 (__USER_LABEL_PREFIX__, x)
     35 #else
     36 #define CNAME(x) x
     37 #endif
     38 #endif
     39 
     40 #define cfi_adjust_cfa_offset(off)	.cfi_adjust_cfa_offset off
     41 #define cfi_rel_offset(reg, off)	.cfi_rel_offset reg, off
     42 #define cfi_restore(reg)		.cfi_restore reg
     43 #define cfi_def_cfa_register(reg)	.cfi_def_cfa_register reg
     44 
     45         .text
     46         .globl CNAME(ffi_call_SYSV)
     47 #ifdef __ELF__
     48         .type CNAME(ffi_call_SYSV), #function
     49 #endif
     50 #ifdef __APPLE__
     51         .align 2
     52 #endif
     53 
     54 /* ffi_call_SYSV()
     55 
     56    Create a stack frame, setup an argument context, call the callee
     57    and extract the result.
     58 
     59    The maximum required argument stack size is provided,
     60    ffi_call_SYSV() allocates that stack space then calls the
     61    prepare_fn to populate register context and stack.  The
     62    argument passing registers are loaded from the register
     63    context and the callee called, on return the register passing
     64    register are saved back to the context.  Our caller will
     65    extract the return value from the final state of the saved
     66    register context.
     67 
     68    Prototype:
     69 
     70    extern unsigned
     71    ffi_call_SYSV (void (*)(struct call_context *context, unsigned char *,
     72 			   extended_cif *),
     73                   struct call_context *context,
     74                   extended_cif *,
     75                   size_t required_stack_size,
     76                   void (*fn)(void));
     77 
     78    Therefore on entry we have:
     79 
     80    x0 prepare_fn
     81    x1 &context
     82    x2 &ecif
     83    x3 bytes
     84    x4 fn
     85 
     86    This function uses the following stack frame layout:
     87 
     88    ==
     89                 saved x30(lr)
     90    x29(fp)->    saved x29(fp)
     91                 saved x24
     92                 saved x23
     93                 saved x22
     94    sp'    ->    saved x21
     95                 ...
     96    sp     ->    (constructed callee stack arguments)
     97    ==
     98 
     99    Voila! */
    100 
    101 #define ffi_call_SYSV_FS (8 * 4)
    102 
    103         .cfi_startproc
    104 CNAME(ffi_call_SYSV):
    105         stp     x29, x30, [sp, #-16]!
    106 	cfi_adjust_cfa_offset (16)
    107         cfi_rel_offset (x29, 0)
    108         cfi_rel_offset (x30, 8)
    109 
    110         mov     x29, sp
    111 	cfi_def_cfa_register (x29)
    112         sub     sp, sp, #ffi_call_SYSV_FS
    113 
    114         stp     x21, x22, [sp, #0]
    115         cfi_rel_offset (x21, 0 - ffi_call_SYSV_FS)
    116         cfi_rel_offset (x22, 8 - ffi_call_SYSV_FS)
    117 
    118         stp     x23, x24, [sp, #16]
    119         cfi_rel_offset (x23, 16 - ffi_call_SYSV_FS)
    120         cfi_rel_offset (x24, 24 - ffi_call_SYSV_FS)
    121 
    122         mov     x21, x1
    123         mov     x22, x2
    124         mov     x24, x4
    125 
    126         /* Allocate the stack space for the actual arguments, many
    127            arguments will be passed in registers, but we assume
    128            worst case and allocate sufficient stack for ALL of
    129            the arguments.  */
    130         sub     sp, sp, x3
    131 
    132         /* unsigned (*prepare_fn) (struct call_context *context,
    133 				   unsigned char *stack, extended_cif *ecif);
    134 	 */
    135         mov     x23, x0
    136         mov     x0, x1
    137         mov     x1, sp
    138         /* x2 already in place */
    139         blr     x23
    140 
    141         /* Preserve the flags returned.  */
    142         mov     x23, x0
    143 
    144         /* Figure out if we should touch the vector registers.  */
    145         tbz     x23, #AARCH64_FFI_WITH_V_BIT, 1f
    146 
    147         /* Load the vector argument passing registers.  */
    148         ldp     q0, q1, [x21, #8*32 +  0]
    149         ldp     q2, q3, [x21, #8*32 + 32]
    150         ldp     q4, q5, [x21, #8*32 + 64]
    151         ldp     q6, q7, [x21, #8*32 + 96]
    152 1:
    153         /* Load the core argument passing registers.  */
    154         ldp     x0, x1, [x21,  #0]
    155         ldp     x2, x3, [x21, #16]
    156         ldp     x4, x5, [x21, #32]
    157         ldp     x6, x7, [x21, #48]
    158 
    159         /* Don't forget x8 which may be holding the address of a return buffer.
    160 	 */
    161         ldr     x8,     [x21, #8*8]
    162 
    163         blr     x24
    164 
    165         /* Save the core argument passing registers.  */
    166         stp     x0, x1, [x21,  #0]
    167         stp     x2, x3, [x21, #16]
    168         stp     x4, x5, [x21, #32]
    169         stp     x6, x7, [x21, #48]
    170 
    171         /* Note nothing useful ever comes back in x8!  */
    172 
    173         /* Figure out if we should touch the vector registers.  */
    174         tbz     x23, #AARCH64_FFI_WITH_V_BIT, 1f
    175 
    176         /* Save the vector argument passing registers.  */
    177         stp     q0, q1, [x21, #8*32 + 0]
    178         stp     q2, q3, [x21, #8*32 + 32]
    179         stp     q4, q5, [x21, #8*32 + 64]
    180         stp     q6, q7, [x21, #8*32 + 96]
    181 1:
    182         /* All done, unwind our stack frame.  */
    183         ldp     x21, x22, [x29,  # - ffi_call_SYSV_FS]
    184         cfi_restore (x21)
    185         cfi_restore (x22)
    186 
    187         ldp     x23, x24, [x29,  # - ffi_call_SYSV_FS + 16]
    188         cfi_restore (x23)
    189         cfi_restore (x24)
    190 
    191         mov     sp, x29
    192 	cfi_def_cfa_register (sp)
    193 
    194         ldp     x29, x30, [sp], #16
    195 	cfi_adjust_cfa_offset (-16)
    196         cfi_restore (x29)
    197         cfi_restore (x30)
    198 
    199         ret
    200 
    201         .cfi_endproc
    202 #ifdef __ELF__
    203         .size CNAME(ffi_call_SYSV), .-CNAME(ffi_call_SYSV)
    204 #endif
    205 
    206 #define ffi_closure_SYSV_FS (8 * 2 + AARCH64_CALL_CONTEXT_SIZE)
    207 
    208 /* ffi_closure_SYSV
    209 
    210    Closure invocation glue. This is the low level code invoked directly by
    211    the closure trampoline to setup and call a closure.
    212 
    213    On entry x17 points to a struct trampoline_data, x16 has been clobbered
    214    all other registers are preserved.
    215 
    216    We allocate a call context and save the argument passing registers,
    217    then invoked the generic C ffi_closure_SYSV_inner() function to do all
    218    the real work, on return we load the result passing registers back from
    219    the call context.
    220 
    221    On entry
    222 
    223    extern void
    224    ffi_closure_SYSV (struct trampoline_data *);
    225 
    226    struct trampoline_data
    227    {
    228         UINT64 *ffi_closure;
    229         UINT64 flags;
    230    };
    231 
    232    This function uses the following stack frame layout:
    233 
    234    ==
    235                 saved x30(lr)
    236    x29(fp)->    saved x29(fp)
    237                 saved x22
    238                 saved x21
    239                 ...
    240    sp     ->    call_context
    241    ==
    242 
    243    Voila!  */
    244 
    245         .text
    246         .globl CNAME(ffi_closure_SYSV)
    247 #ifdef __APPLE__
    248         .align 2
    249 #endif
    250         .cfi_startproc
    251 CNAME(ffi_closure_SYSV):
    252         stp     x29, x30, [sp, #-16]!
    253 	cfi_adjust_cfa_offset (16)
    254         cfi_rel_offset (x29, 0)
    255         cfi_rel_offset (x30, 8)
    256 
    257         mov     x29, sp
    258         cfi_def_cfa_register (x29)
    259 
    260         sub     sp, sp, #ffi_closure_SYSV_FS
    261 
    262         stp     x21, x22, [x29, #-16]
    263         cfi_rel_offset (x21, -16)
    264         cfi_rel_offset (x22, -8)
    265 
    266         /* Load x21 with &call_context.  */
    267         mov     x21, sp
    268         /* Preserve our struct trampoline_data *  */
    269         mov     x22, x17
    270 
    271         /* Save the rest of the argument passing registers.  */
    272         stp     x0, x1, [x21, #0]
    273         stp     x2, x3, [x21, #16]
    274         stp     x4, x5, [x21, #32]
    275         stp     x6, x7, [x21, #48]
    276         /* Don't forget we may have been given a result scratch pad address.
    277 	 */
    278         str     x8,     [x21, #64]
    279 
    280         /* Figure out if we should touch the vector registers.  */
    281         ldr     x0, [x22, #8]
    282         tbz     x0, #AARCH64_FFI_WITH_V_BIT, 1f
    283 
    284         /* Save the argument passing vector registers.  */
    285         stp     q0, q1, [x21, #8*32 + 0]
    286         stp     q2, q3, [x21, #8*32 + 32]
    287         stp     q4, q5, [x21, #8*32 + 64]
    288         stp     q6, q7, [x21, #8*32 + 96]
    289 1:
    290         /* Load &ffi_closure..  */
    291         ldr     x0, [x22, #0]
    292         mov     x1, x21
    293         /* Compute the location of the stack at the point that the
    294            trampoline was called.  */
    295         add     x2, x29, #16
    296 
    297         bl      CNAME(ffi_closure_SYSV_inner)
    298 
    299         /* Figure out if we should touch the vector registers.  */
    300         ldr     x0, [x22, #8]
    301         tbz     x0, #AARCH64_FFI_WITH_V_BIT, 1f
    302 
    303         /* Load the result passing vector registers.  */
    304         ldp     q0, q1, [x21, #8*32 + 0]
    305         ldp     q2, q3, [x21, #8*32 + 32]
    306         ldp     q4, q5, [x21, #8*32 + 64]
    307         ldp     q6, q7, [x21, #8*32 + 96]
    308 1:
    309         /* Load the result passing core registers.  */
    310         ldp     x0, x1, [x21,  #0]
    311         ldp     x2, x3, [x21, #16]
    312         ldp     x4, x5, [x21, #32]
    313         ldp     x6, x7, [x21, #48]
    314         /* Note nothing useful is returned in x8.  */
    315 
    316         /* We are done, unwind our frame.  */
    317         ldp     x21, x22, [x29,  #-16]
    318         cfi_restore (x21)
    319         cfi_restore (x22)
    320 
    321         mov     sp, x29
    322         cfi_def_cfa_register (sp)
    323 
    324         ldp     x29, x30, [sp], #16
    325 	cfi_adjust_cfa_offset (-16)
    326         cfi_restore (x29)
    327         cfi_restore (x30)
    328 
    329         ret
    330         .cfi_endproc
    331 #ifdef __ELF__
    332         .size CNAME(ffi_closure_SYSV), .-CNAME(ffi_closure_SYSV)
    333 #endif
    334