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