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: dhwbi a2, 0 173 ihi a2, 0 174 addi a2, a2, 4 175 blt a2, a3, 1b 176 177 retw 178 179END(ffi_cacheflush) 180 181/* ffi_trampoline is copied to the stack */ 182 183ENTRY(ffi_trampoline) 184 185 entry a1, 16 + (FFI_REGISTER_NARGS * 4) + (4 * 4) # [ 0] 186 j 2f # [ 3] 187 .align 4 # [ 6] 1881: .long 0 # [ 8] 1892: l32r a15, 1b # [12] 190 _mov a14, a0 # [15] 191 callx0 a15 # [18] 192 # [21] 193END(ffi_trampoline) 194 195/* 196 * ffi_closure() 197 * 198 * a0: closure + 21 199 * a14: return address (a0) 200 */ 201 202ENTRY(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 2371: movi a11, FFI_TYPE_SINT8 238 bne a10, a11, 1f 239 sext a2, a2, 7 240 retw 241 2421: movi a11, FFI_TYPE_UINT16 243 bne a10, a11, 1f 244 extui a2, a2, 0, 16 245 retw 246 2471: movi a11, FFI_TYPE_SINT16 248 bne a10, a11, 1f 249 sext a2, a2, 15 250 2511: retw 252 253END(ffi_closure_SYSV) 254