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 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"
22 #include "exec/user/thunk.h"
26 static unsigned int max_struct_entries
;
27 StructEntry
*struct_entries
;
29 static const argtype
*thunk_type_next_ptr(const argtype
*type_ptr
);
31 static inline const argtype
*thunk_type_next(const argtype
*type_ptr
)
48 return thunk_type_next_ptr(type_ptr
);
50 return thunk_type_next_ptr(type_ptr
+ 1);
58 static const argtype
*thunk_type_next_ptr(const argtype
*type_ptr
)
60 return thunk_type_next(type_ptr
);
63 void thunk_register_struct(int id
, const char *name
, const argtype
*types
)
65 const argtype
*type_ptr
;
67 int nb_fields
, offset
, max_align
, align
, size
, i
, j
;
69 assert(id
< max_struct_entries
);
71 /* first we count the number of fields */
74 while (*type_ptr
!= TYPE_NULL
) {
75 type_ptr
= thunk_type_next(type_ptr
);
78 assert(nb_fields
> 0);
79 se
= struct_entries
+ id
;
80 se
->field_types
= types
;
81 se
->nb_fields
= nb_fields
;
84 printf("struct %s: id=%d nb_fields=%d\n",
85 se
->name
, id
, se
->nb_fields
);
87 /* now we can alloc the data */
89 for(i
= 0;i
< 2; i
++) {
92 se
->field_offsets
[i
] = malloc(nb_fields
* sizeof(int));
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
;
100 if (align
> max_align
)
102 type_ptr
= thunk_type_next(type_ptr
);
104 offset
= (offset
+ max_align
- 1) & ~(max_align
- 1);
105 se
->size
[i
] = offset
;
106 se
->align
[i
] = max_align
;
108 printf("%s: size=%d align=%d\n",
109 i
== THUNK_HOST
? "host" : "target", offset
, max_align
);
114 void thunk_register_struct_direct(int id
, const char *name
,
115 const StructEntry
*se1
)
119 assert(id
< max_struct_entries
);
120 se
= struct_entries
+ id
;
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
)
135 *(uint8_t *)dst
= *(uint8_t *)src
;
138 *(uint16_t *)dst
= tswap16(*(uint16_t *)src
);
141 *(uint32_t *)dst
= tswap32(*(uint32_t *)src
);
145 *(uint64_t *)dst
= tswap64(*(uint64_t *)src
);
147 #if HOST_LONG_BITS == 32 && TARGET_ABI_BITS == 32
151 *(uint32_t *)dst
= tswap32(*(uint32_t *)src
);
153 #elif HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 32
158 if (type
== TYPE_LONG
) {
160 *(uint64_t *)dst
= (int32_t)tswap32(*(uint32_t *)src
);
162 *(uint64_t *)dst
= tswap32(*(uint32_t *)src
);
165 *(uint32_t *)dst
= tswap32(*(uint64_t *)src
& 0xffffffff);
168 #elif HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 64
172 *(uint64_t *)dst
= tswap64(*(uint64_t *)src
);
174 #elif HOST_LONG_BITS == 32 && TARGET_ABI_BITS == 64
179 *(uint32_t *)dst
= tswap64(*(uint64_t *)src
);
181 if (type
== TYPE_LONG
) {
183 *(uint64_t *)dst
= tswap64(*(int32_t *)src
);
185 *(uint64_t *)dst
= tswap64(*(uint32_t *)src
);
190 #warning unsupported conversion
195 switch (thunk_type_size(type_ptr
- 1, !to_host
)) {
197 val
= *(uint16_t *)src
;
200 val
= *(uint32_t *)src
;
203 val
= *(uint64_t *)src
;
206 switch (thunk_type_size(type_ptr
- 1, to_host
)) {
208 *(uint16_t *)dst
= tswap16(val
);
211 *(uint32_t *)dst
= tswap32(val
);
214 *(uint64_t *)dst
= tswap64(val
);
221 int array_length
, i
, dst_size
, src_size
;
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
);
230 for(i
= 0;i
< array_length
; i
++) {
231 thunk_convert(d
, s
, type_ptr
, to_host
);
235 type_ptr
= thunk_type_next(type_ptr
);
241 const StructEntry
*se
;
244 const argtype
*field_types
;
245 const int *dst_offsets
, *src_offsets
;
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
);
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
];
259 for(i
= 0;i
< se
->nb_fields
; i
++) {
260 field_types
= thunk_convert(d
+ dst_offsets
[i
],
262 field_types
, to_host
);
268 fprintf(stderr
, "Invalid type 0x%x\n", type
);
276 /* Utility function: Table-driven functions to translate bitmasks
277 * between host and target formats
279 unsigned int target_to_host_bitmask(unsigned int target_mask
,
280 const bitmask_transtbl
* trans_tbl
)
282 const bitmask_transtbl
*btp
;
283 unsigned int host_mask
= 0;
285 for (btp
= trans_tbl
; btp
->target_mask
&& btp
->host_mask
; btp
++) {
286 if ((target_mask
& btp
->target_mask
) == btp
->target_bits
) {
287 host_mask
|= btp
->host_bits
;
293 unsigned int host_to_target_bitmask(unsigned int host_mask
,
294 const bitmask_transtbl
* trans_tbl
)
296 const bitmask_transtbl
*btp
;
297 unsigned int target_mask
= 0;
299 for (btp
= trans_tbl
; btp
->target_mask
&& btp
->host_mask
; btp
++) {
300 if ((host_mask
& btp
->host_mask
) == btp
->host_bits
) {
301 target_mask
|= btp
->target_bits
;
307 int thunk_type_size_array(const argtype
*type_ptr
, int is_host
)
309 return thunk_type_size(type_ptr
, is_host
);
312 int thunk_type_align_array(const argtype
*type_ptr
, int is_host
)
314 return thunk_type_align(type_ptr
, is_host
);
317 void thunk_init(unsigned int max_structs
)
319 max_struct_entries
= max_structs
;
320 struct_entries
= g_new0(StructEntry
, max_structs
);