Home | History | Annotate | Download | only in qemu
      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 */
     31 StructEntry struct_entries[MAX_STRUCTS];
     32 
     33 static const argtype *thunk_type_next_ptr(const argtype *type_ptr);
     34 
     35 static 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 
     61 static const argtype *thunk_type_next_ptr(const argtype *type_ptr)
     62 {
     63     return thunk_type_next(type_ptr);
     64 }
     65 
     66 void 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 
    115 void 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 */
    126 const 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  */
    250 unsigned 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 
    264 unsigned 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
    279 int thunk_type_size_array(const argtype *type_ptr, int is_host)
    280 {
    281     return thunk_type_size(type_ptr, is_host);
    282 }
    283 
    284 int 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