1/* ----------------------------------------------------------------------- 2 sysv.S - Copyright (c) 2013 Imagination Technologies Ltd. 3 4 Meta 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 18 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, 19 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 22 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 23 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 DEALINGS IN THE SOFTWARE. 26 ----------------------------------------------------------------------- */ 27 28#define LIBFFI_ASM 29#include <fficonfig.h> 30#include <ffi.h> 31#ifdef HAVE_MACHINE_ASM_H 32#include <machine/asm.h> 33#else 34#ifdef __USER_LABEL_PREFIX__ 35#define CONCAT1(a, b) CONCAT2(a, b) 36#define CONCAT2(a, b) a ## b 37 38/* Use the right prefix for global labels. */ 39#define CNAME(x) CONCAT1 (__USER_LABEL_PREFIX__, x) 40#else 41#define CNAME(x) x 42#endif 43#define ENTRY(x) .globl CNAME(x); .type CNAME(x), %function; CNAME(x): 44#endif 45 46#ifdef __ELF__ 47#define LSYM(x) .x 48#else 49#define LSYM(x) x 50#endif 51 52.macro call_reg x= 53 .text 54 .balign 4 55 mov D1RtP, \x 56 swap D1RtP, PC 57.endm 58 59! Save register arguments 60.macro SAVE_ARGS 61 .text 62 .balign 4 63 setl [A0StP++], D0Ar6, D1Ar5 64 setl [A0StP++], D0Ar4, D1Ar3 65 setl [A0StP++], D0Ar2, D1Ar1 66.endm 67 68! Save retrun, frame pointer and other regs 69.macro SAVE_REGS regs= 70 .text 71 .balign 4 72 setl [A0StP++], D0FrT, D1RtP 73 ! Needs to be a pair of regs 74 .ifnc "\regs","" 75 setl [A0StP++], \regs 76 .endif 77.endm 78 79! Declare a global function 80.macro METAG_FUNC_START name 81 .text 82 .balign 4 83 ENTRY(\name) 84.endm 85 86! Return registers from the stack. Reverse SAVE_REGS operation 87.macro RET_REGS regs=, cond= 88 .ifnc "\regs", "" 89 getl \regs, [--A0StP] 90 .endif 91 getl D0FrT, D1RtP, [--A0StP] 92.endm 93 94! Return arguments 95.macro RET_ARGS 96 getl D0Ar2, D1Ar1, [--A0StP] 97 getl D0Ar4, D1Ar3, [--A0StP] 98 getl D0Ar6, D1Ar5, [--A0StP] 99.endm 100 101 102 ! D1Ar1: fn 103 ! D0Ar2: &ecif 104 ! D1Ar3: cif->bytes 105 ! D0Ar4: fig->flags 106 ! D1Ar5: ecif.rvalue 107 108 ! This assumes we are using GNU as 109METAG_FUNC_START ffi_call_SYSV 110 ! Save argument registers 111 112 SAVE_ARGS 113 114 ! new frame 115 mov D0FrT, A0FrP 116 add A0FrP, A0StP, #0 117 118 ! Preserve the old frame pointer 119 SAVE_REGS "D1.5, D0.5" 120 121 ! Make room for new args. cifs->bytes is the total space for input 122 ! and return arguments 123 124 add A0StP, A0StP, D1Ar3 125 126 ! Preserve cifs->bytes & fn 127 mov D0.5, D1Ar3 128 mov D1.5, D1Ar1 129 130 ! Place all of the ffi_prep_args in position 131 mov D1Ar1, A0StP 132 133 ! Call ffi_prep_args(stack, &ecif) 134#ifdef __PIC__ 135 callr D1RtP, CNAME(ffi_prep_args@PLT) 136#else 137 callr D1RtP, CNAME(ffi_prep_args) 138#endif 139 140 ! Restore fn pointer 141 142 ! The foreign stack should look like this 143 ! XXXXX XXXXXX <--- stack pointer 144 ! FnArgN rvalue 145 ! FnArgN+2 FnArgN+1 146 ! FnArgN+4 FnArgN+3 147 ! .... 148 ! 149 150 ! A0StP now points to the first (or return) argument + 4 151 152 ! Preserve cif->bytes 153 getl D0Ar2, D1Ar1, [--A0StP] 154 getl D0Ar4, D1Ar3, [--A0StP] 155 getl D0Ar6, D1Ar5, [--A0StP] 156 157 ! Place A0StP to the first argument again 158 add A0StP, A0StP, #24 ! That's because we loaded 6 regs x 4 byte each 159 160 ! A0FrP points to the initial stack without the reserved space for the 161 ! cifs->bytes, whilst A0StP points to the stack after the space allocation 162 163 ! fn was the first argument of ffi_call_SYSV. 164 ! The stack at this point looks like this: 165 ! 166 ! A0StP(on entry to _SYSV) -> Arg6 Arg5 | low 167 ! Arg4 Arg3 | 168 ! Arg2 Arg1 | 169 ! A0FrP ----> D0FrtP D1RtP | 170 ! D1.5 D0.5 | 171 ! A0StP(bf prep_args) -> FnArgn FnArgn-1 | 172 ! FnArgn-2FnArgn-3 | 173 ! ................ | <= cifs->bytes 174 ! FnArg4 FnArg3 | 175 ! A0StP (prv_A0StP+cifs->bytes) FnArg2 FnArg1 | high 176 ! 177 ! fn was in Arg1 so it's located in in A0FrP+#-0xC 178 ! 179 180 ! D0Re0 contains the size of arguments stored in registers 181 sub A0StP, A0StP, D0Re0 182 183 ! Arg1 is the function pointer for the foreign call. This has been 184 ! preserved in D1.5 185 186 ! Time to call (fn). Arguments should be like this: 187 ! Arg1-Arg6 are loaded to regs 188 ! The rest of the arguments are stored in stack pointed by A0StP 189 190 call_reg D1.5 191 192 ! Reset stack. 193 194 mov A0StP, A0FrP 195 196 ! Load Arg1 with the pointer to storage for the return type 197 ! This was stored in Arg5 198 199 getd D1Ar1, [A0FrP+#-20] 200 201 ! Load D0Ar2 with the return type code. This was stored in Arg4 (flags) 202 203 getd D0Ar2, [A0FrP+#-16] 204 205 ! We are ready to start processing the return value 206 ! D0Re0 (and D1Re0) hold the return value 207 208 ! If the return value is NULL, assume no return value 209 cmp D1Ar1, #0 210 beq LSYM(Lepilogue) 211 212 ! return INT 213 cmp D0Ar2, #FFI_TYPE_INT 214 ! Sadly, there is no setd{cc} instruction so we need to workaround that 215 bne .INT64 216 setd [D1Ar1], D0Re0 217 b LSYM(Lepilogue) 218 219 ! return INT64 220.INT64: 221 cmp D0Ar2, #FFI_TYPE_SINT64 222 setleq [D1Ar1], D0Re0, D1Re0 223 224 ! return DOUBLE 225 cmp D0Ar2, #FFI_TYPE_DOUBLE 226 setl [D1AR1++], D0Re0, D1Re0 227 228LSYM(Lepilogue): 229 ! At this point, the stack pointer points right after the argument 230 ! saved area. We need to restore 4 regs, therefore we need to move 231 ! 16 bytes ahead. 232 add A0StP, A0StP, #16 233 RET_REGS "D1.5, D0.5" 234 RET_ARGS 235 getd D0Re0, [A0StP] 236 mov A0FrP, D0FrT 237 swap D1RtP, PC 238 239.ffi_call_SYSV_end: 240 .size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV) 241 242 243/* 244 (called by ffi_metag_trampoline) 245 void ffi_closure_SYSV (ffi_closure*) 246 247 (called by ffi_closure_SYSV) 248 unsigned int FFI_HIDDEN 249 ffi_closure_SYSV_inner (closure,respp, args) 250 ffi_closure *closure; 251 void **respp; 252 void *args; 253*/ 254 255METAG_FUNC_START ffi_closure_SYSV 256 ! We assume that D1Ar1 holds the address of the 257 ! ffi_closure struct. We will use that to fetch the 258 ! arguments. The stack pointer points to an empty space 259 ! and it is ready to store more data. 260 261 ! D1Ar1 is ready 262 ! Allocate stack space for return value 263 add A0StP, A0StP, #8 264 ! Store it to D0Ar2 265 sub D0Ar2, A0StP, #8 266 267 sub D1Ar3, A0FrP, #4 268 269 ! D1Ar3 contains the address of the original D1Ar1 argument 270 ! We need to subtract #4 later on 271 272 ! Preverve D0Ar2 273 mov D0.5, D0Ar2 274 275#ifdef __PIC__ 276 callr D1RtP, CNAME(ffi_closure_SYSV_inner@PLT) 277#else 278 callr D1RtP, CNAME(ffi_closure_SYSV_inner) 279#endif 280 281 ! Check the return value and store it to D0.5 282 cmp D0Re0, #FFI_TYPE_INT 283 beq .Lretint 284 cmp D0Re0, #FFI_TYPE_DOUBLE 285 beq .Lretdouble 286.Lclosure_epilogue: 287 sub A0StP, A0StP, #8 288 RET_REGS "D1.5, D0.5" 289 RET_ARGS 290 swap D1RtP, PC 291 292.Lretint: 293 setd [D0.5], D0Re0 294 b .Lclosure_epilogue 295.Lretdouble: 296 setl [D0.5++], D0Re0, D1Re0 297 b .Lclosure_epilogue 298.ffi_closure_SYSV_end: 299.size CNAME(ffi_closure_SYSV),.ffi_closure_SYSV_end-CNAME(ffi_closure_SYSV) 300 301 302ENTRY(ffi_metag_trampoline) 303 SAVE_ARGS 304 ! New frame 305 mov A0FrP, A0StP 306 SAVE_REGS "D1.5, D0.5" 307 mov D0.5, PC 308 ! Load D1Ar1 the value of ffi_metag_trampoline 309 getd D1Ar1, [D0.5 + #8] 310 ! Jump to ffi_closure_SYSV 311 getd PC, [D0.5 + #12] 312