qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

thunk.c (13628B)


      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(unsigned int target_mask,
    440                                     const bitmask_transtbl * trans_tbl)
    441 {
    442     const bitmask_transtbl *btp;
    443     unsigned int host_mask = 0;
    444 
    445     for (btp = trans_tbl; btp->target_mask && btp->host_mask; btp++) {
    446         if ((target_mask & btp->target_mask) == btp->target_bits) {
    447             host_mask |= btp->host_bits;
    448         }
    449     }
    450     return host_mask;
    451 }
    452 
    453 unsigned int host_to_target_bitmask(unsigned int host_mask,
    454                                     const bitmask_transtbl * trans_tbl)
    455 {
    456     const bitmask_transtbl *btp;
    457     unsigned int target_mask = 0;
    458 
    459     for (btp = trans_tbl; btp->target_mask && btp->host_mask; btp++) {
    460         if ((host_mask & btp->host_mask) == btp->host_bits) {
    461             target_mask |= btp->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 }