return -ENOSYS;
}
#endif
-#if defined(TARGET_NR_getdents) && defined(__NR_getdents)
+
+/* For the 64-bit guest on 32-bit host case we must emulate
+ * getdents using getdents64, because otherwise the host
+ * might hand us back more dirent records than we can fit
+ * into the guest buffer after structure format conversion.
+ * Otherwise we emulate getdents with getdents if the host has it.
+ */
+#if defined(__NR_getdents) && HOST_LONG_BITS >= TARGET_ABI_BITS
+#define EMULATE_GETDENTS_WITH_GETDENTS
+#endif
+
+#if defined(TARGET_NR_getdents) && defined(EMULATE_GETDENTS_WITH_GETDENTS)
_syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count);
#endif
-#if !defined(__NR_getdents) || \
+#if (defined(TARGET_NR_getdents) && \
+ !defined(EMULATE_GETDENTS_WITH_GETDENTS)) || \
(defined(TARGET_NR_getdents64) && defined(__NR_getdents64))
_syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count);
#endif
QEMU_IFLA_BR_PAD,
QEMU_IFLA_BR_VLAN_STATS_ENABLED,
QEMU_IFLA_BR_MCAST_STATS_ENABLED,
+ QEMU_IFLA_BR_MCAST_IGMP_VERSION,
+ QEMU_IFLA_BR_MCAST_MLD_VERSION,
QEMU___IFLA_BR_MAX,
};
QEMU_IFLA_GSO_MAX_SIZE,
QEMU_IFLA_PAD,
QEMU_IFLA_XDP,
+ QEMU_IFLA_EVENT,
+ QEMU_IFLA_NEW_NETNSID,
+ QEMU_IFLA_IF_NETNSID,
+ QEMU_IFLA_CARRIER_UP_COUNT,
+ QEMU_IFLA_CARRIER_DOWN_COUNT,
+ QEMU_IFLA_NEW_IFINDEX,
QEMU___IFLA_MAX
};
QEMU_IFLA_BRPORT_FLUSH,
QEMU_IFLA_BRPORT_MULTICAST_ROUTER,
QEMU_IFLA_BRPORT_PAD,
+ QEMU_IFLA_BRPORT_MCAST_FLOOD,
+ QEMU_IFLA_BRPORT_MCAST_TO_UCAST,
+ QEMU_IFLA_BRPORT_VLAN_TUNNEL,
+ QEMU_IFLA_BRPORT_BCAST_FLOOD,
+ QEMU_IFLA_BRPORT_GROUP_FWD_MASK,
+ QEMU_IFLA_BRPORT_NEIGH_SUPPRESS,
QEMU___IFLA_BRPORT_MAX
};
QEMU___IFLA_INET6_MAX
};
+enum {
+ QEMU_IFLA_XDP_UNSPEC,
+ QEMU_IFLA_XDP_FD,
+ QEMU_IFLA_XDP_ATTACHED,
+ QEMU_IFLA_XDP_FLAGS,
+ QEMU_IFLA_XDP_PROG_ID,
+ QEMU___IFLA_XDP_MAX,
+};
+
typedef abi_long (*TargetFdDataFunc)(void *, size_t);
typedef abi_long (*TargetFdAddrFunc)(void *, abi_ulong, socklen_t);
typedef struct TargetFdTrans {
return ret;
}
-static inline int is_error(abi_long ret)
-{
- return (abi_ulong)ret >= (abi_ulong)(-4096);
-}
-
const char *target_strerror(int err)
{
if (err == TARGET_ERESTARTSYS) {
/* Payload types which need a different size of payload on
* the target must adjust tgt_len here.
*/
+ tgt_len = len;
switch (cmsg->cmsg_level) {
case SOL_SOCKET:
switch (cmsg->cmsg_type) {
default:
break;
}
+ break;
default:
- tgt_len = len;
break;
}
case QEMU_IFLA_BR_NF_CALL_IPTABLES:
case QEMU_IFLA_BR_NF_CALL_IP6TABLES:
case QEMU_IFLA_BR_NF_CALL_ARPTABLES:
+ case QEMU_IFLA_BR_VLAN_STATS_ENABLED:
+ case QEMU_IFLA_BR_MCAST_STATS_ENABLED:
+ case QEMU_IFLA_BR_MCAST_IGMP_VERSION:
+ case QEMU_IFLA_BR_MCAST_MLD_VERSION:
break;
/* uint16_t */
case QEMU_IFLA_BR_PRIORITY:
case QEMU_IFLA_BRPORT_TOPOLOGY_CHANGE_ACK:
case QEMU_IFLA_BRPORT_CONFIG_PENDING:
case QEMU_IFLA_BRPORT_MULTICAST_ROUTER:
+ case QEMU_IFLA_BRPORT_MCAST_FLOOD:
+ case QEMU_IFLA_BRPORT_MCAST_TO_UCAST:
+ case QEMU_IFLA_BRPORT_VLAN_TUNNEL:
+ case QEMU_IFLA_BRPORT_BCAST_FLOOD:
+ case QEMU_IFLA_BRPORT_NEIGH_SUPPRESS:
break;
/* uint16_t */
case QEMU_IFLA_BRPORT_PRIORITY:
case QEMU_IFLA_BRPORT_DESIGNATED_COST:
case QEMU_IFLA_BRPORT_ID:
case QEMU_IFLA_BRPORT_NO:
+ case QEMU_IFLA_BRPORT_GROUP_FWD_MASK:
u16 = NLA_DATA(nlattr);
*u16 = tswap16(*u16);
break;
return 0;
}
+static abi_long host_to_target_data_xdp_nlattr(struct nlattr *nlattr,
+ void *context)
+{
+ uint32_t *u32;
+
+ switch (nlattr->nla_type) {
+ /* uint8_t */
+ case QEMU_IFLA_XDP_ATTACHED:
+ break;
+ /* uint32_t */
+ case QEMU_IFLA_XDP_PROG_ID:
+ u32 = NLA_DATA(nlattr);
+ *u32 = tswap32(*u32);
+ break;
+ default:
+ gemu_log("Unknown host XDP type: %d\n", nlattr->nla_type);
+ break;
+ }
+ return 0;
+}
+
static abi_long host_to_target_data_link_rtattr(struct rtattr *rtattr)
{
uint32_t *u32;
case QEMU_IFLA_NUM_VF:
case QEMU_IFLA_GSO_MAX_SEGS:
case QEMU_IFLA_GSO_MAX_SIZE:
+ case QEMU_IFLA_CARRIER_UP_COUNT:
+ case QEMU_IFLA_CARRIER_DOWN_COUNT:
u32 = RTA_DATA(rtattr);
*u32 = tswap32(*u32);
break;
return host_to_target_for_each_nlattr(RTA_DATA(rtattr), rtattr->rta_len,
NULL,
host_to_target_data_spec_nlattr);
+ case QEMU_IFLA_XDP:
+ return host_to_target_for_each_nlattr(RTA_DATA(rtattr), rtattr->rta_len,
+ NULL,
+ host_to_target_data_xdp_nlattr);
default:
gemu_log("Unknown host QEMU_IFLA type: %d\n", rtattr->rta_type);
break;
return ret;
}
+/* Convert target low/high pair representing file offset into the host
+ * low/high pair. This function doesn't handle offsets bigger than 64 bits
+ * as the kernel doesn't handle them either.
+ */
+static void target_to_host_low_high(abi_ulong tlow,
+ abi_ulong thigh,
+ unsigned long *hlow,
+ unsigned long *hhigh)
+{
+ uint64_t off = tlow |
+ ((unsigned long long)thigh << TARGET_LONG_BITS / 2) <<
+ TARGET_LONG_BITS / 2;
+
+ *hlow = off;
+ *hhigh = (off >> HOST_LONG_BITS / 2) >> HOST_LONG_BITS / 2;
+}
+
static struct iovec *lock_iovec(int type, abi_ulong target_addr,
abi_ulong count, int copy)
{
ts = g_new0(TaskState, 1);
init_task_state(ts);
+
+ /* Grab a mutex so that thread setup appears atomic. */
+ pthread_mutex_lock(&clone_lock);
+
/* we create a new CPU instance. */
new_env = cpu_copy(env);
/* Init regs that differ from the parent. */
cpu_set_tls (new_env, newtls);
}
- /* Grab a mutex so that thread setup appears atomic. */
- pthread_mutex_lock(&clone_lock);
-
memset(&info, 0, sizeof(info));
pthread_mutex_init(&info.mutex, NULL);
pthread_mutex_lock(&info.mutex);
return -TARGET_EINVAL;
}
-#define TRANSTBL_CONVERT(a) { -1, TARGET_##a, -1, a }
-static const bitmask_transtbl flock_tbl[] = {
- TRANSTBL_CONVERT(F_RDLCK),
- TRANSTBL_CONVERT(F_WRLCK),
- TRANSTBL_CONVERT(F_UNLCK),
- TRANSTBL_CONVERT(F_EXLCK),
- TRANSTBL_CONVERT(F_SHLCK),
- { 0, 0, 0, 0 }
-};
+#define FLOCK_TRANSTBL \
+ switch (type) { \
+ TRANSTBL_CONVERT(F_RDLCK); \
+ TRANSTBL_CONVERT(F_WRLCK); \
+ TRANSTBL_CONVERT(F_UNLCK); \
+ TRANSTBL_CONVERT(F_EXLCK); \
+ TRANSTBL_CONVERT(F_SHLCK); \
+ }
+
+static int target_to_host_flock(int type)
+{
+#define TRANSTBL_CONVERT(a) case TARGET_##a: return a
+ FLOCK_TRANSTBL
+#undef TRANSTBL_CONVERT
+ return -TARGET_EINVAL;
+}
+
+static int host_to_target_flock(int type)
+{
+#define TRANSTBL_CONVERT(a) case a: return TARGET_##a
+ FLOCK_TRANSTBL
+#undef TRANSTBL_CONVERT
+ /* if we don't know how to convert the value coming
+ * from the host we copy to the target field as-is
+ */
+ return type;
+}
static inline abi_long copy_from_user_flock(struct flock64 *fl,
abi_ulong target_flock_addr)
{
struct target_flock *target_fl;
- short l_type;
+ int l_type;
if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
return -TARGET_EFAULT;
}
__get_user(l_type, &target_fl->l_type);
- fl->l_type = target_to_host_bitmask(l_type, flock_tbl);
+ l_type = target_to_host_flock(l_type);
+ if (l_type < 0) {
+ return l_type;
+ }
+ fl->l_type = l_type;
__get_user(fl->l_whence, &target_fl->l_whence);
__get_user(fl->l_start, &target_fl->l_start);
__get_user(fl->l_len, &target_fl->l_len);
return -TARGET_EFAULT;
}
- l_type = host_to_target_bitmask(fl->l_type, flock_tbl);
+ l_type = host_to_target_flock(fl->l_type);
__put_user(l_type, &target_fl->l_type);
__put_user(fl->l_whence, &target_fl->l_whence);
__put_user(fl->l_start, &target_fl->l_start);
typedef abi_long to_flock64_fn(abi_ulong target_addr, const struct flock64 *fl);
#if defined(TARGET_ARM) && TARGET_ABI_BITS == 32
-static inline abi_long copy_from_user_eabi_flock64(struct flock64 *fl,
+static inline abi_long copy_from_user_oabi_flock64(struct flock64 *fl,
abi_ulong target_flock_addr)
{
- struct target_eabi_flock64 *target_fl;
- short l_type;
+ struct target_oabi_flock64 *target_fl;
+ int l_type;
if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
return -TARGET_EFAULT;
}
__get_user(l_type, &target_fl->l_type);
- fl->l_type = target_to_host_bitmask(l_type, flock_tbl);
+ l_type = target_to_host_flock(l_type);
+ if (l_type < 0) {
+ return l_type;
+ }
+ fl->l_type = l_type;
__get_user(fl->l_whence, &target_fl->l_whence);
__get_user(fl->l_start, &target_fl->l_start);
__get_user(fl->l_len, &target_fl->l_len);
return 0;
}
-static inline abi_long copy_to_user_eabi_flock64(abi_ulong target_flock_addr,
+static inline abi_long copy_to_user_oabi_flock64(abi_ulong target_flock_addr,
const struct flock64 *fl)
{
- struct target_eabi_flock64 *target_fl;
+ struct target_oabi_flock64 *target_fl;
short l_type;
if (!lock_user_struct(VERIFY_WRITE, target_fl, target_flock_addr, 0)) {
return -TARGET_EFAULT;
}
- l_type = host_to_target_bitmask(fl->l_type, flock_tbl);
+ l_type = host_to_target_flock(fl->l_type);
__put_user(l_type, &target_fl->l_type);
__put_user(fl->l_whence, &target_fl->l_whence);
__put_user(fl->l_start, &target_fl->l_start);
abi_ulong target_flock_addr)
{
struct target_flock64 *target_fl;
- short l_type;
+ int l_type;
if (!lock_user_struct(VERIFY_READ, target_fl, target_flock_addr, 1)) {
return -TARGET_EFAULT;
}
__get_user(l_type, &target_fl->l_type);
- fl->l_type = target_to_host_bitmask(l_type, flock_tbl);
+ l_type = target_to_host_flock(l_type);
+ if (l_type < 0) {
+ return l_type;
+ }
+ fl->l_type = l_type;
__get_user(fl->l_whence, &target_fl->l_whence);
__get_user(fl->l_start, &target_fl->l_start);
__get_user(fl->l_len, &target_fl->l_len);
return -TARGET_EFAULT;
}
- l_type = host_to_target_bitmask(fl->l_type, flock_tbl);
+ l_type = host_to_target_flock(fl->l_type);
__put_user(l_type, &target_fl->l_type);
__put_user(fl->l_whence, &target_fl->l_whence);
__put_user(fl->l_start, &target_fl->l_start);
if (!is_error(ret)) {
/* Overwrite the native machine name with whatever is being
emulated. */
- strcpy (buf->machine, cpu_to_uname_machine(cpu_env));
+ g_strlcpy(buf->machine, cpu_to_uname_machine(cpu_env),
+ sizeof(buf->machine));
/* Allow the user to override the reported release. */
if (qemu_uname_release && *qemu_uname_release) {
g_strlcpy(buf->release, qemu_uname_release,
#endif
#ifdef TARGET_NR_getdents
case TARGET_NR_getdents:
-#ifdef __NR_getdents
+#ifdef EMULATE_GETDENTS_WITH_GETDENTS
#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
{
struct target_dirent *target_dirp;
{
struct iovec *vec = lock_iovec(VERIFY_WRITE, arg2, arg3, 0);
if (vec != NULL) {
- ret = get_errno(safe_preadv(arg1, vec, arg3, arg4, arg5));
+ unsigned long low, high;
+
+ target_to_host_low_high(arg4, arg5, &low, &high);
+ ret = get_errno(safe_preadv(arg1, vec, arg3, low, high));
unlock_iovec(vec, arg2, arg3, 1);
} else {
ret = -host_to_target_errno(errno);
{
struct iovec *vec = lock_iovec(VERIFY_READ, arg2, arg3, 1);
if (vec != NULL) {
- ret = get_errno(safe_pwritev(arg1, vec, arg3, arg4, arg5));
+ unsigned long low, high;
+
+ target_to_host_low_high(arg4, arg5, &low, &high);
+ ret = get_errno(safe_pwritev(arg1, vec, arg3, low, high));
unlock_iovec(vec, arg2, arg3, 0);
} else {
ret = -host_to_target_errno(errno);
#ifdef TARGET_NR_fadvise64_64
case TARGET_NR_fadvise64_64:
-#if defined(TARGET_PPC)
+#if defined(TARGET_PPC) || defined(TARGET_XTENSA)
/* 6 args: fd, advice, offset (high, low), len (high, low) */
ret = arg2;
arg2 = arg3;
to_flock64_fn *copyto = copy_to_user_flock64;
#ifdef TARGET_ARM
- if (((CPUARMState *)cpu_env)->eabi) {
- copyfrom = copy_from_user_eabi_flock64;
- copyto = copy_to_user_eabi_flock64;
+ if (!((CPUARMState *)cpu_env)->eabi) {
+ copyfrom = copy_from_user_oabi_flock64;
+ copyto = copy_to_user_oabi_flock64;
}
#endif
goto unimplemented_nowarn;
#endif
+#ifdef TARGET_NR_clock_settime
+ case TARGET_NR_clock_settime:
+ {
+ struct timespec ts;
+
+ ret = target_to_host_timespec(&ts, arg2);
+ if (!is_error(ret)) {
+ ret = get_errno(clock_settime(arg1, &ts));
+ }
+ break;
+ }
+#endif
#ifdef TARGET_NR_clock_gettime
case TARGET_NR_clock_gettime:
{
struct timespec ts;
ret = get_errno(clock_gettime(arg1, &ts));
if (!is_error(ret)) {
- host_to_target_timespec(arg2, &ts);
+ ret = host_to_target_timespec(arg2, &ts);
}
break;
}
{
struct mq_attr posix_mq_attr_in, posix_mq_attr_out;
ret = 0;
- if (arg3 != 0) {
- ret = mq_getattr(arg1, &posix_mq_attr_out);
- copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
- }
if (arg2 != 0) {
copy_from_user_mq_attr(&posix_mq_attr_in, arg2);
- ret |= mq_setattr(arg1, &posix_mq_attr_in, &posix_mq_attr_out);
+ ret = get_errno(mq_setattr(arg1, &posix_mq_attr_in,
+ &posix_mq_attr_out));
+ } else if (arg3 != 0) {
+ ret = get_errno(mq_getattr(arg1, &posix_mq_attr_out));
+ }
+ if (ret == 0 && arg3 != 0) {
+ copy_to_user_mq_attr(arg3, &posix_mq_attr_out);
}
-
}
break;
#endif