These changes are the raw update to qemu-2.6.
[kvmfornfv.git] / qemu / 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 "qemu/osdep.h"
20
21 #include "qemu.h"
22 #include "exec/user/thunk.h"
23
24 //#define DEBUG
25
26 static unsigned int max_struct_entries;
27 StructEntry *struct_entries;
28
29 static const argtype *thunk_type_next_ptr(const argtype *type_ptr);
30
31 static inline const argtype *thunk_type_next(const argtype *type_ptr)
32 {
33     int type;
34
35     type = *type_ptr++;
36     switch(type) {
37     case TYPE_CHAR:
38     case TYPE_SHORT:
39     case TYPE_INT:
40     case TYPE_LONGLONG:
41     case TYPE_ULONGLONG:
42     case TYPE_LONG:
43     case TYPE_ULONG:
44     case TYPE_PTRVOID:
45     case TYPE_OLDDEVT:
46         return type_ptr;
47     case TYPE_PTR:
48         return thunk_type_next_ptr(type_ptr);
49     case TYPE_ARRAY:
50         return thunk_type_next_ptr(type_ptr + 1);
51     case TYPE_STRUCT:
52         return type_ptr + 1;
53     default:
54         return NULL;
55     }
56 }
57
58 static const argtype *thunk_type_next_ptr(const argtype *type_ptr)
59 {
60     return thunk_type_next(type_ptr);
61 }
62
63 void thunk_register_struct(int id, const char *name, const argtype *types)
64 {
65     const argtype *type_ptr;
66     StructEntry *se;
67     int nb_fields, offset, max_align, align, size, i, j;
68
69     assert(id < max_struct_entries);
70     se = struct_entries + id;
71
72     /* first we count the number of fields */
73     type_ptr = types;
74     nb_fields = 0;
75     while (*type_ptr != TYPE_NULL) {
76         type_ptr = thunk_type_next(type_ptr);
77         nb_fields++;
78     }
79     se->field_types = types;
80     se->nb_fields = nb_fields;
81     se->name = name;
82 #ifdef DEBUG
83     printf("struct %s: id=%d nb_fields=%d\n",
84            se->name, id, se->nb_fields);
85 #endif
86     /* now we can alloc the data */
87
88     for(i = 0;i < 2; i++) {
89         offset = 0;
90         max_align = 1;
91         se->field_offsets[i] = malloc(nb_fields * sizeof(int));
92         type_ptr = se->field_types;
93         for(j = 0;j < nb_fields; j++) {
94             size = thunk_type_size(type_ptr, i);
95             align = thunk_type_align(type_ptr, i);
96             offset = (offset + align - 1) & ~(align - 1);
97             se->field_offsets[i][j] = offset;
98             offset += size;
99             if (align > max_align)
100                 max_align = align;
101             type_ptr = thunk_type_next(type_ptr);
102         }
103         offset = (offset + max_align - 1) & ~(max_align - 1);
104         se->size[i] = offset;
105         se->align[i] = max_align;
106 #ifdef DEBUG
107         printf("%s: size=%d align=%d\n",
108                i == THUNK_HOST ? "host" : "target", offset, max_align);
109 #endif
110     }
111 }
112
113 void thunk_register_struct_direct(int id, const char *name,
114                                   const StructEntry *se1)
115 {
116     StructEntry *se;
117
118     assert(id < max_struct_entries);
119     se = struct_entries + id;
120     *se = *se1;
121     se->name = name;
122 }
123
124
125 /* now we can define the main conversion functions */
126 const argtype *thunk_convert(void *dst, const void *src,
127                              const argtype *type_ptr, int to_host)
128 {
129     int type;
130
131     type = *type_ptr++;
132     switch(type) {
133     case TYPE_CHAR:
134         *(uint8_t *)dst = *(uint8_t *)src;
135         break;
136     case TYPE_SHORT:
137         *(uint16_t *)dst = tswap16(*(uint16_t *)src);
138         break;
139     case TYPE_INT:
140         *(uint32_t *)dst = tswap32(*(uint32_t *)src);
141         break;
142     case TYPE_LONGLONG:
143     case TYPE_ULONGLONG:
144         *(uint64_t *)dst = tswap64(*(uint64_t *)src);
145         break;
146 #if HOST_LONG_BITS == 32 && TARGET_ABI_BITS == 32
147     case TYPE_LONG:
148     case TYPE_ULONG:
149     case TYPE_PTRVOID:
150         *(uint32_t *)dst = tswap32(*(uint32_t *)src);
151         break;
152 #elif HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 32
153     case TYPE_LONG:
154     case TYPE_ULONG:
155     case TYPE_PTRVOID:
156         if (to_host) {
157             if (type == TYPE_LONG) {
158                 /* sign extension */
159                 *(uint64_t *)dst = (int32_t)tswap32(*(uint32_t *)src);
160             } else {
161                 *(uint64_t *)dst = tswap32(*(uint32_t *)src);
162             }
163         } else {
164             *(uint32_t *)dst = tswap32(*(uint64_t *)src & 0xffffffff);
165         }
166         break;
167 #elif HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 64
168     case TYPE_LONG:
169     case TYPE_ULONG:
170     case TYPE_PTRVOID:
171         *(uint64_t *)dst = tswap64(*(uint64_t *)src);
172         break;
173 #elif HOST_LONG_BITS == 32 && TARGET_ABI_BITS == 64
174     case TYPE_LONG:
175     case TYPE_ULONG:
176     case TYPE_PTRVOID:
177         if (to_host) {
178             *(uint32_t *)dst = tswap64(*(uint64_t *)src);
179         } else {
180             if (type == TYPE_LONG) {
181                 /* sign extension */
182                 *(uint64_t *)dst = tswap64(*(int32_t *)src);
183             } else {
184                 *(uint64_t *)dst = tswap64(*(uint32_t *)src);
185             }
186         }
187         break;
188 #else
189 #warning unsupported conversion
190 #endif
191     case TYPE_OLDDEVT:
192     {
193         uint64_t val = 0;
194         switch (thunk_type_size(type_ptr - 1, !to_host)) {
195         case 2:
196             val = *(uint16_t *)src;
197             break;
198         case 4:
199             val = *(uint32_t *)src;
200             break;
201         case 8:
202             val = *(uint64_t *)src;
203             break;
204         }
205         switch (thunk_type_size(type_ptr - 1, to_host)) {
206         case 2:
207             *(uint16_t *)dst = tswap16(val);
208             break;
209         case 4:
210             *(uint32_t *)dst = tswap32(val);
211             break;
212         case 8:
213             *(uint64_t *)dst = tswap64(val);
214             break;
215         }
216         break;
217     }
218     case TYPE_ARRAY:
219         {
220             int array_length, i, dst_size, src_size;
221             const uint8_t *s;
222             uint8_t  *d;
223
224             array_length = *type_ptr++;
225             dst_size = thunk_type_size(type_ptr, to_host);
226             src_size = thunk_type_size(type_ptr, 1 - to_host);
227             d = dst;
228             s = src;
229             for(i = 0;i < array_length; i++) {
230                 thunk_convert(d, s, type_ptr, to_host);
231                 d += dst_size;
232                 s += src_size;
233             }
234             type_ptr = thunk_type_next(type_ptr);
235         }
236         break;
237     case TYPE_STRUCT:
238         {
239             int i;
240             const StructEntry *se;
241             const uint8_t *s;
242             uint8_t  *d;
243             const argtype *field_types;
244             const int *dst_offsets, *src_offsets;
245
246             assert(*type_ptr < max_struct_entries);
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 */
317
318 void thunk_init(unsigned int max_structs)
319 {
320     max_struct_entries = max_structs;
321     struct_entries = g_new0(StructEntry, max_structs);
322 }