From: Stacey Son <[email protected]> Add main ioctl emulation dispatcher that handles table-driven ioctl translation with thunk-based structure conversion. Supports TYPE_NULL, TYPE_INT, and TYPE_PTR argument types with read, write, and read-write access modes.
Signed-off-by: Stacey Son <[email protected]> Reviewed-by: Pierrick Bouvier <[email protected]> Signed-off-by: Warner Losh <[email protected]> --- bsd-user/bsd-ioctl.c | 100 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/bsd-user/bsd-ioctl.c b/bsd-user/bsd-ioctl.c index 8d25d84dbe..3940a69260 100644 --- a/bsd-user/bsd-ioctl.c +++ b/bsd-user/bsd-ioctl.c @@ -292,3 +292,103 @@ static abi_long do_ioctl_in6_ifreq_sockaddr_int(const IOCTLEntry *ie, return ret; } + +abi_long do_bsd_ioctl(int fd, abi_long cmd, abi_long arg) +{ + const IOCTLEntry *ie; + const argtype *arg_type; + abi_long ret; + uint8_t buf_temp[MAX_STRUCT_SIZE]; + int target_size; + void *argptr; + + ie = ioctl_entries; + for (;;) { + if (ie->target_cmd == 0) { + gemu_log("QEMU unsupported ioctl: "); + log_unsupported_ioctl(cmd); + return -TARGET_ENOSYS; + } + if (ie->target_cmd == cmd) { + break; + } + ie++; + } + arg_type = ie->arg_type; +#if defined(DEBUG) + gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name); +#endif + if (ie->do_ioctl) { + return ie->do_ioctl(ie, buf_temp, fd, cmd, arg); + } + + switch (arg_type[0]) { + case TYPE_NULL: + /* no argument */ + ret = get_errno(safe_ioctl(fd, ie->host_cmd)); + break; + + case TYPE_PTRVOID: + case TYPE_INT: + /* int argument */ + ret = get_errno(safe_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(safe_ioctl(fd, ie->host_cmd, buf_temp)); + if (!is_error(ret)) { + argptr = lock_user(VERIFY_WRITE, arg, + target_size, 0); + if (!argptr) { + return -TARGET_EFAULT; + } + thunk_convert(argptr, buf_temp, arg_type, + THUNK_TARGET); + unlock_user(argptr, arg, target_size); + } + break; + + case IOC_W: + argptr = lock_user(VERIFY_READ, arg, target_size, 1); + if (!argptr) { + return -TARGET_EFAULT; + } + thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST); + unlock_user(argptr, arg, 0); + ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp)); + break; + + case IOC_RW: + /* fallthrough */ + default: + argptr = lock_user(VERIFY_READ, arg, target_size, 1); + if (!argptr) { + return -TARGET_EFAULT; + } + thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST); + unlock_user(argptr, arg, 0); + ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp)); + if (!is_error(ret)) { + argptr = lock_user(VERIFY_WRITE, arg, target_size, 0); + if (!argptr) { + return -TARGET_EFAULT; + } + thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET); + unlock_user(argptr, arg, target_size); + } + break; + } + break; + + default: + gemu_log("QEMU unknown ioctl: type=%d ", arg_type[0]); + log_unsupported_ioctl(cmd); + ret = -TARGET_ENOSYS; + break; + } + return ret; +} -- 2.52.0
