]>
Commit | Line | Data |
---|---|---|
b1760f7f RH |
1 | /* ----------------------------------------------------------------------- |
2 | ffi.c - Copyright (c) 2013 Synopsys, Inc. (www.synopsys.com) | |
3 | ||
4 | ARC 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, EXPRESS | |
18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |
20 | IN NO EVENT SHALL RENESAS TECHNOLOGY BE LIABLE FOR ANY CLAIM, DAMAGES OR | |
21 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |
22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
23 | OTHER DEALINGS IN THE SOFTWARE. | |
24 | ----------------------------------------------------------------------- */ | |
25 | ||
26 | #include <ffi.h> | |
27 | #include <ffi_common.h> | |
28 | ||
29 | #include <stdlib.h> | |
30 | #include <stdint.h> | |
31 | ||
32 | #include <sys/cachectl.h> | |
33 | ||
34 | /* for little endian ARC, the code is in fact stored as mixed endian for | |
35 | performance reasons */ | |
36 | #if __BIG_ENDIAN__ | |
37 | #define CODE_ENDIAN(x) (x) | |
38 | #else | |
39 | #define CODE_ENDIAN(x) ( (((uint32_t) (x)) << 16) | (((uint32_t) (x)) >> 16)) | |
40 | #endif | |
41 | ||
42 | /* ffi_prep_args is called by the assembly routine once stack | |
43 | space has been allocated for the function's arguments. */ | |
44 | ||
45 | void | |
46 | ffi_prep_args (char *stack, extended_cif * ecif) | |
47 | { | |
48 | unsigned int i; | |
b1760f7f RH |
49 | void **p_argv; |
50 | char *argp; | |
51 | ffi_type **p_arg; | |
52 | ||
b1760f7f RH |
53 | argp = stack; |
54 | ||
55 | if (ecif->cif->rtype->type == FFI_TYPE_STRUCT) | |
56 | { | |
57 | *(void **) argp = ecif->rvalue; | |
58 | argp += 4; | |
59 | } | |
60 | ||
61 | p_argv = ecif->avalue; | |
62 | ||
63 | for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; | |
64 | (i != 0); i--, p_arg++) | |
65 | { | |
66 | size_t z; | |
67 | int alignment; | |
68 | ||
69 | /* align alignment to 4 */ | |
70 | alignment = (((*p_arg)->alignment - 1) | 3) + 1; | |
71 | ||
72 | /* Align if necessary. */ | |
73 | if ((alignment - 1) & (unsigned) argp) | |
92456a4e | 74 | argp = (char *) FFI_ALIGN (argp, alignment); |
b1760f7f RH |
75 | |
76 | z = (*p_arg)->size; | |
77 | if (z < sizeof (int)) | |
78 | { | |
79 | z = sizeof (int); | |
80 | ||
81 | switch ((*p_arg)->type) | |
82 | { | |
83 | case FFI_TYPE_SINT8: | |
84 | *(signed int *) argp = (signed int) *(SINT8 *) (*p_argv); | |
85 | break; | |
86 | ||
87 | case FFI_TYPE_UINT8: | |
88 | *(unsigned int *) argp = (unsigned int) *(UINT8 *) (*p_argv); | |
89 | break; | |
90 | ||
91 | case FFI_TYPE_SINT16: | |
92 | *(signed int *) argp = (signed int) *(SINT16 *) (*p_argv); | |
93 | break; | |
94 | ||
95 | case FFI_TYPE_UINT16: | |
96 | *(unsigned int *) argp = (unsigned int) *(UINT16 *) (*p_argv); | |
97 | break; | |
98 | ||
99 | case FFI_TYPE_STRUCT: | |
100 | memcpy (argp, *p_argv, (*p_arg)->size); | |
101 | break; | |
102 | ||
103 | default: | |
104 | FFI_ASSERT (0); | |
105 | } | |
106 | } | |
107 | else if (z == sizeof (int)) | |
108 | { | |
109 | *(unsigned int *) argp = (unsigned int) *(UINT32 *) (*p_argv); | |
110 | } | |
111 | else | |
112 | { | |
113 | if ((*p_arg)->type == FFI_TYPE_STRUCT) | |
114 | { | |
115 | memcpy (argp, *p_argv, z); | |
116 | } | |
117 | else | |
118 | { | |
119 | /* Double or long long 64bit. */ | |
120 | memcpy (argp, *p_argv, z); | |
121 | } | |
122 | } | |
123 | p_argv++; | |
124 | argp += z; | |
125 | } | |
126 | ||
127 | return; | |
128 | } | |
129 | ||
130 | /* Perform machine dependent cif processing. */ | |
131 | ffi_status | |
132 | ffi_prep_cif_machdep (ffi_cif * cif) | |
133 | { | |
134 | /* Set the return type flag. */ | |
135 | switch (cif->rtype->type) | |
136 | { | |
137 | case FFI_TYPE_VOID: | |
138 | cif->flags = (unsigned) cif->rtype->type; | |
139 | break; | |
140 | ||
141 | case FFI_TYPE_STRUCT: | |
142 | cif->flags = (unsigned) cif->rtype->type; | |
143 | break; | |
144 | ||
145 | case FFI_TYPE_SINT64: | |
146 | case FFI_TYPE_UINT64: | |
147 | case FFI_TYPE_DOUBLE: | |
148 | cif->flags = FFI_TYPE_DOUBLE; | |
149 | break; | |
150 | ||
151 | case FFI_TYPE_FLOAT: | |
152 | default: | |
153 | cif->flags = FFI_TYPE_INT; | |
154 | break; | |
155 | } | |
156 | ||
157 | return FFI_OK; | |
158 | } | |
159 | ||
160 | extern void ffi_call_ARCompact (void (*)(char *, extended_cif *), | |
161 | extended_cif *, unsigned, unsigned, | |
162 | unsigned *, void (*fn) (void)); | |
163 | ||
164 | void | |
165 | ffi_call (ffi_cif * cif, void (*fn) (void), void *rvalue, void **avalue) | |
166 | { | |
167 | extended_cif ecif; | |
168 | ||
169 | ecif.cif = cif; | |
170 | ecif.avalue = avalue; | |
171 | ||
172 | /* If the return value is a struct and we don't have | |
173 | a return value address then we need to make one. */ | |
174 | if ((rvalue == NULL) && (cif->rtype->type == FFI_TYPE_STRUCT)) | |
175 | { | |
176 | ecif.rvalue = alloca (cif->rtype->size); | |
177 | } | |
178 | else | |
179 | ecif.rvalue = rvalue; | |
180 | ||
181 | switch (cif->abi) | |
182 | { | |
183 | case FFI_ARCOMPACT: | |
184 | ffi_call_ARCompact (ffi_prep_args, &ecif, cif->bytes, | |
185 | cif->flags, ecif.rvalue, fn); | |
186 | break; | |
187 | ||
188 | default: | |
189 | FFI_ASSERT (0); | |
190 | break; | |
191 | } | |
192 | } | |
193 | ||
194 | int | |
195 | ffi_closure_inner_ARCompact (ffi_closure * closure, void *rvalue, | |
196 | ffi_arg * args) | |
197 | { | |
198 | void **arg_area, **p_argv; | |
199 | ffi_cif *cif = closure->cif; | |
200 | char *argp = (char *) args; | |
201 | ffi_type **p_argt; | |
202 | int i; | |
203 | ||
204 | arg_area = (void **) alloca (cif->nargs * sizeof (void *)); | |
205 | ||
206 | /* handle hidden argument */ | |
207 | if (cif->flags == FFI_TYPE_STRUCT) | |
208 | { | |
209 | rvalue = *(void **) argp; | |
210 | argp += 4; | |
211 | } | |
212 | ||
213 | p_argv = arg_area; | |
214 | ||
215 | for (i = 0, p_argt = cif->arg_types; i < cif->nargs; | |
216 | i++, p_argt++, p_argv++) | |
217 | { | |
218 | size_t z; | |
219 | int alignment; | |
220 | ||
221 | /* align alignment to 4 */ | |
222 | alignment = (((*p_argt)->alignment - 1) | 3) + 1; | |
223 | ||
224 | /* Align if necessary. */ | |
225 | if ((alignment - 1) & (unsigned) argp) | |
92456a4e | 226 | argp = (char *) FFI_ALIGN (argp, alignment); |
b1760f7f RH |
227 | |
228 | z = (*p_argt)->size; | |
229 | *p_argv = (void *) argp; | |
230 | argp += z; | |
231 | } | |
232 | ||
233 | (closure->fun) (cif, rvalue, arg_area, closure->user_data); | |
234 | ||
235 | return cif->flags; | |
236 | } | |
237 | ||
238 | extern void ffi_closure_ARCompact (void); | |
239 | ||
240 | ffi_status | |
241 | ffi_prep_closure_loc (ffi_closure * closure, ffi_cif * cif, | |
242 | void (*fun) (ffi_cif *, void *, void **, void *), | |
243 | void *user_data, void *codeloc) | |
244 | { | |
245 | uint32_t *tramp = (uint32_t *) & (closure->tramp[0]); | |
246 | ||
247 | switch (cif->abi) | |
248 | { | |
249 | case FFI_ARCOMPACT: | |
250 | FFI_ASSERT (tramp == codeloc); | |
251 | tramp[0] = CODE_ENDIAN (0x200a1fc0); /* mov r8, pcl */ | |
252 | tramp[1] = CODE_ENDIAN (0x20200f80); /* j [long imm] */ | |
253 | tramp[2] = CODE_ENDIAN (ffi_closure_ARCompact); | |
254 | break; | |
255 | ||
256 | default: | |
257 | return FFI_BAD_ABI; | |
258 | } | |
259 | ||
260 | closure->cif = cif; | |
261 | closure->fun = fun; | |
262 | closure->user_data = user_data; | |
263 | cacheflush (codeloc, FFI_TRAMPOLINE_SIZE, BCACHE); | |
264 | ||
265 | return FFI_OK; | |
266 | } |