sync with latest
[sdk/emulator/qemu.git] / thunk.c
1 /*
2  *  Generic thunking code to convert data between host and target CPU
3  *
4  *  Copyright (c) 2003 Fabrice Bellard
5  *
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.
10  *
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.
15  *
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/>.
18  */
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <stdarg.h>
22
23 #include "qemu.h"
24 #include "thunk.h"
25
26 //#define DEBUG
27
28 #define MAX_STRUCTS 128
29
30 /* XXX: make it dynamic */
31 StructEntry struct_entries[MAX_STRUCTS];
32
33 static const argtype *thunk_type_next_ptr(const argtype *type_ptr);
34
35 static inline const argtype *thunk_type_next(const argtype *type_ptr)
36 {
37     int type;
38
39     type = *type_ptr++;
40     switch(type) {
41     case TYPE_CHAR:
42     case TYPE_SHORT:
43     case TYPE_INT:
44     case TYPE_LONGLONG:
45     case TYPE_ULONGLONG:
46     case TYPE_LONG:
47     case TYPE_ULONG:
48     case TYPE_PTRVOID:
49     case TYPE_OLDDEVT:
50         return type_ptr;
51     case TYPE_PTR:
52         return thunk_type_next_ptr(type_ptr);
53     case TYPE_ARRAY:
54         return thunk_type_next_ptr(type_ptr + 1);
55     case TYPE_STRUCT:
56         return type_ptr + 1;
57     default:
58         return NULL;
59     }
60 }
61
62 static const argtype *thunk_type_next_ptr(const argtype *type_ptr)
63 {
64     return thunk_type_next(type_ptr);
65 }
66
67 void thunk_register_struct(int id, const char *name, const argtype *types)
68 {
69     const argtype *type_ptr;
70     StructEntry *se;
71     int nb_fields, offset, max_align, align, size, i, j;
72
73     se = struct_entries + id;
74
75     /* first we count the number of fields */
76     type_ptr = types;
77     nb_fields = 0;
78     while (*type_ptr != TYPE_NULL) {
79         type_ptr = thunk_type_next(type_ptr);
80         nb_fields++;
81     }
82     se->field_types = types;
83     se->nb_fields = nb_fields;
84     se->name = name;
85 #ifdef DEBUG
86     printf("struct %s: id=%d nb_fields=%d\n",
87            se->name, id, se->nb_fields);
88 #endif
89     /* now we can alloc the data */
90
91     for(i = 0;i < 2; i++) {
92         offset = 0;
93         max_align = 1;
94         se->field_offsets[i] = malloc(nb_fields * sizeof(int));
95         type_ptr = se->field_types;
96         for(j = 0;j < nb_fields; j++) {
97             size = thunk_type_size(type_ptr, i);
98             align = thunk_type_align(type_ptr, i);
99             offset = (offset + align - 1) & ~(align - 1);
100             se->field_offsets[i][j] = offset;
101             offset += size;
102             if (align > max_align)
103                 max_align = align;
104             type_ptr = thunk_type_next(type_ptr);
105         }
106         offset = (offset + max_align - 1) & ~(max_align - 1);
107         se->size[i] = offset;
108         se->align[i] = max_align;
109 #ifdef DEBUG
110         printf("%s: size=%d align=%d\n",
111                i == THUNK_HOST ? "host" : "target", offset, max_align);
112 #endif
113     }
114 }
115
116 void thunk_register_struct_direct(int id, const char *name,
117                                   const StructEntry *se1)
118 {
119     StructEntry *se;
120     se = struct_entries + id;
121     *se = *se1;
122     se->name = name;
123 }
124
125
126 /* now we can define the main conversion functions */
127 const argtype *thunk_convert(void *dst, const void *src,
128                              const argtype *type_ptr, int to_host)
129 {
130     int type;
131
132     type = *type_ptr++;
133     switch(type) {
134     case TYPE_CHAR:
135         *(uint8_t *)dst = *(uint8_t *)src;
136         break;
137     case TYPE_SHORT:
138         *(uint16_t *)dst = tswap16(*(uint16_t *)src);
139         break;
140     case TYPE_INT:
141         *(uint32_t *)dst = tswap32(*(uint32_t *)src);
142         break;
143     case TYPE_LONGLONG:
144     case TYPE_ULONGLONG:
145         *(uint64_t *)dst = tswap64(*(uint64_t *)src);
146         break;
147 #if HOST_LONG_BITS == 32 && TARGET_ABI_BITS == 32
148     case TYPE_LONG:
149     case TYPE_ULONG:
150     case TYPE_PTRVOID:
151         *(uint32_t *)dst = tswap32(*(uint32_t *)src);
152         break;
153 #elif HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 32
154     case TYPE_LONG:
155     case TYPE_ULONG:
156     case TYPE_PTRVOID:
157         if (to_host) {
158             if (type == TYPE_LONG) {
159                 /* sign extension */
160                 *(uint64_t *)dst = (int32_t)tswap32(*(uint32_t *)src);
161             } else {
162                 *(uint64_t *)dst = tswap32(*(uint32_t *)src);
163             }
164         } else {
165             *(uint32_t *)dst = tswap32(*(uint64_t *)src & 0xffffffff);
166         }
167         break;
168 #elif HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 64
169     case TYPE_LONG:
170     case TYPE_ULONG:
171     case TYPE_PTRVOID:
172         *(uint64_t *)dst = tswap64(*(uint64_t *)src);
173         break;
174 #elif HOST_LONG_BITS == 32 && TARGET_ABI_BITS == 64
175     case TYPE_LONG:
176     case TYPE_ULONG:
177     case TYPE_PTRVOID:
178         if (to_host) {
179             *(uint32_t *)dst = tswap64(*(uint64_t *)src);
180         } else {
181             if (type == TYPE_LONG) {
182                 /* sign extension */
183                 *(uint64_t *)dst = tswap64(*(int32_t *)src);
184             } else {
185                 *(uint64_t *)dst = tswap64(*(uint32_t *)src);
186             }
187         }
188         break;
189 #else
190 #warning unsupported conversion
191 #endif
192     case TYPE_OLDDEVT:
193     {
194         uint64_t val = 0;
195         switch (thunk_type_size(type_ptr - 1, !to_host)) {
196         case 2:
197             val = *(uint16_t *)src;
198             break;
199         case 4:
200             val = *(uint32_t *)src;
201             break;
202         case 8:
203             val = *(uint64_t *)src;
204             break;
205         }
206         switch (thunk_type_size(type_ptr - 1, to_host)) {
207         case 2:
208             *(uint16_t *)dst = tswap16(val);
209             break;
210         case 4:
211             *(uint32_t *)dst = tswap32(val);
212             break;
213         case 8:
214             *(uint64_t *)dst = tswap64(val);
215             break;
216         }
217         break;
218     }
219     case TYPE_ARRAY:
220         {
221             int array_length, i, dst_size, src_size;
222             const uint8_t *s;
223             uint8_t  *d;
224
225             array_length = *type_ptr++;
226             dst_size = thunk_type_size(type_ptr, to_host);
227             src_size = thunk_type_size(type_ptr, 1 - to_host);
228             d = dst;
229             s = src;
230             for(i = 0;i < array_length; i++) {
231                 thunk_convert(d, s, type_ptr, to_host);
232                 d += dst_size;
233                 s += src_size;
234             }
235             type_ptr = thunk_type_next(type_ptr);
236         }
237         break;
238     case TYPE_STRUCT:
239         {
240             int i;
241             const StructEntry *se;
242             const uint8_t *s;
243             uint8_t  *d;
244             const argtype *field_types;
245             const int *dst_offsets, *src_offsets;
246
247             se = struct_entries + *type_ptr++;
248             if (se->convert[0] != NULL) {
249                 /* specific conversion is needed */
250                 (*se->convert[to_host])(dst, src);
251             } else {
252                 /* standard struct conversion */
253                 field_types = se->field_types;
254                 dst_offsets = se->field_offsets[to_host];
255                 src_offsets = se->field_offsets[1 - to_host];
256                 d = dst;
257                 s = src;
258                 for(i = 0;i < se->nb_fields; i++) {
259                     field_types = thunk_convert(d + dst_offsets[i],
260                                                 s + src_offsets[i],
261                                                 field_types, to_host);
262                 }
263             }
264         }
265         break;
266     default:
267         fprintf(stderr, "Invalid type 0x%x\n", type);
268         break;
269     }
270     return type_ptr;
271 }
272
273 /* from em86 */
274
275 /* Utility function: Table-driven functions to translate bitmasks
276  * between X86 and Alpha formats...
277  */
278 unsigned int target_to_host_bitmask(unsigned int x86_mask,
279                                     const bitmask_transtbl * trans_tbl)
280 {
281     const bitmask_transtbl *btp;
282     unsigned int        alpha_mask = 0;
283
284     for(btp = trans_tbl; btp->x86_mask && btp->alpha_mask; btp++) {
285         if((x86_mask & btp->x86_mask) == btp->x86_bits) {
286             alpha_mask |= btp->alpha_bits;
287         }
288     }
289     return(alpha_mask);
290 }
291
292 unsigned int host_to_target_bitmask(unsigned int alpha_mask,
293                                     const bitmask_transtbl * trans_tbl)
294 {
295     const bitmask_transtbl *btp;
296     unsigned int        x86_mask = 0;
297
298     for(btp = trans_tbl; btp->x86_mask && btp->alpha_mask; btp++) {
299         if((alpha_mask & btp->alpha_mask) == btp->alpha_bits) {
300             x86_mask |= btp->x86_bits;
301         }
302     }
303     return(x86_mask);
304 }
305
306 #ifndef NO_THUNK_TYPE_SIZE
307 int thunk_type_size_array(const argtype *type_ptr, int is_host)
308 {
309     return thunk_type_size(type_ptr, is_host);
310 }
311
312 int thunk_type_align_array(const argtype *type_ptr, int is_host)
313 {
314     return thunk_type_align(type_ptr, is_host);
315 }
316 #endif /* ndef NO_THUNK_TYPE_SIZE */