$OpenBSD: patch-src_m68k_ffi_c,v 1.2 2013/07/15 19:01:56 miod Exp $

Match the calling convention used by NetBSD and OpenBSD on m68k/ELF, which
differs from Linux/ELF: structs are always passed on the stack, functions
returning structs receive the struct pointer in %a0 instead of %a1.

Add an OpenBSD-specific function to flush the instruction cache after
building closure trampolines.

--- src/m68k/ffi.c.orig	Tue Dec 29 15:22:26 2009
+++ src/m68k/ffi.c	Mon Jul 15 18:53:57 2013
@@ -9,8 +9,12 @@
 
 #include <stdlib.h>
 #include <unistd.h>
+#ifdef __OpenBSD__
+void ffi_sync_icache(void *, unsigned int);
+#else
 #include <sys/syscall.h>
 #include <asm/cachectl.h>
+#endif
 
 void ffi_call_SYSV (extended_cif *,
 		    unsigned, unsigned,
@@ -103,6 +107,8 @@ ffi_prep_args (void *stack, extended_cif *ecif)
 #define CIF_FLAGS_POINTER	32
 #define CIF_FLAGS_STRUCT1	64
 #define CIF_FLAGS_STRUCT2	128
+#define CIF_FLAGS_SINT8		256
+#define CIF_FLAGS_SINT16	512
 
 /* Perform machine dependent cif processing */
 ffi_status
@@ -116,6 +122,16 @@ ffi_prep_cif_machdep (ffi_cif *cif)
       break;
 
     case FFI_TYPE_STRUCT:
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+      cif->flags = 0;	/* structs are always passed on the stack */
+#else
+      if (cif->rtype->elements[0]->type == FFI_TYPE_STRUCT &&
+	  cif->rtype->elements[1])
+	{
+	  cif->flags = 0;
+	  break;
+	}
+
       switch (cif->rtype->size)
 	{
 	case 1:
@@ -134,6 +150,7 @@ ffi_prep_cif_machdep (ffi_cif *cif)
 	  cif->flags = 0;
 	  break;
 	}
+#endif
       break;
 
     case FFI_TYPE_FLOAT:
@@ -157,6 +174,14 @@ ffi_prep_cif_machdep (ffi_cif *cif)
       cif->flags = CIF_FLAGS_DINT;
       break;
 
+    case FFI_TYPE_SINT16:
+      cif->flags = CIF_FLAGS_SINT16;
+      break;
+
+    case FFI_TYPE_SINT8:
+      cif->flags = CIF_FLAGS_SINT8;
+      break;
+
     default:
       cif->flags = CIF_FLAGS_INT;
       break;
@@ -178,7 +203,7 @@ ffi_call (ffi_cif *cif, void (*fn) (), void *rvalue, v
 
   if (rvalue == NULL
       && cif->rtype->type == FFI_TYPE_STRUCT
-      && cif->rtype->size > 8)
+      && cif->flags == 0)
     ecif.rvalue = alloca (cif->rtype->size);
   else
     ecif.rvalue = rvalue;
@@ -257,17 +282,26 @@ ffi_prep_closure_loc (ffi_closure* closure,
 {
   FFI_ASSERT (cif->abi == FFI_SYSV);
 
-  *(unsigned short *)closure->tramp = 0x207c;
   *(void **)(closure->tramp + 2) = codeloc;
-  *(unsigned short *)(closure->tramp + 6) = 0x4ef9;
+  *(unsigned short *)(closure->tramp + 6) = 0x4ef9; /* jmp ffi_closure_... */
   if (cif->rtype->type == FFI_TYPE_STRUCT
       && !cif->flags)
-    *(void **)(closure->tramp + 8) = ffi_closure_struct_SYSV;
+    {
+      *(unsigned short *)closure->tramp = 0x227c; /* moval #codeloc, %a1 */
+      *(void **)(closure->tramp + 8) = ffi_closure_struct_SYSV;
+    }
   else
-    *(void **)(closure->tramp + 8) = ffi_closure_SYSV;
+    {
+      *(unsigned short *)closure->tramp = 0x207c; /* moval #codeloc, %a0 */
+      *(void **)(closure->tramp + 8) = ffi_closure_SYSV;
+    }
 
+#ifdef __OpenBSD__
+  ffi_sync_icache(codeloc, FFI_TRAMPOLINE_SIZE);
+#else
   syscall(SYS_cacheflush, codeloc, FLUSH_SCOPE_LINE,
 	  FLUSH_CACHE_BOTH, FFI_TRAMPOLINE_SIZE);
+#endif
 
   closure->cif  = cif;
   closure->user_data = user_data;
