Merge remote-tracking branch 'qemu/master'
[qemu/ar7.git] / thunk.c
blob8508cd66fb2f5fcba9b892b1fbc50ab84b39fad7
1 /*
2 * Generic thunking code to convert data between host and target CPU
4 * Copyright (c) 2003 Fabrice Bellard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
20 #include "qemu-common.h"
21 #include "qemu.h"
22 #include "exec/user/thunk.h"
24 //#define DEBUG
26 #define MAX_STRUCTS 128
28 /* XXX: make it dynamic */
29 StructEntry struct_entries[MAX_STRUCTS];
31 static const argtype *thunk_type_next_ptr(const argtype *type_ptr);
33 static inline const argtype *thunk_type_next(const argtype *type_ptr)
35 int type;
37 type = *type_ptr++;
38 switch(type) {
39 case TYPE_CHAR:
40 case TYPE_SHORT:
41 case TYPE_INT:
42 case TYPE_LONGLONG:
43 case TYPE_ULONGLONG:
44 case TYPE_LONG:
45 case TYPE_ULONG:
46 case TYPE_PTRVOID:
47 case TYPE_OLDDEVT:
48 return type_ptr;
49 case TYPE_PTR:
50 return thunk_type_next_ptr(type_ptr);
51 case TYPE_ARRAY:
52 return thunk_type_next_ptr(type_ptr + 1);
53 case TYPE_STRUCT:
54 return type_ptr + 1;
55 default:
56 return NULL;
60 static const argtype *thunk_type_next_ptr(const argtype *type_ptr)
62 return thunk_type_next(type_ptr);
65 void thunk_register_struct(int id, const char *name, const argtype *types)
67 const argtype *type_ptr;
68 StructEntry *se;
69 int nb_fields, offset, max_align, align, size, i, j;
71 se = struct_entries + id;
73 /* first we count the number of fields */
74 type_ptr = types;
75 nb_fields = 0;
76 while (*type_ptr != TYPE_NULL) {
77 type_ptr = thunk_type_next(type_ptr);
78 nb_fields++;
80 se->field_types = types;
81 se->nb_fields = nb_fields;
82 se->name = name;
83 #ifdef DEBUG
84 printf("struct %s: id=%d nb_fields=%d\n",
85 se->name, id, se->nb_fields);
86 #endif
87 /* now we can alloc the data */
89 for(i = 0;i < 2; i++) {
90 offset = 0;
91 max_align = 1;
92 se->field_offsets[i] = malloc(nb_fields * sizeof(int));
93 type_ptr = se->field_types;
94 for(j = 0;j < nb_fields; j++) {
95 size = thunk_type_size(type_ptr, i);
96 align = thunk_type_align(type_ptr, i);
97 offset = (offset + align - 1) & ~(align - 1);
98 se->field_offsets[i][j] = offset;
99 offset += size;
100 if (align > max_align)
101 max_align = align;
102 type_ptr = thunk_type_next(type_ptr);
104 offset = (offset + max_align - 1) & ~(max_align - 1);
105 se->size[i] = offset;
106 se->align[i] = max_align;
107 #ifdef DEBUG
108 printf("%s: size=%d align=%d\n",
109 i == THUNK_HOST ? "host" : "target", offset, max_align);
110 #endif
114 void thunk_register_struct_direct(int id, const char *name,
115 const StructEntry *se1)
117 StructEntry *se;
118 se = struct_entries + id;
119 *se = *se1;
120 se->name = name;
124 /* now we can define the main conversion functions */
125 const argtype *thunk_convert(void *dst, const void *src,
126 const argtype *type_ptr, int to_host)
128 int type;
130 type = *type_ptr++;
131 switch(type) {
132 case TYPE_CHAR:
133 *(uint8_t *)dst = *(uint8_t *)src;
134 break;
135 case TYPE_SHORT:
136 *(uint16_t *)dst = tswap16(*(uint16_t *)src);
137 break;
138 case TYPE_INT:
139 *(uint32_t *)dst = tswap32(*(uint32_t *)src);
140 break;
141 case TYPE_LONGLONG:
142 case TYPE_ULONGLONG:
143 *(uint64_t *)dst = tswap64(*(uint64_t *)src);
144 break;
145 #if HOST_LONG_BITS == 32 && TARGET_ABI_BITS == 32
146 case TYPE_LONG:
147 case TYPE_ULONG:
148 case TYPE_PTRVOID:
149 *(uint32_t *)dst = tswap32(*(uint32_t *)src);
150 break;
151 #elif HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 32
152 case TYPE_LONG:
153 case TYPE_ULONG:
154 case TYPE_PTRVOID:
155 if (to_host) {
156 if (type == TYPE_LONG) {
157 /* sign extension */
158 *(uint64_t *)dst = (int32_t)tswap32(*(uint32_t *)src);
159 } else {
160 *(uint64_t *)dst = tswap32(*(uint32_t *)src);
162 } else {
163 *(uint32_t *)dst = tswap32(*(uint64_t *)src & 0xffffffff);
165 break;
166 #elif HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 64
167 case TYPE_LONG:
168 case TYPE_ULONG:
169 case TYPE_PTRVOID:
170 *(uint64_t *)dst = tswap64(*(uint64_t *)src);
171 break;
172 #elif HOST_LONG_BITS == 32 && TARGET_ABI_BITS == 64
173 case TYPE_LONG:
174 case TYPE_ULONG:
175 case TYPE_PTRVOID:
176 if (to_host) {
177 *(uint32_t *)dst = tswap64(*(uint64_t *)src);
178 } else {
179 if (type == TYPE_LONG) {
180 /* sign extension */
181 *(uint64_t *)dst = tswap64(*(int32_t *)src);
182 } else {
183 *(uint64_t *)dst = tswap64(*(uint32_t *)src);
186 break;
187 #else
188 #warning unsupported conversion
189 #endif
190 case TYPE_OLDDEVT:
192 uint64_t val = 0;
193 switch (thunk_type_size(type_ptr - 1, !to_host)) {
194 case 2:
195 val = *(uint16_t *)src;
196 break;
197 case 4:
198 val = *(uint32_t *)src;
199 break;
200 case 8:
201 val = *(uint64_t *)src;
202 break;
204 switch (thunk_type_size(type_ptr - 1, to_host)) {
205 case 2:
206 *(uint16_t *)dst = tswap16(val);
207 break;
208 case 4:
209 *(uint32_t *)dst = tswap32(val);
210 break;
211 case 8:
212 *(uint64_t *)dst = tswap64(val);
213 break;
215 break;
217 case TYPE_ARRAY:
219 int array_length, i, dst_size, src_size;
220 const uint8_t *s;
221 uint8_t *d;
223 array_length = *type_ptr++;
224 dst_size = thunk_type_size(type_ptr, to_host);
225 src_size = thunk_type_size(type_ptr, 1 - to_host);
226 d = dst;
227 s = src;
228 for(i = 0;i < array_length; i++) {
229 thunk_convert(d, s, type_ptr, to_host);
230 d += dst_size;
231 s += src_size;
233 type_ptr = thunk_type_next(type_ptr);
235 break;
236 case TYPE_STRUCT:
238 int i;
239 const StructEntry *se;
240 const uint8_t *s;
241 uint8_t *d;
242 const argtype *field_types;
243 const int *dst_offsets, *src_offsets;
245 se = struct_entries + *type_ptr++;
246 if (se->convert[0] != NULL) {
247 /* specific conversion is needed */
248 (*se->convert[to_host])(dst, src);
249 } else {
250 /* standard struct conversion */
251 field_types = se->field_types;
252 dst_offsets = se->field_offsets[to_host];
253 src_offsets = se->field_offsets[1 - to_host];
254 d = dst;
255 s = src;
256 for(i = 0;i < se->nb_fields; i++) {
257 field_types = thunk_convert(d + dst_offsets[i],
258 s + src_offsets[i],
259 field_types, to_host);
263 break;
264 default:
265 fprintf(stderr, "Invalid type 0x%x\n", type);
266 break;
268 return type_ptr;
271 /* from em86 */
273 /* Utility function: Table-driven functions to translate bitmasks
274 * between X86 and Alpha formats...
276 unsigned int target_to_host_bitmask(unsigned int x86_mask,
277 const bitmask_transtbl * trans_tbl)
279 const bitmask_transtbl *btp;
280 unsigned int alpha_mask = 0;
282 for(btp = trans_tbl; btp->x86_mask && btp->alpha_mask; btp++) {
283 if((x86_mask & btp->x86_mask) == btp->x86_bits) {
284 alpha_mask |= btp->alpha_bits;
287 return(alpha_mask);
290 unsigned int host_to_target_bitmask(unsigned int alpha_mask,
291 const bitmask_transtbl * trans_tbl)
293 const bitmask_transtbl *btp;
294 unsigned int x86_mask = 0;
296 for(btp = trans_tbl; btp->x86_mask && btp->alpha_mask; btp++) {
297 if((alpha_mask & btp->alpha_mask) == btp->alpha_bits) {
298 x86_mask |= btp->x86_bits;
301 return(x86_mask);
304 #ifndef NO_THUNK_TYPE_SIZE
305 int thunk_type_size_array(const argtype *type_ptr, int is_host)
307 return thunk_type_size(type_ptr, is_host);
310 int thunk_type_align_array(const argtype *type_ptr, int is_host)
312 return thunk_type_align(type_ptr, is_host);
314 #endif /* ndef NO_THUNK_TYPE_SIZE */