cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

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
     27static unsigned int max_struct_entries;
     28StructEntry *struct_entries;
     29
     30static const argtype *thunk_type_next_ptr(const argtype *type_ptr);
     31
     32static 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
     59static const argtype *thunk_type_next_ptr(const argtype *type_ptr)
     60{
     61    return thunk_type_next(type_ptr);
     62}
     63
     64void 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
    115void 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 */
    128const 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
    275const 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 */
    439unsigned 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
    453unsigned 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
    467int thunk_type_size_array(const argtype *type_ptr, int is_host)
    468{
    469    return thunk_type_size(type_ptr, is_host);
    470}
    471
    472int thunk_type_align_array(const argtype *type_ptr, int is_host)
    473{
    474    return thunk_type_align(type_ptr, is_host);
    475}
    476
    477void thunk_init(unsigned int max_structs)
    478{
    479    max_struct_entries = max_structs;
    480    struct_entries = g_new0(StructEntry, max_structs);
    481}