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 56ENTRY(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 123store_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 159END(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 168ENTRY(ffi_cacheflush) 169 170 entry a1, 16 171 1721: 173#if XCHAL_DCACHE_SIZE 174 dhwbi a2, 0 175#endif 176#if XCHAL_ICACHE_SIZE 177 ihi a2, 0 178#endif 179 addi a2, a2, 4 180 blt a2, a3, 1b 181 182 retw 183 184END(ffi_cacheflush) 185 186/* ffi_trampoline is copied to the stack */ 187 188ENTRY(ffi_trampoline) 189 190 entry a1, 16 + (FFI_REGISTER_NARGS * 4) + (4 * 4) # [ 0] 191 j 2f # [ 3] 192 .align 4 # [ 6] 1931: .long 0 # [ 8] 1942: l32r a15, 1b # [12] 195 _mov a14, a0 # [15] 196 callx0 a15 # [18] 197 # [21] 198END(ffi_trampoline) 199 200/* 201 * ffi_closure() 202 * 203 * a0: closure + 21 204 * a14: return address (a0) 205 */ 206 207ENTRY(ffi_closure_SYSV) 208 209 /* intentionally omitting entry here */ 210 211 # restore return address (a0) and move pointer to closure to a10 212 addi a10, a0, -21 213 mov a0, a14 214 215 # allow up to 4 arguments as return values 216 addi a11, a1, 4 * 4 217 218 # save up to 6 arguments to stack (allocated by entry below) 219 s32i a2, a11, 0 220 s32i a3, a11, 4 221 s32i a4, a11, 8 222 s32i a5, a11, 12 223 s32i a6, a11, 16 224 s32i a7, a11, 20 225 226 movi a8, ffi_closure_SYSV_inner 227 mov a12, a1 228 callx8 a8 # .._inner(*closure, **avalue, *rvalue) 229 230 # load up to four return arguments 231 l32i a2, a1, 0 232 l32i a3, a1, 4 233 l32i a4, a1, 8 234 l32i a5, a1, 12 235 236 # (sign-)extend return value 237 movi a11, FFI_TYPE_UINT8 238 bne a10, a11, 1f 239 extui a2, a2, 0, 8 240 retw 241 2421: movi a11, FFI_TYPE_SINT8 243 bne a10, a11, 1f 244 sext a2, a2, 7 245 retw 246 2471: movi a11, FFI_TYPE_UINT16 248 bne a10, a11, 1f 249 extui a2, a2, 0, 16 250 retw 251 2521: movi a11, FFI_TYPE_SINT16 253 bne a10, a11, 1f 254 sext a2, a2, 15 255 2561: retw 257 258END(ffi_closure_SYSV) 259