xref: /openbmc/qemu/linux-user/thunk.c (revision 56c39a41adadfc567e1ac22089670bfde6b35365)
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.1 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  #include "qemu/log.h"
21  
22  #include "qemu.h"
23  #include "exec/user/thunk.h"
24  
25  //#define DEBUG
26  
27  static unsigned int max_struct_entries;
28  StructEntry *struct_entries;
29  
30  static const argtype *thunk_type_next_ptr(const argtype *type_ptr);
31  
32  static inline const argtype *thunk_type_next(const argtype *type_ptr)
33  {
34      int type;
35  
36      type = *type_ptr++;
37      switch(type) {
38      case TYPE_CHAR:
39      case TYPE_SHORT:
40      case TYPE_INT:
41      case TYPE_LONGLONG:
42      case TYPE_ULONGLONG:
43      case TYPE_LONG:
44      case TYPE_ULONG:
45      case TYPE_PTRVOID:
46      case TYPE_OLDDEVT:
47          return type_ptr;
48      case TYPE_PTR:
49          return thunk_type_next_ptr(type_ptr);
50      case TYPE_ARRAY:
51          return thunk_type_next_ptr(type_ptr + 1);
52      case TYPE_STRUCT:
53          return type_ptr + 1;
54      default:
55          return NULL;
56      }
57  }
58  
59  static const argtype *thunk_type_next_ptr(const argtype *type_ptr)
60  {
61      return thunk_type_next(type_ptr);
62  }
63  
64  void thunk_register_struct(int id, const char *name, const argtype *types)
65  {
66      const argtype *type_ptr;
67      StructEntry *se;
68      int nb_fields, offset, max_align, align, size, i, j;
69  
70      assert(id < max_struct_entries);
71  
72      /* first we count the number of fields */
73      type_ptr = types;
74      nb_fields = 0;
75      while (*type_ptr != TYPE_NULL) {
76          type_ptr = thunk_type_next(type_ptr);
77          nb_fields++;
78      }
79      assert(nb_fields > 0);
80      se = struct_entries + id;
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 < ARRAY_SIZE(se->field_offsets); i++) {
91          offset = 0;
92          max_align = 1;
93          se->field_offsets[i] = g_new(int, nb_fields);
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  const argtype *thunk_print(void *arg, const argtype *type_ptr)
276  {
277      int type;
278  
279      type = *type_ptr++;
280  
281      switch (type) {
282      case TYPE_CHAR:
283          qemu_log("%c", *(uint8_t *)arg);
284          break;
285      case TYPE_SHORT:
286          qemu_log("%" PRId16, tswap16(*(uint16_t *)arg));
287          break;
288      case TYPE_INT:
289          qemu_log("%" PRId32, tswap32(*(uint32_t *)arg));
290          break;
291      case TYPE_LONGLONG:
292          qemu_log("%" PRId64, tswap64(*(uint64_t *)arg));
293          break;
294      case TYPE_ULONGLONG:
295          qemu_log("%" PRIu64, tswap64(*(uint64_t *)arg));
296          break;
297  #if HOST_LONG_BITS == 32 && TARGET_ABI_BITS == 32
298      case TYPE_PTRVOID:
299          qemu_log("0x%" PRIx32, tswap32(*(uint32_t *)arg));
300          break;
301      case TYPE_LONG:
302          qemu_log("%" PRId32, tswap32(*(uint32_t *)arg));
303          break;
304      case TYPE_ULONG:
305          qemu_log("%" PRIu32, tswap32(*(uint32_t *)arg));
306          break;
307  #elif HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 32
308      case TYPE_PTRVOID:
309          qemu_log("0x%" PRIx32, tswap32(*(uint64_t *)arg & 0xffffffff));
310          break;
311      case TYPE_LONG:
312          qemu_log("%" PRId32, tswap32(*(uint64_t *)arg & 0xffffffff));
313          break;
314      case TYPE_ULONG:
315          qemu_log("%" PRIu32, tswap32(*(uint64_t *)arg & 0xffffffff));
316          break;
317  #elif HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 64
318      case TYPE_PTRVOID:
319          qemu_log("0x%" PRIx64, tswap64(*(uint64_t *)arg));
320          break;
321      case TYPE_LONG:
322          qemu_log("%" PRId64, tswap64(*(uint64_t *)arg));
323          break;
324      case TYPE_ULONG:
325          qemu_log("%" PRIu64, tswap64(*(uint64_t *)arg));
326          break;
327  #else
328      case TYPE_PTRVOID:
329          qemu_log("0x%" PRIx64, tswap64(*(uint64_t *)arg));
330          break;
331      case TYPE_LONG:
332          qemu_log("%" PRId64, tswap64(*(uint64_t *)arg));
333          break;
334      case TYPE_ULONG:
335          qemu_log("%" PRIu64, tswap64(*(uint64_t *)arg));
336          break;
337  #endif
338      case TYPE_OLDDEVT:
339      {
340          uint64_t val = 0;
341          switch (thunk_type_size(type_ptr - 1, 1)) {
342          case 2:
343              val = *(uint16_t *)arg;
344              break;
345          case 4:
346              val = *(uint32_t *)arg;
347              break;
348          case 8:
349              val = *(uint64_t *)arg;
350              break;
351          }
352          switch (thunk_type_size(type_ptr - 1, 0)) {
353          case 2:
354              qemu_log("%" PRIu16, tswap16(val));
355              break;
356          case 4:
357              qemu_log("%" PRIu32, tswap32(val));
358              break;
359          case 8:
360              qemu_log("%" PRIu64, tswap64(val));
361              break;
362          }
363      }
364      break;
365      case TYPE_ARRAY:
366          {
367              int i, array_length, arg_size;
368              uint8_t *a;
369              int is_string = 0;
370  
371              array_length = *type_ptr++;
372              arg_size = thunk_type_size(type_ptr, 0);
373              a = arg;
374  
375              if (*type_ptr == TYPE_CHAR) {
376                  qemu_log("\"");
377                  is_string = 1;
378              } else {
379                  qemu_log("[");
380              }
381  
382              for (i = 0; i < array_length; i++) {
383                  if (i > 0 && !is_string) {
384                      qemu_log(",");
385                  }
386                  thunk_print(a, type_ptr);
387                  a += arg_size;
388              }
389  
390              if (is_string) {
391                  qemu_log("\"");
392              } else {
393                  qemu_log("]");
394              }
395  
396              type_ptr = thunk_type_next(type_ptr);
397          }
398          break;
399      case TYPE_STRUCT:
400          {
401              int i;
402              const StructEntry *se;
403              uint8_t  *a;
404              const argtype *field_types;
405              const int *arg_offsets;
406  
407              se = struct_entries + *type_ptr++;
408  
409              if (se->print != NULL) {
410                  se->print(arg);
411              } else {
412                  a = arg;
413  
414                  field_types = se->field_types;
415                  arg_offsets = se->field_offsets[0];
416  
417                  qemu_log("{");
418                  for (i = 0; i < se->nb_fields; i++) {
419                      if (i > 0) {
420                          qemu_log(",");
421                      }
422                      field_types = thunk_print(a + arg_offsets[i], field_types);
423                  }
424                  qemu_log("}");
425              }
426          }
427          break;
428      default:
429          g_assert_not_reached();
430      }
431      return type_ptr;
432  }
433  
434  /* from em86 */
435  
436  /* Utility function: Table-driven functions to translate bitmasks
437   * between host and target formats
438   */
439  unsigned int target_to_host_bitmask_len(unsigned int target_mask,
440                                          const bitmask_transtbl *tbl,
441                                          size_t len)
442  {
443      unsigned int host_mask = 0;
444  
445      for (size_t i = 0; i < len; ++i) {
446          if ((target_mask & tbl[i].target_mask) == tbl[i].target_bits) {
447              host_mask |= tbl[i].host_bits;
448          }
449      }
450      return host_mask;
451  }
452  
453  unsigned int host_to_target_bitmask_len(unsigned int host_mask,
454                                          const bitmask_transtbl *tbl,
455                                          size_t len)
456  {
457      unsigned int target_mask = 0;
458  
459      for (size_t i = 0; i < len; ++i) {
460          if ((host_mask & tbl[i].host_mask) == tbl[i].host_bits) {
461              target_mask |= tbl[i].target_bits;
462          }
463      }
464      return target_mask;
465  }
466  
467  int thunk_type_size_array(const argtype *type_ptr, int is_host)
468  {
469      return thunk_type_size(type_ptr, is_host);
470  }
471  
472  int thunk_type_align_array(const argtype *type_ptr, int is_host)
473  {
474      return thunk_type_align(type_ptr, is_host);
475  }
476  
477  void thunk_init(unsigned int max_structs)
478  {
479      max_struct_entries = max_structs;
480      struct_entries = g_new0(StructEntry, max_structs);
481  }
482