better than nothing 64 bit support - added sign extension for TYPE_LONG
[qemu] / 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 StructEntry struct_entries[MAX_STRUCTS];
33
34 static inline const argtype *thunk_type_next(const argtype *type_ptr)
35 {
36     int type;
37
38     type = *type_ptr++;
39     switch(type) {
40     case TYPE_CHAR:
41     case TYPE_SHORT:
42     case TYPE_INT:
43     case TYPE_LONGLONG:
44     case TYPE_ULONGLONG:
45     case TYPE_LONG:
46     case TYPE_ULONG:
47     case TYPE_PTRVOID:
48         return type_ptr;
49     case TYPE_PTR:
50         return thunk_type_next(type_ptr);
51     case TYPE_ARRAY:
52         return thunk_type_next(type_ptr + 1);
53     case TYPE_STRUCT:
54         return type_ptr + 1;
55     default:
56         return NULL;
57     }
58 }
59
60 void thunk_register_struct(int id, const char *name, const argtype *types)
61 {
62     const argtype *type_ptr;
63     StructEntry *se;
64     int nb_fields, offset, max_align, align, size, i, j;
65
66     se = struct_entries + id;
67
68     /* first we count the number of fields */
69     type_ptr = types;
70     nb_fields = 0;
71     while (*type_ptr != TYPE_NULL) {
72         type_ptr = thunk_type_next(type_ptr);
73         nb_fields++;
74     }
75     se->field_types = types;
76     se->nb_fields = nb_fields;
77     se->name = name;
78 #ifdef DEBUG
79     printf("struct %s: id=%d nb_fields=%d\n",
80            se->name, id, se->nb_fields);
81 #endif
82     /* now we can alloc the data */
83
84     for(i = 0;i < 2; i++) {
85         offset = 0;
86         max_align = 1;
87         se->field_offsets[i] = malloc(nb_fields * sizeof(int));
88         type_ptr = se->field_types;
89         for(j = 0;j < nb_fields; j++) {
90             size = thunk_type_size(type_ptr, i);
91             align = thunk_type_align(type_ptr, i);
92             offset = (offset + align - 1) & ~(align - 1);
93             se->field_offsets[i][j] = offset;
94             offset += size;
95             if (align > max_align)
96                 max_align = align;
97             type_ptr = thunk_type_next(type_ptr);
98         }
99         offset = (offset + max_align - 1) & ~(max_align - 1);
100         se->size[i] = offset;
101         se->align[i] = max_align;
102 #ifdef DEBUG
103         printf("%s: size=%d align=%d\n",
104                i == THUNK_HOST ? "host" : "target", offset, max_align);
105 #endif
106     }
107 }
108
109 void thunk_register_struct_direct(int id, const char *name, StructEntry *se1)
110 {
111     StructEntry *se;
112     se = struct_entries + id;
113     *se = *se1;
114     se->name = name;
115 }
116
117
118 /* now we can define the main conversion functions */
119 const argtype *thunk_convert(void *dst, const void *src,
120                              const argtype *type_ptr, int to_host)
121 {
122     int type;
123
124     type = *type_ptr++;
125     switch(type) {
126     case TYPE_CHAR:
127         *(uint8_t *)dst = *(uint8_t *)src;
128         break;
129     case TYPE_SHORT:
130         *(uint16_t *)dst = tswap16(*(uint16_t *)src);
131         break;
132     case TYPE_INT:
133         *(uint32_t *)dst = tswap32(*(uint32_t *)src);
134         break;
135     case TYPE_LONGLONG:
136     case TYPE_ULONGLONG:
137         *(uint64_t *)dst = tswap64(*(uint64_t *)src);
138         break;
139 #if HOST_LONG_BITS == 32 && TARGET_ABI_BITS == 32
140     case TYPE_LONG:
141     case TYPE_ULONG:
142     case TYPE_PTRVOID:
143         *(uint32_t *)dst = tswap32(*(uint32_t *)src);
144         break;
145 #elif HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 32
146     case TYPE_LONG:
147     case TYPE_ULONG:
148     case TYPE_PTRVOID:
149         if (to_host) {
150             if (type == TYPE_LONG) {
151                 /* sign extension */
152                 *(uint64_t *)dst = (int32_t)tswap32(*(uint32_t *)src);
153             } else {
154                 *(uint64_t *)dst = tswap32(*(uint32_t *)src);
155             }
156         } else {
157             *(uint32_t *)dst = tswap32(*(uint64_t *)src & 0xffffffff);
158         }
159         break;
160 #elif HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 64
161     case TYPE_LONG:
162     case TYPE_ULONG:
163     case TYPE_PTRVOID:
164         *(uint64_t *)dst = tswap64(*(uint64_t *)src);
165         break;
166 #elif HOST_LONG_BITS == 32 && TARGET_ABI_BITS == 64
167     case TYPE_LONG:
168     case TYPE_ULONG:
169     case TYPE_PTRVOID:
170         if (to_host) {
171             *(uint32_t *)dst = tswap64(*(uint64_t *)src);
172         } else {
173             if (type == TYPE_LONG) {
174                 /* sign extension */
175                 *(uint64_t *)dst = tswap64(*(int32_t *)src);
176             } else {
177                 *(uint64_t *)dst = tswap64(*(uint32_t *)src);
178             }
179         }
180         break;
181 #else
182 #warning unsupported conversion
183 #endif
184     case TYPE_ARRAY:
185         {
186             int array_length, i, dst_size, src_size;
187             const uint8_t *s;
188             uint8_t  *d;
189
190             array_length = *type_ptr++;
191             dst_size = thunk_type_size(type_ptr, to_host);
192             src_size = thunk_type_size(type_ptr, 1 - to_host);
193             d = dst;
194             s = src;
195             for(i = 0;i < array_length; i++) {
196                 thunk_convert(d, s, type_ptr, to_host);
197                 d += dst_size;
198                 s += src_size;
199             }
200             type_ptr = thunk_type_next(type_ptr);
201         }
202         break;
203     case TYPE_STRUCT:
204         {
205             int i;
206             const StructEntry *se;
207             const uint8_t *s;
208             uint8_t  *d;
209             const argtype *field_types;
210             const int *dst_offsets, *src_offsets;
211
212             se = struct_entries + *type_ptr++;
213             if (se->convert[0] != NULL) {
214                 /* specific conversion is needed */
215                 (*se->convert[to_host])(dst, src);
216             } else {
217                 /* standard struct conversion */
218                 field_types = se->field_types;
219                 dst_offsets = se->field_offsets[to_host];
220                 src_offsets = se->field_offsets[1 - to_host];
221                 d = dst;
222                 s = src;
223                 for(i = 0;i < se->nb_fields; i++) {
224                     field_types = thunk_convert(d + dst_offsets[i],
225                                                 s + src_offsets[i],
226                                                 field_types, to_host);
227                 }
228             }
229         }
230         break;
231     default:
232         fprintf(stderr, "Invalid type 0x%x\n", type);
233         break;
234     }
235     return type_ptr;
236 }
237
238 /* from em86 */
239
240 /* Utility function: Table-driven functions to translate bitmasks
241  * between X86 and Alpha formats...
242  */
243 unsigned int target_to_host_bitmask(unsigned int x86_mask,
244                                     bitmask_transtbl * trans_tbl)
245 {
246     bitmask_transtbl *  btp;
247     unsigned int        alpha_mask = 0;
248
249     for(btp = trans_tbl; btp->x86_mask && btp->alpha_mask; btp++) {
250         if((x86_mask & btp->x86_mask) == btp->x86_bits) {
251             alpha_mask |= btp->alpha_bits;
252         }
253     }
254     return(alpha_mask);
255 }
256
257 unsigned int host_to_target_bitmask(unsigned int alpha_mask,
258                                     bitmask_transtbl * trans_tbl)
259 {
260     bitmask_transtbl *  btp;
261     unsigned int        x86_mask = 0;
262
263     for(btp = trans_tbl; btp->x86_mask && btp->alpha_mask; btp++) {
264         if((alpha_mask & btp->alpha_mask) == btp->alpha_bits) {
265             x86_mask |= btp->x86_bits;
266         }
267     }
268     return(x86_mask);
269 }