]> git.proxmox.com Git - qemu.git/blob - thunk.c
64 bit fix
[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 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, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <stdarg.h>
23
24 #include "qemu.h"
25 #include "thunk.h"
26
27 //#define DEBUG
28
29 #define MAX_STRUCTS 128
30
31 /* XXX: make it dynamic */
32 static StructEntry struct_entries[MAX_STRUCTS];
33
34 static inline int thunk_type_size(const argtype *type_ptr, int is_host)
35 {
36 int type, size;
37 const StructEntry *se;
38
39 type = *type_ptr;
40 switch(type) {
41 case TYPE_CHAR:
42 return 1;
43 case TYPE_SHORT:
44 return 2;
45 case TYPE_INT:
46 return 4;
47 case TYPE_LONGLONG:
48 case TYPE_ULONGLONG:
49 return 8;
50 case TYPE_LONG:
51 case TYPE_ULONG:
52 case TYPE_PTRVOID:
53 case TYPE_PTR:
54 if (is_host) {
55 return HOST_LONG_SIZE;
56 } else {
57 return TARGET_LONG_SIZE;
58 }
59 break;
60 case TYPE_ARRAY:
61 size = type_ptr[1];
62 return size * thunk_type_size(type_ptr + 2, is_host);
63 case TYPE_STRUCT:
64 se = struct_entries + type_ptr[1];
65 return se->size[is_host];
66 default:
67 return -1;
68 }
69 }
70
71 static inline int thunk_type_align(const argtype *type_ptr, int is_host)
72 {
73 int type;
74 const StructEntry *se;
75
76 type = *type_ptr;
77 switch(type) {
78 case TYPE_CHAR:
79 return 1;
80 case TYPE_SHORT:
81 return 2;
82 case TYPE_INT:
83 return 4;
84 case TYPE_LONGLONG:
85 case TYPE_ULONGLONG:
86 return 8;
87 case TYPE_LONG:
88 case TYPE_ULONG:
89 case TYPE_PTRVOID:
90 case TYPE_PTR:
91 if (is_host) {
92 return HOST_LONG_SIZE;
93 } else {
94 return TARGET_LONG_SIZE;
95 }
96 break;
97 case TYPE_ARRAY:
98 return thunk_type_align(type_ptr + 2, is_host);
99 case TYPE_STRUCT:
100 se = struct_entries + type_ptr[1];
101 return se->align[is_host];
102 default:
103 return -1;
104 }
105 }
106
107 static inline const argtype *thunk_type_next(const argtype *type_ptr)
108 {
109 int type;
110
111 type = *type_ptr++;
112 switch(type) {
113 case TYPE_CHAR:
114 case TYPE_SHORT:
115 case TYPE_INT:
116 case TYPE_LONGLONG:
117 case TYPE_ULONGLONG:
118 case TYPE_LONG:
119 case TYPE_ULONG:
120 case TYPE_PTRVOID:
121 return type_ptr;
122 case TYPE_PTR:
123 return thunk_type_next(type_ptr);
124 case TYPE_ARRAY:
125 return thunk_type_next(type_ptr + 1);
126 case TYPE_STRUCT:
127 return type_ptr + 1;
128 default:
129 return NULL;
130 }
131 }
132
133 void thunk_register_struct(int id, const char *name, const argtype *types)
134 {
135 const argtype *type_ptr;
136 StructEntry *se;
137 int nb_fields, offset, max_align, align, size, i, j;
138
139 se = struct_entries + id;
140
141 /* first we count the number of fields */
142 type_ptr = types;
143 nb_fields = 0;
144 while (*type_ptr != TYPE_NULL) {
145 type_ptr = thunk_type_next(type_ptr);
146 nb_fields++;
147 }
148 se->field_types = types;
149 se->nb_fields = nb_fields;
150 se->name = name;
151 #ifdef DEBUG
152 printf("struct %s: id=%d nb_fields=%d\n",
153 se->name, id, se->nb_fields);
154 #endif
155 /* now we can alloc the data */
156
157 for(i = 0;i < 2; i++) {
158 offset = 0;
159 max_align = 1;
160 se->field_offsets[i] = malloc(nb_fields * sizeof(int));
161 type_ptr = se->field_types;
162 for(j = 0;j < nb_fields; j++) {
163 size = thunk_type_size(type_ptr, i);
164 align = thunk_type_align(type_ptr, i);
165 offset = (offset + align - 1) & ~(align - 1);
166 se->field_offsets[i][j] = offset;
167 offset += size;
168 if (align > max_align)
169 max_align = align;
170 }
171 offset = (offset + max_align - 1) & ~(max_align - 1);
172 se->size[i] = offset;
173 se->align[i] = max_align;
174 #ifdef DEBUG
175 printf("%s: size=%d align=%d\n",
176 i == THUNK_HOST ? "host" : "target", offset, max_align);
177 #endif
178 }
179 }
180
181 void thunk_register_struct_direct(int id, const char *name, StructEntry *se1)
182 {
183 StructEntry *se;
184 se = struct_entries + id;
185 *se = *se1;
186 se->name = name;
187 }
188
189
190 /* now we can define the main conversion functions */
191 const argtype *thunk_convert(void *dst, const void *src,
192 const argtype *type_ptr, int to_host)
193 {
194 int type;
195
196 type = *type_ptr++;
197 switch(type) {
198 case TYPE_CHAR:
199 *(uint8_t *)dst = *(uint8_t *)src;
200 break;
201 case TYPE_SHORT:
202 *(uint16_t *)dst = tswap16(*(uint16_t *)src);
203 break;
204 case TYPE_INT:
205 *(uint32_t *)dst = tswap32(*(uint32_t *)src);
206 break;
207 case TYPE_LONGLONG:
208 case TYPE_ULONGLONG:
209 *(uint64_t *)dst = tswap64(*(uint64_t *)src);
210 break;
211 #if HOST_LONG_BITS == 32 && TARGET_LONG_BITS == 32
212 case TYPE_LONG:
213 case TYPE_ULONG:
214 case TYPE_PTRVOID:
215 *(uint32_t *)dst = tswap32(*(uint32_t *)src);
216 break;
217 #elif HOST_LONG_BITS == 64 && TARGET_LONG_BITS == 32
218 case TYPE_LONG:
219 case TYPE_ULONG:
220 case TYPE_PTRVOID:
221 if (to_host) {
222 *(uint64_t *)dst = tswap32(*(uint32_t *)src);
223 } else {
224 *(uint32_t *)dst = tswap32(*(uint64_t *)src & 0xffffffff);
225 }
226 break;
227 #else
228 #error unsupported conversion
229 #endif
230 case TYPE_ARRAY:
231 {
232 int array_length, i, dst_size, src_size;
233 const uint8_t *s;
234 uint8_t *d;
235
236 array_length = *type_ptr++;
237 dst_size = thunk_type_size(type_ptr, to_host);
238 src_size = thunk_type_size(type_ptr, 1 - to_host);
239 d = dst;
240 s = src;
241 for(i = 0;i < array_length; i++) {
242 thunk_convert(d, s, type_ptr, to_host);
243 d += dst_size;
244 s += src_size;
245 }
246 type_ptr = thunk_type_next(type_ptr);
247 }
248 break;
249 case TYPE_STRUCT:
250 {
251 int i;
252 const StructEntry *se;
253 const uint8_t *s;
254 uint8_t *d;
255 const argtype *field_types;
256 const int *dst_offsets, *src_offsets;
257
258 se = struct_entries + *type_ptr++;
259 if (se->convert[0] != NULL) {
260 /* specific conversion is needed */
261 (*se->convert[to_host])(dst, src);
262 } else {
263 /* standard struct conversion */
264 field_types = se->field_types;
265 dst_offsets = se->field_offsets[to_host];
266 src_offsets = se->field_offsets[1 - to_host];
267 d = dst;
268 s = src;
269 for(i = 0;i < se->nb_fields; i++) {
270 field_types = thunk_convert(d + dst_offsets[i],
271 s + src_offsets[i],
272 field_types, to_host);
273 }
274 }
275 }
276 break;
277 default:
278 fprintf(stderr, "Invalid type 0x%x\n", type);
279 break;
280 }
281 return type_ptr;
282 }
283
284 /* from em86 */
285
286 /* Utility function: Table-driven functions to translate bitmasks
287 * between X86 and Alpha formats...
288 */
289 unsigned int target_to_host_bitmask(unsigned int x86_mask,
290 bitmask_transtbl * trans_tbl)
291 {
292 bitmask_transtbl * btp;
293 unsigned int alpha_mask = 0;
294
295 for(btp = trans_tbl; btp->x86_mask && btp->alpha_mask; btp++) {
296 if((x86_mask & btp->x86_mask) == btp->x86_bits) {
297 alpha_mask |= btp->alpha_bits;
298 }
299 }
300 return(alpha_mask);
301 }
302
303 unsigned int host_to_target_bitmask(unsigned int alpha_mask,
304 bitmask_transtbl * trans_tbl)
305 {
306 bitmask_transtbl * btp;
307 unsigned int x86_mask = 0;
308
309 for(btp = trans_tbl; btp->x86_mask && btp->alpha_mask; btp++) {
310 if((alpha_mask & btp->alpha_mask) == btp->alpha_bits) {
311 x86_mask |= btp->x86_mask;
312 }
313 }
314 return(x86_mask);
315 }