xref: /aosp_15_r20/external/libffi/src/powerpc/ffi.c (revision 1fd5a2e1d639cd1ddf29dd0c484c123bbd850c21)
1*1fd5a2e1SPrashanth Swaminathan /* -----------------------------------------------------------------------
2*1fd5a2e1SPrashanth Swaminathan    ffi.c - Copyright (C) 2013 IBM
3*1fd5a2e1SPrashanth Swaminathan            Copyright (C) 2011 Anthony Green
4*1fd5a2e1SPrashanth Swaminathan            Copyright (C) 2011 Kyle Moffett
5*1fd5a2e1SPrashanth Swaminathan            Copyright (C) 2008 Red Hat, Inc
6*1fd5a2e1SPrashanth Swaminathan            Copyright (C) 2007, 2008 Free Software Foundation, Inc
7*1fd5a2e1SPrashanth Swaminathan 	   Copyright (c) 1998 Geoffrey Keating
8*1fd5a2e1SPrashanth Swaminathan 
9*1fd5a2e1SPrashanth Swaminathan    PowerPC Foreign Function Interface
10*1fd5a2e1SPrashanth Swaminathan 
11*1fd5a2e1SPrashanth Swaminathan    Permission is hereby granted, free of charge, to any person obtaining
12*1fd5a2e1SPrashanth Swaminathan    a copy of this software and associated documentation files (the
13*1fd5a2e1SPrashanth Swaminathan    ``Software''), to deal in the Software without restriction, including
14*1fd5a2e1SPrashanth Swaminathan    without limitation the rights to use, copy, modify, merge, publish,
15*1fd5a2e1SPrashanth Swaminathan    distribute, sublicense, and/or sell copies of the Software, and to
16*1fd5a2e1SPrashanth Swaminathan    permit persons to whom the Software is furnished to do so, subject to
17*1fd5a2e1SPrashanth Swaminathan    the following conditions:
18*1fd5a2e1SPrashanth Swaminathan 
19*1fd5a2e1SPrashanth Swaminathan    The above copyright notice and this permission notice shall be included
20*1fd5a2e1SPrashanth Swaminathan    in all copies or substantial portions of the Software.
21*1fd5a2e1SPrashanth Swaminathan 
22*1fd5a2e1SPrashanth Swaminathan    THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
23*1fd5a2e1SPrashanth Swaminathan    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24*1fd5a2e1SPrashanth Swaminathan    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
25*1fd5a2e1SPrashanth Swaminathan    IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR
26*1fd5a2e1SPrashanth Swaminathan    OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
27*1fd5a2e1SPrashanth Swaminathan    ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28*1fd5a2e1SPrashanth Swaminathan    OTHER DEALINGS IN THE SOFTWARE.
29*1fd5a2e1SPrashanth Swaminathan    ----------------------------------------------------------------------- */
30*1fd5a2e1SPrashanth Swaminathan 
31*1fd5a2e1SPrashanth Swaminathan #include "ffi.h"
32*1fd5a2e1SPrashanth Swaminathan #include "ffi_common.h"
33*1fd5a2e1SPrashanth Swaminathan #include "ffi_powerpc.h"
34*1fd5a2e1SPrashanth Swaminathan 
35*1fd5a2e1SPrashanth Swaminathan #if HAVE_LONG_DOUBLE_VARIANT
36*1fd5a2e1SPrashanth Swaminathan /* Adjust ffi_type_longdouble.  */
37*1fd5a2e1SPrashanth Swaminathan void FFI_HIDDEN
ffi_prep_types(ffi_abi abi)38*1fd5a2e1SPrashanth Swaminathan ffi_prep_types (ffi_abi abi)
39*1fd5a2e1SPrashanth Swaminathan {
40*1fd5a2e1SPrashanth Swaminathan # if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
41*1fd5a2e1SPrashanth Swaminathan #  ifdef POWERPC64
42*1fd5a2e1SPrashanth Swaminathan   ffi_prep_types_linux64 (abi);
43*1fd5a2e1SPrashanth Swaminathan #  else
44*1fd5a2e1SPrashanth Swaminathan   ffi_prep_types_sysv (abi);
45*1fd5a2e1SPrashanth Swaminathan #  endif
46*1fd5a2e1SPrashanth Swaminathan # endif
47*1fd5a2e1SPrashanth Swaminathan }
48*1fd5a2e1SPrashanth Swaminathan #endif
49*1fd5a2e1SPrashanth Swaminathan 
50*1fd5a2e1SPrashanth Swaminathan /* Perform machine dependent cif processing */
51*1fd5a2e1SPrashanth Swaminathan ffi_status FFI_HIDDEN
ffi_prep_cif_machdep(ffi_cif * cif)52*1fd5a2e1SPrashanth Swaminathan ffi_prep_cif_machdep (ffi_cif *cif)
53*1fd5a2e1SPrashanth Swaminathan {
54*1fd5a2e1SPrashanth Swaminathan #ifdef POWERPC64
55*1fd5a2e1SPrashanth Swaminathan   return ffi_prep_cif_linux64 (cif);
56*1fd5a2e1SPrashanth Swaminathan #else
57*1fd5a2e1SPrashanth Swaminathan   return ffi_prep_cif_sysv (cif);
58*1fd5a2e1SPrashanth Swaminathan #endif
59*1fd5a2e1SPrashanth Swaminathan }
60*1fd5a2e1SPrashanth Swaminathan 
61*1fd5a2e1SPrashanth Swaminathan ffi_status FFI_HIDDEN
ffi_prep_cif_machdep_var(ffi_cif * cif,unsigned int nfixedargs MAYBE_UNUSED,unsigned int ntotalargs MAYBE_UNUSED)62*1fd5a2e1SPrashanth Swaminathan ffi_prep_cif_machdep_var (ffi_cif *cif,
63*1fd5a2e1SPrashanth Swaminathan 			  unsigned int nfixedargs MAYBE_UNUSED,
64*1fd5a2e1SPrashanth Swaminathan 			  unsigned int ntotalargs MAYBE_UNUSED)
65*1fd5a2e1SPrashanth Swaminathan {
66*1fd5a2e1SPrashanth Swaminathan #ifdef POWERPC64
67*1fd5a2e1SPrashanth Swaminathan   return ffi_prep_cif_linux64_var (cif, nfixedargs, ntotalargs);
68*1fd5a2e1SPrashanth Swaminathan #else
69*1fd5a2e1SPrashanth Swaminathan   return ffi_prep_cif_sysv (cif);
70*1fd5a2e1SPrashanth Swaminathan #endif
71*1fd5a2e1SPrashanth Swaminathan }
72*1fd5a2e1SPrashanth Swaminathan 
73*1fd5a2e1SPrashanth Swaminathan static void
ffi_call_int(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue,void * closure)74*1fd5a2e1SPrashanth Swaminathan ffi_call_int (ffi_cif *cif,
75*1fd5a2e1SPrashanth Swaminathan 	      void (*fn) (void),
76*1fd5a2e1SPrashanth Swaminathan 	      void *rvalue,
77*1fd5a2e1SPrashanth Swaminathan 	      void **avalue,
78*1fd5a2e1SPrashanth Swaminathan 	      void *closure)
79*1fd5a2e1SPrashanth Swaminathan {
80*1fd5a2e1SPrashanth Swaminathan   /* The final SYSV ABI says that structures smaller or equal 8 bytes
81*1fd5a2e1SPrashanth Swaminathan      are returned in r3/r4.  A draft ABI used by linux instead returns
82*1fd5a2e1SPrashanth Swaminathan      them in memory.
83*1fd5a2e1SPrashanth Swaminathan 
84*1fd5a2e1SPrashanth Swaminathan      We bounce-buffer SYSV small struct return values so that sysv.S
85*1fd5a2e1SPrashanth Swaminathan      can write r3 and r4 to memory without worrying about struct size.
86*1fd5a2e1SPrashanth Swaminathan 
87*1fd5a2e1SPrashanth Swaminathan      For ELFv2 ABI, use a bounce buffer for homogeneous structs too,
88*1fd5a2e1SPrashanth Swaminathan      for similar reasons. This bounce buffer must be aligned to 16
89*1fd5a2e1SPrashanth Swaminathan      bytes for use with homogeneous structs of vectors (float128).  */
90*1fd5a2e1SPrashanth Swaminathan   float128 smst_buffer[8];
91*1fd5a2e1SPrashanth Swaminathan   extended_cif ecif;
92*1fd5a2e1SPrashanth Swaminathan 
93*1fd5a2e1SPrashanth Swaminathan   ecif.cif = cif;
94*1fd5a2e1SPrashanth Swaminathan   ecif.avalue = avalue;
95*1fd5a2e1SPrashanth Swaminathan 
96*1fd5a2e1SPrashanth Swaminathan   ecif.rvalue = rvalue;
97*1fd5a2e1SPrashanth Swaminathan   if ((cif->flags & FLAG_RETURNS_SMST) != 0)
98*1fd5a2e1SPrashanth Swaminathan     ecif.rvalue = smst_buffer;
99*1fd5a2e1SPrashanth Swaminathan   /* Ensure that we have a valid struct return value.
100*1fd5a2e1SPrashanth Swaminathan      FIXME: Isn't this just papering over a user problem?  */
101*1fd5a2e1SPrashanth Swaminathan   else if (!rvalue && cif->rtype->type == FFI_TYPE_STRUCT)
102*1fd5a2e1SPrashanth Swaminathan     ecif.rvalue = alloca (cif->rtype->size);
103*1fd5a2e1SPrashanth Swaminathan 
104*1fd5a2e1SPrashanth Swaminathan #ifdef POWERPC64
105*1fd5a2e1SPrashanth Swaminathan   ffi_call_LINUX64 (&ecif, fn, ecif.rvalue, cif->flags, closure,
106*1fd5a2e1SPrashanth Swaminathan 		    -(long) cif->bytes);
107*1fd5a2e1SPrashanth Swaminathan #else
108*1fd5a2e1SPrashanth Swaminathan   ffi_call_SYSV (&ecif, fn, ecif.rvalue, cif->flags, closure, -cif->bytes);
109*1fd5a2e1SPrashanth Swaminathan #endif
110*1fd5a2e1SPrashanth Swaminathan 
111*1fd5a2e1SPrashanth Swaminathan   /* Check for a bounce-buffered return value */
112*1fd5a2e1SPrashanth Swaminathan   if (rvalue && ecif.rvalue == smst_buffer)
113*1fd5a2e1SPrashanth Swaminathan     {
114*1fd5a2e1SPrashanth Swaminathan       unsigned int rsize = cif->rtype->size;
115*1fd5a2e1SPrashanth Swaminathan #ifndef __LITTLE_ENDIAN__
116*1fd5a2e1SPrashanth Swaminathan       /* The SYSV ABI returns a structure of up to 4 bytes in size
117*1fd5a2e1SPrashanth Swaminathan 	 left-padded in r3.  */
118*1fd5a2e1SPrashanth Swaminathan # ifndef POWERPC64
119*1fd5a2e1SPrashanth Swaminathan       if (rsize <= 4)
120*1fd5a2e1SPrashanth Swaminathan 	memcpy (rvalue, (char *) smst_buffer + 4 - rsize, rsize);
121*1fd5a2e1SPrashanth Swaminathan       else
122*1fd5a2e1SPrashanth Swaminathan # endif
123*1fd5a2e1SPrashanth Swaminathan 	/* The SYSV ABI returns a structure of up to 8 bytes in size
124*1fd5a2e1SPrashanth Swaminathan 	   left-padded in r3/r4, and the ELFv2 ABI similarly returns a
125*1fd5a2e1SPrashanth Swaminathan 	   structure of up to 8 bytes in size left-padded in r3. But
126*1fd5a2e1SPrashanth Swaminathan 	   note that a structure of a single float is not paddded.  */
127*1fd5a2e1SPrashanth Swaminathan 	if (rsize <= 8 && (cif->flags & FLAG_RETURNS_FP) == 0)
128*1fd5a2e1SPrashanth Swaminathan 	  memcpy (rvalue, (char *) smst_buffer + 8 - rsize, rsize);
129*1fd5a2e1SPrashanth Swaminathan 	else
130*1fd5a2e1SPrashanth Swaminathan #endif
131*1fd5a2e1SPrashanth Swaminathan 	  memcpy (rvalue, smst_buffer, rsize);
132*1fd5a2e1SPrashanth Swaminathan     }
133*1fd5a2e1SPrashanth Swaminathan }
134*1fd5a2e1SPrashanth Swaminathan 
135*1fd5a2e1SPrashanth Swaminathan void
ffi_call(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue)136*1fd5a2e1SPrashanth Swaminathan ffi_call (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue)
137*1fd5a2e1SPrashanth Swaminathan {
138*1fd5a2e1SPrashanth Swaminathan   ffi_call_int (cif, fn, rvalue, avalue, NULL);
139*1fd5a2e1SPrashanth Swaminathan }
140*1fd5a2e1SPrashanth Swaminathan 
141*1fd5a2e1SPrashanth Swaminathan void
ffi_call_go(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue,void * closure)142*1fd5a2e1SPrashanth Swaminathan ffi_call_go (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue,
143*1fd5a2e1SPrashanth Swaminathan 	     void *closure)
144*1fd5a2e1SPrashanth Swaminathan {
145*1fd5a2e1SPrashanth Swaminathan   ffi_call_int (cif, fn, rvalue, avalue, closure);
146*1fd5a2e1SPrashanth Swaminathan }
147*1fd5a2e1SPrashanth Swaminathan 
148*1fd5a2e1SPrashanth Swaminathan ffi_status
ffi_prep_closure_loc(ffi_closure * closure,ffi_cif * cif,void (* fun)(ffi_cif *,void *,void **,void *),void * user_data,void * codeloc)149*1fd5a2e1SPrashanth Swaminathan ffi_prep_closure_loc (ffi_closure *closure,
150*1fd5a2e1SPrashanth Swaminathan 		      ffi_cif *cif,
151*1fd5a2e1SPrashanth Swaminathan 		      void (*fun) (ffi_cif *, void *, void **, void *),
152*1fd5a2e1SPrashanth Swaminathan 		      void *user_data,
153*1fd5a2e1SPrashanth Swaminathan 		      void *codeloc)
154*1fd5a2e1SPrashanth Swaminathan {
155*1fd5a2e1SPrashanth Swaminathan #ifdef POWERPC64
156*1fd5a2e1SPrashanth Swaminathan   return ffi_prep_closure_loc_linux64 (closure, cif, fun, user_data, codeloc);
157*1fd5a2e1SPrashanth Swaminathan #else
158*1fd5a2e1SPrashanth Swaminathan   return ffi_prep_closure_loc_sysv (closure, cif, fun, user_data, codeloc);
159*1fd5a2e1SPrashanth Swaminathan #endif
160*1fd5a2e1SPrashanth Swaminathan }
161*1fd5a2e1SPrashanth Swaminathan 
162*1fd5a2e1SPrashanth Swaminathan ffi_status
ffi_prep_go_closure(ffi_go_closure * closure,ffi_cif * cif,void (* fun)(ffi_cif *,void *,void **,void *))163*1fd5a2e1SPrashanth Swaminathan ffi_prep_go_closure (ffi_go_closure *closure,
164*1fd5a2e1SPrashanth Swaminathan 		     ffi_cif *cif,
165*1fd5a2e1SPrashanth Swaminathan 		     void (*fun) (ffi_cif *, void *, void **, void *))
166*1fd5a2e1SPrashanth Swaminathan {
167*1fd5a2e1SPrashanth Swaminathan #ifdef POWERPC64
168*1fd5a2e1SPrashanth Swaminathan   closure->tramp = ffi_go_closure_linux64;
169*1fd5a2e1SPrashanth Swaminathan #else
170*1fd5a2e1SPrashanth Swaminathan   closure->tramp = ffi_go_closure_sysv;
171*1fd5a2e1SPrashanth Swaminathan #endif
172*1fd5a2e1SPrashanth Swaminathan   closure->cif = cif;
173*1fd5a2e1SPrashanth Swaminathan   closure->fun = fun;
174*1fd5a2e1SPrashanth Swaminathan   return FFI_OK;
175*1fd5a2e1SPrashanth Swaminathan }
176