xref: /qemu/linux-user/thunk.c (revision b21e2380)
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 #include "qemu/log.h"
21 
22 #include "qemu.h"
23 #include "exec/user/thunk.h"
24 
25 //#define DEBUG
26 
27 static unsigned int max_struct_entries;
28 StructEntry *struct_entries;
29 
30 static const argtype *thunk_type_next_ptr(const argtype *type_ptr);
31 
32 static inline const argtype *thunk_type_next(const argtype *type_ptr)
33 {
34     int type;
35 
36     type = *type_ptr++;
37     switch(type) {
38     case TYPE_CHAR:
39     case TYPE_SHORT:
40     case TYPE_INT:
41     case TYPE_LONGLONG:
42     case TYPE_ULONGLONG:
43     case TYPE_LONG:
44     case TYPE_ULONG:
45     case TYPE_PTRVOID:
46     case TYPE_OLDDEVT:
47         return type_ptr;
48     case TYPE_PTR:
49         return thunk_type_next_ptr(type_ptr);
50     case TYPE_ARRAY:
51         return thunk_type_next_ptr(type_ptr + 1);
52     case TYPE_STRUCT:
53         return type_ptr + 1;
54     default:
55         return NULL;
56     }
57 }
58 
59 static const argtype *thunk_type_next_ptr(const argtype *type_ptr)
60 {
61     return thunk_type_next(type_ptr);
62 }
63 
64 void thunk_register_struct(int id, const char *name, const argtype *types)
65 {
66     const argtype *type_ptr;
67     StructEntry *se;
68     int nb_fields, offset, max_align, align, size, i, j;
69 
70     assert(id < max_struct_entries);
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     assert(nb_fields > 0);
80     se = struct_entries + id;
81     se->field_types = types;
82     se->nb_fields = nb_fields;
83     se->name = name;
84 #ifdef DEBUG
85     printf("struct %s: id=%d nb_fields=%d\n",
86            se->name, id, se->nb_fields);
87 #endif
88     /* now we can alloc the data */
89 
90     for (i = 0; i < ARRAY_SIZE(se->field_offsets); i++) {
91         offset = 0;
92         max_align = 1;
93         se->field_offsets[i] = g_new(int, nb_fields);
94         type_ptr = se->field_types;
95         for(j = 0;j < nb_fields; j++) {
96             size = thunk_type_size(type_ptr, i);
97             align = thunk_type_align(type_ptr, i);
98             offset = (offset + align - 1) & ~(align - 1);
99             se->field_offsets[i][j] = offset;
100             offset += size;
101             if (align > max_align)
102                 max_align = align;
103             type_ptr = thunk_type_next(type_ptr);
104         }
105         offset = (offset + max_align - 1) & ~(max_align - 1);
106         se->size[i] = offset;
107         se->align[i] = max_align;
108 #ifdef DEBUG
109         printf("%s: size=%d align=%d\n",
110                i == THUNK_HOST ? "host" : "target", offset, max_align);
111 #endif
112     }
113 }
114 
115 void thunk_register_struct_direct(int id, const char *name,
116                                   const StructEntry *se1)
117 {
118     StructEntry *se;
119 
120     assert(id < max_struct_entries);
121     se = struct_entries + id;
122     *se = *se1;
123     se->name = name;
124 }
125 
126 
127 /* now we can define the main conversion functions */
128 const argtype *thunk_convert(void *dst, const void *src,
129                              const argtype *type_ptr, int to_host)
130 {
131     int type;
132 
133     type = *type_ptr++;
134     switch(type) {
135     case TYPE_CHAR:
136         *(uint8_t *)dst = *(uint8_t *)src;
137         break;
138     case TYPE_SHORT:
139         *(uint16_t *)dst = tswap16(*(uint16_t *)src);
140         break;
141     case TYPE_INT:
142         *(uint32_t *)dst = tswap32(*(uint32_t *)src);
143         break;
144     case TYPE_LONGLONG:
145     case TYPE_ULONGLONG:
146         *(uint64_t *)dst = tswap64(*(uint64_t *)src);
147         break;
148 #if HOST_LONG_BITS == 32 && TARGET_ABI_BITS == 32
149     case TYPE_LONG:
150     case TYPE_ULONG:
151     case TYPE_PTRVOID:
152         *(uint32_t *)dst = tswap32(*(uint32_t *)src);
153         break;
154 #elif HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 32
155     case TYPE_LONG:
156     case TYPE_ULONG:
157     case TYPE_PTRVOID:
158         if (to_host) {
159             if (type == TYPE_LONG) {
160                 /* sign extension */
161                 *(uint64_t *)dst = (int32_t)tswap32(*(uint32_t *)src);
162             } else {
163                 *(uint64_t *)dst = tswap32(*(uint32_t *)src);
164             }
165         } else {
166             *(uint32_t *)dst = tswap32(*(uint64_t *)src & 0xffffffff);
167         }
168         break;
169 #elif HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 64
170     case TYPE_LONG:
171     case TYPE_ULONG:
172     case TYPE_PTRVOID:
173         *(uint64_t *)dst = tswap64(*(uint64_t *)src);
174         break;
175 #elif HOST_LONG_BITS == 32 && TARGET_ABI_BITS == 64
176     case TYPE_LONG:
177     case TYPE_ULONG:
178     case TYPE_PTRVOID:
179         if (to_host) {
180             *(uint32_t *)dst = tswap64(*(uint64_t *)src);
181         } else {
182             if (type == TYPE_LONG) {
183                 /* sign extension */
184                 *(uint64_t *)dst = tswap64(*(int32_t *)src);
185             } else {
186                 *(uint64_t *)dst = tswap64(*(uint32_t *)src);
187             }
188         }
189         break;
190 #else
191 #warning unsupported conversion
192 #endif
193     case TYPE_OLDDEVT:
194     {
195         uint64_t val = 0;
196         switch (thunk_type_size(type_ptr - 1, !to_host)) {
197         case 2:
198             val = *(uint16_t *)src;
199             break;
200         case 4:
201             val = *(uint32_t *)src;
202             break;
203         case 8:
204             val = *(uint64_t *)src;
205             break;
206         }
207         switch (thunk_type_size(type_ptr - 1, to_host)) {
208         case 2:
209             *(uint16_t *)dst = tswap16(val);
210             break;
211         case 4:
212             *(uint32_t *)dst = tswap32(val);
213             break;
214         case 8:
215             *(uint64_t *)dst = tswap64(val);
216             break;
217         }
218         break;
219     }
220     case TYPE_ARRAY:
221         {
222             int array_length, i, dst_size, src_size;
223             const uint8_t *s;
224             uint8_t  *d;
225 
226             array_length = *type_ptr++;
227             dst_size = thunk_type_size(type_ptr, to_host);
228             src_size = thunk_type_size(type_ptr, 1 - to_host);
229             d = dst;
230             s = src;
231             for(i = 0;i < array_length; i++) {
232                 thunk_convert(d, s, type_ptr, to_host);
233                 d += dst_size;
234                 s += src_size;
235             }
236             type_ptr = thunk_type_next(type_ptr);
237         }
238         break;
239     case TYPE_STRUCT:
240         {
241             int i;
242             const StructEntry *se;
243             const uint8_t *s;
244             uint8_t  *d;
245             const argtype *field_types;
246             const int *dst_offsets, *src_offsets;
247 
248             assert(*type_ptr < max_struct_entries);
249             se = struct_entries + *type_ptr++;
250             if (se->convert[0] != NULL) {
251                 /* specific conversion is needed */
252                 (*se->convert[to_host])(dst, src);
253             } else {
254                 /* standard struct conversion */
255                 field_types = se->field_types;
256                 dst_offsets = se->field_offsets[to_host];
257                 src_offsets = se->field_offsets[1 - to_host];
258                 d = dst;
259                 s = src;
260                 for(i = 0;i < se->nb_fields; i++) {
261                     field_types = thunk_convert(d + dst_offsets[i],
262                                                 s + src_offsets[i],
263                                                 field_types, to_host);
264                 }
265             }
266         }
267         break;
268     default:
269         fprintf(stderr, "Invalid type 0x%x\n", type);
270         break;
271     }
272     return type_ptr;
273 }
274 
275 const argtype *thunk_print(void *arg, const argtype *type_ptr)
276 {
277     int type;
278 
279     type = *type_ptr++;
280 
281     switch (type) {
282     case TYPE_CHAR:
283         qemu_log("%c", *(uint8_t *)arg);
284         break;
285     case TYPE_SHORT:
286         qemu_log("%" PRId16, tswap16(*(uint16_t *)arg));
287         break;
288     case TYPE_INT:
289         qemu_log("%" PRId32, tswap32(*(uint32_t *)arg));
290         break;
291     case TYPE_LONGLONG:
292         qemu_log("%" PRId64, tswap64(*(uint64_t *)arg));
293         break;
294     case TYPE_ULONGLONG:
295         qemu_log("%" PRIu64, tswap64(*(uint64_t *)arg));
296         break;
297 #if HOST_LONG_BITS == 32 && TARGET_ABI_BITS == 32
298     case TYPE_PTRVOID:
299         qemu_log("0x%" PRIx32, tswap32(*(uint32_t *)arg));
300         break;
301     case TYPE_LONG:
302         qemu_log("%" PRId32, tswap32(*(uint32_t *)arg));
303         break;
304     case TYPE_ULONG:
305         qemu_log("%" PRIu32, tswap32(*(uint32_t *)arg));
306         break;
307 #elif HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 32
308     case TYPE_PTRVOID:
309         qemu_log("0x%" PRIx32, tswap32(*(uint64_t *)arg & 0xffffffff));
310         break;
311     case TYPE_LONG:
312         qemu_log("%" PRId32, tswap32(*(uint64_t *)arg & 0xffffffff));
313         break;
314     case TYPE_ULONG:
315         qemu_log("%" PRIu32, tswap32(*(uint64_t *)arg & 0xffffffff));
316         break;
317 #elif HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 64
318     case TYPE_PTRVOID:
319         qemu_log("0x%" PRIx64, tswap64(*(uint64_t *)arg));
320         break;
321     case TYPE_LONG:
322         qemu_log("%" PRId64, tswap64(*(uint64_t *)arg));
323         break;
324     case TYPE_ULONG:
325         qemu_log("%" PRIu64, tswap64(*(uint64_t *)arg));
326         break;
327 #else
328     case TYPE_PTRVOID:
329         qemu_log("0x%" PRIx64, tswap64(*(uint64_t *)arg));
330         break;
331     case TYPE_LONG:
332         qemu_log("%" PRId64, tswap64(*(uint64_t *)arg));
333         break;
334     case TYPE_ULONG:
335         qemu_log("%" PRIu64, tswap64(*(uint64_t *)arg));
336         break;
337 #endif
338     case TYPE_OLDDEVT:
339     {
340         uint64_t val = 0;
341         switch (thunk_type_size(type_ptr - 1, 1)) {
342         case 2:
343             val = *(uint16_t *)arg;
344             break;
345         case 4:
346             val = *(uint32_t *)arg;
347             break;
348         case 8:
349             val = *(uint64_t *)arg;
350             break;
351         }
352         switch (thunk_type_size(type_ptr - 1, 0)) {
353         case 2:
354             qemu_log("%" PRIu16, tswap16(val));
355             break;
356         case 4:
357             qemu_log("%" PRIu32, tswap32(val));
358             break;
359         case 8:
360             qemu_log("%" PRIu64, tswap64(val));
361             break;
362         }
363     }
364     break;
365     case TYPE_ARRAY:
366         {
367             int i, array_length, arg_size;
368             uint8_t *a;
369             int is_string = 0;
370 
371             array_length = *type_ptr++;
372             arg_size = thunk_type_size(type_ptr, 0);
373             a = arg;
374 
375             if (*type_ptr == TYPE_CHAR) {
376                 qemu_log("\"");
377                 is_string = 1;
378             } else {
379                 qemu_log("[");
380             }
381 
382             for (i = 0; i < array_length; i++) {
383                 if (i > 0 && !is_string) {
384                     qemu_log(",");
385                 }
386                 thunk_print(a, type_ptr);
387                 a += arg_size;
388             }
389 
390             if (is_string) {
391                 qemu_log("\"");
392             } else {
393                 qemu_log("]");
394             }
395 
396             type_ptr = thunk_type_next(type_ptr);
397         }
398         break;
399     case TYPE_STRUCT:
400         {
401             int i;
402             const StructEntry *se;
403             uint8_t  *a;
404             const argtype *field_types;
405             const int *arg_offsets;
406 
407             se = struct_entries + *type_ptr++;
408 
409             if (se->print != NULL) {
410                 se->print(arg);
411             } else {
412                 a = arg;
413 
414                 field_types = se->field_types;
415                 arg_offsets = se->field_offsets[0];
416 
417                 qemu_log("{");
418                 for (i = 0; i < se->nb_fields; i++) {
419                     if (i > 0) {
420                         qemu_log(",");
421                     }
422                     field_types = thunk_print(a + arg_offsets[i], field_types);
423                 }
424                 qemu_log("}");
425             }
426         }
427         break;
428     default:
429         g_assert_not_reached();
430     }
431     return type_ptr;
432 }
433 
434 /* from em86 */
435 
436 /* Utility function: Table-driven functions to translate bitmasks
437  * between host and target formats
438  */
439 unsigned int target_to_host_bitmask(unsigned int target_mask,
440                                     const bitmask_transtbl * trans_tbl)
441 {
442     const bitmask_transtbl *btp;
443     unsigned int host_mask = 0;
444 
445     for (btp = trans_tbl; btp->target_mask && btp->host_mask; btp++) {
446         if ((target_mask & btp->target_mask) == btp->target_bits) {
447             host_mask |= btp->host_bits;
448         }
449     }
450     return host_mask;
451 }
452 
453 unsigned int host_to_target_bitmask(unsigned int host_mask,
454                                     const bitmask_transtbl * trans_tbl)
455 {
456     const bitmask_transtbl *btp;
457     unsigned int target_mask = 0;
458 
459     for (btp = trans_tbl; btp->target_mask && btp->host_mask; btp++) {
460         if ((host_mask & btp->host_mask) == btp->host_bits) {
461             target_mask |= btp->target_bits;
462         }
463     }
464     return target_mask;
465 }
466 
467 int thunk_type_size_array(const argtype *type_ptr, int is_host)
468 {
469     return thunk_type_size(type_ptr, is_host);
470 }
471 
472 int thunk_type_align_array(const argtype *type_ptr, int is_host)
473 {
474     return thunk_type_align(type_ptr, is_host);
475 }
476 
477 void thunk_init(unsigned int max_structs)
478 {
479     max_struct_entries = max_structs;
480     struct_entries = g_new0(StructEntry, max_structs);
481 }
482