1/* Copyright (c) 2009, 2010, 2011, 2012 ARM Ltd. 2 3Permission is hereby granted, free of charge, to any person obtaining 4a copy of this software and associated documentation files (the 5``Software''), to deal in the Software without restriction, including 6without limitation the rights to use, copy, modify, merge, publish, 7distribute, sublicense, and/or sell copies of the Software, and to 8permit persons to whom the Software is furnished to do so, subject to 9the following conditions: 10 11The above copyright notice and this permission notice shall be 12included in all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, 15EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 20SOFTWARE 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 104CNAME(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] 1521: 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] 1811: 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 251CNAME(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] 2891: 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] 3081: 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