1/* -----------------------------------------------------------------------
2   sysv.S - Copyright (c) 2009  Bradley Smith <brad@brad-smith.co.uk>
3
4   AVR32 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 NONINFRINGEMENT.
20   IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21   CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22   TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23   SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24   --------------------------------------------------------------------- */
25
26#define LIBFFI_ASM
27#include <fficonfig.h>
28#include <ffi.h>
29
30    /* r12:  ffi_prep_args
31     * r11:  &ecif
32     * r10:  size
33     * r9:   cif->flags
34     * r8:   ecif.rvalue
35     * sp+0: cif->rstruct_flag
36     * sp+4: fn */
37
38    .text
39    .align  1
40    .globl  ffi_call_SYSV
41    .type   ffi_call_SYSV, @function
42ffi_call_SYSV:
43    stm     --sp, r0,r1,lr
44    stm     --sp, r8-r12
45    mov     r0, sp
46
47    /* Make room for all of the new args. */
48    sub     sp, r10
49    /* Pad to make way for potential skipped registers */
50    sub     sp, 20
51
52    /* Call ffi_prep_args(stack, &ecif). */
53    /* r11 already set */
54    mov     r1, r12
55    mov     r12, sp
56    icall   r1
57
58    /* Save new argument size */
59    mov     r1, r12
60
61    /* Move first 5 parameters in registers. */
62    ldm     sp++, r8-r12
63
64    /* call (fn) (...). */
65    ld.w    r1, r0[36]
66    icall   r1
67
68    /* Remove the space we pushed for the args. */
69    mov     sp, r0
70
71    /* Load r1 with the rstruct flag. */
72    ld.w    r1, sp[32]
73
74    /* Load r9 with the return type code. */
75    ld.w    r9, sp[12]
76
77    /* Load r8 with the return value pointer. */
78    ld.w    r8, sp[16]
79
80    /* If the return value pointer is NULL, assume no return value. */
81    cp.w    r8, 0
82    breq    .Lend
83
84    /* Check if return type is actually a struct */
85    cp.w    r1, 0
86    breq    1f
87
88    /* Return 8bit */
89    cp.w    r9, FFI_TYPE_UINT8
90    breq    .Lstore8
91
92    /* Return 16bit */
93    cp.w    r9, FFI_TYPE_UINT16
94    breq    .Lstore16
95
961:
97    /* Return 32bit */
98    cp.w    r9, FFI_TYPE_UINT32
99    breq    .Lstore32
100    cp.w    r9, FFI_TYPE_UINT16
101    breq    .Lstore32
102    cp.w    r9, FFI_TYPE_UINT8
103    breq    .Lstore32
104
105    /* Return 64bit */
106    cp.w    r9, FFI_TYPE_UINT64
107    breq    .Lstore64
108
109    /* Didn't match anything */
110    bral    .Lend
111
112.Lstore64:
113    st.w    r8[0], r11
114    st.w    r8[4], r10
115    bral    .Lend
116
117.Lstore32:
118    st.w    r8[0], r12
119    bral    .Lend
120
121.Lstore16:
122    st.h    r8[0], r12
123    bral    .Lend
124
125.Lstore8:
126    st.b    r8[0], r12
127    bral    .Lend
128
129.Lend:
130    sub     sp, -20
131    ldm     sp++, r0,r1,pc
132
133    .size   ffi_call_SYSV, . - ffi_call_SYSV
134
135
136    /* r12:  __ctx
137     * r11:  __rstruct_flag
138     * r10:  __inner */
139
140    .align  1
141    .globl  ffi_closure_SYSV
142    .type   ffi_closure_SYSV, @function
143ffi_closure_SYSV:
144    stm     --sp, r0,lr
145    mov     r0, r11
146    mov     r8, r10
147    sub     r10, sp, -8
148    sub     sp, 12
149    st.w    sp[8], sp
150    sub     r11, sp, -8
151    icall   r8
152
153    /* Check if return type is actually a struct */
154    cp.w    r0, 0
155    breq    1f
156
157    /* Return 8bit */
158    cp.w    r12, FFI_TYPE_UINT8
159    breq    .Lget8
160
161    /* Return 16bit */
162    cp.w    r12, FFI_TYPE_UINT16
163    breq    .Lget16
164
1651:
166    /* Return 32bit */
167    cp.w    r12, FFI_TYPE_UINT32
168    breq    .Lget32
169    cp.w    r12, FFI_TYPE_UINT16
170    breq    .Lget32
171    cp.w    r12, FFI_TYPE_UINT8
172    breq    .Lget32
173
174    /* Return 64bit */
175    cp.w    r12, FFI_TYPE_UINT64
176    breq    .Lget64
177
178    /* Didn't match anything */
179    bral    .Lclend
180
181.Lget64:
182    ld.w    r11, sp[0]
183    ld.w    r10, sp[4]
184    bral    .Lclend
185
186.Lget32:
187    ld.w    r12, sp[0]
188    bral    .Lclend
189
190.Lget16:
191    ld.uh   r12, sp[0]
192    bral    .Lclend
193
194.Lget8:
195    ld.ub   r12, sp[0]
196    bral    .Lclend
197
198.Lclend:
199    sub     sp, -12
200    ldm     sp++, r0,lr
201    sub     sp, -20
202    mov     pc, lr
203
204    .size   ffi_closure_SYSV, . - ffi_closure_SYSV
205
206#if defined __ELF__ && defined __linux__
207    .section    .note.GNU-stack,"",@progbits
208#endif
209