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 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 <stdlib.h>
  20#include <stdio.h>
  21#include <stdarg.h>
  22
  23#include "qemu.h"
  24#include "exec/user/thunk.h"
  25
  26//#define DEBUG
  27
  28#define MAX_STRUCTS 128
  29
  30/* XXX: make it dynamic */
  31StructEntry struct_entries[MAX_STRUCTS];
  32
  33static const argtype *thunk_type_next_ptr(const argtype *type_ptr);
  34
  35static inline const argtype *thunk_type_next(const argtype *type_ptr)
  36{
  37    int type;
  38
  39    type = *type_ptr++;
  40    switch(type) {
  41    case TYPE_CHAR:
  42    case TYPE_SHORT:
  43    case TYPE_INT:
  44    case TYPE_LONGLONG:
  45    case TYPE_ULONGLONG:
  46    case TYPE_LONG:
  47    case TYPE_ULONG:
  48    case TYPE_PTRVOID:
  49    case TYPE_OLDDEVT:
  50        return type_ptr;
  51    case TYPE_PTR:
  52        return thunk_type_next_ptr(type_ptr);
  53    case TYPE_ARRAY:
  54        return thunk_type_next_ptr(type_ptr + 1);
  55    case TYPE_STRUCT:
  56        return type_ptr + 1;
  57    default:
  58        return NULL;
  59    }
  60}
  61
  62static const argtype *thunk_type_next_ptr(const argtype *type_ptr)
  63{
  64    return thunk_type_next(type_ptr);
  65}
  66
  67void thunk_register_struct(int id, const char *name, const argtype *types)
  68{
  69    const argtype *type_ptr;
  70    StructEntry *se;
  71    int nb_fields, offset, max_align, align, size, i, j;
  72
  73    se = struct_entries + id;
  74
  75    /* first we count the number of fields */
  76    type_ptr = types;
  77    nb_fields = 0;
  78    while (*type_ptr != TYPE_NULL) {
  79        type_ptr = thunk_type_next(type_ptr);
  80        nb_fields++;
  81    }
  82    se->field_types = types;
  83    se->nb_fields = nb_fields;
  84    se->name = name;
  85#ifdef DEBUG
  86    printf("struct %s: id=%d nb_fields=%d\n",
  87           se->name, id, se->nb_fields);
  88#endif
  89    /* now we can alloc the data */
  90
  91    for(i = 0;i < 2; i++) {
  92        offset = 0;
  93        max_align = 1;
  94        se->field_offsets[i] = malloc(nb_fields * sizeof(int));
  95        type_ptr = se->field_types;
  96        for(j = 0;j < nb_fields; j++) {
  97            size = thunk_type_size(type_ptr, i);
  98            align = thunk_type_align(type_ptr, i);
  99            offset = (offset + align - 1) & ~(align - 1);
 100            se->field_offsets[i][j] = offset;
 101            offset += size;
 102            if (align > max_align)
 103                max_align = align;
 104            type_ptr = thunk_type_next(type_ptr);
 105        }
 106        offset = (offset + max_align - 1) & ~(max_align - 1);
 107        se->size[i] = offset;
 108        se->align[i] = max_align;
 109#ifdef DEBUG
 110        printf("%s: size=%d align=%d\n",
 111               i == THUNK_HOST ? "host" : "target", offset, max_align);
 112#endif
 113    }
 114}
 115
 116void thunk_register_struct_direct(int id, const char *name,
 117                                  const StructEntry *se1)
 118{
 119    StructEntry *se;
 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            se = struct_entries + *type_ptr++;
 248            if (se->convert[0] != NULL) {
 249                /* specific conversion is needed */
 250                (*se->convert[to_host])(dst, src);
 251            } else {
 252                /* standard struct conversion */
 253                field_types = se->field_types;
 254                dst_offsets = se->field_offsets[to_host];
 255                src_offsets = se->field_offsets[1 - to_host];
 256                d = dst;
 257                s = src;
 258                for(i = 0;i < se->nb_fields; i++) {
 259                    field_types = thunk_convert(d + dst_offsets[i],
 260                                                s + src_offsets[i],
 261                                                field_types, to_host);
 262                }
 263            }
 264        }
 265        break;
 266    default:
 267        fprintf(stderr, "Invalid type 0x%x\n", type);
 268        break;
 269    }
 270    return type_ptr;
 271}
 272
 273/* from em86 */
 274
 275/* Utility function: Table-driven functions to translate bitmasks
 276 * between X86 and Alpha formats...
 277 */
 278unsigned int target_to_host_bitmask(unsigned int x86_mask,
 279                                    const bitmask_transtbl * trans_tbl)
 280{
 281    const bitmask_transtbl *btp;
 282    unsigned int        alpha_mask = 0;
 283
 284    for(btp = trans_tbl; btp->x86_mask && btp->alpha_mask; btp++) {
 285        if((x86_mask & btp->x86_mask) == btp->x86_bits) {
 286            alpha_mask |= btp->alpha_bits;
 287        }
 288    }
 289    return(alpha_mask);
 290}
 291
 292unsigned int host_to_target_bitmask(unsigned int alpha_mask,
 293                                    const bitmask_transtbl * trans_tbl)
 294{
 295    const bitmask_transtbl *btp;
 296    unsigned int        x86_mask = 0;
 297
 298    for(btp = trans_tbl; btp->x86_mask && btp->alpha_mask; btp++) {
 299        if((alpha_mask & btp->alpha_mask) == btp->alpha_bits) {
 300            x86_mask |= btp->x86_bits;
 301        }
 302    }
 303    return(x86_mask);
 304}
 305
 306#ifndef NO_THUNK_TYPE_SIZE
 307int thunk_type_size_array(const argtype *type_ptr, int is_host)
 308{
 309    return thunk_type_size(type_ptr, is_host);
 310}
 311
 312int thunk_type_align_array(const argtype *type_ptr, int is_host)
 313{
 314    return thunk_type_align(type_ptr, is_host);
 315}
 316#endif /* ndef NO_THUNK_TYPE_SIZE */
 317