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