sparc64 support (Blue Swirl)
[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_LONG_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_LONG_BITS == 32
146     case TYPE_LONG:
147     case TYPE_ULONG:
148     case TYPE_PTRVOID:
149         if (to_host) {
150             *(uint64_t *)dst = tswap32(*(uint32_t *)src);
151         } else {
152             *(uint32_t *)dst = tswap32(*(uint64_t *)src & 0xffffffff);
153         }
154         break;
155 #else
156 #warning unsupported conversion
157 #endif
158     case TYPE_ARRAY:
159         {
160             int array_length, i, dst_size, src_size;
161             const uint8_t *s;
162             uint8_t  *d;
163
164             array_length = *type_ptr++;
165             dst_size = thunk_type_size(type_ptr, to_host);
166             src_size = thunk_type_size(type_ptr, 1 - to_host);
167             d = dst;
168             s = src;
169             for(i = 0;i < array_length; i++) {
170                 thunk_convert(d, s, type_ptr, to_host);
171                 d += dst_size;
172                 s += src_size;
173             }
174             type_ptr = thunk_type_next(type_ptr);
175         }
176         break;
177     case TYPE_STRUCT:
178         {
179             int i;
180             const StructEntry *se;
181             const uint8_t *s;
182             uint8_t  *d;
183             const argtype *field_types;
184             const int *dst_offsets, *src_offsets;
185             
186             se = struct_entries + *type_ptr++;
187             if (se->convert[0] != NULL) {
188                 /* specific conversion is needed */
189                 (*se->convert[to_host])(dst, src);
190             } else {
191                 /* standard struct conversion */
192                 field_types = se->field_types;
193                 dst_offsets = se->field_offsets[to_host];
194                 src_offsets = se->field_offsets[1 - to_host];
195                 d = dst;
196                 s = src;
197                 for(i = 0;i < se->nb_fields; i++) {
198                     field_types = thunk_convert(d + dst_offsets[i], 
199                                                 s + src_offsets[i], 
200                                                 field_types, to_host);
201                 }
202             }
203         }
204         break;
205     default:
206         fprintf(stderr, "Invalid type 0x%x\n", type);
207         break;
208     }
209     return type_ptr;
210 }
211
212 /* from em86 */
213
214 /* Utility function: Table-driven functions to translate bitmasks
215  * between X86 and Alpha formats...
216  */
217 unsigned int target_to_host_bitmask(unsigned int x86_mask, 
218                                     bitmask_transtbl * trans_tbl)
219 {
220     bitmask_transtbl *  btp;
221     unsigned int        alpha_mask = 0;
222
223     for(btp = trans_tbl; btp->x86_mask && btp->alpha_mask; btp++) {
224         if((x86_mask & btp->x86_mask) == btp->x86_bits) {
225             alpha_mask |= btp->alpha_bits;
226         }
227     }
228     return(alpha_mask);
229 }
230
231 unsigned int host_to_target_bitmask(unsigned int alpha_mask, 
232                                     bitmask_transtbl * trans_tbl)
233 {
234     bitmask_transtbl *  btp;
235     unsigned int        x86_mask = 0;
236
237     for(btp = trans_tbl; btp->x86_mask && btp->alpha_mask; btp++) {
238         if((alpha_mask & btp->alpha_mask) == btp->alpha_bits) {
239             x86_mask |= btp->x86_bits;
240         }
241     }
242     return(x86_mask);
243 }