2 * Generic thunking code to convert data between host and target CPU
4 * Copyright (c) 2003 Fabrice Bellard
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.
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.
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/>.
19 #include "qemu/osdep.h"
23 #include "user/thunk.h"
27 static unsigned int max_struct_entries
;
28 StructEntry
*struct_entries
;
30 static const argtype
*thunk_type_next_ptr(const argtype
*type_ptr
);
32 static inline const argtype
*thunk_type_next(const argtype
*type_ptr
)
49 return thunk_type_next_ptr(type_ptr
);
51 return thunk_type_next_ptr(type_ptr
+ 1);
59 static const argtype
*thunk_type_next_ptr(const argtype
*type_ptr
)
61 return thunk_type_next(type_ptr
);
64 void thunk_register_struct(int id
, const char *name
, const argtype
*types
)
66 const argtype
*type_ptr
;
68 int nb_fields
, offset
, max_align
, align
, size
, i
, j
;
70 assert(id
< max_struct_entries
);
72 /* first we count the number of fields */
75 while (*type_ptr
!= TYPE_NULL
) {
76 type_ptr
= thunk_type_next(type_ptr
);
79 assert(nb_fields
> 0);
80 se
= struct_entries
+ id
;
81 se
->field_types
= types
;
82 se
->nb_fields
= nb_fields
;
85 printf("struct %s: id=%d nb_fields=%d\n",
86 se
->name
, id
, se
->nb_fields
);
88 /* now we can alloc the data */
90 for (i
= 0; i
< ARRAY_SIZE(se
->field_offsets
); i
++) {
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
;
101 if (align
> max_align
)
103 type_ptr
= thunk_type_next(type_ptr
);
105 offset
= (offset
+ max_align
- 1) & ~(max_align
- 1);
106 se
->size
[i
] = offset
;
107 se
->align
[i
] = max_align
;
109 printf("%s: size=%d align=%d\n",
110 i
== THUNK_HOST
? "host" : "target", offset
, max_align
);
115 void thunk_register_struct_direct(int id
, const char *name
,
116 const StructEntry
*se1
)
120 assert(id
< max_struct_entries
);
121 se
= struct_entries
+ id
;
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
)
136 *(uint8_t *)dst
= *(uint8_t *)src
;
139 *(uint16_t *)dst
= tswap16(*(uint16_t *)src
);
142 *(uint32_t *)dst
= tswap32(*(uint32_t *)src
);
146 *(uint64_t *)dst
= tswap64(*(uint64_t *)src
);
148 #if HOST_LONG_BITS == 32 && TARGET_ABI_BITS == 32
152 *(uint32_t *)dst
= tswap32(*(uint32_t *)src
);
154 #elif HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 32
159 if (type
== TYPE_LONG
) {
161 *(uint64_t *)dst
= (int32_t)tswap32(*(uint32_t *)src
);
163 *(uint64_t *)dst
= tswap32(*(uint32_t *)src
);
166 *(uint32_t *)dst
= tswap32(*(uint64_t *)src
& 0xffffffff);
169 #elif HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 64
173 *(uint64_t *)dst
= tswap64(*(uint64_t *)src
);
175 #elif HOST_LONG_BITS == 32 && TARGET_ABI_BITS == 64
180 *(uint32_t *)dst
= tswap64(*(uint64_t *)src
);
182 if (type
== TYPE_LONG
) {
184 *(uint64_t *)dst
= tswap64(*(int32_t *)src
);
186 *(uint64_t *)dst
= tswap64(*(uint32_t *)src
);
191 #warning unsupported conversion
196 switch (thunk_type_size(type_ptr
- 1, !to_host
)) {
198 val
= *(uint16_t *)src
;
201 val
= *(uint32_t *)src
;
204 val
= *(uint64_t *)src
;
207 switch (thunk_type_size(type_ptr
- 1, to_host
)) {
209 *(uint16_t *)dst
= tswap16(val
);
212 *(uint32_t *)dst
= tswap32(val
);
215 *(uint64_t *)dst
= tswap64(val
);
222 int array_length
, i
, dst_size
, src_size
;
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
);
231 for(i
= 0;i
< array_length
; i
++) {
232 thunk_convert(d
, s
, type_ptr
, to_host
);
236 type_ptr
= thunk_type_next(type_ptr
);
242 const StructEntry
*se
;
245 const argtype
*field_types
;
246 const int *dst_offsets
, *src_offsets
;
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
);
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
];
260 for(i
= 0;i
< se
->nb_fields
; i
++) {
261 field_types
= thunk_convert(d
+ dst_offsets
[i
],
263 field_types
, to_host
);
269 fprintf(stderr
, "Invalid type 0x%x\n", type
);
275 const argtype
*thunk_print(void *arg
, const argtype
*type_ptr
)
283 qemu_log("%c", *(uint8_t *)arg
);
286 qemu_log("%" PRId16
, tswap16(*(uint16_t *)arg
));
289 qemu_log("%" PRId32
, tswap32(*(uint32_t *)arg
));
292 qemu_log("%" PRId64
, tswap64(*(uint64_t *)arg
));
295 qemu_log("%" PRIu64
, tswap64(*(uint64_t *)arg
));
297 #if HOST_LONG_BITS == 32 && TARGET_ABI_BITS == 32
299 qemu_log("0x%" PRIx32
, tswap32(*(uint32_t *)arg
));
302 qemu_log("%" PRId32
, tswap32(*(uint32_t *)arg
));
305 qemu_log("%" PRIu32
, tswap32(*(uint32_t *)arg
));
307 #elif HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 32
309 qemu_log("0x%" PRIx32
, tswap32(*(uint64_t *)arg
& 0xffffffff));
312 qemu_log("%" PRId32
, tswap32(*(uint64_t *)arg
& 0xffffffff));
315 qemu_log("%" PRIu32
, tswap32(*(uint64_t *)arg
& 0xffffffff));
317 #elif HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 64
319 qemu_log("0x%" PRIx64
, tswap64(*(uint64_t *)arg
));
322 qemu_log("%" PRId64
, tswap64(*(uint64_t *)arg
));
325 qemu_log("%" PRIu64
, tswap64(*(uint64_t *)arg
));
329 qemu_log("0x%" PRIx64
, tswap64(*(uint64_t *)arg
));
332 qemu_log("%" PRId64
, tswap64(*(uint64_t *)arg
));
335 qemu_log("%" PRIu64
, tswap64(*(uint64_t *)arg
));
341 switch (thunk_type_size(type_ptr
- 1, 1)) {
343 val
= *(uint16_t *)arg
;
346 val
= *(uint32_t *)arg
;
349 val
= *(uint64_t *)arg
;
352 switch (thunk_type_size(type_ptr
- 1, 0)) {
354 qemu_log("%" PRIu16
, tswap16(val
));
357 qemu_log("%" PRIu32
, tswap32(val
));
360 qemu_log("%" PRIu64
, tswap64(val
));
367 int i
, array_length
, arg_size
;
371 array_length
= *type_ptr
++;
372 arg_size
= thunk_type_size(type_ptr
, 0);
375 if (*type_ptr
== TYPE_CHAR
) {
382 for (i
= 0; i
< array_length
; i
++) {
383 if (i
> 0 && !is_string
) {
386 thunk_print(a
, type_ptr
);
396 type_ptr
= thunk_type_next(type_ptr
);
402 const StructEntry
*se
;
404 const argtype
*field_types
;
405 const int *arg_offsets
;
407 se
= struct_entries
+ *type_ptr
++;
409 if (se
->print
!= NULL
) {
414 field_types
= se
->field_types
;
415 arg_offsets
= se
->field_offsets
[0];
418 for (i
= 0; i
< se
->nb_fields
; i
++) {
422 field_types
= thunk_print(a
+ arg_offsets
[i
], field_types
);
429 g_assert_not_reached();
436 /* Utility function: Table-driven functions to translate bitmasks
437 * between host and target formats
439 unsigned int target_to_host_bitmask_len(unsigned int target_mask
,
440 const bitmask_transtbl
*tbl
,
443 unsigned int host_mask
= 0;
445 for (size_t i
= 0; i
< len
; ++i
) {
446 if ((target_mask
& tbl
[i
].target_mask
) == tbl
[i
].target_bits
) {
447 host_mask
|= tbl
[i
].host_bits
;
453 unsigned int host_to_target_bitmask_len(unsigned int host_mask
,
454 const bitmask_transtbl
*tbl
,
457 unsigned int target_mask
= 0;
459 for (size_t i
= 0; i
< len
; ++i
) {
460 if ((host_mask
& tbl
[i
].host_mask
) == tbl
[i
].host_bits
) {
461 target_mask
|= tbl
[i
].target_bits
;
467 int thunk_type_size_array(const argtype
*type_ptr
, int is_host
)
469 return thunk_type_size(type_ptr
, is_host
);
472 int thunk_type_align_array(const argtype
*type_ptr
, int is_host
)
474 return thunk_type_align(type_ptr
, is_host
);
477 void thunk_init(unsigned int max_structs
)
479 max_struct_entries
= max_structs
;
480 struct_entries
= g_new0(StructEntry
, max_structs
);