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
  21#include "qemu.h"
  22#include "exec/user/thunk.h"
  23
  24//#define DEBUG
  25
  26static unsigned int max_struct_entries;
  27StructEntry *struct_entries;
  28
  29static const argtype *thunk_type_next_ptr(const argtype *type_ptr);
  30
  31static inline const argtype *thunk_type_next(const argtype *type_ptr)
  32{
  33    int type;
  34
  35    type = *type_ptr++;
  36    switch(type) {
  37    case TYPE_CHAR:
  38    case TYPE_SHORT:
  39    case TYPE_INT:
  40    case TYPE_LONGLONG:
  41    case TYPE_ULONGLONG:
  42    case TYPE_LONG:
  43    case TYPE_ULONG:
  44    case TYPE_PTRVOID:
  45    case TYPE_OLDDEVT:
  46        return type_ptr;
  47    case TYPE_PTR:
  48        return thunk_type_next_ptr(type_ptr);
  49    case TYPE_ARRAY:
  50        return thunk_type_next_ptr(type_ptr + 1);
  51    case TYPE_STRUCT:
  52        return type_ptr + 1;
  53    default:
  54        return NULL;
  55    }
  56}
  57
  58static const argtype *thunk_type_next_ptr(const argtype *type_ptr)
  59{
  60    return thunk_type_next(type_ptr);
  61}
  62
  63void thunk_register_struct(int id, const char *name, const argtype *types)
  64{
  65    const argtype *type_ptr;
  66    StructEntry *se;
  67    int nb_fields, offset, max_align, align, size, i, j;
  68
  69    assert(id < max_struct_entries);
  70
  71    /* first we count the number of fields */
  72    type_ptr = types;
  73    nb_fields = 0;
  74    while (*type_ptr != TYPE_NULL) {
  75        type_ptr = thunk_type_next(type_ptr);
  76        nb_fields++;
  77    }
  78    assert(nb_fields > 0);
  79    se = struct_entries + id;
  80    se->field_types = types;
  81    se->nb_fields = nb_fields;
  82    se->name = name;
  83#ifdef DEBUG
  84    printf("struct %s: id=%d nb_fields=%d\n",
  85           se->name, id, se->nb_fields);
  86#endif
  87    /* now we can alloc the data */
  88
  89    for (i = 0; i < ARRAY_SIZE(se->field_offsets); i++) {
  90        offset = 0;
  91        max_align = 1;
  92        se->field_offsets[i] = g_new(int, nb_fields);
  93        type_ptr = se->field_types;
  94        for(j = 0;j < nb_fields; j++) {
  95            size = thunk_type_size(type_ptr, i);
  96            align = thunk_type_align(type_ptr, i);
  97            offset = (offset + align - 1) & ~(align - 1);
  98            se->field_offsets[i][j] = offset;
  99            offset += size;
 100            if (align > max_align)
 101                max_align = align;
 102            type_ptr = thunk_type_next(type_ptr);
 103        }
 104        offset = (offset + max_align - 1) & ~(max_align - 1);
 105        se->size[i] = offset;
 106        se->align[i] = max_align;
 107#ifdef DEBUG
 108        printf("%s: size=%d align=%d\n",
 109               i == THUNK_HOST ? "host" : "target", offset, max_align);
 110#endif
 111    }
 112}
 113
 114void thunk_register_struct_direct(int id, const char *name,
 115                                  const StructEntry *se1)
 116{
 117    StructEntry *se;
 118
 119    assert(id < max_struct_entries);
 120    se = struct_entries + id;
 121    *se = *se1;
 122    se->name = name;
 123}
 124
 125
 126/* now we can define the main conversion functions */
 127const argtype *thunk_convert(void *dst, const void *src,
 128                             const argtype *type_ptr, int to_host)
 129{
 130    int type;
 131
 132    type = *type_ptr++;
 133    switch(type) {
 134    case TYPE_CHAR:
 135        *(uint8_t *)dst = *(uint8_t *)src;
 136        break;
 137    case TYPE_SHORT:
 138        *(uint16_t *)dst = tswap16(*(uint16_t *)src);
 139        break;
 140    case TYPE_INT:
 141        *(uint32_t *)dst = tswap32(*(uint32_t *)src);
 142        break;
 143    case TYPE_LONGLONG:
 144    case TYPE_ULONGLONG:
 145        *(uint64_t *)dst = tswap64(*(uint64_t *)src);
 146        break;
 147#if HOST_LONG_BITS == 32 && TARGET_ABI_BITS == 32
 148    case TYPE_LONG:
 149    case TYPE_ULONG:
 150    case TYPE_PTRVOID:
 151        *(uint32_t *)dst = tswap32(*(uint32_t *)src);
 152        break;
 153#elif HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 32
 154    case TYPE_LONG:
 155    case TYPE_ULONG:
 156    case TYPE_PTRVOID:
 157        if (to_host) {
 158            if (type == TYPE_LONG) {
 159                /* sign extension */
 160                *(uint64_t *)dst = (int32_t)tswap32(*(uint32_t *)src);
 161            } else {
 162                *(uint64_t *)dst = tswap32(*(uint32_t *)src);
 163            }
 164        } else {
 165            *(uint32_t *)dst = tswap32(*(uint64_t *)src & 0xffffffff);
 166        }
 167        break;
 168#elif HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 64
 169    case TYPE_LONG:
 170    case TYPE_ULONG:
 171    case TYPE_PTRVOID:
 172        *(uint64_t *)dst = tswap64(*(uint64_t *)src);
 173        break;
 174#elif HOST_LONG_BITS == 32 && TARGET_ABI_BITS == 64
 175    case TYPE_LONG:
 176    case TYPE_ULONG:
 177    case TYPE_PTRVOID:
 178        if (to_host) {
 179            *(uint32_t *)dst = tswap64(*(uint64_t *)src);
 180        } else {
 181            if (type == TYPE_LONG) {
 182                /* sign extension */
 183                *(uint64_t *)dst = tswap64(*(int32_t *)src);
 184            } else {
 185                *(uint64_t *)dst = tswap64(*(uint32_t *)src);
 186            }
 187        }
 188        break;
 189#else
 190#warning unsupported conversion
 191#endif
 192    case TYPE_OLDDEVT:
 193    {
 194        uint64_t val = 0;
 195        switch (thunk_type_size(type_ptr - 1, !to_host)) {
 196        case 2:
 197            val = *(uint16_t *)src;
 198            break;
 199        case 4:
 200            val = *(uint32_t *)src;
 201            break;
 202        case 8:
 203            val = *(uint64_t *)src;
 204            break;
 205        }
 206        switch (thunk_type_size(type_ptr - 1, to_host)) {
 207        case 2:
 208            *(uint16_t *)dst = tswap16(val);
 209            break;
 210        case 4:
 211            *(uint32_t *)dst = tswap32(val);
 212            break;
 213        case 8:
 214            *(uint64_t *)dst = tswap64(val);
 215            break;
 216        }
 217        break;
 218    }
 219    case TYPE_ARRAY:
 220        {
 221            int array_length, i, dst_size, src_size;
 222            const uint8_t *s;
 223            uint8_t  *d;
 224
 225            array_length = *type_ptr++;
 226            dst_size = thunk_type_size(type_ptr, to_host);
 227            src_size = thunk_type_size(type_ptr, 1 - to_host);
 228            d = dst;
 229            s = src;
 230            for(i = 0;i < array_length; i++) {
 231                thunk_convert(d, s, type_ptr, to_host);
 232                d += dst_size;
 233                s += src_size;
 234            }
 235            type_ptr = thunk_type_next(type_ptr);
 236        }
 237        break;
 238    case TYPE_STRUCT:
 239        {
 240            int i;
 241            const StructEntry *se;
 242            const uint8_t *s;
 243            uint8_t  *d;
 244            const argtype *field_types;
 245            const int *dst_offsets, *src_offsets;
 246
 247            assert(*type_ptr < max_struct_entries);
 248            se = struct_entries + *type_ptr++;
 249            if (se->convert[0] != NULL) {
 250                /* specific conversion is needed */
 251                (*se->convert[to_host])(dst, src);
 252            } else {
 253                /* standard struct conversion */
 254                field_types = se->field_types;
 255                dst_offsets = se->field_offsets[to_host];
 256                src_offsets = se->field_offsets[1 - to_host];
 257                d = dst;
 258                s = src;
 259                for(i = 0;i < se->nb_fields; i++) {
 260                    field_types = thunk_convert(d + dst_offsets[i],
 261                                                s + src_offsets[i],
 262                                                field_types, to_host);
 263                }
 264            }
 265        }
 266        break;
 267    default:
 268        fprintf(stderr, "Invalid type 0x%x\n", type);
 269        break;
 270    }
 271    return type_ptr;
 272}
 273
 274const argtype *thunk_print(void *arg, const argtype *type_ptr)
 275{
 276    int type;
 277
 278    type = *type_ptr++;
 279
 280    switch (type) {
 281    case TYPE_CHAR:
 282        qemu_log("%c", *(uint8_t *)arg);
 283        break;
 284    case TYPE_SHORT:
 285        qemu_log("%" PRId16, tswap16(*(uint16_t *)arg));
 286        break;
 287    case TYPE_INT:
 288        qemu_log("%" PRId32, tswap32(*(uint32_t *)arg));
 289        break;
 290    case TYPE_LONGLONG:
 291        qemu_log("%" PRId64, tswap64(*(uint64_t *)arg));
 292        break;
 293    case TYPE_ULONGLONG:
 294        qemu_log("%" PRIu64, tswap64(*(uint64_t *)arg));
 295        break;
 296#if HOST_LONG_BITS == 32 && TARGET_ABI_BITS == 32
 297    case TYPE_PTRVOID:
 298        qemu_log("0x%" PRIx32, tswap32(*(uint32_t *)arg));
 299        break;
 300    case TYPE_LONG:
 301        qemu_log("%" PRId32, tswap32(*(uint32_t *)arg));
 302        break;
 303    case TYPE_ULONG:
 304        qemu_log("%" PRIu32, tswap32(*(uint32_t *)arg));
 305        break;
 306#elif HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 32
 307    case TYPE_PTRVOID:
 308        qemu_log("0x%" PRIx32, tswap32(*(uint64_t *)arg & 0xffffffff));
 309        break;
 310    case TYPE_LONG:
 311        qemu_log("%" PRId32, tswap32(*(uint64_t *)arg & 0xffffffff));
 312        break;
 313    case TYPE_ULONG:
 314        qemu_log("%" PRIu32, tswap32(*(uint64_t *)arg & 0xffffffff));
 315        break;
 316#elif HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 64
 317    case TYPE_PTRVOID:
 318        qemu_log("0x%" PRIx64, tswap64(*(uint64_t *)arg));
 319        break;
 320    case TYPE_LONG:
 321        qemu_log("%" PRId64, tswap64(*(uint64_t *)arg));
 322        break;
 323    case TYPE_ULONG:
 324        qemu_log("%" PRIu64, tswap64(*(uint64_t *)arg));
 325        break;
 326#else
 327    case TYPE_PTRVOID:
 328        qemu_log("0x%" PRIx64, tswap64(*(uint64_t *)arg));
 329        break;
 330    case TYPE_LONG:
 331        qemu_log("%" PRId64, tswap64(*(uint64_t *)arg));
 332        break;
 333    case TYPE_ULONG:
 334        qemu_log("%" PRIu64, tswap64(*(uint64_t *)arg));
 335        break;
 336#endif
 337    case TYPE_OLDDEVT:
 338    {
 339        uint64_t val = 0;
 340        switch (thunk_type_size(type_ptr - 1, 1)) {
 341        case 2:
 342            val = *(uint16_t *)arg;
 343            break;
 344        case 4:
 345            val = *(uint32_t *)arg;
 346            break;
 347        case 8:
 348            val = *(uint64_t *)arg;
 349            break;
 350        }
 351        switch (thunk_type_size(type_ptr - 1, 0)) {
 352        case 2:
 353            qemu_log("%" PRIu16, tswap16(val));
 354            break;
 355        case 4:
 356            qemu_log("%" PRIu32, tswap32(val));
 357            break;
 358        case 8:
 359            qemu_log("%" PRIu64, tswap64(val));
 360            break;
 361        }
 362    }
 363    break;
 364    case TYPE_ARRAY:
 365        {
 366            int i, array_length, arg_size;
 367            uint8_t *a;
 368            int is_string = 0;
 369
 370            array_length = *type_ptr++;
 371            arg_size = thunk_type_size(type_ptr, 0);
 372            a = arg;
 373
 374            if (*type_ptr == TYPE_CHAR) {
 375                qemu_log("\"");
 376                is_string = 1;
 377            } else {
 378                qemu_log("[");
 379            }
 380
 381            for (i = 0; i < array_length; i++) {
 382                if (i > 0 && !is_string) {
 383                    qemu_log(",");
 384                }
 385                thunk_print(a, type_ptr);
 386                a += arg_size;
 387            }
 388
 389            if (is_string) {
 390                qemu_log("\"");
 391            } else {
 392                qemu_log("]");
 393            }
 394
 395            type_ptr = thunk_type_next(type_ptr);
 396        }
 397        break;
 398    case TYPE_STRUCT:
 399        {
 400            int i;
 401            const StructEntry *se;
 402            uint8_t  *a;
 403            const argtype *field_types;
 404            const int *arg_offsets;
 405
 406            se = struct_entries + *type_ptr++;
 407
 408            if (se->print != NULL) {
 409                se->print(arg);
 410            } else {
 411                a = arg;
 412
 413                field_types = se->field_types;
 414                arg_offsets = se->field_offsets[0];
 415
 416                qemu_log("{");
 417                for (i = 0; i < se->nb_fields; i++) {
 418                    if (i > 0) {
 419                        qemu_log(",");
 420                    }
 421                    field_types = thunk_print(a + arg_offsets[i], field_types);
 422                }
 423                qemu_log("}");
 424            }
 425        }
 426        break;
 427    default:
 428        g_assert_not_reached();
 429    }
 430    return type_ptr;
 431}
 432
 433/* from em86 */
 434
 435/* Utility function: Table-driven functions to translate bitmasks
 436 * between host and target formats
 437 */
 438unsigned int target_to_host_bitmask(unsigned int target_mask,
 439                                    const bitmask_transtbl * trans_tbl)
 440{
 441    const bitmask_transtbl *btp;
 442    unsigned int host_mask = 0;
 443
 444    for (btp = trans_tbl; btp->target_mask && btp->host_mask; btp++) {
 445        if ((target_mask & btp->target_mask) == btp->target_bits) {
 446            host_mask |= btp->host_bits;
 447        }
 448    }
 449    return host_mask;
 450}
 451
 452unsigned int host_to_target_bitmask(unsigned int host_mask,
 453                                    const bitmask_transtbl * trans_tbl)
 454{
 455    const bitmask_transtbl *btp;
 456    unsigned int target_mask = 0;
 457
 458    for (btp = trans_tbl; btp->target_mask && btp->host_mask; btp++) {
 459        if ((host_mask & btp->host_mask) == btp->host_bits) {
 460            target_mask |= btp->target_bits;
 461        }
 462    }
 463    return target_mask;
 464}
 465
 466int thunk_type_size_array(const argtype *type_ptr, int is_host)
 467{
 468    return thunk_type_size(type_ptr, is_host);
 469}
 470
 471int thunk_type_align_array(const argtype *type_ptr, int is_host)
 472{
 473    return thunk_type_align(type_ptr, is_host);
 474}
 475
 476void thunk_init(unsigned int max_structs)
 477{
 478    max_struct_entries = max_structs;
 479    struct_entries = g_new0(StructEntry, max_structs);
 480}
 481