1/* ----------------------------------------------------------------------- 2 sysv.S - 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#define LIBFFI_ASM 28#include <fficonfig.h> 29#include <ffi.h> 30 31 /* 32 * arg[0] (r5) = ffi_prep_args, 33 * arg[1] (r6) = &ecif, 34 * arg[2] (r7) = cif->bytes, 35 * arg[3] (r8) = cif->flags, 36 * arg[4] (r9) = ecif.rvalue, 37 * arg[5] (r10) = fn 38 * arg[6] (sp[0]) = cif->rtype->type 39 * arg[7] (sp[4]) = cif->rtype->size 40 */ 41 .text 42 .globl ffi_call_SYSV 43 .type ffi_call_SYSV, @function 44ffi_call_SYSV: 45 /* push callee saves */ 46 addik r1, r1, -20 47 swi r19, r1, 0 /* Frame Pointer */ 48 swi r20, r1, 4 /* PIC register */ 49 swi r21, r1, 8 /* PIC register */ 50 swi r22, r1, 12 /* save for locals */ 51 swi r23, r1, 16 /* save for locals */ 52 53 /* save the r5-r10 registers in the stack */ 54 addik r1, r1, -24 /* increment sp to store 6x 32-bit words */ 55 swi r5, r1, 0 56 swi r6, r1, 4 57 swi r7, r1, 8 58 swi r8, r1, 12 59 swi r9, r1, 16 60 swi r10, r1, 20 61 62 /* save function pointer */ 63 addik r3, r5, 0 /* copy ffi_prep_args into r3 */ 64 addik r22, r1, 0 /* save sp for unallocated args into r22 (callee-saved) */ 65 addik r23, r10, 0 /* save function address into r23 (callee-saved) */ 66 67 /* prepare stack with allocation for n (bytes = r7) args */ 68 rsub r1, r7, r1 /* subtract bytes from sp */ 69 70 /* prep args for ffi_prep_args call */ 71 addik r5, r1, 0 /* store stack pointer into arg[0] */ 72 /* r6 still holds ecif for arg[1] */ 73 74 /* Call ffi_prep_args(stack, &ecif). */ 75 addik r1, r1, -4 76 swi r15, r1, 0 /* store the link register in the frame */ 77 brald r15, r3 78 nop /* branch has delay slot */ 79 lwi r15, r1, 0 80 addik r1, r1, 4 /* restore the link register from the frame */ 81 /* returns calling stack pointer location */ 82 83 /* prepare args for fn call, prep_args populates them onto the stack */ 84 lwi r5, r1, 0 /* arg[0] */ 85 lwi r6, r1, 4 /* arg[1] */ 86 lwi r7, r1, 8 /* arg[2] */ 87 lwi r8, r1, 12 /* arg[3] */ 88 lwi r9, r1, 16 /* arg[4] */ 89 lwi r10, r1, 20 /* arg[5] */ 90 91 /* call (fn) (...). */ 92 addik r1, r1, -4 93 swi r15, r1, 0 /* store the link register in the frame */ 94 brald r15, r23 95 nop /* branch has delay slot */ 96 lwi r15, r1, 0 97 addik r1, r1, 4 /* restore the link register from the frame */ 98 99 /* Remove the space we pushed for the args. */ 100 addik r1, r22, 0 /* restore old SP */ 101 102 /* restore this functions parameters */ 103 lwi r5, r1, 0 /* arg[0] */ 104 lwi r6, r1, 4 /* arg[1] */ 105 lwi r7, r1, 8 /* arg[2] */ 106 lwi r8, r1, 12 /* arg[3] */ 107 lwi r9, r1, 16 /* arg[4] */ 108 lwi r10, r1, 20 /* arg[5] */ 109 addik r1, r1, 24 /* decrement sp to de-allocate 6x 32-bit words */ 110 111 /* If the return value pointer is NULL, assume no return value. */ 112 beqi r9, ffi_call_SYSV_end 113 114 lwi r22, r1, 48 /* get return type (20 for locals + 28 for arg[6]) */ 115 lwi r23, r1, 52 /* get return size (20 for locals + 32 for arg[7]) */ 116 117 /* Check if return type is actually a struct, do nothing */ 118 rsubi r11, r22, FFI_TYPE_STRUCT 119 beqi r11, ffi_call_SYSV_end 120 121 /* Return 8bit */ 122 rsubi r11, r23, 1 123 beqi r11, ffi_call_SYSV_store8 124 125 /* Return 16bit */ 126 rsubi r11, r23, 2 127 beqi r11, ffi_call_SYSV_store16 128 129 /* Return 32bit */ 130 rsubi r11, r23, 4 131 beqi r11, ffi_call_SYSV_store32 132 133 /* Return 64bit */ 134 rsubi r11, r23, 8 135 beqi r11, ffi_call_SYSV_store64 136 137 /* Didn't match anything */ 138 bri ffi_call_SYSV_end 139 140ffi_call_SYSV_store64: 141 swi r3, r9, 0 /* store word r3 into return value */ 142 swi r4, r9, 4 /* store word r4 into return value */ 143 bri ffi_call_SYSV_end 144 145ffi_call_SYSV_store32: 146 swi r3, r9, 0 /* store word r3 into return value */ 147 bri ffi_call_SYSV_end 148 149ffi_call_SYSV_store16: 150#ifdef __BIG_ENDIAN__ 151 shi r3, r9, 2 /* store half-word r3 into return value */ 152#else 153 shi r3, r9, 0 /* store half-word r3 into return value */ 154#endif 155 bri ffi_call_SYSV_end 156 157ffi_call_SYSV_store8: 158#ifdef __BIG_ENDIAN__ 159 sbi r3, r9, 3 /* store byte r3 into return value */ 160#else 161 sbi r3, r9, 0 /* store byte r3 into return value */ 162#endif 163 bri ffi_call_SYSV_end 164 165ffi_call_SYSV_end: 166 /* callee restores */ 167 lwi r19, r1, 0 /* frame pointer */ 168 lwi r20, r1, 4 /* PIC register */ 169 lwi r21, r1, 8 /* PIC register */ 170 lwi r22, r1, 12 171 lwi r23, r1, 16 172 addik r1, r1, 20 173 174 /* return from sub-routine (with delay slot) */ 175 rtsd r15, 8 176 nop 177 178 .size ffi_call_SYSV, . - ffi_call_SYSV 179 180/* ------------------------------------------------------------------------- */ 181 182 /* 183 * args passed into this function, are passed down to the callee. 184 * this function is the target of the closure trampoline, as such r12 is 185 * a pointer to the closure object. 186 */ 187 .text 188 .globl ffi_closure_SYSV 189 .type ffi_closure_SYSV, @function 190ffi_closure_SYSV: 191 /* push callee saves */ 192 addik r11, r1, 28 /* save stack args start location (excluding regs/link) */ 193 addik r1, r1, -12 194 swi r19, r1, 0 /* Frame Pointer */ 195 swi r20, r1, 4 /* PIC register */ 196 swi r21, r1, 8 /* PIC register */ 197 198 /* store register args on stack */ 199 addik r1, r1, -24 200 swi r5, r1, 0 201 swi r6, r1, 4 202 swi r7, r1, 8 203 swi r8, r1, 12 204 swi r9, r1, 16 205 swi r10, r1, 20 206 207 /* setup args */ 208 addik r5, r1, 0 /* register_args */ 209 addik r6, r11, 0 /* stack_args */ 210 addik r7, r12, 0 /* closure object */ 211 addik r1, r1, -8 /* allocate return value */ 212 addik r8, r1, 0 /* void* rvalue */ 213 addik r1, r1, -8 /* allocate for return type/size values */ 214 addik r9, r1, 0 /* void* rtype */ 215 addik r10, r1, 4 /* void* rsize */ 216 217 /* call the wrap_call function */ 218 addik r1, r1, -28 /* allocate args + link reg */ 219 swi r15, r1, 0 /* store the link register in the frame */ 220 brald r15, r3 221 nop /* branch has delay slot */ 222 lwi r15, r1, 0 223 addik r1, r1, 28 /* restore the link register from the frame */ 224 225ffi_closure_SYSV_prepare_return: 226 lwi r9, r1, 0 /* rtype */ 227 lwi r10, r1, 4 /* rsize */ 228 addik r1, r1, 8 /* de-allocate return info values */ 229 230 /* Check if return type is actually a struct, store 4 bytes */ 231 rsubi r11, r9, FFI_TYPE_STRUCT 232 beqi r11, ffi_closure_SYSV_store32 233 234 /* Return 8bit */ 235 rsubi r11, r10, 1 236 beqi r11, ffi_closure_SYSV_store8 237 238 /* Return 16bit */ 239 rsubi r11, r10, 2 240 beqi r11, ffi_closure_SYSV_store16 241 242 /* Return 32bit */ 243 rsubi r11, r10, 4 244 beqi r11, ffi_closure_SYSV_store32 245 246 /* Return 64bit */ 247 rsubi r11, r10, 8 248 beqi r11, ffi_closure_SYSV_store64 249 250 /* Didn't match anything */ 251 bri ffi_closure_SYSV_end 252 253ffi_closure_SYSV_store64: 254 lwi r3, r1, 0 /* store word r3 into return value */ 255 lwi r4, r1, 4 /* store word r4 into return value */ 256 /* 64 bits == 2 words, no sign extend occurs */ 257 bri ffi_closure_SYSV_end 258 259ffi_closure_SYSV_store32: 260 lwi r3, r1, 0 /* store word r3 into return value */ 261 /* 32 bits == 1 word, no sign extend occurs */ 262 bri ffi_closure_SYSV_end 263 264ffi_closure_SYSV_store16: 265#ifdef __BIG_ENDIAN__ 266 lhui r3, r1, 2 /* store half-word r3 into return value */ 267#else 268 lhui r3, r1, 0 /* store half-word r3 into return value */ 269#endif 270 rsubi r11, r9, FFI_TYPE_SINT16 271 bnei r11, ffi_closure_SYSV_end 272 sext16 r3, r3 /* fix sign extend of sint8 */ 273 bri ffi_closure_SYSV_end 274 275ffi_closure_SYSV_store8: 276#ifdef __BIG_ENDIAN__ 277 lbui r3, r1, 3 /* store byte r3 into return value */ 278#else 279 lbui r3, r1, 0 /* store byte r3 into return value */ 280#endif 281 rsubi r11, r9, FFI_TYPE_SINT8 282 bnei r11, ffi_closure_SYSV_end 283 sext8 r3, r3 /* fix sign extend of sint8 */ 284 bri ffi_closure_SYSV_end 285 286ffi_closure_SYSV_end: 287 addik r1, r1, 8 /* de-allocate return value */ 288 289 /* de-allocate stored args */ 290 addik r1, r1, 24 291 292 /* callee restores */ 293 lwi r19, r1, 0 /* frame pointer */ 294 lwi r20, r1, 4 /* PIC register */ 295 lwi r21, r1, 8 /* PIC register */ 296 addik r1, r1, 12 297 298 /* return from sub-routine (with delay slot) */ 299 rtsd r15, 8 300 nop 301 302 .size ffi_closure_SYSV, . - ffi_closure_SYSV 303