Home | History | Annotate | Download | only in metag
      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
    109 METAG_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 
    228 LSYM(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 
    255 METAG_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 
    302 ENTRY(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