summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Macke <sebastian@macke.de>2014-09-27 00:19:15 +0000
committerSebastian Macke <sebastian@macke.de>2014-09-27 00:56:56 +0000
commit0f316ab7c11b8315a838a6ae4645d36ff2c46f4c (patch)
tree68fb61beebdb68338c65cf17e58692a73b979645
parent6695983d2f0857caab220862de12f3f94a55bcf6 (diff)
downloadlibffi-0f316ab7c11b8315a838a6ae4645d36ff2c46f4c.tar.gz
Add OpenRISC support
This patch adds support for the OpenRISC architecture. (http://opencores.org/or1k/Main_Page) This patch has been tested under Linux with QEMU-user emulation support. - 32 Bit - big endian - delayed instructions This is the only available configuration under Linux. The description of the ABI can be found on the official website. Is passes the testsuite except of the unwindtest_ffi_call.cc testcase, which seems to be a problem of gcc and not libffi. Some testcases of the gcc testsuite still fail. Signed-off-by: Sebastian Macke <sebastian@macke.de>
-rw-r--r--Makefile.am4
-rw-r--r--README1
-rw-r--r--configure.ac5
-rw-r--r--src/or1k/ffi.c328
-rw-r--r--src/or1k/ffitarget.h58
-rw-r--r--src/or1k/sysv.S107
6 files changed, 503 insertions, 0 deletions
diff --git a/Makefile.am b/Makefile.am
index 1dcdc81..0e40451 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -24,6 +24,7 @@ EXTRA_DIST = LICENSE ChangeLog.v1 ChangeLog.libgcj \
src/microblaze/ffi.c src/microblaze/sysv.S \
src/microblaze/ffitarget.h \
src/nios2/ffi.c src/nios2/ffitarget.h src/nios2/sysv.S \
+ src/or1k/ffi.c src/or1k/ffitarget.h src/or1k/sysv.S \
src/powerpc/ffi.c src/powerpc/ffi_powerpc.h \
src/powerpc/ffi_sysv.c src/powerpc/ffi_linux64.c \
src/powerpc/sysv.S src/powerpc/linux64.S \
@@ -169,6 +170,9 @@ endif
if NIOS2
nodist_libffi_la_SOURCES += src/nios2/sysv.S src/nios2/ffi.c
endif
+if OR1K
+nodist_libffi_la_SOURCES += src/or1k/sysv.S src/or1k/ffi.c
+endif
if POWERPC
nodist_libffi_la_SOURCES += src/powerpc/ffi.c src/powerpc/ffi_sysv.c src/powerpc/ffi_linux64.c src/powerpc/sysv.S src/powerpc/ppc_closure.S src/powerpc/linux64.S src/powerpc/linux64_closure.S
endif
diff --git a/README b/README
index 765e8d7..44c070a 100644
--- a/README
+++ b/README
@@ -74,6 +74,7 @@ tested:
| MIPS64 | Linux | GCC |
| Moxie | Bare metal | GCC |
| Nios II | Linux | GCC |
+| OpenRISC | Linux | GCC |
| PowerPC 32-bit | AIX | IBM XL C |
| PowerPC 64-bit | AIX | IBM XL C |
| PowerPC | AMIGA | GCC |
diff --git a/configure.ac b/configure.ac
index 4c3922f..4a44bff 100644
--- a/configure.ac
+++ b/configure.ac
@@ -230,6 +230,10 @@ case "$host" in
TARGET=NIOS2; TARGETDIR=nios2
;;
+ or1k*-linux*)
+ TARGET=OR1K; TARGETDIR=or1k
+ ;;
+
powerpc*-*-linux* | powerpc-*-sysv*)
TARGET=POWERPC; TARGETDIR=powerpc
HAVE_LONG_DOUBLE_VARIANT=1
@@ -312,6 +316,7 @@ AM_CONDITIONAL(MICROBLAZE, test x$TARGET = xMICROBLAZE)
AM_CONDITIONAL(METAG, test x$TARGET = xMETAG)
AM_CONDITIONAL(MOXIE, test x$TARGET = xMOXIE)
AM_CONDITIONAL(NIOS2, test x$TARGET = xNIOS2)
+AM_CONDITIONAL(OR1K, test x$TARGET = xOR1K)
AM_CONDITIONAL(POWERPC, test x$TARGET = xPOWERPC)
AM_CONDITIONAL(POWERPC_AIX, test x$TARGET = xPOWERPC_AIX)
AM_CONDITIONAL(POWERPC_DARWIN, test x$TARGET = xPOWERPC_DARWIN)
diff --git a/src/or1k/ffi.c b/src/or1k/ffi.c
new file mode 100644
index 0000000..2bad938
--- /dev/null
+++ b/src/or1k/ffi.c
@@ -0,0 +1,328 @@
+/* -----------------------------------------------------------------------
+ ffi.c - Copyright (c) 2014 Sebastian Macke <sebastian@macke.de>
+
+ OpenRISC Foreign Function Interface
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ ``Software''), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+ ----------------------------------------------------------------------- */
+
+#include <ffi.h>
+#include "ffi_common.h"
+
+/* ffi_prep_args is called by the assembly routine once stack space
+ has been allocated for the function's arguments */
+
+void* ffi_prep_args(char *stack, extended_cif *ecif)
+{
+ char *stacktemp = stack;
+ int i, s;
+ ffi_type **arg;
+ int count = 0;
+ int nfixedargs;
+
+ nfixedargs = ecif->cif->nfixedargs;
+ arg = ecif->cif->arg_types;
+ void **argv = ecif->avalue;
+
+ if (ecif->cif->rtype->type == FFI_TYPE_STRUCT)
+ {
+ *(void **) stack = ecif->rvalue;
+ stack += 4;
+ count = 4;
+ }
+ for(i=0; i<ecif->cif->nargs; i++)
+ {
+
+ /* variadic args are saved on stack */
+ if ((nfixedargs == 0) && (count < 24))
+ {
+ count = 24;
+ stack = stacktemp + 24;
+ }
+ nfixedargs--;
+
+ s = 4;
+ switch((*arg)->type)
+ {
+ case FFI_TYPE_STRUCT:
+ *(void **)stack = *argv;
+ break;
+
+ case FFI_TYPE_SINT8:
+ *(signed int *) stack = (signed int)*(SINT8 *)(* argv);
+ break;
+
+ case FFI_TYPE_UINT8:
+ *(unsigned int *) stack = (unsigned int)*(UINT8 *)(* argv);
+ break;
+
+ case FFI_TYPE_SINT16:
+ *(signed int *) stack = (signed int)*(SINT16 *)(* argv);
+ break;
+
+ case FFI_TYPE_UINT16:
+ *(unsigned int *) stack = (unsigned int)*(UINT16 *)(* argv);
+ break;
+
+ case FFI_TYPE_SINT32:
+ case FFI_TYPE_UINT32:
+ case FFI_TYPE_FLOAT:
+ case FFI_TYPE_POINTER:
+ *(int *)stack = *(int*)(*argv);
+ break;
+
+ default: /* 8 byte types */
+ if (count == 20) /* never split arguments */
+ {
+ stack += 4;
+ count += 4;
+ }
+ s = (*arg)->size;
+ memcpy(stack, *argv, s);
+ break;
+ }
+
+ stack += s;
+ count += s;
+ argv++;
+ arg++;
+ }
+ return stacktemp + ((count>24)?24:0);
+}
+
+extern void ffi_call_SYSV(unsigned,
+ extended_cif *,
+ void *(*)(int *, extended_cif *),
+ unsigned *,
+ void (*fn)(void),
+ unsigned);
+
+
+void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
+{
+ int i;
+ int size;
+ ffi_type **arg;
+
+ /* Calculate size to allocate on stack */
+
+ for(i = 0, arg = cif->arg_types, size=0; i < cif->nargs; i++, arg++)
+ {
+ if ((*arg)->type == FFI_TYPE_STRUCT)
+ size += 4;
+ else
+ if ((*arg)->size <= 4)
+ size += 4;
+ else
+ size += 8;
+ }
+
+ /* for variadic functions more space is needed on the stack */
+ if (cif->nargs != cif->nfixedargs)
+ size += 24;
+
+ if (cif->rtype->type == FFI_TYPE_STRUCT)
+ size += 4;
+
+
+ extended_cif ecif;
+ ecif.cif = cif;
+ ecif.avalue = avalue;
+ ecif.rvalue = rvalue;
+
+ switch (cif->abi)
+ {
+ case FFI_SYSV:
+ ffi_call_SYSV(size, &ecif, ffi_prep_args, rvalue, fn, cif->flags);
+ break;
+ default:
+ FFI_ASSERT(0);
+ break;
+ }
+}
+
+
+void ffi_closure_SYSV(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7, unsigned long r8)
+{
+ register int *sp __asm__ ("r17");
+ register int *r13 __asm__ ("r13");
+
+ ffi_closure* closure = (ffi_closure*) r13;
+ char *stack_args = sp;
+
+ /* Lay the register arguments down in a continuous chunk of memory. */
+ unsigned register_args[6] =
+ { r3, r4, r5, r6, r7, r8 };
+
+ /* Pointer to a struct return value. */
+ void *struct_rvalue = (void *) r3;
+
+ ffi_cif *cif = closure->cif;
+ ffi_type **arg_types = cif->arg_types;
+ void **avalue = alloca (cif->nargs * sizeof(void *));
+ char *ptr = (char *) register_args;
+ int count = 0;
+ int nfixedargs = cif->nfixedargs;
+ int i;
+
+ /* preserve struct type return pointer passing */
+
+ if ((cif->rtype != NULL) && (cif->rtype->type == FFI_TYPE_STRUCT))
+ {
+ ptr += 4;
+ count = 4;
+ }
+
+ /* Find the address of each argument. */
+ for (i = 0; i < cif->nargs; i++)
+ {
+
+ /* variadic args are saved on stack */
+ if ((nfixedargs == 0) && (count < 24))
+ {
+ ptr = stack_args;
+ count = 24;
+ }
+ nfixedargs--;
+
+ switch (arg_types[i]->type)
+ {
+ case FFI_TYPE_SINT8:
+ case FFI_TYPE_UINT8:
+ avalue[i] = ptr + 3;
+ break;
+
+ case FFI_TYPE_SINT16:
+ case FFI_TYPE_UINT16:
+ avalue[i] = ptr + 2;
+ break;
+
+ case FFI_TYPE_SINT32:
+ case FFI_TYPE_UINT32:
+ case FFI_TYPE_FLOAT:
+ case FFI_TYPE_POINTER:
+ avalue[i] = ptr;
+ break;
+
+ case FFI_TYPE_STRUCT:
+ avalue[i] = *(void**)ptr;
+ break;
+
+ default:
+ /* 8-byte values */
+
+ /* arguments are never splitted */
+ if (ptr == &register_args[5])
+ ptr = stack_args;
+ avalue[i] = ptr;
+ ptr += 4;
+ count += 4;
+ break;
+ }
+ ptr += 4;
+ count += 4;
+
+ /* If we've handled more arguments than fit in registers,
+ start looking at the those passed on the stack. */
+
+ if (count == 24)
+ ptr = stack_args;
+ }
+
+ if (cif->rtype && (cif->rtype->type == FFI_TYPE_STRUCT))
+ {
+ (closure->fun) (cif, struct_rvalue, avalue, closure->user_data);
+ } else
+ {
+ long long rvalue;
+ (closure->fun) (cif, &rvalue, avalue, closure->user_data);
+ if (cif->rtype)
+ asm ("l.ori r12, %0, 0x0\n l.lwz r11, 0(r12)\n l.lwz r12, 4(r12)" : : "r" (&rvalue));
+ }
+}
+
+
+ffi_status
+ffi_prep_closure_loc (ffi_closure* closure,
+ ffi_cif* cif,
+ void (*fun)(ffi_cif*,void*,void**,void*),
+ void *user_data,
+ void *codeloc)
+{
+ unsigned short *tramp = (unsigned short *) closure->tramp;
+ unsigned long fn = (unsigned long) ffi_closure_SYSV;
+ unsigned long cls = (unsigned long) codeloc;
+
+ if (cif->abi != FFI_SYSV)
+ return FFI_BAD_ABI;
+
+ closure->cif = cif;
+ closure->user_data = user_data;
+ closure->fun = fun;
+
+ /* write pointers to temporary registers */
+ tramp[0] = (0x6 << 10) | (13 << 5); /* l.movhi r13, ... */
+ tramp[1] = cls >> 16;
+ tramp[2] = (0x2a << 10) | (13 << 5) | 13; /* l.ori r13, r13, ... */
+ tramp[3] = cls & 0xFFFF;
+
+ tramp[4] = (0x6 << 10) | (15 << 5); /* l.movhi r15, ... */
+ tramp[5] = fn >> 16;
+ tramp[6] = (0x2a << 10) | (15 << 5) | 15; /* l.ori r15, r15 ... */
+ tramp[7] = fn & 0xFFFF;
+
+ tramp[8] = (0x11 << 10); /* l.jr r15 */
+ tramp[9] = 15 << 11;
+
+ tramp[10] = (0x2a << 10) | (17 << 5) | 1; /* l.ori r17, r1, ... */
+ tramp[11] = 0x0;
+
+ return FFI_OK;
+}
+
+
+ffi_status ffi_prep_cif_machdep (ffi_cif *cif)
+{
+ cif->flags = 0;
+
+ /* structures are returned as pointers */
+ if (cif->rtype->type == FFI_TYPE_STRUCT)
+ cif->flags = FFI_TYPE_STRUCT;
+ else
+ if (cif->rtype->size > 4)
+ cif->flags = FFI_TYPE_UINT64;
+
+ cif->nfixedargs = cif->nargs;
+
+ return FFI_OK;
+}
+
+
+ffi_status ffi_prep_cif_machdep_var(ffi_cif *cif,
+ unsigned int nfixedargs, unsigned int ntotalargs)
+{
+ ffi_status status;
+
+ status = ffi_prep_cif_machdep (cif);
+ cif->nfixedargs = nfixedargs;
+ return status;
+}
diff --git a/src/or1k/ffitarget.h b/src/or1k/ffitarget.h
new file mode 100644
index 0000000..e55da28
--- /dev/null
+++ b/src/or1k/ffitarget.h
@@ -0,0 +1,58 @@
+/* -----------------------------------------------------------------------
+ ffitarget.h - Copyright (c) 2014 Sebastian Macke <sebastian@macke.de>
+
+ OpenRISC Target configuration macros
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ ``Software''), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+ ----------------------------------------------------------------------- */
+
+#ifndef LIBFFI_TARGET_H
+#define LIBFFI_TARGET_H
+
+#ifndef LIBFFI_H
+#error "Please do not include ffitarget.h directly into your source. Use ffi.h instead."
+#endif
+
+/* ---- System specific configurations ----------------------------------- */
+
+#ifndef LIBFFI_ASM
+typedef unsigned long ffi_arg;
+typedef signed long ffi_sarg;
+
+typedef enum ffi_abi {
+ FFI_FIRST_ABI = 0,
+ FFI_SYSV,
+ FFI_LAST_ABI,
+ FFI_DEFAULT_ABI = FFI_SYSV
+} ffi_abi;
+#endif
+
+/* ---- Definitions for closures ----------------------------------------- */
+
+#define FFI_CLOSURES 1
+#define FFI_NATIVE_RAW_API 0
+#define FFI_TRAMPOLINE_SIZE (24)
+
+#define FFI_TARGET_SPECIFIC_VARIADIC 1
+#define FFI_EXTRA_CIF_FIELDS unsigned nfixedargs;
+
+#endif
+
diff --git a/src/or1k/sysv.S b/src/or1k/sysv.S
new file mode 100644
index 0000000..df6570b
--- /dev/null
+++ b/src/or1k/sysv.S
@@ -0,0 +1,107 @@
+/* -----------------------------------------------------------------------
+ sysv.S - Copyright (c) 2014 Sebastian Macke <sebastian@macke.de>
+
+ OpenRISC Foreign Function Interface
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ ``Software''), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+ ----------------------------------------------------------------------- */
+
+#define LIBFFI_ASM
+#include <fficonfig.h>
+#include <ffi.h>
+
+.text
+ .globl ffi_call_SYSV
+ .type ffi_call_SYSV, @function
+/*
+ r3: size to allocate on stack
+ r4: extended cif structure
+ r5: function pointer ffi_prep_args
+ r6: ret address
+ r7: function to call
+ r8: flag for return type
+*/
+
+ffi_call_SYSV:
+ /* Store registers used on stack */
+ l.sw -4(r1), r9 /* return address */
+ l.sw -8(r1), r1 /* stack address */
+ l.sw -12(r1), r14 /* callee saved registers */
+ l.sw -16(r1), r16
+ l.sw -20(r1), r18
+ l.sw -24(r1), r20
+
+ l.ori r14, r1, 0x0 /* save stack pointer */
+ l.addi r1, r1, -24
+
+ l.ori r16, r7, 0x0 /* save function address */
+ l.ori r18, r6, 0x0 /* save ret address */
+ l.ori r20, r8, 0x0 /* save flag */
+
+ l.sub r1, r1, r3 /* reserve space on stack */
+
+ /* Call ffi_prep_args */
+ l.ori r3, r1, 0x0 /* first argument stack address, second already ecif */
+ l.jalr r5
+ l.nop
+
+ /* Load register arguments and call*/
+
+ l.lwz r3, 0(r1)
+ l.lwz r4, 4(r1)
+ l.lwz r5, 8(r1)
+ l.lwz r6, 12(r1)
+ l.lwz r7, 16(r1)
+ l.lwz r8, 20(r1)
+ l.ori r1, r11, 0x0 /* new stack pointer */
+ l.jalr r16
+ l.nop
+
+ /* handle return values */
+
+ l.sfeqi r20, FFI_TYPE_STRUCT
+ l.bf ret /* structs don't return an rvalue */
+ l.nop
+
+ /* copy ret address */
+
+ l.sfeqi r20, FFI_TYPE_UINT64
+ l.bnf four_byte_ret /* 8 byte value is returned */
+ l.nop
+
+ l.sw 4(r18), r12
+
+four_byte_ret:
+ l.sw 0(r18), r11
+
+ret:
+ /* return */
+ l.ori r1, r14, 0x0 /* reset stack pointer */
+ l.lwz r9, -4(r1)
+ l.lwz r1, -8(r1)
+ l.lwz r14, -12(r1)
+ l.lwz r16, -16(r1)
+ l.lwz r18, -20(r1)
+ l.lwz r20, -24(r1)
+ l.jr r9
+ l.nop
+
+.size ffi_call_SYSV, .-ffi_call_SYSV