Home | History | Annotate | Download | only in xtensa
      1 /* -----------------------------------------------------------------------
      2    sysv.S - Copyright (c) 2013 Tensilica, Inc.
      3 
      4    XTENSA 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 #define LIBFFI_ASM
     28 #include <fficonfig.h>
     29 #include <ffi.h>
     30 
     31 #define ENTRY(name) .text; .globl name; .type  name,@function; .align 4; name:
     32 #define END(name) .size name , . - name
     33 
     34 /* Assert that the table below is in sync with ffi.h.  */
     35 
     36 #if	   FFI_TYPE_UINT8 != 5          \
     37         || FFI_TYPE_SINT8 != 6          \
     38         || FFI_TYPE_UINT16 != 7         \
     39         || FFI_TYPE_SINT16 != 8         \
     40         || FFI_TYPE_UINT32 != 9         \
     41         || FFI_TYPE_SINT32 != 10        \
     42         || FFI_TYPE_UINT64 != 11
     43 #error "xtensa/sysv.S out of sync with ffi.h"
     44 #endif
     45 
     46 
     47 /* ffi_call_SYSV (rvalue, rbytes, flags, (*fnaddr)(), bytes, ecif)
     48       void *rvalue;            a2
     49       unsigned long rbytes;    a3
     50       unsigned flags;          a4
     51       void (*fnaddr)();        a5
     52       unsigned long bytes;     a6
     53       extended_cif* ecif)      a7
     54 */
     55 
     56 ENTRY(ffi_call_SYSV)
     57 
     58 	entry	a1, 32              # 32 byte frame for using call8 below
     59 
     60 	mov	a10, a7             # a10(->arg0): ecif
     61 	sub	a11, a1, a6         # a11(->arg1): stack pointer
     62 	mov	a7, a1              # fp
     63 	movsp	a1, a11             # set new sp = old_sp - bytes
     64 
     65 	movi	a8, ffi_prep_args
     66 	callx8	a8                  # ffi_prep_args(ecif, stack)
     67 
     68 	# prepare to move stack pointer back up to 6 arguments
     69 	# note that 'bytes' is already aligned
     70 
     71 	movi	a10, 6*4
     72 	sub	a11, a6, a10
     73 	movgez	a6, a10, a11
     74 	add	a6, a1, a6
     75 
     76 
     77 	# we can pass up to 6 arguments in registers
     78 	# for simplicity, just load 6 arguments
     79 	# (the stack size is at least 32 bytes, so no risk to cross boundaries)
     80 
     81 	l32i	a10, a1, 0
     82 	l32i	a11, a1, 4
     83 	l32i	a12, a1, 8
     84 	l32i	a13, a1, 12
     85 	l32i	a14, a1, 16
     86 	l32i	a15, a1, 20
     87 
     88 	# move stack pointer
     89 
     90 	movsp	a1, a6
     91 
     92 	callx8	a5                  # (*fn)(args...)
     93 
     94 	# Handle return value(s)
     95 
     96 	beqz	a2, .Lexit
     97 
     98 	movi	a5, FFI_TYPE_STRUCT
     99 	bne	a4, a5, .Lstore
    100 	movi	a5, 16
    101 	blt	a5, a3, .Lexit
    102 
    103 	s32i	a10, a2, 0
    104 	blti	a3, 5, .Lexit
    105 	addi	a3, a3, -1
    106 	s32i	a11, a2, 4
    107 	blti	a3, 8, .Lexit
    108 	s32i	a12, a2, 8
    109 	blti	a3, 12, .Lexit
    110 	s32i	a13, a2, 12
    111 
    112 .Lexit:	retw
    113 
    114 .Lstore:
    115 	addi	a4, a4, -FFI_TYPE_UINT8
    116 	bgei	a4, 7, .Lexit	# should never happen
    117 	movi	a6, store_calls
    118 	add	a4, a4, a4
    119 	addx4	a6, a4, a6	# store_table + idx * 8
    120 	jx	a6
    121 
    122 	.align	8
    123 store_calls:
    124 	# UINT8
    125 	s8i	a10, a2, 0
    126 	retw
    127 
    128 	# SINT8
    129 	.align	8
    130 	s8i	a10, a2, 0
    131 	retw
    132 
    133 	# UINT16
    134 	.align	8
    135 	s16i	a10, a2, 0
    136 	retw
    137 
    138 	# SINT16
    139 	.align	8
    140 	s16i	a10, a2, 0
    141 	retw
    142 
    143 	# UINT32
    144 	.align	8
    145 	s32i	a10, a2, 0
    146 	retw
    147 
    148 	# SINT32
    149 	.align	8
    150 	s32i	a10, a2, 0
    151 	retw
    152 
    153 	# UINT64
    154 	.align	8
    155 	s32i	a10, a2, 0
    156 	s32i	a11, a2, 4
    157 	retw
    158 
    159 END(ffi_call_SYSV)
    160 
    161 
    162 /*
    163  * void ffi_cacheflush (unsigned long start, unsigned long end)
    164  */
    165 
    166 #define EXTRA_ARGS_SIZE	24
    167 
    168 ENTRY(ffi_cacheflush)
    169 
    170 	entry	a1, 16
    171 
    172 1:	dhwbi	a2, 0
    173 	ihi	a2, 0
    174 	addi	a2, a2, 4
    175 	blt	a2, a3, 1b
    176 
    177 	retw
    178 
    179 END(ffi_cacheflush)
    180 
    181 /* ffi_trampoline is copied to the stack */
    182 
    183 ENTRY(ffi_trampoline)
    184 
    185 	entry	a1, 16 + (FFI_REGISTER_NARGS * 4) + (4 * 4)   # [ 0]
    186 	j	2f                                # [ 3]
    187 	.align	4                                 # [ 6]
    188 1:	.long	0                                 # [ 8]
    189 2:	l32r	a15, 1b                           # [12]
    190 	_mov 	a14, a0                           # [15]
    191 	callx0	a15                               # [18]
    192                                                   # [21]
    193 END(ffi_trampoline)
    194 
    195 /*
    196  * ffi_closure()
    197  *
    198  * a0:  closure + 21
    199  * a14: return address (a0)
    200  */
    201 
    202 ENTRY(ffi_closure_SYSV)
    203 
    204 	/* intentionally omitting entry here */
    205 
    206 	# restore return address (a0) and move pointer to closure to a10
    207 	addi	a10, a0, -21
    208 	mov	a0, a14
    209 
    210 	# allow up to 4 arguments as return values
    211 	addi	a11, a1, 4 * 4
    212 
    213 	# save up to 6 arguments to stack (allocated by entry below)
    214 	s32i	a2, a11,  0
    215 	s32i	a3, a11,  4
    216 	s32i	a4, a11,  8
    217 	s32i	a5, a11, 12
    218 	s32i	a6, a11, 16
    219 	s32i	a7, a11, 20
    220 
    221 	movi	a8, ffi_closure_SYSV_inner
    222 	mov	a12, a1
    223 	callx8	a8			# .._inner(*closure, **avalue, *rvalue)
    224 
    225 	# load up to four return arguments
    226 	l32i	a2, a1,  0
    227 	l32i	a3, a1,  4
    228 	l32i	a4, a1,  8
    229 	l32i	a5, a1, 12
    230 
    231 	# (sign-)extend return value
    232 	movi	a11, FFI_TYPE_UINT8
    233 	bne	a10, a11, 1f
    234 	extui	a2, a2, 0, 8
    235 	retw
    236 
    237 1:	movi	a11, FFI_TYPE_SINT8
    238 	bne	a10, a11, 1f
    239 	sext	a2, a2, 7
    240 	retw
    241 
    242 1:	movi	a11, FFI_TYPE_UINT16
    243 	bne	a10, a11, 1f
    244 	extui	a2, a2, 0, 16
    245 	retw
    246 
    247 1:	movi	a11, FFI_TYPE_SINT16
    248 	bne	a10, a11, 1f
    249 	sext	a2, a2, 15
    250 
    251 1:	retw
    252 
    253 END(ffi_closure_SYSV)
    254