OSDN Git Service

docs: Fix documentation Copyright date
[qmiga/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.1 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
71     /* first we count the number of fields */
72     type_ptr = types;
73     nb_fields = 0;
74     while (*type_ptr != TYPE_NULL) {
75         type_ptr = thunk_type_next(type_ptr);
76         nb_fields++;
77     }
78     assert(nb_fields > 0);
79     se = struct_entries + id;
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 */
88
89     for (i = 0; i < ARRAY_SIZE(se->field_offsets); i++) {
90         offset = 0;
91         max_align = 1;
92         se->field_offsets[i] = g_new(int, nb_fields);
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);
103         }
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
111     }
112 }
113
114 void thunk_register_struct_direct(int id, const char *name,
115                                   const StructEntry *se1)
116 {
117     StructEntry *se;
118
119     assert(id < max_struct_entries);
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             assert(*type_ptr < max_struct_entries);
248             se = struct_entries + *type_ptr++;
249             if (se->convert[0] != NULL) {
250                 /* specific conversion is needed */
251                 (*se->convert[to_host])(dst, src);
252             } else {
253                 /* standard struct conversion */
254                 field_types = se->field_types;
255                 dst_offsets = se->field_offsets[to_host];
256                 src_offsets = se->field_offsets[1 - to_host];
257                 d = dst;
258                 s = src;
259                 for(i = 0;i < se->nb_fields; i++) {
260                     field_types = thunk_convert(d + dst_offsets[i],
261                                                 s + src_offsets[i],
262                                                 field_types, to_host);
263                 }
264             }
265         }
266         break;
267     default:
268         fprintf(stderr, "Invalid type 0x%x\n", type);
269         break;
270     }
271     return type_ptr;
272 }
273
274 const argtype *thunk_print(void *arg, const argtype *type_ptr)
275 {
276     int type;
277
278     type = *type_ptr++;
279
280     switch (type) {
281     case TYPE_CHAR:
282         qemu_log("%c", *(uint8_t *)arg);
283         break;
284     case TYPE_SHORT:
285         qemu_log("%" PRId16, tswap16(*(uint16_t *)arg));
286         break;
287     case TYPE_INT:
288         qemu_log("%" PRId32, tswap32(*(uint32_t *)arg));
289         break;
290     case TYPE_LONGLONG:
291         qemu_log("%" PRId64, tswap64(*(uint64_t *)arg));
292         break;
293     case TYPE_ULONGLONG:
294         qemu_log("%" PRIu64, tswap64(*(uint64_t *)arg));
295         break;
296 #if HOST_LONG_BITS == 32 && TARGET_ABI_BITS == 32
297     case TYPE_PTRVOID:
298         qemu_log("0x%" PRIx32, tswap32(*(uint32_t *)arg));
299         break;
300     case TYPE_LONG:
301         qemu_log("%" PRId32, tswap32(*(uint32_t *)arg));
302         break;
303     case TYPE_ULONG:
304         qemu_log("%" PRIu32, tswap32(*(uint32_t *)arg));
305         break;
306 #elif HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 32
307     case TYPE_PTRVOID:
308         qemu_log("0x%" PRIx32, tswap32(*(uint64_t *)arg & 0xffffffff));
309         break;
310     case TYPE_LONG:
311         qemu_log("%" PRId32, tswap32(*(uint64_t *)arg & 0xffffffff));
312         break;
313     case TYPE_ULONG:
314         qemu_log("%" PRIu32, tswap32(*(uint64_t *)arg & 0xffffffff));
315         break;
316 #elif HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 64
317     case TYPE_PTRVOID:
318         qemu_log("0x%" PRIx64, tswap64(*(uint64_t *)arg));
319         break;
320     case TYPE_LONG:
321         qemu_log("%" PRId64, tswap64(*(uint64_t *)arg));
322         break;
323     case TYPE_ULONG:
324         qemu_log("%" PRIu64, tswap64(*(uint64_t *)arg));
325         break;
326 #else
327     case TYPE_PTRVOID:
328         qemu_log("0x%" PRIx64, tswap64(*(uint64_t *)arg));
329         break;
330     case TYPE_LONG:
331         qemu_log("%" PRId64, tswap64(*(uint64_t *)arg));
332         break;
333     case TYPE_ULONG:
334         qemu_log("%" PRIu64, tswap64(*(uint64_t *)arg));
335         break;
336 #endif
337     case TYPE_OLDDEVT:
338     {
339         uint64_t val = 0;
340         switch (thunk_type_size(type_ptr - 1, 1)) {
341         case 2:
342             val = *(uint16_t *)arg;
343             break;
344         case 4:
345             val = *(uint32_t *)arg;
346             break;
347         case 8:
348             val = *(uint64_t *)arg;
349             break;
350         }
351         switch (thunk_type_size(type_ptr - 1, 0)) {
352         case 2:
353             qemu_log("%" PRIu16, tswap16(val));
354             break;
355         case 4:
356             qemu_log("%" PRIu32, tswap32(val));
357             break;
358         case 8:
359             qemu_log("%" PRIu64, tswap64(val));
360             break;
361         }
362     }
363     break;
364     case TYPE_ARRAY:
365         {
366             int i, array_length, arg_size;
367             uint8_t *a;
368             int is_string = 0;
369
370             array_length = *type_ptr++;
371             arg_size = thunk_type_size(type_ptr, 0);
372             a = arg;
373
374             if (*type_ptr == TYPE_CHAR) {
375                 qemu_log("\"");
376                 is_string = 1;
377             } else {
378                 qemu_log("[");
379             }
380
381             for (i = 0; i < array_length; i++) {
382                 if (i > 0 && !is_string) {
383                     qemu_log(",");
384                 }
385                 thunk_print(a, type_ptr);
386                 a += arg_size;
387             }
388
389             if (is_string) {
390                 qemu_log("\"");
391             } else {
392                 qemu_log("]");
393             }
394
395             type_ptr = thunk_type_next(type_ptr);
396         }
397         break;
398     case TYPE_STRUCT:
399         {
400             int i;
401             const StructEntry *se;
402             uint8_t  *a;
403             const argtype *field_types;
404             const int *arg_offsets;
405
406             se = struct_entries + *type_ptr++;
407
408             if (se->print != NULL) {
409                 se->print(arg);
410             } else {
411                 a = arg;
412
413                 field_types = se->field_types;
414                 arg_offsets = se->field_offsets[0];
415
416                 qemu_log("{");
417                 for (i = 0; i < se->nb_fields; i++) {
418                     if (i > 0) {
419                         qemu_log(",");
420                     }
421                     field_types = thunk_print(a + arg_offsets[i], field_types);
422                 }
423                 qemu_log("}");
424             }
425         }
426         break;
427     default:
428         g_assert_not_reached();
429     }
430     return type_ptr;
431 }
432
433 /* from em86 */
434
435 /* Utility function: Table-driven functions to translate bitmasks
436  * between host and target formats
437  */
438 unsigned int target_to_host_bitmask(unsigned int target_mask,
439                                     const bitmask_transtbl * trans_tbl)
440 {
441     const bitmask_transtbl *btp;
442     unsigned int host_mask = 0;
443
444     for (btp = trans_tbl; btp->target_mask && btp->host_mask; btp++) {
445         if ((target_mask & btp->target_mask) == btp->target_bits) {
446             host_mask |= btp->host_bits;
447         }
448     }
449     return host_mask;
450 }
451
452 unsigned int host_to_target_bitmask(unsigned int host_mask,
453                                     const bitmask_transtbl * trans_tbl)
454 {
455     const bitmask_transtbl *btp;
456     unsigned int target_mask = 0;
457
458     for (btp = trans_tbl; btp->target_mask && btp->host_mask; btp++) {
459         if ((host_mask & btp->host_mask) == btp->host_bits) {
460             target_mask |= btp->target_bits;
461         }
462     }
463     return target_mask;
464 }
465
466 int thunk_type_size_array(const argtype *type_ptr, int is_host)
467 {
468     return thunk_type_size(type_ptr, is_host);
469 }
470
471 int thunk_type_align_array(const argtype *type_ptr, int is_host)
472 {
473     return thunk_type_align(type_ptr, is_host);
474 }
475
476 void thunk_init(unsigned int max_structs)
477 {
478     max_struct_entries = max_structs;
479     struct_entries = g_new0(StructEntry, max_structs);
480 }