Mercurial > pub > dyncall > dyncall
changeset 653:0c8838766866
- riscv64 support for calls and callbacks (but lacking aggr and syscall support) - thanks Jun Jeon! :)
- mark riscv64 as implemented in manual overview
author | Tassilo Philipp |
---|---|
date | Thu, 07 Mar 2024 17:42:13 +0100 |
parents | e7ffb0fb1520 |
children | 0079a8fa894e |
files | doc/manual/manual_overview.tex dyncall/dyncall.h dyncall/dyncall_call.S dyncall/dyncall_call_riscv64.S dyncall/dyncall_callvm.c dyncall/dyncall_callvm_riscv64.c dyncall/dyncall_callvm_riscv64.h dyncall/dyncall_macros.h dyncallback/dyncall_args.c dyncallback/dyncall_args_riscv64.c dyncallback/dyncall_callback.c dyncallback/dyncall_callback_arch.S dyncallback/dyncall_callback_riscv64.S dyncallback/dyncall_callback_riscv64.c dyncallback/dyncall_thunk.c dyncallback/dyncall_thunk.h dyncallback/dyncall_thunk_riscv64.c dyncallback/dyncall_thunk_riscv64.h |
diffstat | 18 files changed, 810 insertions(+), 8 deletions(-) [+] |
line wrap: on
line diff
--- a/doc/manual/manual_overview.tex Thu Mar 07 14:48:03 2024 +0100 +++ b/doc/manual/manual_overview.tex Thu Mar 07 17:42:13 2024 +0100 @@ -232,7 +232,7 @@ \hline RISC-V & & \marknotx & \marknimp & \marknotx & \marknotx & \marknotx & \marknotx & \marknotx & \marknotx & \marknotx & \marknotx & \marknotx & \marknotx & \marknotx \\%& \\ \hline -RISC-V 64 & & \marknotx & \marknimp & \marknotx & \marknimp & \marknotx & \marknimp & \marknotx & \marknotx & \marknotx & \marknotx & \marknotx & \marknotx & \marknotx \\%& \\ +RISC-V 64 & & \marknotx & \markimpl & \marknotx & \markimpl & \markunkn & \markunkn & \marknotx & \marknotx & \marknotx & \marknotx & \marknotx & \marknotx & \marknotx \\%& \\ \end{tabular} \caption{Supported platforms}%
--- a/dyncall/dyncall.h Thu Mar 07 14:48:03 2024 +0100 +++ b/dyncall/dyncall.h Thu Mar 07 17:42:13 2024 +0100 @@ -75,6 +75,7 @@ #define DC_CALL_C_ARM64 22 #define DC_CALL_C_PPC64 23 #define DC_CALL_C_PPC64_LINUX DC_CALL_C_PPC64 /* alias */ +#define DC_CALL_C_RISCV64 24 /* syscalls, default */ #define DC_CALL_SYS_DEFAULT 200 /* syscalls, platform specific */
--- a/dyncall/dyncall_call.S Thu Mar 07 14:48:03 2024 +0100 +++ b/dyncall/dyncall_call.S Thu Mar 07 17:42:13 2024 +0100 @@ -80,6 +80,8 @@ # include "dyncall_call_sparc64.s" # elif defined(DC__Arch_Sparc) # include "dyncall_call_sparc.s" +# elif defined(DC__Arch_RiscV64) +# include "dyncall_call_riscv64.S" # else # error Unsupported Architecture. # endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dyncall/dyncall_call_riscv64.S Thu Mar 07 17:42:13 2024 +0100 @@ -0,0 +1,124 @@ +/* + + Package: dyncall + Library: dyncall + File: dyncall/dyncall_call_riscv64.S + Description: Call Kernel for RISCV64 Architecture + License: + + Copyright (c) 2023 Jun Jeon <yjeon@netflix.com> + + Permission to use, copy, modify, and distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +*/ + + +/* ============================================================================ + DynCall Call Kernel for RISCV64 Architecture + ---------------------------------------------------------------------------- + C Interface: + dcCall_riscv64 (DCpointer target, DCpointer data, DCsize size, DCfloat* regdata); +*/ + +.text +/* + DynCall Back-End riscv64 + + Supports: + - arch=rv64g, abi=lp64d +*/ + +.globl dcCall_riscv64 +dcCall_riscv64: +.align 2 + +/* input: + a0: target (address of target) + a1: data (address of stack copy data) + a2: size (number of 'pair' 16-byte units) + a3: regdata (address of register data) +*/ + +/* prolog: */ + + add sp, sp, -16 /* alloc frame */ + sd ra, 0(sp) /* save ret addr */ + sd s0, 8(sp) /* save stk ptr */ + mv s0, sp /* set cur stk ptr */ + +/* load 64-bit floating-point registers */ + + fld fa0, 0(a3) + fld fa1, 8(a3) + fld fa2, 16(a3) + fld fa3, 24(a3) + fld fa4, 32(a3) + fld fa5, 40(a3) + fld fa6, 48(a3) + fld fa7, 56(a3) + +/* copy to stack */ + + sub sp, sp, a2 /* create call-frame */ + + mv t1, zero /* t1: cnt = 0 */ + mv t2, a1 /* t2: read pointer = data */ + mv t3, sp /* t3: write pointer = sp */ + +.next: + bge t1, a2, .done + + ld t4, 0(t2) /* read 8b from mem */ + sd t4, 0(t3) /* write 8b to mem */ + + /* advance the pointers */ + add t2, t2, 8 + add t3, t3, 8 + add t1, t1, 8 + + j .next + +.done: + +/* rescue temp int registers */ + + mv t1, a0 /* t1: target */ + add t2, a3, 64 /* t2: integer reg buffer */ + +/* load 64-bit integer registers ( 8 x 64-bit ) */ + + /* load register set */ + + ld a0, 0(t2) + ld a1, 8(t2) + ld a2, 16(t2) + ld a3, 24(t2) + ld a4, 32(t2) + ld a5, 40(t2) + ld a6, 48(t2) + ld a7, 56(t2) + +/* call target: */ + + jalr ra, 0(t1) + +/* epilog: */ + + mv sp, s0 + + ld ra, 0(sp) + ld s0, 8(sp) + add sp, sp, 16 + + ret +
--- a/dyncall/dyncall_callvm.c Thu Mar 07 14:48:03 2024 +0100 +++ b/dyncall/dyncall_callvm.c Thu Mar 07 17:42:13 2024 +0100 @@ -6,7 +6,7 @@ Description: auto-select default callvm (includes other C sources). License: - Copyright (c) 2007-2018 Daniel Adler <dadler@uni-goettingen.de>, + Copyright (c) 2007-2024 Daniel Adler <dadler@uni-goettingen.de>, Tassilo Philipp <tphilipp@potion-studios.com> Permission to use, copy, modify, and distribute this software for any @@ -69,8 +69,8 @@ # include "dyncall_callvm_sparc.c" #elif defined(DC__Arch_Sparc64) # include "dyncall_callvm_sparc64.c" -#elif defined(DC__Arch_RiscV) -# include "dyncall_callvm_riscv.c" +#elif defined(DC__Arch_RiscV64) +# include "dyncall_callvm_riscv64.c" #else # error unsupported platform #endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dyncall/dyncall_callvm_riscv64.c Thu Mar 07 17:42:13 2024 +0100 @@ -0,0 +1,252 @@ +/* + + Package: dyncall + Library: dyncall + File: dyncall/dyncall_callvm_riscv64.c + Description: RISC-V ABI implementation + License: + + Copyright (c) 2023 Jun Jeon <yjeon@netflix.com> + + Permission to use, copy, modify, and distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +*/ + + +#include "dyncall_callvm_riscv64.h" +#include "dyncall_alloc.h" + + +void dcCall_riscv64(DCpointer target, DCpointer data, DCsize size, DCpointer regdata); + + +static void reset(DCCallVM* in_p) +{ + DCCallVM_riscv64* p = (DCCallVM_riscv64*)in_p; + p->i = 0; + p->f = 0; + dcVecReset(&p->mVecHead); + /* single precision fp values in 64b float registers require all 32 high bits * + * to be set: set all bits on init, will be overwritten when doubles are used */ + for(int i=0; i<RISCV_NUM_FLOAT_REGISTERS; ++i) + p->u.I[i] = -1; +} + + +static void deinit(DCCallVM* in_self) +{ + dcFreeMem(in_self); +} + + + +static void a_i64(DCCallVM* in_self, DClonglong x) +{ + DCCallVM_riscv64* p = (DCCallVM_riscv64*)in_self; + if (p->i < RISCV_NUM_INT_REGISTERS) { + p->I[p->i] = x; + p->i++; + } else { + dcVecAppend(&p->mVecHead, &x, sizeof(DClonglong)); + } +} + +static void a_bool (DCCallVM* self, DCbool x) { a_i64(self, (DClonglong)x); } +static void a_char (DCCallVM* self, DCchar x) { a_i64(self, x); } +static void a_short (DCCallVM* self, DCshort x) { a_i64(self, x); } +static void a_int (DCCallVM* self, DCint x) { a_i64(self, x); } +static void a_long (DCCallVM* self, DClong x) { a_i64(self, x); } +static void a_pointer (DCCallVM* self, DCpointer x) { a_i64(self, (DClonglong) x ); } + +static void a_float(DCCallVM* in_p, DCfloat x) +{ + DCCallVM_riscv64* p = (DCCallVM_riscv64*)in_p; + + if (p->f < RISCV_NUM_FLOAT_REGISTERS) { + /* trivial case; just use float arg reg */ + p->u.S[p->f << 1] = x; + ++p->f; + } else if (p->i < RISCV_NUM_INT_REGISTERS) { + /* risc-v will use int arg reg to pass float args */ + p->I[p->i] = (unsigned)*(DCint*)&x; + ++p->i; + } else { + /* now everything has to go on stack */ + dcVecAppend(&p->mVecHead, &x, sizeof(DCfloat)); + dcVecSkip(&p->mVecHead, 4); /* align to 8-bytes */ + } +} + +static void a_double(DCCallVM* in_p, DCdouble x) +{ + DCCallVM_riscv64* p = (DCCallVM_riscv64*)in_p; + if (p->f < RISCV_NUM_FLOAT_REGISTERS) { + /* trivial case; just use float arg reg */ + p->u.D[p->f] = x; + ++p->f; + } else if (p->i < RISCV_NUM_INT_REGISTERS) { + /* risc-v will use int arg reg to pass float args */ + p->I[p->i] = *(DClonglong*)&x; + ++p->i; + } else { + /* now everything has to go on stack */ + dcVecAppend(&p->mVecHead, &x, sizeof(DCdouble)); + } +} + + +/* for variadic args, push everything onto stack, according to the RISC-V calling convention */ + +static void var_i64(DCCallVM* in_self, DClonglong x) +{ + DCCallVM_riscv64* p = (DCCallVM_riscv64*)in_self; + /* first use int registers, then spill over onto stack */ + if (p->i < RISCV_NUM_INT_REGISTERS) { + p->I[p->i] = *(DClonglong*)&x; + p->i++; + } else { + dcVecAppend(&p->mVecHead, &x, sizeof(DClonglong)); + } +} + +static void var_bool (DCCallVM* self, DCbool x) { var_i64(self, (DClonglong)x); } +static void var_char (DCCallVM* self, DCchar x) { var_i64(self, (DClonglong)x); } +static void var_short (DCCallVM* self, DCshort x) { var_i64(self, (DClonglong)x); } +static void var_int (DCCallVM* self, DCint x) { var_i64(self, (DClonglong)x); } +static void var_long (DCCallVM* self, DClong x) { var_i64(self, (DClonglong)x); } +static void var_pointer (DCCallVM* self, DCpointer x) { var_i64(self, (DClonglong)x); } + +static void var_double(DCCallVM* in_p, DCdouble x) +{ + DCCallVM_riscv64* p = (DCCallVM_riscv64*)in_p; + /* first use int registers, then spill over onto stack */ + if (p->i < RISCV_NUM_INT_REGISTERS) { + p->I[p->i] = *(DClonglong*)&x; + p->i++; + } else { + dcVecAppend(&p->mVecHead, &x, sizeof(DCdouble)); + } +} + +static void var_float(DCCallVM* in_p, DCfloat x) +{ + var_double(in_p, (DCdouble)x); +} + + +void call(DCCallVM* in_p, DCpointer target) +{ + DCCallVM_riscv64* p = (DCCallVM_riscv64*)in_p; + + /* + ** copy 'size' argument is given in number of 16-byte 'pair' blocks. + sp is always 16-byte aligned + ref: https://riscv.org/wp-content/uploads/2015/01/riscv-calling.pdf, page 3 + */ + dcCall_riscv64(target, dcVecData(&p->mVecHead), ( dcVecSize(&p->mVecHead) + 15 ) & -16, &p->u.S[0]); +} + +static void mode(DCCallVM* in_self, DCint mode); + +DCCallVM_vt vt_riscv64 = +{ + &deinit +, &reset +, &mode +, &a_bool +, &a_char +, &a_short +, &a_int +, &a_long +, &a_i64 +, &a_float +, &a_double +, &a_pointer +, NULL /* argAggr */ +, (DCvoidvmfunc*) &call +, (DCboolvmfunc*) &call +, (DCcharvmfunc*) &call +, (DCshortvmfunc*) &call +, (DCintvmfunc*) &call +, (DClongvmfunc*) &call +, (DClonglongvmfunc*) &call +, (DCfloatvmfunc*) &call +, (DCdoublevmfunc*) &call +, (DCpointervmfunc*) &call +, NULL /* callAggr */ +, NULL /* beginAggr */ +}; + +DCCallVM_vt vt_riscv64_varargs = +{ + &deinit +, &reset +, &mode +, &var_bool +, &var_char +, &var_short +, &var_int +, &var_long +, &var_i64 +, &var_float +, &var_double +, &var_pointer +, NULL /* argAggr */ +, (DCvoidvmfunc*) &call +, (DCboolvmfunc*) &call +, (DCcharvmfunc*) &call +, (DCshortvmfunc*) &call +, (DCintvmfunc*) &call +, (DClongvmfunc*) &call +, (DClonglongvmfunc*) &call +, (DCfloatvmfunc*) &call +, (DCdoublevmfunc*) &call +, (DCpointervmfunc*) &call +, NULL /* callAggr */ +, NULL /* beginAggr */ +}; + +static void mode(DCCallVM* in_self, DCint mode) +{ + DCCallVM_riscv64* self = (DCCallVM_riscv64*)in_self; + DCCallVM_vt* vt; + + switch(mode) { + case DC_CALL_C_DEFAULT: + case DC_CALL_C_RISCV64: + case DC_CALL_C_ELLIPSIS: + vt = &vt_riscv64; + break; + case DC_CALL_C_ELLIPSIS_VARARGS: + vt = &vt_riscv64_varargs; + break; + default: + self->mInterface.mError = DC_ERROR_UNSUPPORTED_MODE; + return; + } + dc_callvm_base_init(&self->mInterface, vt); +} + +/* Public API. */ +DCCallVM* dcNewCallVM(DCsize size) +{ + DCCallVM_riscv64* p = (DCCallVM_riscv64*)dcAllocMem(sizeof(DCCallVM_riscv64)+size); + + mode((DCCallVM*)p, DC_CALL_C_DEFAULT); + + dcVecInit(&p->mVecHead, size); + reset((DCCallVM*)p); + + return (DCCallVM*)p; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dyncall/dyncall_callvm_riscv64.h Thu Mar 07 17:42:13 2024 +0100 @@ -0,0 +1,49 @@ +/* + + Package: dyncall + Library: dyncall + File: dyncall/dyncall_callvm_riscv64.h + Description: + License: + + Copyright (c) 2023 Jun Jeon <yjeon@netflix.com> + + Permission to use, copy, modify, and distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +*/ + +#ifndef DYNCALL_CALLVM_RISCV64_H +#define DYNCALL_CALLVM_RISCV64_H + +#include "dyncall_callvm.h" +#include "dyncall_vector.h" + +#define RISCV_NUM_INT_REGISTERS 8 +#define RISCV_NUM_FLOAT_REGISTERS 8 + +typedef struct +{ + DCCallVM mInterface; + unsigned int i; /* int register counter */ + unsigned int f; /* float register counter */ + union { /* float register buffer */ + DCfloat S[RISCV_NUM_FLOAT_REGISTERS << 1]; + DCdouble D[RISCV_NUM_FLOAT_REGISTERS]; + DClonglong I[RISCV_NUM_FLOAT_REGISTERS]; /* helper */ + } u; + DCulonglong I[RISCV_NUM_INT_REGISTERS]; /* int register buffer */ + DCVecHead mVecHead; /* argument buffer head */ +} DCCallVM_riscv64; + +#endif /* DYNCALL_CALLVM_RISCV64_H */ +
--- a/dyncall/dyncall_macros.h Thu Mar 07 14:48:03 2024 +0100 +++ b/dyncall/dyncall_macros.h Thu Mar 07 17:42:13 2024 +0100 @@ -207,6 +207,14 @@ # else # define DC__Arch_Sparc # endif +#elif defined(__riscv) +# if __riscv_xlen == 32 +# define DC__Arch_RiscV32 +# elif __riscv_xlen == 64 +# define DC__Arch_RiscV64 +# elif __riscv_xlen == 128 +# define DC__Arch_RiscV128 +# endif #endif @@ -298,15 +306,16 @@ /* -- Endianness detection ------------------------------------------ */ -#if defined(DC__Arch_Intel_x86) || defined(DC__Arch_AMD64) /* always little */ +#if defined(DC__Arch_Intel_x86) || defined(DC__Arch_AMD64) /* always little */ # define DC__Endian_LITTLE -#elif defined(DC__Arch_Sparc) /* always purely big until v9 */ +#elif defined(DC__Arch_Sparc) /* always purely big until v9 */ # define DC__Endian_BIG -#else /* all others are bi-endian */ +#elif defined(DC__Arch_RiscV32) || defined(DC__Arch_RiscV64) || defined(DC__Arch_RiscV128) /* always little */ +# define DC__Endian_LITTLE +#else /* all others are bi-endian */ /* @@@check flags used on following bi-endianness archs: DC__Arch_Itanium DC__Arch_PPC32 -DC__Arch_PPC64 DC__Arch_SuperH */ # if (defined(DC__Arch_PPC64) && (DC__ABI_PPC64_ELF_V == 1)) || defined(MIPSEB) || defined(_MIPSEB) || defined(__MIPSEB) || defined(__MIPSEB__) || defined(__ARMEB__) || defined(__AARCH64EB__)
--- a/dyncallback/dyncall_args.c Thu Mar 07 14:48:03 2024 +0100 +++ b/dyncallback/dyncall_args.c Thu Mar 07 17:42:13 2024 +0100 @@ -57,5 +57,7 @@ # else # include "dyncall_args_arm64.c" # endif +#elif defined(DC__Arch_RiscV64) +# include "dyncall_args_riscv64.c" #endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dyncallback/dyncall_args_riscv64.c Thu Mar 07 17:42:13 2024 +0100 @@ -0,0 +1,82 @@ +/* + + Package: dyncall + Library: dyncallback + File: dyncallback/dyncall_args_riscv64.c + Description: Callback's Arguments VM - Implementation for RISCV64 + License: + + Copyright (c) 2023 Jun Jeon <yjeon@netflix.com> + + Permission to use, copy, modify, and distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +*/ +#include "dyncall_args.h" + +#include <stdint.h> + +typedef union { + struct { double value; } d; + struct { float value; } f; +} DCFPU_t; + +struct DCArgs +{ + /* buffers and stack-pointer: */ + uint64_t I[8]; + DCFPU_t F[8]; + uint64_t* sp; + + /* counters: */ + int i; + int f; +}; + +DClonglong dcbArgLongLong (DCArgs* p) { + return (p->i < 8) ? p->I[p->i++] : *(p->sp)++; +} + +DCdouble dcbArgDouble (DCArgs* p) { + if (p->f < 8) + return p->F[p->f++].d.value; + else if (p->i < 8) + return ((DCFPU_t*)&(p->I[p->i++]))->d.value; + else + return *(double*)(p->sp++); +} +DCfloat dcbArgFloat (DCArgs* p) { + if (p->f < 8) + return p->F[p->f++].f.value; + else if (p->i < 8) + return ((DCFPU_t*)&(p->I[p->i++]))->f.value; + else + return *(float*)(p->sp++); +} + + +DClong dcbArgLong (DCArgs* p) { return (DClong) dcbArgLongLong(p); } +DCint dcbArgInt (DCArgs* p) { return (DCint) dcbArgLongLong(p); } +DCshort dcbArgShort (DCArgs* p) { return (DCshort) dcbArgLongLong(p); } +DCchar dcbArgChar (DCArgs* p) { return (DCchar) dcbArgLongLong(p); } +DCbool dcbArgBool (DCArgs* p) { return dcbArgLongLong(p) & 0x1; } +DCpointer dcbArgPointer (DCArgs* p) { return (DCpointer)dcbArgLongLong(p); } + +DCuint dcbArgUInt (DCArgs* p) { return (DCuint) dcbArgInt(p); } +DCuchar dcbArgUChar (DCArgs* p) { return (DCuchar) dcbArgChar(p); } +DCushort dcbArgUShort (DCArgs* p) { return (DCushort) dcbArgShort(p); } +DCulong dcbArgULong (DCArgs* p) { return (DCulong) dcbArgLong(p); } +DCulonglong dcbArgULongLong(DCArgs* p) { return (DCulonglong)dcbArgLongLong(p); } + +DCpointer dcbArgAggr (DCArgs* p, DCpointer target) { /* @@@AGGR not impl */ return NULL; } +void dcbReturnAggr (DCArgs *args, DCValue *result, DCpointer ret) { /* @@@AGGR not impl */ } +
--- a/dyncallback/dyncall_callback.c Thu Mar 07 14:48:03 2024 +0100 +++ b/dyncallback/dyncall_callback.c Thu Mar 07 17:42:13 2024 +0100 @@ -46,6 +46,8 @@ #include "dyncall_callback_sparc64.c" #elif defined(DC__Arch_ARM64) #include "dyncall_callback_arm64.c" +#elif defined(DC__Arch_RiscV64) +#include "dyncall_callback_riscv64.c" #else #error unsupported platform #endif
--- a/dyncallback/dyncall_callback_arch.S Thu Mar 07 14:48:03 2024 +0100 +++ b/dyncallback/dyncall_callback_arch.S Thu Mar 07 17:42:13 2024 +0100 @@ -86,6 +86,8 @@ # include "dyncall_callback_sparc64.s" # elif defined(DC__Arch_ARM64) # include "dyncall_callback_arm64.S" +# elif defined(DC__Arch_RiscV64) +# include "dyncall_callback_riscv64.S" # endif #endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dyncallback/dyncall_callback_riscv64.S Thu Mar 07 17:42:13 2024 +0100 @@ -0,0 +1,132 @@ +/* + + Package: dyncall + Library: dyncallback + File: dyncallback/dyncall_callback_riscv64.S + Description: Callback Thunk - Implementation for RISCV64 + License: + + Copyright (c) 2023 Jun Jeon <yjeon@netflix.com> + + Permission to use, copy, modify, and distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +*/ + +/* struct DCCallback + type off size + ---------|------|------ + DCThunk | 0 | 32 + handler | 32 | 8 + userdata | 40 | 8 +*/ + +.align 4 +.globl dcCallbackThunkEntry +dcCallbackThunkEntry: + +/* called from dcbInitThunk() in dyncall_thunk_riscv64.c */ + +/* input: + t5: DCCallback* pcb + a0..a7 ?? GP regs + fa0..fa7 ?? FP/SIMD regs + sp... ?? arguments on stack + + locals: + type off size + ---------|------|------ + Frame 0 16 + DCArgs 16 144 + DCValue 160 16 + + size 176 + aligned 176 + + ra - ret addr + s0/fp - frame ptr + + locals: + t0: orig sp + t1: DCArgs* args +*/ + + mv t0, sp + + add sp, sp, -176 + + /* save ra and s0 */ + sd ra, 0(sp) + sd s0, 8(sp) + + /* save frame ptr */ + mv s0, sp + + add t1, s0, 16 + + /* just saving everything on stack, as defined in DCArgs in dyncall_args_riscv64.c */ + +/* save regs */ + + sd a0, 0(t1) + sd a1, 8(t1) + sd a2, 16(t1) + sd a3, 24(t1) + sd a4, 32(t1) + sd a5, 40(t1) + sd a6, 48(t1) + sd a7, 56(t1) + + fsd fa0, 64(t1) + fsd fa1, 72(t1) + fsd fa2, 80(t1) + fsd fa3, 88(t1) + fsd fa4, 96(t1) + fsd fa5, 104(t1) + fsd fa6, 112(t1) + fsd fa7, 120(t1) + + sd t0, 128(t1) /* sp=sp */ + sd zero, 136(t1) /* i=f=0 */ + +/* call handler/callback */ + + mv a0, t5 /* DCCallback* pcb */ + add a1, s0, 16 /* DCArgs* args */ + add a2, s0, 160 /* DCValue* result */ + ld a3, 40(t5) /* void* userdata */ + + ld t2, 32(t5) + jalr ra, 0(t2) + + and t3, a0, 255 + add t4, zero, 'f' /* single precition floats are sign extended on */ + beq t3, t4, .retf /* riscv with the D extension, handle specifically */ + add t4, zero, 'd' + beq t3, t4, .retd + +.reti: + ld a0, 160(s0) + j .ret +.retf: + flw fa0, 160(s0) + j .ret +.retd: + fld fa0, 160(s0) +.ret: + /* recover ra and s0 */ + ld ra, 0(sp) + ld s0, 8(sp) + + add sp, sp, 176 + ret +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dyncallback/dyncall_callback_riscv64.c Thu Mar 07 17:42:13 2024 +0100 @@ -0,0 +1,66 @@ +/* + + Package: dyncall + Library: dyncallback + File: dyncallback/dyncall_callback_riscv64.c + Description: Callback - Implementation for RISCV64 + License: + + Copyright (c) 2023 Jun Jeon <yjeon@netflix.com> + + Permission to use, copy, modify, and distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +*/ + + +#include "dyncall_callback.h" +#include "dyncall_alloc_wx.h" +#include "dyncall_thunk.h" + +/* Callback symbol. */ +extern void dcCallbackThunkEntry(); + +struct DCCallback /* off size */ +{ /* ----|----- */ + DCThunk thunk; /* 0 32 */ + DCCallbackHandler* handler; /* 32 8 */ + void* userdata; /* 40 8 */ +}; /* total 48 */ + /* aligned 48 */ + +void dcbInitCallback2(DCCallback* pcb, const DCsigchar* signature, DCCallbackHandler* handler, void* userdata, DCaggr *const * aggrs) +{ + pcb->handler = handler; + pcb->userdata = userdata; +} + +DCCallback* dcbNewCallback2(const DCsigchar* signature, DCCallbackHandler* handler, void* userdata, DCaggr *const * aggrs) +{ + int err; + DCCallback* pcb; + err = dcAllocWX(sizeof(DCCallback), (void**) &pcb); + if(err) + return NULL; + + dcbInitCallback2(pcb, signature, handler, userdata, aggrs); + dcbInitThunk(&pcb->thunk, dcCallbackThunkEntry); + + err = dcInitExecWX(pcb, sizeof(DCCallback)); + if(err) { + dcFreeWX(pcb, sizeof(DCCallback)); + return NULL; + } + + return pcb; +} +
--- a/dyncallback/dyncall_thunk.c Thu Mar 07 14:48:03 2024 +0100 +++ b/dyncallback/dyncall_thunk.c Thu Mar 07 17:42:13 2024 +0100 @@ -51,5 +51,7 @@ #include "dyncall_thunk_sparc64.c" #elif defined(DC__Arch_ARM64) #include "dyncall_thunk_arm64.c" +#elif defined(DC__Arch_RiscV64) +#include "dyncall_thunk_riscv64.c" #endif
--- a/dyncallback/dyncall_thunk.h Thu Mar 07 14:48:03 2024 +0100 +++ b/dyncallback/dyncall_thunk.h Thu Mar 07 17:42:13 2024 +0100 @@ -48,6 +48,7 @@ ** arm: r12 ** arm64: x9 ** mips: t4 + ** riscv: t5 ** **/ @@ -81,6 +82,8 @@ #include "dyncall_thunk_sparc64.h" #elif defined (DC__Arch_ARM64) #include "dyncall_thunk_arm64.h" +#elif defined (DC__Arch_RiscV64) +#include "dyncall_thunk_riscv64.h" #endif #ifdef __cplusplus
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dyncallback/dyncall_thunk_riscv64.c Thu Mar 07 17:42:13 2024 +0100 @@ -0,0 +1,38 @@ +/* + + Package: dyncall + Library: dyncallback + File: dyncallback/dyncall_thunk_riscv64.c + Description: Thunk - Implementation for RISCV64 + License: + + Copyright (c) 2023 Jun Jeon <yjeon@netflix.com> + + Permission to use, copy, modify, and distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +*/ + + + +#include "dyncall_thunk.h" + +void dcbInitThunk(DCThunk* p, void (*entry)()) +{ + /* t5 - thunk register */ + p->code[0] = 0x00000f17; /* auipc t5, 0 */ + p->code[1] = 0x010f3f83; /* ld t6, 16(t5) */ + p->code[2] = 0x000f8067; /* jr t6 (= jalr x0, 0(t6)) */ + p->code[3] = 0x00000013; /* nop (= addi x0, x0, 0) */ + p->entry = entry; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dyncallback/dyncall_thunk_riscv64.h Thu Mar 07 17:42:13 2024 +0100 @@ -0,0 +1,36 @@ +/* + + Package: dyncall + Library: dyncallback + File: dyncallback/dyncall_thunk_riscv64.h + Description: Thunk - Header for RISCV64 + License: + + Copyright (c) 2023 Jun Jeon <yjeon@netflix.com> + + Permission to use, copy, modify, and distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +*/ + +#ifndef DYNCALL_THUNK_RISCV64_H +#define DYNCALL_THUNK_RISCV64_H + +struct DCThunk_ /* off size */ +{ /* ----|---- */ + unsigned int code[4]; /* 0 16 */ + void (*entry)(); /* 16 8 */ + void* reserved; /* 24 8 */ +}; /* 32 total */ + +#endif /* DYNCALL_THUNK_RISCV64_H */ +