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 "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        return type_ptr;
  50    case TYPE_PTR:
  51        return thunk_type_next_ptr(type_ptr);
  52    case TYPE_ARRAY:
  53        return thunk_type_next_ptr(type_ptr + 1);
  54    case TYPE_STRUCT:
  55        return type_ptr + 1;
  56    default:
  57        return NULL;
  58    }
  59}
  60
  61static const argtype *thunk_type_next_ptr(const argtype *type_ptr)
  62{
  63    return thunk_type_next(type_ptr);
  64}
  65
  66void thunk_register_struct(int id, const char *name, const argtype *types)
  67{
  68    const argtype *type_ptr;
  69    StructEntry *se;
  70    int nb_fields, offset, max_align, align, size, i, j;
  71
  72    se = struct_entries + id;
  73
  74    /* first we count the number of fields */
  75    type_ptr = types;
  76    nb_fields = 0;
  77    while (*type_ptr != TYPE_NULL) {
  78        type_ptr = thunk_type_next(type_ptr);
  79        nb_fields++;
  80    }
  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 < 2; i++) {
  91        offset = 0;
  92        max_align = 1;
  93        se->field_offsets[i] = malloc(nb_fields * sizeof(int));
  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    se = struct_entries + id;
 120    *se = *se1;
 121    se->name = name;
 122}
 123
 124
 125/* now we can define the main conversion functions */
 126const argtype *thunk_convert(void *dst, const void *src,
 127                             const argtype *type_ptr, int to_host)
 128{
 129    int type;
 130
 131    type = *type_ptr++;
 132    switch(type) {
 133    case TYPE_CHAR:
 134        *(uint8_t *)dst = *(uint8_t *)src;
 135        break;
 136    case TYPE_SHORT:
 137        *(uint16_t *)dst = tswap16(*(uint16_t *)src);
 138        break;
 139    case TYPE_INT:
 140        *(uint32_t *)dst = tswap32(*(uint32_t *)src);
 141        break;
 142    case TYPE_LONGLONG:
 143    case TYPE_ULONGLONG:
 144        *(uint64_t *)dst = tswap64(*(uint64_t *)src);
 145        break;
 146#if HOST_LONG_BITS == 32 && TARGET_ABI_BITS == 32
 147    case TYPE_LONG:
 148    case TYPE_ULONG:
 149    case TYPE_PTRVOID:
 150        *(uint32_t *)dst = tswap32(*(uint32_t *)src);
 151        break;
 152#elif HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 32
 153    case TYPE_LONG:
 154    case TYPE_ULONG:
 155    case TYPE_PTRVOID:
 156        if (to_host) {
 157            if (type == TYPE_LONG) {
 158                /* sign extension */
 159                *(uint64_t *)dst = (int32_t)tswap32(*(uint32_t *)src);
 160            } else {
 161                *(uint64_t *)dst = tswap32(*(uint32_t *)src);
 162            }
 163        } else {
 164            *(uint32_t *)dst = tswap32(*(uint64_t *)src & 0xffffffff);
 165        }
 166        break;
 167#elif HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 64
 168    case TYPE_LONG:
 169    case TYPE_ULONG:
 170    case TYPE_PTRVOID:
 171        *(uint64_t *)dst = tswap64(*(uint64_t *)src);
 172        break;
 173#elif HOST_LONG_BITS == 32 && TARGET_ABI_BITS == 64
 174    case TYPE_LONG:
 175    case TYPE_ULONG:
 176    case TYPE_PTRVOID:
 177        if (to_host) {
 178            *(uint32_t *)dst = tswap64(*(uint64_t *)src);
 179        } else {
 180            if (type == TYPE_LONG) {
 181                /* sign extension */
 182                *(uint64_t *)dst = tswap64(*(int32_t *)src);
 183            } else {
 184                *(uint64_t *)dst = tswap64(*(uint32_t *)src);
 185            }
 186        }
 187        break;
 188#else
 189#warning unsupported conversion
 190#endif
 191    case TYPE_ARRAY:
 192        {
 193            int array_length, i, dst_size, src_size;
 194            const uint8_t *s;
 195            uint8_t  *d;
 196
 197            array_length = *type_ptr++;
 198            dst_size = thunk_type_size(type_ptr, to_host);
 199            src_size = thunk_type_size(type_ptr, 1 - to_host);
 200            d = dst;
 201            s = src;
 202            for(i = 0;i < array_length; i++) {
 203                thunk_convert(d, s, type_ptr, to_host);
 204                d += dst_size;
 205                s += src_size;
 206            }
 207            type_ptr = thunk_type_next(type_ptr);
 208        }
 209        break;
 210    case TYPE_STRUCT:
 211        {
 212            int i;
 213            const StructEntry *se;
 214            const uint8_t *s;
 215            uint8_t  *d;
 216            const argtype *field_types;
 217            const int *dst_offsets, *src_offsets;
 218
 219            se = struct_entries + *type_ptr++;
 220            if (se->convert[0] != NULL) {
 221                /* specific conversion is needed */
 222                (*se->convert[to_host])(dst, src);
 223            } else {
 224                /* standard struct conversion */
 225                field_types = se->field_types;
 226                dst_offsets = se->field_offsets[to_host];
 227                src_offsets = se->field_offsets[1 - to_host];
 228                d = dst;
 229                s = src;
 230                for(i = 0;i < se->nb_fields; i++) {
 231                    field_types = thunk_convert(d + dst_offsets[i],
 232                                                s + src_offsets[i],
 233                                                field_types, to_host);
 234                }
 235            }
 236        }
 237        break;
 238    default:
 239        fprintf(stderr, "Invalid type 0x%x\n", type);
 240        break;
 241    }
 242    return type_ptr;
 243}
 244
 245/* from em86 */
 246
 247/* Utility function: Table-driven functions to translate bitmasks
 248 * between X86 and Alpha formats...
 249 */
 250unsigned int target_to_host_bitmask(unsigned int x86_mask,
 251                                    const bitmask_transtbl * trans_tbl)
 252{
 253    const bitmask_transtbl *btp;
 254    unsigned int        alpha_mask = 0;
 255
 256    for(btp = trans_tbl; btp->x86_mask && btp->alpha_mask; btp++) {
 257        if((x86_mask & btp->x86_mask) == btp->x86_bits) {
 258            alpha_mask |= btp->alpha_bits;
 259        }
 260    }
 261    return(alpha_mask);
 262}
 263
 264unsigned int host_to_target_bitmask(unsigned int alpha_mask,
 265                                    const bitmask_transtbl * trans_tbl)
 266{
 267    const bitmask_transtbl *btp;
 268    unsigned int        x86_mask = 0;
 269
 270    for(btp = trans_tbl; btp->x86_mask && btp->alpha_mask; btp++) {
 271        if((alpha_mask & btp->alpha_mask) == btp->alpha_bits) {
 272            x86_mask |= btp->x86_bits;
 273        }
 274    }
 275    return(x86_mask);
 276}
 277
 278#ifndef NO_THUNK_TYPE_SIZE
 279int thunk_type_size_array(const argtype *type_ptr, int is_host)
 280{
 281    return thunk_type_size(type_ptr, is_host);
 282}
 283
 284int thunk_type_align_array(const argtype *type_ptr, int is_host)
 285{
 286    return thunk_type_align(type_ptr, is_host);
 287}
 288#endif /* ndef NO_THUNK_TYPE_SIZE */
 289