This is the mail archive of the libffi-discuss@sourceware.org mailing list for the libffi project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] libffi: Add support for Imagination Technologies Meta


This patch adds support for Imagination's Meta architecture.
The Meta Linux kernel port will be included in the Linux Kernel
v3.9

Signed-off-by: Markos Chandras <markos.chandras@imgtec.com>
---
 ChangeLog             |    9 ++
 Makefile.am           |    4 +
 README                |    1 +
 configure.ac          |    5 +
 src/metag/ffi.c       |  330 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/metag/ffitarget.h |   53 ++++++++
 src/metag/sysv.S      |  311 ++++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 713 insertions(+), 0 deletions(-)
 create mode 100644 src/metag/ffi.c
 create mode 100644 src/metag/ffitarget.h
 create mode 100644 src/metag/sysv.S

diff --git a/ChangeLog b/ChangeLog
index 92c1a15..7bfa7fe 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2013-03-13  Markos Chandras <markos.chandras@imgtec.com>
+
+	* configure.ac: Add support for Imagination Technologies Meta.
+	* Makefile.am: Likewise.
+	* README: Add Imagination Technologies Meta details.
+	* src/metag/ffi.c: New.
+	* src/metag/ffitarget.h: Likewise.
+	* src/metag/sysv.S: Likewise.
+
 2013-02-11  Anthony Green <green@moxielogic.com>
 
 	* configure.ac: Update release number to 3.0.12.
diff --git a/Makefile.am b/Makefile.am
index 8f1362a..cf5caa9 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -38,6 +38,7 @@ EXTRA_DIST = LICENSE ChangeLog.v1 ChangeLog.libgcj configure.host	\
 	src/frv/ffitarget.h src/dlmalloc.c src/tile/ffi.c		\
 	src/tile/ffitarget.h src/tile/tile.S libtool-version		\
 	src/xtensa/ffitarget.h src/xtensa/ffi.c src/xtensa/sysv.S	\
+	src/metag/ffi.c src/metag/ffitarget.h src/metag/sysv.S		\
 	 ChangeLog.libffi m4/libtool.m4 m4/lt~obsolete.m4		\
 	 m4/ltoptions.m4 m4/ltsugar.m4 m4/ltversion.m4			\
 	 m4/ltversion.m4 src/arm/gentramp.sh src/debug.c msvcc.sh	\
@@ -208,6 +209,9 @@ endif
 if XTENSA
 nodist_libffi_la_SOURCES += src/xtensa/sysv.S src/xtensa/ffi.c
 endif
+if METAG
+nodist_libffi_la_SOURCES += src/metag/sysv.S src/metag/ffi.c
+endif
 
 libffi_convenience_la_SOURCES = $(libffi_la_SOURCES)
 nodist_libffi_convenience_la_SOURCES = $(nodist_libffi_la_SOURCES)
diff --git a/README b/README
index 82b2104..0b1eec4 100644
--- a/README
+++ b/README
@@ -63,6 +63,7 @@ tested:
 | M68K            | FreeMiNT         | GCC                     |
 | M68K            | Linux	     | GCC                     |
 | M68K            | RTEMS            | GCC                     |
+| Meta            | Linux            | GCC                     |
 | MicroBlaze      | Linux            | GCC                     |
 | MIPS            | IRIX             | GCC                     |
 | MIPS            | Linux            | GCC                     |
diff --git a/configure.ac b/configure.ac
index 428d938..99a2f22 100644
--- a/configure.ac
+++ b/configure.ac
@@ -199,6 +199,10 @@ case "$host" in
 	TARGET=MOXIE; TARGETDIR=moxie
 	;;
 
+  metag-*-*)
+	TARGET=METAG; TARGETDIR=metag
+	;;
+
   mips-sgi-irix5.* | mips-sgi-irix6.* | mips*-*-rtems*)
 	TARGET=MIPS; TARGETDIR=mips
 	;;
@@ -278,6 +282,7 @@ AM_CONDITIONAL(IA64, test x$TARGET = xIA64)
 AM_CONDITIONAL(M32R, test x$TARGET = xM32R)
 AM_CONDITIONAL(M68K, test x$TARGET = xM68K)
 AM_CONDITIONAL(MICROBLAZE, test x$TARGET = xMICROBLAZE)
+AM_CONDITIONAL(METAG, test x$TARGET = xMETAG)
 AM_CONDITIONAL(MOXIE, test x$TARGET = xMOXIE)
 AM_CONDITIONAL(POWERPC, test x$TARGET = xPOWERPC)
 AM_CONDITIONAL(POWERPC_AIX, test x$TARGET = xPOWERPC_AIX)
diff --git a/src/metag/ffi.c b/src/metag/ffi.c
new file mode 100644
index 0000000..46b383e
--- /dev/null
+++ b/src/metag/ffi.c
@@ -0,0 +1,330 @@
+/* ----------------------------------------------------------------------
+  ffi.c - Copyright (c) 2013 Imagination Technologies
+
+  Meta 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 SIMON POSNJAK 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>
+
+#include <stdlib.h>
+
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+
+/*
+ * ffi_prep_args is called by the assembly routine once stack space has been
+ * allocated for the function's arguments
+ */
+
+unsigned int ffi_prep_args(char *stack, extended_cif *ecif)
+{
+	register unsigned int i;
+	register void **p_argv;
+	register char *argp;
+	register ffi_type **p_arg;
+
+	argp = stack;
+
+	/* Store return value */
+	if ( ecif->cif->flags == FFI_TYPE_STRUCT ) {
+		argp -= 4;
+		*(void **) argp = ecif->rvalue;
+	}
+
+	p_argv = ecif->avalue;
+
+	/* point to next location */
+	for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; (i != 0); i--, p_arg++, p_argv++)
+	{
+		size_t z;
+
+		/* Move argp to address of argument */
+		z = (*p_arg)->size;
+		argp -= z;
+
+		/* Align if necessary */
+		argp = (char *) ALIGN_DOWN(ALIGN_DOWN(argp, (*p_arg)->alignment), 4);
+
+		if (z < sizeof(int)) {
+			z = sizeof(int);
+			switch ((*p_arg)->type)
+			{
+			case FFI_TYPE_SINT8:
+				*(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
+				break;
+			case FFI_TYPE_UINT8:
+				*(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
+				break;
+			case FFI_TYPE_SINT16:
+				*(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
+				break;
+			case FFI_TYPE_UINT16:
+				*(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
+			case FFI_TYPE_STRUCT:
+				memcpy(argp, *p_argv, (*p_arg)->size);
+				break;
+			default:
+				FFI_ASSERT(0);
+			}
+		} else if ( z == sizeof(int)) {
+			*(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
+		} else {
+			memcpy(argp, *p_argv, z);
+		}
+	}
+
+	/* return the size of the arguments to be passed in registers,
+	   padded to an 8 byte boundary to preserve stack alignment */
+	return ALIGN(MIN(stack - argp, 6*4), 8);
+}
+
+/* Perform machine dependent cif processing */
+ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
+{
+	ffi_type **ptr;
+	unsigned i, bytes = 0;
+
+	for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) {
+		if ((*ptr)->size == 0)
+			return FFI_BAD_TYPEDEF;
+
+		/* Perform a sanity check on the argument type, do this
+		   check after the initialization.  */
+		FFI_ASSERT_VALID_TYPE(*ptr);
+
+		/* Add any padding if necessary */
+		if (((*ptr)->alignment - 1) & bytes)
+			bytes = ALIGN(bytes, (*ptr)->alignment);
+
+		bytes += ALIGN((*ptr)->size, 4);
+	}
+
+	/* Ensure arg space is aligned to an 8-byte boundary */
+	bytes = ALIGN(bytes, 8);
+
+	/* Make space for the return structure pointer */
+	if (cif->rtype->type == FFI_TYPE_STRUCT) {
+		bytes += sizeof(void*);
+
+		/* Ensure stack is aligned to an 8-byte boundary */
+		bytes = ALIGN(bytes, 8);
+	}
+
+	cif->bytes = bytes;
+
+	/* Set the return type flag */
+	switch (cif->rtype->type) {
+	case FFI_TYPE_VOID:
+	case FFI_TYPE_FLOAT:
+	case FFI_TYPE_DOUBLE:
+		cif->flags = (unsigned) cif->rtype->type;
+		break;
+	case FFI_TYPE_SINT64:
+	case FFI_TYPE_UINT64:
+		cif->flags = (unsigned) FFI_TYPE_SINT64;
+		break;
+	case FFI_TYPE_STRUCT:
+		/* Meta can store return values which are <= 64 bits */
+		if (cif->rtype->size <= 4)
+			/* Returned to D0Re0 as 32-bit value */
+			cif->flags = (unsigned)FFI_TYPE_INT;
+		else if ((cif->rtype->size > 4) && (cif->rtype->size <= 8))
+			/* Returned valued is stored to D1Re0|R0Re0 */
+			cif->flags = (unsigned)FFI_TYPE_DOUBLE;
+		else
+			/* value stored in memory */
+			cif->flags = (unsigned)FFI_TYPE_STRUCT;
+		break;
+	default:
+		cif->flags = (unsigned)FFI_TYPE_INT;
+		break;
+	}
+	return FFI_OK;
+}
+
+extern void ffi_call_SYSV(void (*fn)(void), extended_cif *, unsigned, unsigned, double *);
+
+/*
+ * Exported in API. Entry point
+ * cif -> ffi_cif object
+ * fn -> function pointer
+ * rvalue -> pointer to return value
+ * avalue -> vector of void * pointers pointing to memory locations holding the
+ * arguments
+ */
+void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
+{
+	extended_cif ecif;
+
+	int small_struct = (((cif->flags == FFI_TYPE_INT) || (cif->flags == FFI_TYPE_DOUBLE)) && (cif->rtype->type == FFI_TYPE_STRUCT));
+	ecif.cif = cif;
+	ecif.avalue = avalue;
+
+	double temp;
+
+	/*
+	 * If the return value is a struct and we don't have a return value address
+	 * then we need to make one
+	 */
+
+	if ((rvalue == NULL ) && (cif->flags == FFI_TYPE_STRUCT))
+		ecif.rvalue = alloca(cif->rtype->size);
+	else if (small_struct)
+		ecif.rvalue = &temp;
+	else
+		ecif.rvalue = rvalue;
+
+	switch (cif->abi) {
+	case FFI_SYSV:
+		ffi_call_SYSV(fn, &ecif, cif->bytes, cif->flags, ecif.rvalue);
+		break;
+	default:
+		FFI_ASSERT(0);
+		break;
+	}
+
+	if (small_struct)
+		memcpy (rvalue, &temp, cif->rtype->size);
+}
+
+/* private members */
+
+static void ffi_prep_incoming_args_SYSV (char *, void **, void **,
+	ffi_cif*, float *);
+
+void ffi_closure_SYSV (ffi_closure *);
+
+/* Do NOT change that without changing the FFI_TRAMPOLINE_SIZE */
+extern unsigned int ffi_metag_trampoline[10]; /* 10 instructions */
+
+/* end of private members */
+
+/*
+ * __tramp: trampoline memory location
+ * __fun: assembly routine
+ * __ctx: memory location for wrapper
+ *
+ * At this point, tramp[0] == __ctx !
+ */
+void ffi_init_trampoline(unsigned char *__tramp, unsigned int __fun, unsigned int __ctx) {
+	memcpy (__tramp, ffi_metag_trampoline, sizeof(ffi_metag_trampoline));
+	*(unsigned int*) &__tramp[40] = __ctx;
+	*(unsigned int*) &__tramp[44] = __fun;
+	/* This will flush the instruction cache */
+	__builtin_meta2_cachewd(&__tramp[0], 1);
+	__builtin_meta2_cachewd(&__tramp[47], 1);
+}
+
+
+
+/* the cif must already be prepared */
+
+ffi_status
+ffi_prep_closure_loc (ffi_closure *closure,
+	ffi_cif* cif,
+	void (*fun)(ffi_cif*,void*,void**,void*),
+	void *user_data,
+	void *codeloc)
+{
+	void (*closure_func)(ffi_closure*) = NULL;
+
+	if (cif->abi == FFI_SYSV)
+		closure_func = &ffi_closure_SYSV;
+	else
+		return FFI_BAD_ABI;
+
+	ffi_init_trampoline(
+		(unsigned char*)&closure->tramp[0],
+		(unsigned int)closure_func,
+		(unsigned int)codeloc);
+
+	closure->cif = cif;
+	closure->user_data = user_data;
+	closure->fun = fun;
+
+	return FFI_OK;
+}
+
+
+/* This function is jumped to by the trampoline */
+unsigned int ffi_closure_SYSV_inner (closure, respp, args, vfp_args)
+	ffi_closure *closure;
+	void **respp;
+	void *args;
+	void *vfp_args;
+{
+	ffi_cif *cif;
+	void **arg_area;
+
+	cif = closure->cif;
+	arg_area = (void**) alloca (cif->nargs * sizeof (void*));
+
+	/*
+	 * This call will initialize ARG_AREA, such that each
+	 * element in that array points to the corresponding
+	 * value on the stack; and if the function returns
+	 * a structure, it will re-set RESP to point to the
+	 * structure return address.
+	 */
+	ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif, vfp_args);
+
+	(closure->fun) ( cif, *respp, arg_area, closure->user_data);
+
+	return cif->flags;
+}
+
+static void ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
+	void **avalue, ffi_cif *cif,
+	float *vfp_stack)
+{
+	register unsigned int i;
+	register void **p_argv;
+	register char *argp;
+	register ffi_type **p_arg;
+
+	/* stack points to original arguments */
+	argp = stack;
+
+	/* Store return value */
+	if ( cif->flags == FFI_TYPE_STRUCT ) {
+		argp -= 4;
+		*rvalue = *(void **) argp;
+	}
+
+	p_argv = avalue;
+
+	for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++) {
+		size_t z;
+		size_t alignment;
+
+		alignment = (*p_arg)->alignment;
+		if (alignment < 4)
+			alignment = 4;
+		if ((alignment - 1) & (unsigned)argp)
+			argp = (char *) ALIGN(argp, alignment);
+
+		z = (*p_arg)->size;
+		*p_argv = (void*) argp;
+		p_argv++;
+		argp -= z;
+	}
+	return;
+}
diff --git a/src/metag/ffitarget.h b/src/metag/ffitarget.h
new file mode 100644
index 0000000..7b9dbeb
--- /dev/null
+++ b/src/metag/ffitarget.h
@@ -0,0 +1,53 @@
+/* -----------------------------------------------------------------*-C-*-
+   ffitarget.h - Copyright (c) 2013 Imagination Technologies Ltd.
+   Target configuration macros for Meta
+
+   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
+
+#ifndef LIBFFI_ASM
+typedef unsigned long          ffi_arg;
+typedef signed long            ffi_sarg;
+
+typedef enum ffi_abi {
+  FFI_FIRST_ABI = 0,
+  FFI_SYSV,
+  FFI_DEFAULT_ABI = FFI_SYSV,
+  FFI_LAST_ABI = FFI_DEFAULT_ABI + 1,
+} ffi_abi;
+#endif
+
+/* ---- Definitions for closures ----------------------------------------- */
+
+#define FFI_CLOSURES 1
+#define FFI_TRAMPOLINE_SIZE 48
+#define FFI_NATIVE_RAW_API 0
+
+#endif
+
diff --git a/src/metag/sysv.S b/src/metag/sysv.S
new file mode 100644
index 0000000..b4b2a3b
--- /dev/null
+++ b/src/metag/sysv.S
@@ -0,0 +1,311 @@
+/* -----------------------------------------------------------------------
+   sysv.S - Copyright (c) 2013 Imagination Technologies Ltd.
+
+   Meta 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>
+#ifdef HAVE_MACHINE_ASM_H
+#include <machine/asm.h>
+#else
+#ifdef __USER_LABEL_PREFIX__
+#define CONCAT1(a, b) CONCAT2(a, b)
+#define CONCAT2(a, b) a ## b
+
+/* Use the right prefix for global labels. */
+#define CNAME(x) CONCAT1 (__USER_LABEL_PREFIX__, x)
+#else
+#define CNAME(x) x
+#endif
+#define ENTRY(x) .globl CNAME(x); .type CNAME(x), %function; CNAME(x):
+#endif
+
+#ifdef __ELF__
+#define LSYM(x) .x
+#else
+#define LSYM(x) x
+#endif
+
+.macro call_reg x=
+	.text
+	.balign 4
+	mov D1RtP, \x
+	swap D1RtP, PC
+.endm
+
+! Save register arguments
+.macro SAVE_ARGS
+	.text
+	.balign 4
+	setl	[A0StP++], D0Ar6, D1Ar5
+	setl	[A0StP++], D0Ar4, D1Ar3
+	setl	[A0StP++], D0Ar2, D1Ar1
+.endm
+
+! Save retrun, frame pointer and other regs
+.macro SAVE_REGS regs=
+	.text
+	.balign 4
+	setl	[A0StP++], D0FrT, D1RtP
+	! Needs to be a pair of regs
+	.ifnc "\regs",""
+	setl	[A0StP++], \regs
+	.endif
+.endm
+
+! Declare a global function
+.macro METAG_FUNC_START name
+	.text
+	.balign 4
+	ENTRY(\name)
+.endm
+
+! Return registers from the stack. Reverse SAVE_REGS operation
+.macro RET_REGS regs=, cond=
+	.ifnc "\regs", ""
+	getl	\regs, [--A0StP]
+	.endif
+	getl	D0FrT, D1RtP, [--A0StP]
+.endm
+
+! Return arguments
+.macro RET_ARGS
+	getl	D0Ar2, D1Ar1, [--A0StP]
+	getl	D0Ar4, D1Ar3, [--A0StP]
+	getl	D0Ar6, D1Ar5, [--A0StP]
+.endm
+
+
+	! D1Ar1:	fn
+	! D0Ar2:	&ecif
+	! D1Ar3:	cif->bytes
+	! D0Ar4:	fig->flags
+	! D1Ar5:	ecif.rvalue
+
+	! This assumes we are using GNU as
+METAG_FUNC_START ffi_call_SYSV
+	! Save argument registers
+
+	SAVE_ARGS
+
+	! new frame
+	mov	D0FrT, A0FrP
+	add     A0FrP, A0StP, #0
+
+	! Preserve the old frame pointer
+	SAVE_REGS "D1.5, D0.5"
+
+	! Make room for new args. cifs->bytes is the total space for input
+	! and return arguments
+
+	add	A0StP, A0StP, D1Ar3
+
+	! Preserve cifs->bytes & fn
+	mov	D0.5, D1Ar3
+	mov	D1.5, D1Ar1
+
+	! Place all of the ffi_prep_args in position
+	mov	D1Ar1, A0StP
+
+	! Call ffi_prep_args(stack, &ecif)
+#ifdef __PIC__
+	callr  D1RtP, CNAME(ffi_prep_args@PLT)
+#else
+	callr  D1RtP, CNAME(ffi_prep_args)
+#endif
+
+	! Restore fn pointer
+
+	! The foreign stack should look like this
+	! XXXXX XXXXXX <--- stack pointer
+	! FnArgN rvalue
+	! FnArgN+2 FnArgN+1
+	! FnArgN+4 FnArgN+3
+	! ....
+	!
+
+	! A0StP now points to the first (or return) argument + 4
+
+	! Preserve cif->bytes
+	getl	D0Ar2, D1Ar1, [--A0StP]
+	getl	D0Ar4, D1Ar3, [--A0StP]
+	getl	D0Ar6, D1Ar5, [--A0StP]
+
+	! Place A0StP to the first argument again
+	add	A0StP, A0StP, #24 ! That's because we loaded 6 regs x 4 byte each
+
+	! A0FrP points to the initial stack without the reserved space for the
+	! cifs->bytes, whilst A0StP points to the stack after the space allocation
+
+	! fn was the first argument of ffi_call_SYSV.
+	! The stack at this point looks like this:
+	!
+	! A0StP(on entry to _SYSV) ->	Arg6	Arg5     | low
+	!				Arg4	Arg3     |
+	! 				Arg2	Arg1     |
+	! A0FrP ---->			D0FrtP	D1RtP    |
+	!				D1.5	D0.5	 |
+	! A0StP(bf prep_args) ->	FnArgn	FnArgn-1 |
+	!				FnArgn-2FnArgn-3 |
+	!				................ | <= cifs->bytes
+	!				FnArg4  FnArg3	 |
+	! A0StP (prv_A0StP+cifs->bytes) FnArg2  FnArg1   | high
+	!
+	! fn was in Arg1 so it's located in in A0FrP+#-0xC
+	!
+
+	! D0Re0 contains the size of arguments stored in registers
+	sub	A0StP, A0StP, D0Re0
+
+	! Arg1 is the function pointer for the foreign call. This has been
+	! preserved in D1.5
+
+	! Time to call (fn). Arguments should be like this:
+	! Arg1-Arg6 are loaded to regs
+	! The rest of the arguments are stored in stack pointed by A0StP
+
+	call_reg D1.5
+
+	! Reset stack.
+
+	mov	A0StP, A0FrP
+
+	! Load Arg1 with the pointer to storage for the return type
+	! This was stored in Arg5
+
+	getd	D1Ar1, [A0FrP+#-20]
+
+	! Load D0Ar2 with the return type code. This was stored in Arg4 (flags)
+
+	getd	D0Ar2, [A0FrP+#-16]
+
+	! We are ready to start processing the return value
+	! D0Re0 (and D1Re0) hold the return value
+
+	! If the return value is NULL, assume no return value
+	cmp	D1Ar1, #0
+	beq	LSYM(Lepilogue)
+
+	! return INT
+	cmp		D0Ar2, #FFI_TYPE_INT
+	! Sadly, there is no setd{cc} instruction so we need to workaround that
+	bne	.INT64
+	setd	[D1Ar1], D0Re0
+	b	LSYM(Lepilogue)
+
+	! return INT64
+.INT64:
+	cmp	D0Ar2, #FFI_TYPE_SINT64
+	setleq	[D1Ar1], D0Re0, D1Re0
+
+	! return DOUBLE
+	cmp	D0Ar2, #FFI_TYPE_DOUBLE
+	setl	[D1AR1++], D0Re0, D1Re0
+
+LSYM(Lepilogue):
+	! At this point, the stack pointer points right after the argument
+	! saved area. We need to restore 4 regs, therefore we need to move
+	! 16 bytes ahead.
+	add     A0StP, A0StP, #16
+	RET_REGS "D1.5, D0.5"
+	RET_ARGS
+	getd	D0Re0, [A0StP]
+	mov     A0FrP, D0FrT
+	swap	D1RtP, PC
+
+.ffi_call_SYSV_end:
+       .size   CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV)
+
+
+/*
+	(called by ffi_metag_trampoline)
+	void ffi_closure_SYSV (ffi_closure*)
+
+	(called by ffi_closure_SYSV)
+	unsigned int FFI_HIDDEN
+	ffi_closure_SYSV_inner (closure,respp, args)
+		ffi_closure *closure;
+		void **respp;
+		void *args;
+*/
+
+METAG_FUNC_START ffi_closure_SYSV
+	! We assume that D1Ar1 holds the address of the
+	! ffi_closure struct. We will use that to fetch the
+	! arguments. The stack pointer points to an empty space
+	! and it is ready to store more data.
+
+	! D1Ar1 is ready
+	! Allocate stack space for return value
+	add A0StP, A0StP, #8
+	! Store it to D0Ar2
+	sub D0Ar2, A0StP, #8
+
+	sub D1Ar3, A0FrP, #4
+
+	! D1Ar3 contains the address of the original D1Ar1 argument
+	! We need to subtract #4 later on
+
+	! Preverve D0Ar2
+	mov D0.5, D0Ar2
+
+#ifdef __PIC__
+	callr D1RtP, CNAME(ffi_closure_SYSV_inner@PLT)
+#else
+	callr D1RtP, CNAME(ffi_closure_SYSV_inner)
+#endif
+
+	! Check the return value and store it to D0.5
+	cmp D0Re0, #FFI_TYPE_INT
+	beq .Lretint
+	cmp D0Re0, #FFI_TYPE_DOUBLE
+	beq .Lretdouble
+.Lclosure_epilogue:
+	sub A0StP, A0StP, #8
+	RET_REGS "D1.5, D0.5"
+	RET_ARGS
+	swap	D1RtP, PC
+
+.Lretint:
+	setd [D0.5], D0Re0
+	b .Lclosure_epilogue
+.Lretdouble:
+	setl [D0.5++], D0Re0, D1Re0
+	b .Lclosure_epilogue
+.ffi_closure_SYSV_end:
+.size CNAME(ffi_closure_SYSV),.ffi_closure_SYSV_end-CNAME(ffi_closure_SYSV)
+
+
+ENTRY(ffi_metag_trampoline)
+	SAVE_ARGS
+	! New frame
+	mov A0FrP, A0StP
+	SAVE_REGS "D1.5, D0.5"
+	mov D0.5, PC
+	! Load D1Ar1 the value of ffi_metag_trampoline
+	getd D1Ar1, [D0.5 + #8]
+	! Jump to ffi_closure_SYSV
+	getd PC, [D0.5 + #12]
-- 
1.7.1



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]