qemu/thunk.c
<<
>>
Prefs
   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}
 482