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