1baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com/* libffi support for Altera Nios II. 2baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 3baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com Copyright (c) 2013 Mentor Graphics. 4baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 5baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com Permission is hereby granted, free of charge, to any person obtaining 6baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com a copy of this software and associated documentation files (the 7baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com ``Software''), to deal in the Software without restriction, including 8baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com without limitation the rights to use, copy, modify, merge, publish, 9baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com distribute, sublicense, and/or sell copies of the Software, and to 10baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com permit persons to whom the Software is furnished to do so, subject to 11baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com the following conditions: 12baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 13baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com The above copyright notice and this permission notice shall be 14baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com included in all copies or substantial portions of the Software. 15baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 16baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, 17baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ 23baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 24baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 25baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#include <ffi.h> 26baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#include <ffi_common.h> 27baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 28baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#include <stdlib.h> 29baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 30baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com/* The Nios II Processor Reference Handbook defines the procedure call 31baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com ABI as follows. 32baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 33baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com Arguments are passed as if a structure containing the types of 34baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com the arguments were constructed. The first 16 bytes are passed in r4 35baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com through r7, the remainder on the stack. The first 16 bytes of a function 36baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com taking variable arguments are passed in r4-r7 in the same way. 37baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 38baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com Return values of types up to 8 bytes are returned in r2 and r3. For 39baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com return values greater than 8 bytes, the caller must allocate memory for 40baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com the result and pass the address as if it were argument 0. 41baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 42baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com While this isn't specified explicitly in the ABI documentation, GCC 43baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com promotes integral arguments smaller than int size to 32 bits. 44baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 45baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com Also of note, the ABI specifies that all structure objects are 46baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com aligned to 32 bits even if all their fields have a smaller natural 47baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com alignment. See FFI_AGGREGATE_ALIGNMENT. */ 48baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 49baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 50baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com/* Declare the assembly language hooks. */ 51baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 52baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.comextern UINT64 ffi_call_sysv (void (*) (char *, extended_cif *), 53baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com extended_cif *, 54baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com unsigned, 55baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com void (*fn) (void)); 56baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.comextern void ffi_closure_sysv (void); 57baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 58baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com/* Perform machine-dependent cif processing. */ 59baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 60baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.comffi_status ffi_prep_cif_machdep (ffi_cif *cif) 61baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com{ 62baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com /* We always want at least 16 bytes in the parameter block since it 63baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com simplifies the low-level call function. Also round the parameter 64baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com block size up to a multiple of 4 bytes to preserve 65baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 32-bit alignment of the stack pointer. */ 66baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com if (cif->bytes < 16) 67baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com cif->bytes = 16; 68baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com else 69baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com cif->bytes = (cif->bytes + 3) & ~3; 70baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 71baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com return FFI_OK; 72baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com} 73baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 74baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 75baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com/* ffi_prep_args is called by the assembly routine to transfer arguments 76baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com to the stack using the pointers in the ecif array. 77baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com Note that the stack buffer is big enough to fit all the arguments, 78baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com but the first 16 bytes will be copied to registers for the actual 79baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com call. */ 80baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 81baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.comvoid ffi_prep_args (char *stack, extended_cif *ecif) 82baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com{ 83baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com char *argp = stack; 84baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com unsigned int i; 85baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 86baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com /* The implicit return value pointer is passed as if it were a hidden 87baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com first argument. */ 88baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com if (ecif->cif->rtype->type == FFI_TYPE_STRUCT 89baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com && ecif->cif->rtype->size > 8) 90baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com { 91baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com (*(void **) argp) = ecif->rvalue; 92baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com argp += 4; 93baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com } 94baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 95baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com for (i = 0; i < ecif->cif->nargs; i++) 96baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com { 97baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com void *avalue = ecif->avalue[i]; 98baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com ffi_type *atype = ecif->cif->arg_types[i]; 99baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com size_t size = atype->size; 100baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com size_t alignment = atype->alignment; 101baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 102baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com /* Align argp as appropriate for the argument type. */ 103baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com if ((alignment - 1) & (unsigned) argp) 104baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com argp = (char *) ALIGN (argp, alignment); 105baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 106baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com /* Copy the argument, promoting integral types smaller than a 107baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com word to word size. */ 108baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com if (size < sizeof (int)) 109baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com { 110baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com size = sizeof (int); 111baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com switch (atype->type) 112baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com { 113baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com case FFI_TYPE_SINT8: 114baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com *(signed int *) argp = (signed int) *(SINT8 *) avalue; 115baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com break; 116baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 117baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com case FFI_TYPE_UINT8: 118baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com *(unsigned int *) argp = (unsigned int) *(UINT8 *) avalue; 119baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com break; 120baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 121baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com case FFI_TYPE_SINT16: 122baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com *(signed int *) argp = (signed int) *(SINT16 *) avalue; 123baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com break; 124baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 125baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com case FFI_TYPE_UINT16: 126baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com *(unsigned int *) argp = (unsigned int) *(UINT16 *) avalue; 127baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com break; 128baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 129baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com case FFI_TYPE_STRUCT: 130baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com memcpy (argp, avalue, atype->size); 131baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com break; 132baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 133baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com default: 134baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com FFI_ASSERT(0); 135baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com } 136baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com } 137baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com else if (size == sizeof (int)) 138baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com *(unsigned int *) argp = (unsigned int) *(UINT32 *) avalue; 139baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com else 140baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com memcpy (argp, avalue, size); 141baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com argp += size; 142baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com } 143baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com} 144baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 145baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 146baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com/* Call FN using the prepared CIF. RVALUE points to space allocated by 147baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com the caller for the return value, and AVALUE is an array of argument 148baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com pointers. */ 149baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 150baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.comvoid ffi_call (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue) 151baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com{ 152baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 153baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com extended_cif ecif; 154baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com UINT64 result; 155baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 156baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com /* If bigret is true, this is the case where a return value of larger 157baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com than 8 bytes is handled by being passed by reference as an implicit 158baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com argument. */ 159baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com int bigret = (cif->rtype->type == FFI_TYPE_STRUCT 160baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com && cif->rtype->size > 8); 161baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 162baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com ecif.cif = cif; 163baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com ecif.avalue = avalue; 164baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 165baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com /* Allocate space for return value if this is the pass-by-reference case 166baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com and the caller did not provide a buffer. */ 167baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com if (rvalue == NULL && bigret) 168baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com ecif.rvalue = alloca (cif->rtype->size); 169baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com else 170baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com ecif.rvalue = rvalue; 171baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 172baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com result = ffi_call_sysv (ffi_prep_args, &ecif, cif->bytes, fn); 173baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 174baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com /* Now result contains the 64 bit contents returned from fn in 175baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com r2 and r3. Copy the value of the appropriate size to the user-provided 176baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com rvalue buffer. */ 177baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com if (rvalue && !bigret) 178baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com switch (cif->rtype->size) 179baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com { 180baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com case 1: 181baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com *(UINT8 *)rvalue = (UINT8) result; 182baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com break; 183baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com case 2: 184baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com *(UINT16 *)rvalue = (UINT16) result; 185baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com break; 186baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com case 4: 187baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com *(UINT32 *)rvalue = (UINT32) result; 188baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com break; 189baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com case 8: 190baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com *(UINT64 *)rvalue = (UINT64) result; 191baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com break; 192baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com default: 193baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com memcpy (rvalue, (void *)&result, cif->rtype->size); 194baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com break; 195baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com } 196baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com} 197baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 198baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com/* This function is invoked from the closure trampoline to invoke 199baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com CLOSURE with argument block ARGS. Parse ARGS according to 200baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com CLOSURE->cfi and invoke CLOSURE->fun. */ 201baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 202baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.comstatic UINT64 203baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.comffi_closure_helper (unsigned char *args, 204baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com ffi_closure *closure) 205baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com{ 206baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com ffi_cif *cif = closure->cif; 207baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com unsigned char *argp = args; 208baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com void **parsed_args = alloca (cif->nargs * sizeof (void *)); 209baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com UINT64 result; 210baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com void *retptr; 211baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com unsigned int i; 212baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 213baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com /* First figure out what to do about the return type. If this is the 214baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com big-structure-return case, the first arg is the hidden return buffer 215baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com allocated by the caller. */ 216baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com if (cif->rtype->type == FFI_TYPE_STRUCT 217baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com && cif->rtype->size > 8) 218baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com { 219baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com retptr = *((void **) argp); 220baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com argp += 4; 221baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com } 222baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com else 223baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com retptr = (void *) &result; 224baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 225baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com /* Fill in the array of argument pointers. */ 226baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com for (i = 0; i < cif->nargs; i++) 227baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com { 228baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com size_t size = cif->arg_types[i]->size; 229baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com size_t alignment = cif->arg_types[i]->alignment; 230baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 231baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com /* Align argp as appropriate for the argument type. */ 232baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com if ((alignment - 1) & (unsigned) argp) 233baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com argp = (char *) ALIGN (argp, alignment); 234baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 235baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com /* Arguments smaller than an int are promoted to int. */ 236baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com if (size < sizeof (int)) 237baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com size = sizeof (int); 238baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 239baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com /* Store the pointer. */ 240baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com parsed_args[i] = argp; 241baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com argp += size; 242baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com } 243baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 244baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com /* Call the user-supplied function. */ 245baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com (closure->fun) (cif, retptr, parsed_args, closure->user_data); 246baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com return result; 247baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com} 248baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 249baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 250baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com/* Initialize CLOSURE with a trampoline to call FUN with 251baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com CIF and USER_DATA. */ 252baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.comffi_status 253baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.comffi_prep_closure_loc (ffi_closure* closure, 254baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com ffi_cif* cif, 255baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com void (*fun) (ffi_cif*, void*, void**, void*), 256baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com void *user_data, 257baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com void *codeloc) 258baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com{ 259baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com unsigned int *tramp = (unsigned int *) &closure->tramp[0]; 260baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com int i; 261baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 262baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com if (cif->abi != FFI_SYSV) 263baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com return FFI_BAD_ABI; 264baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 265baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com /* The trampoline looks like: 266baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com movhi r8, %hi(ffi_closure_sysv) 267baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com ori r8, r8, %lo(ffi_closure_sysv) 268baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com movhi r9, %hi(ffi_closure_helper) 269baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com ori r0, r9, %lo(ffi_closure_helper) 270baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com movhi r10, %hi(closure) 271baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com ori r10, r10, %lo(closure) 272baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com jmp r8 273baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com and then ffi_closure_sysv retrieves the closure pointer out of r10 274baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com in addition to the arguments passed in the normal way for the call, 275baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com and invokes ffi_closure_helper. We encode the pointer to 276baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com ffi_closure_helper in the trampoline because making a PIC call 277baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com to it in ffi_closure_sysv would be messy (it would have to indirect 278baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com through the GOT). */ 279baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 280baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#define HI(x) ((((unsigned int) (x)) >> 16) & 0xffff) 281baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#define LO(x) (((unsigned int) (x)) & 0xffff) 282baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com tramp[0] = (0 << 27) | (8 << 22) | (HI (ffi_closure_sysv) << 6) | 0x34; 283baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com tramp[1] = (8 << 27) | (8 << 22) | (LO (ffi_closure_sysv) << 6) | 0x14; 284baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com tramp[2] = (0 << 27) | (9 << 22) | (HI (ffi_closure_helper) << 6) | 0x34; 285baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com tramp[3] = (9 << 27) | (9 << 22) | (LO (ffi_closure_helper) << 6) | 0x14; 286baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com tramp[4] = (0 << 27) | (10 << 22) | (HI (closure) << 6) | 0x34; 287baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com tramp[5] = (10 << 27) | (10 << 22) | (LO (closure) << 6) | 0x14; 288baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com tramp[6] = (8 << 27) | (0x0d << 11) | 0x3a; 289baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#undef HI 290baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#undef LO 291baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 292baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com /* Flush the caches. 293baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com See Example 9-4 in the Nios II Software Developer's Handbook. */ 294baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com for (i = 0; i < 7; i++) 295baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com asm volatile ("flushd 0(%0); flushi %0" :: "r"(tramp + i) : "memory"); 296baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com asm volatile ("flushp" ::: "memory"); 297baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 298baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com closure->cif = cif; 299baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com closure->fun = fun; 300baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com closure->user_data = user_data; 301baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 302baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com return FFI_OK; 303baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com} 304baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com 305