OSDN Git Service

block: Use BdrvChild to discard
[qmiga/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, see <http://www.gnu.org/licenses/>.
18  */
19 #include "qemu/osdep.h"
20
21 #include "qemu.h"
22 #include "exec/user/thunk.h"
23
24 //#define DEBUG
25
26 static unsigned int max_struct_entries;
27 StructEntry *struct_entries;
28
29 static const argtype *thunk_type_next_ptr(const argtype *type_ptr);
30
31 static inline const argtype *thunk_type_next(const argtype *type_ptr)
32 {
33     int type;
34
35     type = *type_ptr++;
36     switch(type) {
37     case TYPE_CHAR:
38     case TYPE_SHORT:
39     case TYPE_INT:
40     case TYPE_LONGLONG:
41     case TYPE_ULONGLONG:
42     case TYPE_LONG:
43     case TYPE_ULONG:
44     case TYPE_PTRVOID:
45     case TYPE_OLDDEVT:
46         return type_ptr;
47     case TYPE_PTR:
48         return thunk_type_next_ptr(type_ptr);
49     case TYPE_ARRAY:
50         return thunk_type_next_ptr(type_ptr + 1);
51     case TYPE_STRUCT:
52         return type_ptr + 1;
53     default:
54         return NULL;
55     }
56 }
57
58 static const argtype *thunk_type_next_ptr(const argtype *type_ptr)
59 {
60     return thunk_type_next(type_ptr);
61 }
62
63 void thunk_register_struct(int id, const char *name, const argtype *types)
64 {
65     const argtype *type_ptr;
66     StructEntry *se;
67     int nb_fields, offset, max_align, align, size, i, j;
68
69     assert(id < max_struct_entries);
70
71     /* first we count the number of fields */
72     type_ptr = types;
73     nb_fields = 0;
74     while (*type_ptr != TYPE_NULL) {
75         type_ptr = thunk_type_next(type_ptr);
76         nb_fields++;
77     }
78     assert(nb_fields > 0);
79     se = struct_entries + id;
80     se->field_types = types;
81     se->nb_fields = nb_fields;
82     se->name = name;
83 #ifdef DEBUG
84     printf("struct %s: id=%d nb_fields=%d\n",
85            se->name, id, se->nb_fields);
86 #endif
87     /* now we can alloc the data */
88
89     for(i = 0;i < 2; i++) {
90         offset = 0;
91         max_align = 1;
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;
99             offset += size;
100             if (align > max_align)
101                 max_align = align;
102             type_ptr = thunk_type_next(type_ptr);
103         }
104         offset = (offset + max_align - 1) & ~(max_align - 1);
105         se->size[i] = offset;
106         se->align[i] = max_align;
107 #ifdef DEBUG
108         printf("%s: size=%d align=%d\n",
109                i == THUNK_HOST ? "host" : "target", offset, max_align);
110 #endif
111     }
112 }
113
114 void thunk_register_struct_direct(int id, const char *name,
115                                   const StructEntry *se1)
116 {
117     StructEntry *se;
118
119     assert(id < max_struct_entries);
120     se = struct_entries + id;
121     *se = *se1;
122     se->name = name;
123 }
124
125
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)
129 {
130     int type;
131
132     type = *type_ptr++;
133     switch(type) {
134     case TYPE_CHAR:
135         *(uint8_t *)dst = *(uint8_t *)src;
136         break;
137     case TYPE_SHORT:
138         *(uint16_t *)dst = tswap16(*(uint16_t *)src);
139         break;
140     case TYPE_INT:
141         *(uint32_t *)dst = tswap32(*(uint32_t *)src);
142         break;
143     case TYPE_LONGLONG:
144     case TYPE_ULONGLONG:
145         *(uint64_t *)dst = tswap64(*(uint64_t *)src);
146         break;
147 #if HOST_LONG_BITS == 32 && TARGET_ABI_BITS == 32
148     case TYPE_LONG:
149     case TYPE_ULONG:
150     case TYPE_PTRVOID:
151         *(uint32_t *)dst = tswap32(*(uint32_t *)src);
152         break;
153 #elif HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 32
154     case TYPE_LONG:
155     case TYPE_ULONG:
156     case TYPE_PTRVOID:
157         if (to_host) {
158             if (type == TYPE_LONG) {
159                 /* sign extension */
160                 *(uint64_t *)dst = (int32_t)tswap32(*(uint32_t *)src);
161             } else {
162                 *(uint64_t *)dst = tswap32(*(uint32_t *)src);
163             }
164         } else {
165             *(uint32_t *)dst = tswap32(*(uint64_t *)src & 0xffffffff);
166         }
167         break;
168 #elif HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 64
169     case TYPE_LONG:
170     case TYPE_ULONG:
171     case TYPE_PTRVOID:
172         *(uint64_t *)dst = tswap64(*(uint64_t *)src);
173         break;
174 #elif HOST_LONG_BITS == 32 && TARGET_ABI_BITS == 64
175     case TYPE_LONG:
176     case TYPE_ULONG:
177     case TYPE_PTRVOID:
178         if (to_host) {
179             *(uint32_t *)dst = tswap64(*(uint64_t *)src);
180         } else {
181             if (type == TYPE_LONG) {
182                 /* sign extension */
183                 *(uint64_t *)dst = tswap64(*(int32_t *)src);
184             } else {
185                 *(uint64_t *)dst = tswap64(*(uint32_t *)src);
186             }
187         }
188         break;
189 #else
190 #warning unsupported conversion
191 #endif
192     case TYPE_OLDDEVT:
193     {
194         uint64_t val = 0;
195         switch (thunk_type_size(type_ptr - 1, !to_host)) {
196         case 2:
197             val = *(uint16_t *)src;
198             break;
199         case 4:
200             val = *(uint32_t *)src;
201             break;
202         case 8:
203             val = *(uint64_t *)src;
204             break;
205         }
206         switch (thunk_type_size(type_ptr - 1, to_host)) {
207         case 2:
208             *(uint16_t *)dst = tswap16(val);
209             break;
210         case 4:
211             *(uint32_t *)dst = tswap32(val);
212             break;
213         case 8:
214             *(uint64_t *)dst = tswap64(val);
215             break;
216         }
217         break;
218     }
219     case TYPE_ARRAY:
220         {
221             int array_length, i, dst_size, src_size;
222             const uint8_t *s;
223             uint8_t  *d;
224
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);
228             d = dst;
229             s = src;
230             for(i = 0;i < array_length; i++) {
231                 thunk_convert(d, s, type_ptr, to_host);
232                 d += dst_size;
233                 s += src_size;
234             }
235             type_ptr = thunk_type_next(type_ptr);
236         }
237         break;
238     case TYPE_STRUCT:
239         {
240             int i;
241             const StructEntry *se;
242             const uint8_t *s;
243             uint8_t  *d;
244             const argtype *field_types;
245             const int *dst_offsets, *src_offsets;
246
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);
252             } else {
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];
257                 d = dst;
258                 s = src;
259                 for(i = 0;i < se->nb_fields; i++) {
260                     field_types = thunk_convert(d + dst_offsets[i],
261                                                 s + src_offsets[i],
262                                                 field_types, to_host);
263                 }
264             }
265         }
266         break;
267     default:
268         fprintf(stderr, "Invalid type 0x%x\n", type);
269         break;
270     }
271     return type_ptr;
272 }
273
274 /* from em86 */
275
276 /* Utility function: Table-driven functions to translate bitmasks
277  * between host and target formats
278  */
279 unsigned int target_to_host_bitmask(unsigned int target_mask,
280                                     const bitmask_transtbl * trans_tbl)
281 {
282     const bitmask_transtbl *btp;
283     unsigned int host_mask = 0;
284
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;
288         }
289     }
290     return host_mask;
291 }
292
293 unsigned int host_to_target_bitmask(unsigned int host_mask,
294                                     const bitmask_transtbl * trans_tbl)
295 {
296     const bitmask_transtbl *btp;
297     unsigned int target_mask = 0;
298
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;
302         }
303     }
304     return target_mask;
305 }
306
307 int thunk_type_size_array(const argtype *type_ptr, int is_host)
308 {
309     return thunk_type_size(type_ptr, is_host);
310 }
311
312 int thunk_type_align_array(const argtype *type_ptr, int is_host)
313 {
314     return thunk_type_align(type_ptr, is_host);
315 }
316
317 void thunk_init(unsigned int max_structs)
318 {
319     max_struct_entries = max_structs;
320     struct_entries = g_new0(StructEntry, max_structs);
321 }