/* now we can define the main conversion functions */ const argtype *thunk_convert(void *dst, const void *src, const argtype *type_ptr, int to_host) { int type; type = *type_ptr++; switch(type) { case TYPE_CHAR: *(uint8_t *)dst = *(uint8_t *)src; break; case TYPE_SHORT: *(uint16_t *)dst = tswap16(*(uint16_t *)src); break; case TYPE_INT: *(uint32_t *)dst = tswap32(*(uint32_t *)src); break; case TYPE_LONGLONG: case TYPE_ULONGLONG: *(uint64_t *)dst = tswap64(*(uint64_t *)src); break; #if HOST_LONG_BITS == 32 && TARGET_ABI_BITS == 32 case TYPE_LONG: case TYPE_ULONG: case TYPE_PTRVOID: *(uint32_t *)dst = tswap32(*(uint32_t *)src); break; #elif HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 32 case TYPE_LONG: case TYPE_ULONG: case TYPE_PTRVOID: if (to_host) { if (type == TYPE_LONG) { /* sign extension */ *(uint64_t *)dst = (int32_t)tswap32(*(uint32_t *)src); } else { *(uint64_t *)dst = tswap32(*(uint32_t *)src); } } else { *(uint32_t *)dst = tswap32(*(uint64_t *)src & 0xffffffff); } break; #elif HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 64 case TYPE_LONG: case TYPE_ULONG: case TYPE_PTRVOID: *(uint64_t *)dst = tswap64(*(uint64_t *)src); break; #elif HOST_LONG_BITS == 32 && TARGET_ABI_BITS == 64 case TYPE_LONG: case TYPE_ULONG: case TYPE_PTRVOID: if (to_host) { *(uint32_t *)dst = tswap64(*(uint64_t *)src); } else { if (type == TYPE_LONG) { /* sign extension */ *(uint64_t *)dst = tswap64(*(int32_t *)src); } else { *(uint64_t *)dst = tswap64(*(uint32_t *)src); } } break; #else #warning unsupported conversion #endif case TYPE_ARRAY: { int array_length, i, dst_size, src_size; const uint8_t *s; uint8_t *d; array_length = *type_ptr++; dst_size = thunk_type_size(type_ptr, to_host); src_size = thunk_type_size(type_ptr, 1 - to_host); d = dst; s = src; for(i = 0;i < array_length; i++) { thunk_convert(d, s, type_ptr, to_host); d += dst_size; s += src_size; } type_ptr = thunk_type_next(type_ptr); } break; case TYPE_STRUCT: { int i; const StructEntry *se; const uint8_t *s; uint8_t *d; const argtype *field_types; const int *dst_offsets, *src_offsets; se = struct_entries + *type_ptr++; if (se->convert[0] != NULL) { /* specific conversion is needed */ (*se->convert[to_host])(dst, src); } else { /* standard struct conversion */ field_types = se->field_types; dst_offsets = se->field_offsets[to_host]; src_offsets = se->field_offsets[1 - to_host]; d = dst; s = src; for(i = 0;i < se->nb_fields; i++) { field_types = thunk_convert(d + dst_offsets[i], s + src_offsets[i], field_types, to_host); } } } break; default: fprintf(stderr, "Invalid type 0x%x\n", type); break; } return type_ptr; }
/* ??? Implement proper locking for ioctls. */ static long do_ioctl(long fd, long cmd, long arg) { const IOCTLEntry *ie; const argtype *arg_type; int ret; uint8_t buf_temp[MAX_STRUCT_SIZE]; int target_size; void *argptr; ie = ioctl_entries; for(;;) { if (ie->target_cmd == 0) { gemu_log("Unsupported ioctl: cmd=0x%04lx\n", cmd); return -ENOSYS; } if (ie->target_cmd == cmd) break; ie++; } arg_type = ie->arg_type; #if defined(DEBUG) gemu_log("ioctl: cmd=0x%04lx (%s)\n", cmd, ie->name); #endif switch(arg_type[0]) { case TYPE_NULL: /* no argument */ ret = get_errno(ioctl(fd, ie->host_cmd)); break; case TYPE_PTRVOID: case TYPE_INT: /* int argment */ ret = get_errno(ioctl(fd, ie->host_cmd, arg)); break; case TYPE_PTR: arg_type++; target_size = thunk_type_size(arg_type, 0); switch(ie->access) { case IOC_R: ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp)); if (!is_error(ret)) { argptr = lock_user(arg, target_size, 0); thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET); unlock_user(argptr, arg, target_size); } break; case IOC_W: argptr = lock_user(arg, target_size, 1); thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST); unlock_user(argptr, arg, 0); ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp)); break; default: case IOC_RW: argptr = lock_user(arg, target_size, 1); thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST); unlock_user(argptr, arg, 0); ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp)); if (!is_error(ret)) { argptr = lock_user(arg, target_size, 0); thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET); unlock_user(argptr, arg, target_size); } break; } break; default: gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n", cmd, arg_type[0]); ret = -ENOSYS; break; } return ret; }