8f3e637b737313898544aa944e0c391f73ca8cc7
[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, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <stdarg.h>
23
24 #include "qemu.h"
25 #include "thunk.h"
26
27 //#define DEBUG
28
29 #define MAX_STRUCTS 128
30
31 /* XXX: make it dynamic */
32 StructEntry struct_entries[MAX_STRUCTS];
33
34 static const argtype *thunk_type_next_ptr(const argtype *type_ptr);
35
36 static inline const argtype *thunk_type_next(const argtype *type_ptr)
37 {
38     int type;
39
40     type = *type_ptr++;
41     switch(type) {
42     case TYPE_CHAR:
43     case TYPE_SHORT:
44     case TYPE_INT:
45     case TYPE_LONGLONG:
46     case TYPE_ULONGLONG:
47     case TYPE_LONG:
48     case TYPE_ULONG:
49     case TYPE_PTRVOID:
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_ARRAY:
193         {
194             int array_length, i, dst_size, src_size;
195             const uint8_t *s;
196             uint8_t  *d;
197
198             array_length = *type_ptr++;
199             dst_size = thunk_type_size(type_ptr, to_host);
200             src_size = thunk_type_size(type_ptr, 1 - to_host);
201             d = dst;
202             s = src;
203             for(i = 0;i < array_length; i++) {
204                 thunk_convert(d, s, type_ptr, to_host);
205                 d += dst_size;
206                 s += src_size;
207             }
208             type_ptr = thunk_type_next(type_ptr);
209         }
210         break;
211     case TYPE_STRUCT:
212         {
213             int i;
214             const StructEntry *se;
215             const uint8_t *s;
216             uint8_t  *d;
217             const argtype *field_types;
218             const int *dst_offsets, *src_offsets;
219
220             se = struct_entries + *type_ptr++;
221             if (se->convert[0] != NULL) {
222                 /* specific conversion is needed */
223                 (*se->convert[to_host])(dst, src);
224             } else {
225                 /* standard struct conversion */
226                 field_types = se->field_types;
227                 dst_offsets = se->field_offsets[to_host];
228                 src_offsets = se->field_offsets[1 - to_host];
229                 d = dst;
230                 s = src;
231                 for(i = 0;i < se->nb_fields; i++) {
232                     field_types = thunk_convert(d + dst_offsets[i],
233                                                 s + src_offsets[i],
234                                                 field_types, to_host);
235                 }
236             }
237         }
238         break;
239     default:
240         fprintf(stderr, "Invalid type 0x%x\n", type);
241         break;
242     }
243     return type_ptr;
244 }
245
246 /* from em86 */
247
248 /* Utility function: Table-driven functions to translate bitmasks
249  * between X86 and Alpha formats...
250  */
251 unsigned int target_to_host_bitmask(unsigned int x86_mask,
252                                     const bitmask_transtbl * trans_tbl)
253 {
254     const bitmask_transtbl *btp;
255     unsigned int        alpha_mask = 0;
256
257     for(btp = trans_tbl; btp->x86_mask && btp->alpha_mask; btp++) {
258         if((x86_mask & btp->x86_mask) == btp->x86_bits) {
259             alpha_mask |= btp->alpha_bits;
260         }
261     }
262     return(alpha_mask);
263 }
264
265 unsigned int host_to_target_bitmask(unsigned int alpha_mask,
266                                     const bitmask_transtbl * trans_tbl)
267 {
268     const bitmask_transtbl *btp;
269     unsigned int        x86_mask = 0;
270
271     for(btp = trans_tbl; btp->x86_mask && btp->alpha_mask; btp++) {
272         if((alpha_mask & btp->alpha_mask) == btp->alpha_bits) {
273             x86_mask |= btp->x86_bits;
274         }
275     }
276     return(x86_mask);
277 }
278
279 #ifndef NO_THUNK_TYPE_SIZE
280 int thunk_type_size_array(const argtype *type_ptr, int is_host)
281 {
282     return thunk_type_size(type_ptr, is_host);
283 }
284
285 int thunk_type_align_array(const argtype *type_ptr, int is_host)
286 {
287     return thunk_type_align(type_ptr, is_host);
288 }
289 #endif /* ndef NO_THUNK_TYPE_SIZE */