(root)/
gcc-13.2.0/
libffi/
src/
microblaze/
ffi.c
       1  /* -----------------------------------------------------------------------
       2     ffi.c - Copyright (c) 2012, 2013 Xilinx, Inc
       3  
       4     MicroBlaze Foreign Function Interface
       5  
       6     Permission is hereby granted, free of charge, to any person obtaining
       7     a copy of this software and associated documentation files (the
       8     ``Software''), to deal in the Software without restriction, including
       9     without limitation the rights to use, copy, modify, merge, publish,
      10     distribute, sublicense, and/or sell copies of the Software, and to
      11     permit persons to whom the Software is furnished to do so, subject to
      12     the following conditions:
      13  
      14     The above copyright notice and this permission notice shall be included
      15     in all copies or substantial portions of the Software.
      16  
      17     THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
      18     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
      19     MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
      20     NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
      21     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
      22     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      23     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      24     DEALINGS IN THE SOFTWARE.
      25     ----------------------------------------------------------------------- */
      26  
      27  #include <ffi.h>
      28  #include <ffi_common.h>
      29  
      30  extern void ffi_call_SYSV(void (*)(void*, extended_cif*), extended_cif*,
      31  		unsigned int, unsigned int, unsigned int*, void (*fn)(void),
      32  		unsigned int, unsigned int);
      33  
      34  extern void ffi_closure_SYSV(void);
      35  
      36  #define WORD_SIZE			sizeof(unsigned int)
      37  #define ARGS_REGISTER_SIZE	(WORD_SIZE * 6)
      38  #define WORD_FFI_ALIGN(x)		FFI_ALIGN(x, WORD_SIZE)
      39  
      40  /* ffi_prep_args is called by the assembly routine once stack space
      41     has been allocated for the function's arguments */
      42  void ffi_prep_args(void* stack, extended_cif* ecif)
      43  {
      44  	unsigned int i;
      45  	ffi_type** p_arg;
      46  	void** p_argv;
      47  	void* stack_args_p = stack;
      48  
      49  	if (ecif == NULL || ecif->cif == NULL) {
      50  		return; /* no description to prepare */
      51  	}
      52  
      53  	p_argv = ecif->avalue;
      54  
      55  	if ((ecif->cif->rtype != NULL) &&
      56  			(ecif->cif->rtype->type == FFI_TYPE_STRUCT))
      57  	{
      58  		/* if return type is a struct which is referenced on the stack/reg5,
      59  		 * by a pointer. Stored the return value pointer in r5.
      60  		 */
      61  		char* addr = stack_args_p;
      62  		memcpy(addr, &(ecif->rvalue), WORD_SIZE);
      63  		stack_args_p += WORD_SIZE;
      64  	}
      65  
      66  	if (ecif->avalue == NULL) {
      67  		return; /* no arguments to prepare */
      68  	}
      69  
      70  	for (i = 0, p_arg = ecif->cif->arg_types; i < ecif->cif->nargs;
      71  			i++, p_arg++)
      72  	{
      73  		size_t size = (*p_arg)->size;
      74  		int type = (*p_arg)->type;
      75  		void* value = p_argv[i];
      76  		char* addr = stack_args_p;
      77  		int aligned_size = WORD_FFI_ALIGN(size);
      78  
      79  		/* force word alignment on the stack */
      80  		stack_args_p += aligned_size;
      81  		
      82  		switch (type)
      83  		{
      84  			case FFI_TYPE_UINT8:
      85  				*(unsigned int *)addr = (unsigned int)*(UINT8*)(value);
      86  				break;
      87  			case FFI_TYPE_SINT8:
      88  				*(signed int *)addr = (signed int)*(SINT8*)(value);
      89  				break;
      90  			case FFI_TYPE_UINT16:
      91  				*(unsigned int *)addr = (unsigned int)*(UINT16*)(value);
      92  				break;
      93  			case FFI_TYPE_SINT16:
      94  				*(signed int *)addr = (signed int)*(SINT16*)(value);
      95  				break;
      96  			case FFI_TYPE_STRUCT:
      97  #if __BIG_ENDIAN__
      98  				/*
      99  				 * MicroBlaze toolchain appears to emit:
     100  				 * bsrli r5, r5, 8 (caller)
     101  				 * ...
     102  				 * <branch to callee>
     103  				 * ...
     104  				 * bslli r5, r5, 8 (callee)
     105  				 * 
     106  				 * For structs like "struct a { uint8_t a[3]; };", when passed
     107  				 * by value.
     108  				 *
     109  				 * Structs like "struct b { uint16_t a; };" are also expected
     110  				 * to be packed strangely in registers.
     111  				 *
     112  				 * This appears to be because the microblaze toolchain expects
     113  				 * "struct b == uint16_t", which is only any issue for big
     114  				 * endian.
     115  				 *
     116  				 * The following is a work around for big-endian only, for the
     117  				 * above mentioned case, it will re-align the contents of a
     118  				 * <= 3-byte struct value.
     119  				 */
     120  				if (size < WORD_SIZE)
     121  				{
     122  				  memcpy (addr + (WORD_SIZE - size), value, size);
     123  				  break;
     124  				}
     125  #endif
     126  			case FFI_TYPE_SINT32:
     127  			case FFI_TYPE_UINT32:
     128  			case FFI_TYPE_FLOAT:
     129  			case FFI_TYPE_SINT64:
     130  			case FFI_TYPE_UINT64:
     131  			case FFI_TYPE_DOUBLE:
     132  			default:
     133  				memcpy(addr, value, aligned_size);
     134  		}
     135  	}
     136  }
     137  
     138  ffi_status ffi_prep_cif_machdep(ffi_cif* cif)
     139  {
     140  	/* check ABI */
     141  	switch (cif->abi)
     142  	{
     143  		case FFI_SYSV:
     144  			break;
     145  		default:
     146  			return FFI_BAD_ABI;
     147  	}
     148  	return FFI_OK;
     149  }
     150  
     151  void ffi_call(ffi_cif* cif, void (*fn)(void), void* rvalue, void** avalue)
     152  {
     153  	extended_cif ecif;
     154  	ecif.cif = cif;
     155  	ecif.avalue = avalue;
     156  
     157  	/* If the return value is a struct and we don't have a return */
     158  	/* value address then we need to make one */
     159  	if ((rvalue == NULL) && (cif->rtype->type == FFI_TYPE_STRUCT)) {
     160  		ecif.rvalue = alloca(cif->rtype->size);
     161  	} else {
     162  		ecif.rvalue = rvalue;
     163  	}
     164  
     165  	switch (cif->abi)
     166  	{
     167  	case FFI_SYSV:
     168  		ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags,
     169  				ecif.rvalue, fn, cif->rtype->type, cif->rtype->size);
     170  		break;
     171  	default:
     172  		FFI_ASSERT(0);
     173  		break;
     174  	}
     175  }
     176  
     177  void ffi_closure_call_SYSV(void* register_args, void* stack_args,
     178  			ffi_closure* closure, void* rvalue,
     179  			unsigned int* rtype, unsigned int* rsize)
     180  {
     181  	/* prepare arguments for closure call */
     182  	ffi_cif* cif = closure->cif;
     183  	ffi_type** arg_types = cif->arg_types;
     184  
     185  	/* re-allocate data for the args. This needs to be done in order to keep
     186  	 * multi-word objects (e.g. structs) in contiguous memory. Callers are not
     187  	 * required to store the value of args in the lower 6 words in the stack
     188  	 * (although they are allocated in the stack).
     189  	 */
     190  	char* stackclone = alloca(cif->bytes);
     191  	void** avalue = alloca(cif->nargs * sizeof(void*));
     192  	void* struct_rvalue = NULL;
     193  	char* ptr = stackclone;
     194  	int i;
     195  
     196  	/* copy registers into stack clone */
     197  	int registers_used = cif->bytes;
     198  	if (registers_used > ARGS_REGISTER_SIZE) {
     199  		registers_used = ARGS_REGISTER_SIZE;
     200  	}
     201  	memcpy(stackclone, register_args, registers_used);
     202  
     203  	/* copy stack allocated args into stack clone */
     204  	if (cif->bytes > ARGS_REGISTER_SIZE) {
     205  		int stack_used = cif->bytes - ARGS_REGISTER_SIZE;
     206  		memcpy(stackclone + ARGS_REGISTER_SIZE, stack_args, stack_used);
     207  	}
     208  
     209  	/* preserve struct type return pointer passing */
     210  	if ((cif->rtype != NULL) && (cif->rtype->type == FFI_TYPE_STRUCT)) {
     211  		struct_rvalue = *((void**)ptr);
     212  		ptr += WORD_SIZE;
     213  	}
     214  
     215  	/* populate arg pointer list */
     216  	for (i = 0; i < cif->nargs; i++)
     217  	{
     218  		switch (arg_types[i]->type)
     219  		{
     220  			case FFI_TYPE_SINT8:
     221  			case FFI_TYPE_UINT8:
     222  #ifdef __BIG_ENDIAN__
     223  				avalue[i] = ptr + 3;
     224  #else
     225  				avalue[i] = ptr;
     226  #endif
     227  				break;
     228  			case FFI_TYPE_SINT16:
     229  			case FFI_TYPE_UINT16:
     230  #ifdef __BIG_ENDIAN__
     231  				avalue[i] = ptr + 2;
     232  #else
     233  				avalue[i] = ptr;
     234  #endif
     235  				break;
     236  			case FFI_TYPE_STRUCT:
     237  #if __BIG_ENDIAN__
     238  				/*
     239  				 * Work around strange ABI behaviour.
     240  				 * (see info in ffi_prep_args)
     241  				 */
     242  				if (arg_types[i]->size < WORD_SIZE)
     243  				{
     244  				  memcpy (ptr, ptr + (WORD_SIZE - arg_types[i]->size), arg_types[i]->size);
     245  				}
     246  #endif
     247  				avalue[i] = (void*)ptr;
     248  				break;
     249  			case FFI_TYPE_UINT64:
     250  			case FFI_TYPE_SINT64:
     251  			case FFI_TYPE_DOUBLE:
     252  				avalue[i] = ptr;
     253  				break;
     254  			case FFI_TYPE_SINT32:
     255  			case FFI_TYPE_UINT32:
     256  			case FFI_TYPE_FLOAT:
     257  			default:
     258  				/* default 4-byte argument */
     259  				avalue[i] = ptr;
     260  				break;
     261  		}
     262  		ptr += WORD_FFI_ALIGN(arg_types[i]->size);
     263  	}
     264  
     265  	/* set the return type info passed back to the wrapper */
     266  	*rsize = cif->rtype->size;
     267  	*rtype = cif->rtype->type;
     268  	if (struct_rvalue != NULL) {
     269  		closure->fun(cif, struct_rvalue, avalue, closure->user_data);
     270  		/* copy struct return pointer value into function return value */
     271  		*((void**)rvalue) = struct_rvalue;
     272  	} else {
     273  		closure->fun(cif, rvalue, avalue, closure->user_data);
     274  	}
     275  }
     276  
     277  ffi_status ffi_prep_closure_loc(
     278  		ffi_closure* closure, ffi_cif* cif,
     279  		void (*fun)(ffi_cif*, void*, void**, void*),
     280  		void* user_data, void* codeloc)
     281  {
     282  	unsigned long* tramp = (unsigned long*)&(closure->tramp[0]);
     283  	unsigned long cls = (unsigned long)codeloc;
     284  	unsigned long fn = 0;
     285  	unsigned long fn_closure_call_sysv = (unsigned long)ffi_closure_call_SYSV;
     286  
     287  	closure->cif = cif;
     288  	closure->fun = fun;
     289  	closure->user_data = user_data;
     290  
     291  	switch (cif->abi)
     292  	{
     293  	case FFI_SYSV:
     294  		fn = (unsigned long)ffi_closure_SYSV;
     295  
     296  		/* load r11 (temp) with fn */
     297  		/* imm fn(upper) */
     298  		tramp[0] = 0xb0000000 | ((fn >> 16) & 0xffff);
     299  		/* addik r11, r0, fn(lower) */
     300  		tramp[1] = 0x31600000 | (fn & 0xffff);
     301  
     302  		/* load r12 (temp) with cls */
     303  		/* imm cls(upper) */
     304  		tramp[2] = 0xb0000000 | ((cls >> 16) & 0xffff);
     305  		/* addik r12, r0, cls(lower) */
     306  		tramp[3] = 0x31800000 | (cls & 0xffff);
     307  
     308  		/* load r3 (temp) with ffi_closure_call_SYSV */
     309  		/* imm fn_closure_call_sysv(upper) */
     310  		tramp[4] = 0xb0000000 | ((fn_closure_call_sysv >> 16) & 0xffff);
     311  		/* addik r3, r0, fn_closure_call_sysv(lower) */
     312  		tramp[5] = 0x30600000 | (fn_closure_call_sysv & 0xffff);
     313  		/* branch/jump to address stored in r11 (fn) */
     314  		tramp[6] = 0x98085800; /* bra r11 */
     315  
     316  		break;
     317  	default:
     318  		return FFI_BAD_ABI;
     319  	}
     320  	return FFI_OK;
     321  }