Brad Bishop | f3fd288 | 2019-06-21 08:06:37 -0400 | [diff] [blame^] | 1 | From 8ac73103bf12ce4f776940cb17f3ced15a362f23 Mon Sep 17 00:00:00 2001 |
| 2 | From: Stef O'Rear <sorear2@gmail.com> |
| 3 | Date: Sun, 11 Mar 2018 05:55:15 -0700 |
| 4 | Subject: [PATCH] New RISC-V port (#281) |
| 5 | |
| 6 | * Add RISC-V support |
| 7 | |
| 8 | This patch adds support for the RISC-V architecture (https://riscv.org). |
| 9 | |
| 10 | This patch has been tested using QEMU user-mode emulation and GCC 7.2.0 |
| 11 | in the following configurations: |
| 12 | |
| 13 | * -march=rv32imac -mabi=ilp32 |
| 14 | * -march=rv32g -mabi=ilp32d |
| 15 | * -march=rv64imac -mabi=lp64 |
| 16 | * -march=rv64g -mabi=lp64d |
| 17 | |
| 18 | The ABI currently can be found at |
| 19 | https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md . |
| 20 | |
| 21 | * Add RISC-V to README |
| 22 | |
| 23 | * RISC-V: fix configure.host |
| 24 | |
| 25 | Upstream-Status: Backport [https://github.com/libffi/libffi/commit/3840d49aaa831d649b1597518a2903dfed0d57f3] |
| 26 | Signed-off-by: Alistair Francis <alistair.francis@wdc.com> |
| 27 | --- |
| 28 | Makefile.am | 4 + |
| 29 | configure.ac | 5 + |
| 30 | src/riscv/ffi.c | 445 ++++++++++++++++++++++++++++++++++++++++++ |
| 31 | src/riscv/ffitarget.h | 68 +++++++ |
| 32 | src/riscv/sysv.S | 214 ++++++++++++++++++++ |
| 33 | 5 files changed, 736 insertions(+) |
| 34 | create mode 100644 src/riscv/ffi.c |
| 35 | create mode 100644 src/riscv/ffitarget.h |
| 36 | create mode 100644 src/riscv/sysv.S |
| 37 | |
| 38 | diff --git a/Makefile.am b/Makefile.am |
| 39 | index 0e40451..3837650 100644 |
| 40 | --- a/Makefile.am |
| 41 | +++ b/Makefile.am |
| 42 | @@ -32,6 +32,7 @@ EXTRA_DIST = LICENSE ChangeLog.v1 ChangeLog.libgcj \ |
| 43 | src/powerpc/asm.h src/powerpc/aix.S src/powerpc/darwin.S \ |
| 44 | src/powerpc/aix_closure.S src/powerpc/darwin_closure.S \ |
| 45 | src/powerpc/ffi_darwin.c src/powerpc/ffitarget.h \ |
| 46 | + src/riscv/ffi.c src/riscv/ffitarget.h src/riscv/sysv.S \ |
| 47 | src/s390/ffi.c src/s390/sysv.S src/s390/ffitarget.h \ |
| 48 | src/sh/ffi.c src/sh/sysv.S src/sh/ffitarget.h src/sh64/ffi.c \ |
| 49 | src/sh64/sysv.S src/sh64/ffitarget.h src/sparc/v8.S \ |
| 50 | @@ -122,6 +123,9 @@ endif |
| 51 | if MIPS |
| 52 | nodist_libffi_la_SOURCES += src/mips/ffi.c src/mips/o32.S src/mips/n32.S |
| 53 | endif |
| 54 | +if RISCV |
| 55 | +nodist_libffi_la_SOURCES += src/riscv/ffi.c src/riscv/sysv.S |
| 56 | +endif |
| 57 | if BFIN |
| 58 | nodist_libffi_la_SOURCES += src/bfin/ffi.c src/bfin/sysv.S |
| 59 | endif |
| 60 | diff --git a/configure.ac b/configure.ac |
| 61 | index ce30853..33375aa 100644 |
| 62 | --- a/configure.ac |
| 63 | +++ b/configure.ac |
| 64 | @@ -226,6 +226,10 @@ case "$host" in |
| 65 | TARGET=MIPS; TARGETDIR=mips |
| 66 | ;; |
| 67 | |
| 68 | + riscv*-*-*) |
| 69 | + TARGET=RISCV; TARGETDIR=riscv |
| 70 | + ;; |
| 71 | + |
| 72 | nios2*-linux*) |
| 73 | TARGET=NIOS2; TARGETDIR=nios2 |
| 74 | ;; |
| 75 | @@ -298,6 +302,7 @@ if test $TARGETDIR = unknown; then |
| 76 | fi |
| 77 | |
| 78 | AM_CONDITIONAL(MIPS, test x$TARGET = xMIPS) |
| 79 | +AM_CONDITIONAL(RISCV, test x$TARGET = xRISCV) |
| 80 | AM_CONDITIONAL(BFIN, test x$TARGET = xBFIN) |
| 81 | AM_CONDITIONAL(SPARC, test x$TARGET = xSPARC) |
| 82 | AM_CONDITIONAL(X86, test x$TARGET = xX86) |
| 83 | diff --git a/src/riscv/ffi.c b/src/riscv/ffi.c |
| 84 | new file mode 100644 |
| 85 | index 0000000..b744fdd |
| 86 | --- /dev/null |
| 87 | +++ b/src/riscv/ffi.c |
| 88 | @@ -0,0 +1,445 @@ |
| 89 | +/* ----------------------------------------------------------------------- |
| 90 | + ffi.c - Copyright (c) 2015 Michael Knyszek <mknyszek@berkeley.edu> |
| 91 | + 2015 Andrew Waterman <waterman@cs.berkeley.edu> |
| 92 | + 2018 Stef O'Rear <sorear2@gmail.com> |
| 93 | + Based on MIPS N32/64 port |
| 94 | + |
| 95 | + RISC-V Foreign Function Interface |
| 96 | + |
| 97 | + Permission is hereby granted, free of charge, to any person obtaining |
| 98 | + a copy of this software and associated documentation files (the |
| 99 | + ``Software''), to deal in the Software without restriction, including |
| 100 | + without limitation the rights to use, copy, modify, merge, publish, |
| 101 | + distribute, sublicense, and/or sell copies of the Software, and to |
| 102 | + permit persons to whom the Software is furnished to do so, subject to |
| 103 | + the following conditions: |
| 104 | + |
| 105 | + The above copyright notice and this permission notice shall be included |
| 106 | + in all copies or substantial portions of the Software. |
| 107 | + |
| 108 | + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, |
| 109 | + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| 110 | + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| 111 | + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
| 112 | + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
| 113 | + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 114 | + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
| 115 | + DEALINGS IN THE SOFTWARE. |
| 116 | + ----------------------------------------------------------------------- */ |
| 117 | + |
| 118 | +#include <ffi.h> |
| 119 | +#include <ffi_common.h> |
| 120 | + |
| 121 | +#include <stdlib.h> |
| 122 | +#include <stdint.h> |
| 123 | + |
| 124 | +#if __riscv_float_abi_double |
| 125 | +#define ABI_FLEN 64 |
| 126 | +#define ABI_FLOAT double |
| 127 | +#elif __riscv_float_abi_single |
| 128 | +#define ABI_FLEN 32 |
| 129 | +#define ABI_FLOAT float |
| 130 | +#endif |
| 131 | + |
| 132 | +#define NARGREG 8 |
| 133 | +#define STKALIGN 16 |
| 134 | +#define MAXCOPYARG (2 * sizeof(double)) |
| 135 | + |
| 136 | +typedef struct call_context |
| 137 | +{ |
| 138 | +#if ABI_FLEN |
| 139 | + ABI_FLOAT fa[8]; |
| 140 | +#endif |
| 141 | + size_t a[8]; |
| 142 | + /* used by the assembly code to in-place construct its own stack frame */ |
| 143 | + char frame[16]; |
| 144 | +} call_context; |
| 145 | + |
| 146 | +typedef struct call_builder |
| 147 | +{ |
| 148 | + call_context *aregs; |
| 149 | + int used_integer; |
| 150 | + int used_float; |
| 151 | + size_t *used_stack; |
| 152 | +} call_builder; |
| 153 | + |
| 154 | +/* integer (not pointer) less than ABI XLEN */ |
| 155 | +/* FFI_TYPE_INT does not appear to be used */ |
| 156 | +#if __SIZEOF_POINTER__ == 8 |
| 157 | +#define IS_INT(type) ((type) >= FFI_TYPE_UINT8 && (type) <= FFI_TYPE_SINT64) |
| 158 | +#else |
| 159 | +#define IS_INT(type) ((type) >= FFI_TYPE_UINT8 && (type) <= FFI_TYPE_SINT32) |
| 160 | +#endif |
| 161 | + |
| 162 | +#if ABI_FLEN |
| 163 | +typedef struct { |
| 164 | + char as_elements, type1, offset2, type2; |
| 165 | +} float_struct_info; |
| 166 | + |
| 167 | +#if ABI_FLEN >= 64 |
| 168 | +#define IS_FLOAT(type) ((type) >= FFI_TYPE_FLOAT && (type) <= FFI_TYPE_DOUBLE) |
| 169 | +#else |
| 170 | +#define IS_FLOAT(type) ((type) == FFI_TYPE_FLOAT) |
| 171 | +#endif |
| 172 | + |
| 173 | +static ffi_type **flatten_struct(ffi_type *in, ffi_type **out, ffi_type **out_end) { |
| 174 | + int i; |
| 175 | + if (out == out_end) return out; |
| 176 | + if (in->type != FFI_TYPE_STRUCT) { |
| 177 | + *(out++) = in; |
| 178 | + } else { |
| 179 | + for (i = 0; in->elements[i]; i++) |
| 180 | + out = flatten_struct(in->elements[i], out, out_end); |
| 181 | + } |
| 182 | + return out; |
| 183 | +} |
| 184 | + |
| 185 | +/* Structs with at most two fields after flattening, one of which is of |
| 186 | + floating point type, are passed in multiple registers if sufficient |
| 187 | + registers are available. */ |
| 188 | +static float_struct_info struct_passed_as_elements(call_builder *cb, ffi_type *top) { |
| 189 | + float_struct_info ret = {0, 0, 0, 0}; |
| 190 | + ffi_type *fields[3]; |
| 191 | + int num_floats, num_ints; |
| 192 | + int num_fields = flatten_struct(top, fields, fields + 3) - fields; |
| 193 | + |
| 194 | + if (num_fields == 1) { |
| 195 | + if (IS_FLOAT(fields[0]->type)) { |
| 196 | + ret.as_elements = 1; |
| 197 | + ret.type1 = fields[0]->type; |
| 198 | + } |
| 199 | + } else if (num_fields == 2) { |
| 200 | + num_floats = IS_FLOAT(fields[0]->type) + IS_FLOAT(fields[1]->type); |
| 201 | + num_ints = IS_INT(fields[0]->type) + IS_INT(fields[1]->type); |
| 202 | + if (num_floats == 0 || num_floats + num_ints != 2) |
| 203 | + return ret; |
| 204 | + if (cb->used_float + num_floats > NARGREG || cb->used_integer + (2 - num_floats) > NARGREG) |
| 205 | + return ret; |
| 206 | + if (!IS_FLOAT(fields[0]->type) && !IS_FLOAT(fields[1]->type)) |
| 207 | + return ret; |
| 208 | + |
| 209 | + ret.type1 = fields[0]->type; |
| 210 | + ret.type2 = fields[1]->type; |
| 211 | + ret.offset2 = ALIGN(fields[0]->size, fields[1]->alignment); |
| 212 | + ret.as_elements = 1; |
| 213 | + } |
| 214 | + |
| 215 | + return ret; |
| 216 | +} |
| 217 | +#endif |
| 218 | + |
| 219 | +/* allocates a single register, float register, or XLEN-sized stack slot to a datum */ |
| 220 | +static void marshal_atom(call_builder *cb, int type, void *data) { |
| 221 | + size_t value = 0; |
| 222 | + switch (type) { |
| 223 | + case FFI_TYPE_UINT8: value = *(uint8_t *)data; break; |
| 224 | + case FFI_TYPE_SINT8: value = *(int8_t *)data; break; |
| 225 | + case FFI_TYPE_UINT16: value = *(uint16_t *)data; break; |
| 226 | + case FFI_TYPE_SINT16: value = *(int16_t *)data; break; |
| 227 | + /* 32-bit quantities are always sign-extended in the ABI */ |
| 228 | + case FFI_TYPE_UINT32: value = *(int32_t *)data; break; |
| 229 | + case FFI_TYPE_SINT32: value = *(int32_t *)data; break; |
| 230 | +#if __SIZEOF_POINTER__ == 8 |
| 231 | + case FFI_TYPE_UINT64: value = *(uint64_t *)data; break; |
| 232 | + case FFI_TYPE_SINT64: value = *(int64_t *)data; break; |
| 233 | +#endif |
| 234 | + case FFI_TYPE_POINTER: value = *(size_t *)data; break; |
| 235 | + |
| 236 | + /* float values may be recoded in an implementation-defined way |
| 237 | + by hardware conforming to 2.1 or earlier, so use asm to |
| 238 | + reinterpret floats as doubles */ |
| 239 | +#if ABI_FLEN >= 32 |
| 240 | + case FFI_TYPE_FLOAT: |
| 241 | + asm("" : "=f"(cb->aregs->fa[cb->used_float++]) : "0"(*(float *)data)); |
| 242 | + return; |
| 243 | +#endif |
| 244 | +#if ABI_FLEN >= 64 |
| 245 | + case FFI_TYPE_DOUBLE: |
| 246 | + asm("" : "=f"(cb->aregs->fa[cb->used_float++]) : "0"(*(double *)data)); |
| 247 | + return; |
| 248 | +#endif |
| 249 | + default: FFI_ASSERT(0); break; |
| 250 | + } |
| 251 | + |
| 252 | + if (cb->used_integer == NARGREG) { |
| 253 | + *cb->used_stack++ = value; |
| 254 | + } else { |
| 255 | + cb->aregs->a[cb->used_integer++] = value; |
| 256 | + } |
| 257 | +} |
| 258 | + |
| 259 | +static void unmarshal_atom(call_builder *cb, int type, void *data) { |
| 260 | + size_t value; |
| 261 | + switch (type) { |
| 262 | +#if ABI_FLEN >= 32 |
| 263 | + case FFI_TYPE_FLOAT: |
| 264 | + asm("" : "=f"(*(float *)data) : "0"(cb->aregs->fa[cb->used_float++])); |
| 265 | + return; |
| 266 | +#endif |
| 267 | +#if ABI_FLEN >= 64 |
| 268 | + case FFI_TYPE_DOUBLE: |
| 269 | + asm("" : "=f"(*(double *)data) : "0"(cb->aregs->fa[cb->used_float++])); |
| 270 | + return; |
| 271 | +#endif |
| 272 | + } |
| 273 | + |
| 274 | + if (cb->used_integer == NARGREG) { |
| 275 | + value = *cb->used_stack++; |
| 276 | + } else { |
| 277 | + value = cb->aregs->a[cb->used_integer++]; |
| 278 | + } |
| 279 | + |
| 280 | + switch (type) { |
| 281 | + case FFI_TYPE_UINT8: *(uint8_t *)data = value; break; |
| 282 | + case FFI_TYPE_SINT8: *(uint8_t *)data = value; break; |
| 283 | + case FFI_TYPE_UINT16: *(uint16_t *)data = value; break; |
| 284 | + case FFI_TYPE_SINT16: *(uint16_t *)data = value; break; |
| 285 | + case FFI_TYPE_UINT32: *(uint32_t *)data = value; break; |
| 286 | + case FFI_TYPE_SINT32: *(uint32_t *)data = value; break; |
| 287 | +#if __SIZEOF_POINTER__ == 8 |
| 288 | + case FFI_TYPE_UINT64: *(uint64_t *)data = value; break; |
| 289 | + case FFI_TYPE_SINT64: *(uint64_t *)data = value; break; |
| 290 | +#endif |
| 291 | + case FFI_TYPE_POINTER: *(size_t *)data = value; break; |
| 292 | + default: FFI_ASSERT(0); break; |
| 293 | + } |
| 294 | +} |
| 295 | + |
| 296 | +/* adds an argument to a call, or a not by reference return value */ |
| 297 | +static void marshal(call_builder *cb, ffi_type *type, int var, void *data) { |
| 298 | + size_t realign[2]; |
| 299 | + |
| 300 | +#if ABI_FLEN |
| 301 | + if (!var && type->type == FFI_TYPE_STRUCT) { |
| 302 | + float_struct_info fsi = struct_passed_as_elements(cb, type); |
| 303 | + if (fsi.as_elements) { |
| 304 | + marshal_atom(cb, fsi.type1, data); |
| 305 | + if (fsi.offset2) |
| 306 | + marshal_atom(cb, fsi.type2, ((char*)data) + fsi.offset2); |
| 307 | + return; |
| 308 | + } |
| 309 | + } |
| 310 | + |
| 311 | + if (!var && cb->used_float < NARGREG && IS_FLOAT(type->type)) { |
| 312 | + marshal_atom(cb, type->type, data); |
| 313 | + return; |
| 314 | + } |
| 315 | +#endif |
| 316 | + |
| 317 | + if (type->size > 2 * __SIZEOF_POINTER__) { |
| 318 | + /* pass by reference */ |
| 319 | + marshal_atom(cb, FFI_TYPE_POINTER, &data); |
| 320 | + } else if (IS_INT(type->type) || type->type == FFI_TYPE_POINTER) { |
| 321 | + marshal_atom(cb, type->type, data); |
| 322 | + } else { |
| 323 | + /* overlong integers, soft-float floats, and structs without special |
| 324 | + float handling are treated identically from this point on */ |
| 325 | + |
| 326 | + /* variadics are aligned even in registers */ |
| 327 | + if (type->alignment > __SIZEOF_POINTER__) { |
| 328 | + if (var) |
| 329 | + cb->used_integer = ALIGN(cb->used_integer, 2); |
| 330 | + cb->used_stack = (size_t *)ALIGN(cb->used_stack, 2*__SIZEOF_POINTER__); |
| 331 | + } |
| 332 | + |
| 333 | + memcpy(realign, data, type->size); |
| 334 | + if (type->size > 0) |
| 335 | + marshal_atom(cb, FFI_TYPE_POINTER, realign); |
| 336 | + if (type->size > __SIZEOF_POINTER__) |
| 337 | + marshal_atom(cb, FFI_TYPE_POINTER, realign + 1); |
| 338 | + } |
| 339 | +} |
| 340 | + |
| 341 | +/* for arguments passed by reference returns the pointer, otherwise the arg is copied (up to MAXCOPYARG bytes) */ |
| 342 | +static void *unmarshal(call_builder *cb, ffi_type *type, int var, void *data) { |
| 343 | + size_t realign[2]; |
| 344 | + void *pointer; |
| 345 | + |
| 346 | +#if ABI_FLEN |
| 347 | + if (!var && type->type == FFI_TYPE_STRUCT) { |
| 348 | + float_struct_info fsi = struct_passed_as_elements(cb, type); |
| 349 | + if (fsi.as_elements) { |
| 350 | + unmarshal_atom(cb, fsi.type1, data); |
| 351 | + if (fsi.offset2) |
| 352 | + unmarshal_atom(cb, fsi.type2, ((char*)data) + fsi.offset2); |
| 353 | + return data; |
| 354 | + } |
| 355 | + } |
| 356 | + |
| 357 | + if (!var && cb->used_float < NARGREG && IS_FLOAT(type->type)) { |
| 358 | + unmarshal_atom(cb, type->type, data); |
| 359 | + return data; |
| 360 | + } |
| 361 | +#endif |
| 362 | + |
| 363 | + if (type->size > 2 * __SIZEOF_POINTER__) { |
| 364 | + /* pass by reference */ |
| 365 | + unmarshal_atom(cb, FFI_TYPE_POINTER, (char*)&pointer); |
| 366 | + return pointer; |
| 367 | + } else if (IS_INT(type->type) || type->type == FFI_TYPE_POINTER) { |
| 368 | + unmarshal_atom(cb, type->type, data); |
| 369 | + return data; |
| 370 | + } else { |
| 371 | + /* overlong integers, soft-float floats, and structs without special |
| 372 | + float handling are treated identically from this point on */ |
| 373 | + |
| 374 | + /* variadics are aligned even in registers */ |
| 375 | + if (type->alignment > __SIZEOF_POINTER__) { |
| 376 | + if (var) |
| 377 | + cb->used_integer = ALIGN(cb->used_integer, 2); |
| 378 | + cb->used_stack = (size_t *)ALIGN(cb->used_stack, 2*__SIZEOF_POINTER__); |
| 379 | + } |
| 380 | + |
| 381 | + if (type->size > 0) |
| 382 | + unmarshal_atom(cb, FFI_TYPE_POINTER, realign); |
| 383 | + if (type->size > __SIZEOF_POINTER__) |
| 384 | + unmarshal_atom(cb, FFI_TYPE_POINTER, realign + 1); |
| 385 | + memcpy(data, realign, type->size); |
| 386 | + return data; |
| 387 | + } |
| 388 | +} |
| 389 | + |
| 390 | +static int passed_by_ref(call_builder *cb, ffi_type *type, int var) { |
| 391 | +#if ABI_FLEN |
| 392 | + if (!var && type->type == FFI_TYPE_STRUCT) { |
| 393 | + float_struct_info fsi = struct_passed_as_elements(cb, type); |
| 394 | + if (fsi.as_elements) return 0; |
| 395 | + } |
| 396 | +#endif |
| 397 | + |
| 398 | + return type->size > 2 * __SIZEOF_POINTER__; |
| 399 | +} |
| 400 | + |
| 401 | +/* Perform machine dependent cif processing */ |
| 402 | +ffi_status ffi_prep_cif_machdep(ffi_cif *cif) { |
| 403 | + cif->riscv_nfixedargs = cif->nargs; |
| 404 | + return FFI_OK; |
| 405 | +} |
| 406 | + |
| 407 | +/* Perform machine dependent cif processing when we have a variadic function */ |
| 408 | + |
| 409 | +ffi_status ffi_prep_cif_machdep_var(ffi_cif *cif, unsigned int nfixedargs, unsigned int ntotalargs) { |
| 410 | + cif->riscv_nfixedargs = nfixedargs; |
| 411 | + return FFI_OK; |
| 412 | +} |
| 413 | + |
| 414 | +/* Low level routine for calling functions */ |
| 415 | +extern void ffi_call_asm(void *stack, struct call_context *regs, void (*fn)(void)) FFI_HIDDEN; |
| 416 | + |
| 417 | +void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) |
| 418 | +{ |
| 419 | + /* this is a conservative estimate, assuming a complex return value and |
| 420 | + that all remaining arguments are long long / __int128 */ |
| 421 | + size_t arg_bytes = cif->nargs <= 3 ? 0 : |
| 422 | + ALIGN(2 * sizeof(size_t) * (cif->nargs - 3), STKALIGN); |
| 423 | + size_t rval_bytes = 0; |
| 424 | + if (rvalue == NULL && cif->rtype->size > 2*__SIZEOF_POINTER__) |
| 425 | + rval_bytes = ALIGN(cif->rtype->size, STKALIGN); |
| 426 | + size_t alloc_size = arg_bytes + rval_bytes + sizeof(call_context); |
| 427 | + |
| 428 | + /* the assembly code will deallocate all stack data at lower addresses |
| 429 | + than the argument region, so we need to allocate the frame and the |
| 430 | + return value after the arguments in a single allocation */ |
| 431 | + size_t alloc_base; |
| 432 | + /* Argument region must be 16-byte aligned */ |
| 433 | + if (_Alignof(max_align_t) >= STKALIGN) { |
| 434 | + /* since sizeof long double is normally 16, the compiler will |
| 435 | + guarantee alloca alignment to at least that much */ |
| 436 | + alloc_base = (size_t)alloca(alloc_size); |
| 437 | + } else { |
| 438 | + alloc_base = ALIGN(alloca(alloc_size + STKALIGN - 1), STKALIGN); |
| 439 | + } |
| 440 | + |
| 441 | + if (rval_bytes) |
| 442 | + rvalue = (void*)(alloc_base + arg_bytes); |
| 443 | + |
| 444 | + call_builder cb; |
| 445 | + cb.used_float = cb.used_integer = 0; |
| 446 | + cb.aregs = (call_context*)(alloc_base + arg_bytes + rval_bytes); |
| 447 | + cb.used_stack = (void*)alloc_base; |
| 448 | + |
| 449 | + int return_by_ref = passed_by_ref(&cb, cif->rtype, 0); |
| 450 | + if (return_by_ref) |
| 451 | + marshal(&cb, &ffi_type_pointer, 0, &rvalue); |
| 452 | + |
| 453 | + int i; |
| 454 | + for (i = 0; i < cif->nargs; i++) |
| 455 | + marshal(&cb, cif->arg_types[i], i >= cif->riscv_nfixedargs, avalue[i]); |
| 456 | + |
| 457 | + ffi_call_asm((void*)alloc_base, cb.aregs, fn); |
| 458 | + |
| 459 | + cb.used_float = cb.used_integer = 0; |
| 460 | + if (!return_by_ref && rvalue) |
| 461 | + unmarshal(&cb, cif->rtype, 0, rvalue); |
| 462 | +} |
| 463 | + |
| 464 | +extern void ffi_closure_asm(void) FFI_HIDDEN; |
| 465 | + |
| 466 | +ffi_status ffi_prep_closure_loc(ffi_closure *closure, ffi_cif *cif, void (*fun)(ffi_cif*,void*,void**,void*), void *user_data, void *codeloc) |
| 467 | +{ |
| 468 | + uint32_t *tramp = (uint32_t *) &closure->tramp[0]; |
| 469 | + uint64_t fn = (uint64_t) (uintptr_t) ffi_closure_asm; |
| 470 | + |
| 471 | + if (cif->abi <= FFI_FIRST_ABI || cif->abi >= FFI_LAST_ABI) |
| 472 | + return FFI_BAD_ABI; |
| 473 | + |
| 474 | + /* we will call ffi_closure_inner with codeloc, not closure, but as long |
| 475 | + as the memory is readable it should work */ |
| 476 | + |
| 477 | + tramp[0] = 0x00000317; /* auipc t1, 0 (i.e. t0 <- codeloc) */ |
| 478 | +#if __SIZEOF_POINTER__ == 8 |
| 479 | + tramp[1] = 0x01033383; /* ld t2, 16(t1) */ |
| 480 | +#else |
| 481 | + tramp[1] = 0x01032383; /* lw t2, 16(t1) */ |
| 482 | +#endif |
| 483 | + tramp[2] = 0x00038067; /* jr t2 */ |
| 484 | + tramp[3] = 0x00000013; /* nop */ |
| 485 | + tramp[4] = fn; |
| 486 | + tramp[5] = fn >> 32; |
| 487 | + |
| 488 | + closure->cif = cif; |
| 489 | + closure->fun = fun; |
| 490 | + closure->user_data = user_data; |
| 491 | + |
| 492 | + __builtin___clear_cache(codeloc, codeloc + FFI_TRAMPOLINE_SIZE); |
| 493 | + |
| 494 | + return FFI_OK; |
| 495 | +} |
| 496 | + |
| 497 | +/* Called by the assembly code with aregs pointing to saved argument registers |
| 498 | + and stack pointing to the stacked arguments. Return values passed in |
| 499 | + registers will be reloaded from aregs. */ |
| 500 | +void FFI_HIDDEN ffi_closure_inner(size_t *stack, call_context *aregs, ffi_closure *closure) { |
| 501 | + ffi_cif *cif = closure->cif; |
| 502 | + void **avalue = alloca(cif->nargs * sizeof(void*)); |
| 503 | + /* storage for arguments which will be copied by unmarshal(). We could |
| 504 | + theoretically avoid the copies in many cases and use at most 128 bytes |
| 505 | + of memory, but allocating disjoint storage for each argument is |
| 506 | + simpler. */ |
| 507 | + char *astorage = alloca(cif->nargs * MAXCOPYARG); |
| 508 | + void *rvalue; |
| 509 | + call_builder cb; |
| 510 | + int return_by_ref; |
| 511 | + int i; |
| 512 | + |
| 513 | + cb.aregs = aregs; |
| 514 | + cb.used_integer = cb.used_float = 0; |
| 515 | + cb.used_stack = stack; |
| 516 | + |
| 517 | + return_by_ref = passed_by_ref(&cb, cif->rtype, 0); |
| 518 | + if (return_by_ref) |
| 519 | + unmarshal(&cb, &ffi_type_pointer, 0, &rvalue); |
| 520 | + else |
| 521 | + rvalue = alloca(cif->rtype->size); |
| 522 | + |
| 523 | + for (i = 0; i < cif->nargs; i++) |
| 524 | + avalue[i] = unmarshal(&cb, cif->arg_types[i], |
| 525 | + i >= cif->riscv_nfixedargs, astorage + i*MAXCOPYARG); |
| 526 | + |
| 527 | + (closure->fun)(cif, rvalue, avalue, closure->user_data); |
| 528 | + |
| 529 | + if (!return_by_ref && cif->rtype->type != FFI_TYPE_VOID) { |
| 530 | + cb.used_integer = cb.used_float = 0; |
| 531 | + marshal(&cb, cif->rtype, 0, rvalue); |
| 532 | + } |
| 533 | +} |
| 534 | diff --git a/src/riscv/ffitarget.h b/src/riscv/ffitarget.h |
| 535 | new file mode 100644 |
| 536 | index 0000000..fcaa899 |
| 537 | --- /dev/null |
| 538 | +++ b/src/riscv/ffitarget.h |
| 539 | @@ -0,0 +1,68 @@ |
| 540 | +/* -----------------------------------------------------------------*-C-*- |
| 541 | + ffitarget.h - 2014 Michael Knyszek |
| 542 | + |
| 543 | + Target configuration macros for RISC-V. |
| 544 | + |
| 545 | + Permission is hereby granted, free of charge, to any person obtaining |
| 546 | + a copy of this software and associated documentation files (the |
| 547 | + ``Software''), to deal in the Software without restriction, including |
| 548 | + without limitation the rights to use, copy, modify, merge, publish, |
| 549 | + distribute, sublicense, and/or sell copies of the Software, and to |
| 550 | + permit persons to whom the Software is furnished to do so, subject to |
| 551 | + the following conditions: |
| 552 | + |
| 553 | + The above copyright notice and this permission notice shall be included |
| 554 | + in all copies or substantial portions of the Software. |
| 555 | + |
| 556 | + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, |
| 557 | + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| 558 | + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| 559 | + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
| 560 | + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
| 561 | + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 562 | + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
| 563 | + DEALINGS IN THE SOFTWARE. |
| 564 | + |
| 565 | + ----------------------------------------------------------------------- */ |
| 566 | + |
| 567 | +#ifndef LIBFFI_TARGET_H |
| 568 | +#define LIBFFI_TARGET_H |
| 569 | + |
| 570 | +#ifndef LIBFFI_H |
| 571 | +#error "Please do not include ffitarget.h directly into your source. Use ffi.h instead." |
| 572 | +#endif |
| 573 | + |
| 574 | +#ifndef __riscv |
| 575 | +#error "libffi was configured for a RISC-V target but this does not appear to be a RISC-V compiler." |
| 576 | +#endif |
| 577 | + |
| 578 | +#ifndef LIBFFI_ASM |
| 579 | + |
| 580 | +typedef unsigned long ffi_arg; |
| 581 | +typedef signed long ffi_sarg; |
| 582 | + |
| 583 | +/* FFI_UNUSED_NN and riscv_unused are to maintain ABI compatibility with a |
| 584 | + distributed Berkeley patch from 2014, and can be removed at SONAME bump */ |
| 585 | +typedef enum ffi_abi { |
| 586 | + FFI_FIRST_ABI = 0, |
| 587 | + FFI_SYSV, |
| 588 | + FFI_UNUSED_1, |
| 589 | + FFI_UNUSED_2, |
| 590 | + FFI_UNUSED_3, |
| 591 | + FFI_LAST_ABI, |
| 592 | + |
| 593 | + FFI_DEFAULT_ABI = FFI_SYSV |
| 594 | +} ffi_abi; |
| 595 | + |
| 596 | +#endif /* LIBFFI_ASM */ |
| 597 | + |
| 598 | +/* ---- Definitions for closures ----------------------------------------- */ |
| 599 | + |
| 600 | +#define FFI_CLOSURES 1 |
| 601 | +#define FFI_TRAMPOLINE_SIZE 24 |
| 602 | +#define FFI_NATIVE_RAW_API 0 |
| 603 | +#define FFI_EXTRA_CIF_FIELDS unsigned riscv_nfixedargs; unsigned riscv_unused; |
| 604 | +#define FFI_TARGET_SPECIFIC_VARIADIC |
| 605 | + |
| 606 | +#endif |
| 607 | + |
| 608 | diff --git a/src/riscv/sysv.S b/src/riscv/sysv.S |
| 609 | new file mode 100644 |
| 610 | index 0000000..2d09865 |
| 611 | --- /dev/null |
| 612 | +++ b/src/riscv/sysv.S |
| 613 | @@ -0,0 +1,214 @@ |
| 614 | +/* ----------------------------------------------------------------------- |
| 615 | + ffi.c - Copyright (c) 2015 Michael Knyszek <mknyszek@berkeley.edu> |
| 616 | + 2015 Andrew Waterman <waterman@cs.berkeley.edu> |
| 617 | + 2018 Stef O'Rear <sorear2@gmail.com> |
| 618 | + |
| 619 | + RISC-V Foreign Function Interface |
| 620 | + |
| 621 | + Permission is hereby granted, free of charge, to any person obtaining |
| 622 | + a copy of this software and associated documentation files (the |
| 623 | + ``Software''), to deal in the Software without restriction, including |
| 624 | + without limitation the rights to use, copy, modify, merge, publish, |
| 625 | + distribute, sublicense, and/or sell copies of the Software, and to |
| 626 | + permit persons to whom the Software is furnished to do so, subject to |
| 627 | + the following conditions: |
| 628 | + |
| 629 | + The above copyright notice and this permission notice shall be included |
| 630 | + in all copies or substantial portions of the Software. |
| 631 | + |
| 632 | + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, |
| 633 | + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| 634 | + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| 635 | + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
| 636 | + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
| 637 | + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 638 | + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
| 639 | + DEALINGS IN THE SOFTWARE. |
| 640 | + ----------------------------------------------------------------------- */ |
| 641 | + |
| 642 | +#define LIBFFI_ASM |
| 643 | +#include <fficonfig.h> |
| 644 | +#include <ffi.h> |
| 645 | + |
| 646 | +/* Define aliases so that we can handle all ABIs uniformly */ |
| 647 | + |
| 648 | +#if __SIZEOF_POINTER__ == 8 |
| 649 | +#define PTRS 8 |
| 650 | +#define LARG ld |
| 651 | +#define SARG sd |
| 652 | +#else |
| 653 | +#define PTRS 4 |
| 654 | +#define LARG lw |
| 655 | +#define SARG sw |
| 656 | +#endif |
| 657 | + |
| 658 | +#if __riscv_float_abi_double |
| 659 | +#define FLTS 8 |
| 660 | +#define FLARG fld |
| 661 | +#define FSARG fsd |
| 662 | +#elif __riscv_float_abi_single |
| 663 | +#define FLTS 4 |
| 664 | +#define FLARG flw |
| 665 | +#define FSARG fsw |
| 666 | +#else |
| 667 | +#define FLTS 0 |
| 668 | +#endif |
| 669 | + |
| 670 | +#define fp s0 |
| 671 | + |
| 672 | + .text |
| 673 | + .globl ffi_call_asm |
| 674 | + .type ffi_call_asm, @function |
| 675 | + .hidden ffi_call_asm |
| 676 | +/* |
| 677 | + struct call_context { |
| 678 | + floatreg fa[8]; |
| 679 | + intreg a[8]; |
| 680 | + intreg pad[rv32 ? 2 : 0]; |
| 681 | + intreg save_fp, save_ra; |
| 682 | + } |
| 683 | + void ffi_call_asm(size_t *stackargs, struct call_context *regargs, |
| 684 | + void (*fn)(void)); |
| 685 | +*/ |
| 686 | + |
| 687 | +#define FRAME_LEN (8 * FLTS + 8 * PTRS + 16) |
| 688 | + |
| 689 | +ffi_call_asm: |
| 690 | + .cfi_startproc |
| 691 | + |
| 692 | + /* |
| 693 | + We are NOT going to set up an ordinary stack frame. In order to pass |
| 694 | + the stacked args to the called function, we adjust our stack pointer to |
| 695 | + a0, which is in the _caller's_ alloca area. We establish our own stack |
| 696 | + frame at the end of the call_context. |
| 697 | + |
| 698 | + Anything below the arguments will be freed at this point, although we |
| 699 | + preserve the call_context so that it can be read back in the caller. |
| 700 | + */ |
| 701 | + |
| 702 | + .cfi_def_cfa 11, FRAME_LEN # interim CFA based on a1 |
| 703 | + SARG fp, FRAME_LEN - 2*PTRS(a1) |
| 704 | + .cfi_offset 8, -2*PTRS |
| 705 | + SARG ra, FRAME_LEN - 1*PTRS(a1) |
| 706 | + .cfi_offset 1, -1*PTRS |
| 707 | + |
| 708 | + addi fp, a1, FRAME_LEN |
| 709 | + mv sp, a0 |
| 710 | + .cfi_def_cfa 8, 0 # our frame is fully set up |
| 711 | + |
| 712 | + # Load arguments |
| 713 | + mv t1, a2 |
| 714 | + |
| 715 | +#if FLTS |
| 716 | + FLARG fa0, -FRAME_LEN+0*FLTS(fp) |
| 717 | + FLARG fa1, -FRAME_LEN+1*FLTS(fp) |
| 718 | + FLARG fa2, -FRAME_LEN+2*FLTS(fp) |
| 719 | + FLARG fa3, -FRAME_LEN+3*FLTS(fp) |
| 720 | + FLARG fa4, -FRAME_LEN+4*FLTS(fp) |
| 721 | + FLARG fa5, -FRAME_LEN+5*FLTS(fp) |
| 722 | + FLARG fa6, -FRAME_LEN+6*FLTS(fp) |
| 723 | + FLARG fa7, -FRAME_LEN+7*FLTS(fp) |
| 724 | +#endif |
| 725 | + |
| 726 | + LARG a0, -FRAME_LEN+8*FLTS+0*PTRS(fp) |
| 727 | + LARG a1, -FRAME_LEN+8*FLTS+1*PTRS(fp) |
| 728 | + LARG a2, -FRAME_LEN+8*FLTS+2*PTRS(fp) |
| 729 | + LARG a3, -FRAME_LEN+8*FLTS+3*PTRS(fp) |
| 730 | + LARG a4, -FRAME_LEN+8*FLTS+4*PTRS(fp) |
| 731 | + LARG a5, -FRAME_LEN+8*FLTS+5*PTRS(fp) |
| 732 | + LARG a6, -FRAME_LEN+8*FLTS+6*PTRS(fp) |
| 733 | + LARG a7, -FRAME_LEN+8*FLTS+7*PTRS(fp) |
| 734 | + |
| 735 | + /* Call */ |
| 736 | + jalr t1 |
| 737 | + |
| 738 | + /* Save return values - only a0/a1 (fa0/fa1) are used */ |
| 739 | +#if FLTS |
| 740 | + FSARG fa0, -FRAME_LEN+0*FLTS(fp) |
| 741 | + FSARG fa1, -FRAME_LEN+1*FLTS(fp) |
| 742 | +#endif |
| 743 | + |
| 744 | + SARG a0, -FRAME_LEN+8*FLTS+0*PTRS(fp) |
| 745 | + SARG a1, -FRAME_LEN+8*FLTS+1*PTRS(fp) |
| 746 | + |
| 747 | + /* Restore and return */ |
| 748 | + addi sp, fp, -FRAME_LEN |
| 749 | + .cfi_def_cfa 2, FRAME_LEN |
| 750 | + LARG ra, -1*PTRS(fp) |
| 751 | + .cfi_restore 1 |
| 752 | + LARG fp, -2*PTRS(fp) |
| 753 | + .cfi_restore 8 |
| 754 | + ret |
| 755 | + .cfi_endproc |
| 756 | + .size ffi_call_asm, .-ffi_call_asm |
| 757 | + |
| 758 | + |
| 759 | +/* |
| 760 | + ffi_closure_asm. Expects address of the passed-in ffi_closure in t1. |
| 761 | + void ffi_closure_inner(size_t *stackargs, struct call_context *regargs, |
| 762 | + ffi_closure *closure); |
| 763 | +*/ |
| 764 | + |
| 765 | + .globl ffi_closure_asm |
| 766 | + .hidden ffi_closure_asm |
| 767 | + .type ffi_closure_asm, @function |
| 768 | +ffi_closure_asm: |
| 769 | + .cfi_startproc |
| 770 | + |
| 771 | + addi sp, sp, -FRAME_LEN |
| 772 | + .cfi_def_cfa_offset FRAME_LEN |
| 773 | + |
| 774 | + /* make a frame */ |
| 775 | + SARG fp, FRAME_LEN - 2*PTRS(sp) |
| 776 | + .cfi_offset 8, -2*PTRS |
| 777 | + SARG ra, FRAME_LEN - 1*PTRS(sp) |
| 778 | + .cfi_offset 1, -1*PTRS |
| 779 | + addi fp, sp, FRAME_LEN |
| 780 | + |
| 781 | + /* save arguments */ |
| 782 | +#if FLTS |
| 783 | + FSARG fa0, 0*FLTS(sp) |
| 784 | + FSARG fa1, 1*FLTS(sp) |
| 785 | + FSARG fa2, 2*FLTS(sp) |
| 786 | + FSARG fa3, 3*FLTS(sp) |
| 787 | + FSARG fa4, 4*FLTS(sp) |
| 788 | + FSARG fa5, 5*FLTS(sp) |
| 789 | + FSARG fa6, 6*FLTS(sp) |
| 790 | + FSARG fa7, 7*FLTS(sp) |
| 791 | +#endif |
| 792 | + |
| 793 | + SARG a0, 8*FLTS+0*PTRS(sp) |
| 794 | + SARG a1, 8*FLTS+1*PTRS(sp) |
| 795 | + SARG a2, 8*FLTS+2*PTRS(sp) |
| 796 | + SARG a3, 8*FLTS+3*PTRS(sp) |
| 797 | + SARG a4, 8*FLTS+4*PTRS(sp) |
| 798 | + SARG a5, 8*FLTS+5*PTRS(sp) |
| 799 | + SARG a6, 8*FLTS+6*PTRS(sp) |
| 800 | + SARG a7, 8*FLTS+7*PTRS(sp) |
| 801 | + |
| 802 | + /* enter C */ |
| 803 | + addi a0, sp, FRAME_LEN |
| 804 | + mv a1, sp |
| 805 | + mv a2, t1 |
| 806 | + |
| 807 | + call ffi_closure_inner |
| 808 | + |
| 809 | + /* return values */ |
| 810 | +#if FLTS |
| 811 | + FLARG fa0, 0*FLTS(sp) |
| 812 | + FLARG fa1, 1*FLTS(sp) |
| 813 | +#endif |
| 814 | + |
| 815 | + LARG a0, 8*FLTS+0*PTRS(sp) |
| 816 | + LARG a1, 8*FLTS+1*PTRS(sp) |
| 817 | + |
| 818 | + /* restore and return */ |
| 819 | + LARG ra, FRAME_LEN-1*PTRS(sp) |
| 820 | + .cfi_restore 1 |
| 821 | + LARG fp, FRAME_LEN-2*PTRS(sp) |
| 822 | + .cfi_restore 8 |
| 823 | + addi sp, sp, FRAME_LEN |
| 824 | + .cfi_def_cfa_offset 0 |
| 825 | + ret |
| 826 | + .cfi_endproc |
| 827 | + .size ffi_closure_asm, .-ffi_closure_asm |