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