From 56d190848b9b8ecb8213835b0d2d05b243bcb5b8 Mon Sep 17 00:00:00 2001 From: Tobias Koch Date: Wed, 28 Oct 2020 22:38:33 +0100 Subject: linux-user/mmap.c: check range of mremap result in target address space If mremap succeeds, an additional check is performed to ensure that the new address range fits into the target address space. This check was previously perfomed in host address space, with the upper bound fixed to abi_ulong. This patch replaces the static check with a call to `guest_range_valid`, performing the range check against the actual size of the target address space. It also moves the corresponding block to prevent it from being called incorrectly when the mapping itself fails. Signed-off-by: Tobias Koch Message-Id: <20201028213833.26592-1-tobias.koch@nonterra.com> Signed-off-by: Laurent Vivier --- linux-user/mmap.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'linux-user') diff --git a/linux-user/mmap.c b/linux-user/mmap.c index 00c05e6..810653c 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -767,20 +767,23 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size, } if (prot == 0) { host_addr = mremap(g2h(old_addr), old_size, new_size, flags); - if (host_addr != MAP_FAILED && reserved_va && old_size > new_size) { - mmap_reserve(old_addr + old_size, old_size - new_size); + + if (host_addr != MAP_FAILED) { + /* Check if address fits target address space */ + if (!guest_range_valid(h2g(host_addr), new_size)) { + /* Revert mremap() changes */ + host_addr = mremap(g2h(old_addr), new_size, old_size, + flags); + errno = ENOMEM; + host_addr = MAP_FAILED; + } else if (reserved_va && old_size > new_size) { + mmap_reserve(old_addr + old_size, old_size - new_size); + } } } else { errno = ENOMEM; host_addr = MAP_FAILED; } - /* Check if address fits target address space */ - if ((unsigned long)host_addr + new_size > (abi_ulong)-1) { - /* Revert mremap() changes */ - host_addr = mremap(g2h(old_addr), new_size, old_size, flags); - errno = ENOMEM; - host_addr = MAP_FAILED; - } } if (host_addr == MAP_FAILED) { -- cgit v1.1 From 6dd97bfc1fd4453c4855109dd508a78617527a6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 14 Dec 2020 01:32:10 +0100 Subject: linux-user/elfload: Move GET_FEATURE macro out of get_elf_hwcap() body MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As we are going to add more macros, keep the function body clear. Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20201214003215.344522-2-f4bug@amsat.org> Signed-off-by: Laurent Vivier --- linux-user/elfload.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'linux-user') diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 0b02a92..aae28fd 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -989,22 +989,22 @@ enum { #define ELF_HWCAP get_elf_hwcap() +#define GET_FEATURE(_flag, _hwcap) \ + do { if (cpu->env.insn_flags & (_flag)) { hwcaps |= _hwcap; } } while (0) + static uint32_t get_elf_hwcap(void) { MIPSCPU *cpu = MIPS_CPU(thread_cpu); uint32_t hwcaps = 0; -#define GET_FEATURE(flag, hwcap) \ - do { if (cpu->env.insn_flags & (flag)) { hwcaps |= hwcap; } } while (0) - GET_FEATURE(ISA_MIPS32R6 | ISA_MIPS64R6, HWCAP_MIPS_R6); GET_FEATURE(ASE_MSA, HWCAP_MIPS_MSA); -#undef GET_FEATURE - return hwcaps; } +#undef GET_FEATURE + #endif /* TARGET_MIPS */ #ifdef TARGET_MICROBLAZE -- cgit v1.1 From 7d9a3d96f57dfed441622ebb9d1516473d51f919 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 14 Dec 2020 01:32:11 +0100 Subject: linux-user/elfload: Rename MIPS GET_FEATURE() as GET_FEATURE_INSN() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We want to add macros similar to GET_FEATURE(). As this one use the 'insn_flags' field, rename it GET_FEATURE_INSN(). Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20201214003215.344522-3-f4bug@amsat.org> Signed-off-by: Laurent Vivier --- linux-user/elfload.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'linux-user') diff --git a/linux-user/elfload.c b/linux-user/elfload.c index aae28fd..0e1d7e7 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -989,7 +989,7 @@ enum { #define ELF_HWCAP get_elf_hwcap() -#define GET_FEATURE(_flag, _hwcap) \ +#define GET_FEATURE_INSN(_flag, _hwcap) \ do { if (cpu->env.insn_flags & (_flag)) { hwcaps |= _hwcap; } } while (0) static uint32_t get_elf_hwcap(void) @@ -997,13 +997,13 @@ static uint32_t get_elf_hwcap(void) MIPSCPU *cpu = MIPS_CPU(thread_cpu); uint32_t hwcaps = 0; - GET_FEATURE(ISA_MIPS32R6 | ISA_MIPS64R6, HWCAP_MIPS_R6); - GET_FEATURE(ASE_MSA, HWCAP_MIPS_MSA); + GET_FEATURE_INSN(ISA_MIPS32R6 | ISA_MIPS64R6, HWCAP_MIPS_R6); + GET_FEATURE_INSN(ASE_MSA, HWCAP_MIPS_MSA); return hwcaps; } -#undef GET_FEATURE +#undef GET_FEATURE_INSN #endif /* TARGET_MIPS */ -- cgit v1.1 From 388765a05bde86de9d9b66348afed6551c58f091 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 14 Dec 2020 01:32:12 +0100 Subject: linux-user/elfload: Introduce MIPS GET_FEATURE_REG_SET() macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ISA features are usually denoted in read-only bits from CPU registers. Add the GET_FEATURE_REG_SET() macro which checks if a CPU register has bits set. Use the macro to check for MSA (which sets the MSAP bit of the Config3 register when the ASE implementation is present). Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20201214003215.344522-4-f4bug@amsat.org> Signed-off-by: Laurent Vivier --- linux-user/elfload.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'linux-user') diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 0e1d7e7..b7c6d30 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -992,17 +992,21 @@ enum { #define GET_FEATURE_INSN(_flag, _hwcap) \ do { if (cpu->env.insn_flags & (_flag)) { hwcaps |= _hwcap; } } while (0) +#define GET_FEATURE_REG_SET(_reg, _mask, _hwcap) \ + do { if (cpu->env._reg & (_mask)) { hwcaps |= _hwcap; } } while (0) + static uint32_t get_elf_hwcap(void) { MIPSCPU *cpu = MIPS_CPU(thread_cpu); uint32_t hwcaps = 0; GET_FEATURE_INSN(ISA_MIPS32R6 | ISA_MIPS64R6, HWCAP_MIPS_R6); - GET_FEATURE_INSN(ASE_MSA, HWCAP_MIPS_MSA); + GET_FEATURE_REG_SET(CP0_Config3, 1 << CP0C3_MSAP, HWCAP_MIPS_MSA); return hwcaps; } +#undef GET_FEATURE_REG_SET #undef GET_FEATURE_INSN #endif /* TARGET_MIPS */ -- cgit v1.1 From ce54384405b77483f5ce06ab8dc7537299453b43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 14 Dec 2020 01:32:13 +0100 Subject: linux-user/elfload: Introduce MIPS GET_FEATURE_REG_EQU() macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ISA features are usually denoted in read-only bits from CPU registers. Add the GET_FEATURE_REG_EQU() macro which checks if a CPU register has bits set to a specific value. Use the macro to check the 'Architecture Revision' level of the Config0 register, which is '2' when the Release 6 ISA is implemented. Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20201214003215.344522-5-f4bug@amsat.org> Signed-off-by: Laurent Vivier --- linux-user/elfload.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'linux-user') diff --git a/linux-user/elfload.c b/linux-user/elfload.c index b7c6d30..8f943f9 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -7,6 +7,7 @@ #include "qemu.h" #include "disas/disas.h" +#include "qemu/bitops.h" #include "qemu/path.h" #include "qemu/queue.h" #include "qemu/guest-random.h" @@ -995,17 +996,26 @@ enum { #define GET_FEATURE_REG_SET(_reg, _mask, _hwcap) \ do { if (cpu->env._reg & (_mask)) { hwcaps |= _hwcap; } } while (0) +#define GET_FEATURE_REG_EQU(_reg, _start, _length, _val, _hwcap) \ + do { \ + if (extract32(cpu->env._reg, (_start), (_length)) == (_val)) { \ + hwcaps |= _hwcap; \ + } \ + } while (0) + static uint32_t get_elf_hwcap(void) { MIPSCPU *cpu = MIPS_CPU(thread_cpu); uint32_t hwcaps = 0; - GET_FEATURE_INSN(ISA_MIPS32R6 | ISA_MIPS64R6, HWCAP_MIPS_R6); + GET_FEATURE_REG_EQU(CP0_Config0, CP0C0_AR, CP0C0_AR_LENGTH, + 2, HWCAP_MIPS_R6); GET_FEATURE_REG_SET(CP0_Config3, 1 << CP0C3_MSAP, HWCAP_MIPS_MSA); return hwcaps; } +#undef GET_FEATURE_REG_EQU #undef GET_FEATURE_REG_SET #undef GET_FEATURE_INSN -- cgit v1.1 From 9ea313ba5d2071f6c3bf0897a7876c7c527964d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 14 Dec 2020 01:32:14 +0100 Subject: linux-user/elfload: Update HWCAP bits from linux 5.7 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20201214003215.344522-6-f4bug@amsat.org> Signed-off-by: Laurent Vivier --- linux-user/elfload.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'linux-user') diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 8f943f9..0836e72 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -986,6 +986,19 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUMIPSState *e enum { HWCAP_MIPS_R6 = (1 << 0), HWCAP_MIPS_MSA = (1 << 1), + HWCAP_MIPS_CRC32 = (1 << 2), + HWCAP_MIPS_MIPS16 = (1 << 3), + HWCAP_MIPS_MDMX = (1 << 4), + HWCAP_MIPS_MIPS3D = (1 << 5), + HWCAP_MIPS_SMARTMIPS = (1 << 6), + HWCAP_MIPS_DSP = (1 << 7), + HWCAP_MIPS_DSP2 = (1 << 8), + HWCAP_MIPS_DSP3 = (1 << 9), + HWCAP_MIPS_MIPS16E2 = (1 << 10), + HWCAP_LOONGSON_MMI = (1 << 11), + HWCAP_LOONGSON_EXT = (1 << 12), + HWCAP_LOONGSON_EXT2 = (1 << 13), + HWCAP_LOONGSON_CPUCFG = (1 << 14), }; #define ELF_HWCAP get_elf_hwcap() -- cgit v1.1 From 53673d0ff4a45964322bd6bfe904eff7dc96197d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 14 Dec 2020 01:32:15 +0100 Subject: linux-user: Add support for MIPS Loongson 2F/3A MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Userland ELF binaries using Loongson SIMD instructions have the HWCAP_LOONGSON_MMI bit set [1]. Binaries compiled for Loongson 3A [2] have the HWCAP_LOONGSON_EXT bit set for the LQ / SQ instructions. [1] commit 8e2d5831e4b ("target/mips: Legalize Loongson insn flags") [2] commit af868995e1b ("target/mips: Add Loongson-3 CPU definition") Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20201214003215.344522-7-f4bug@amsat.org> Signed-off-by: Laurent Vivier --- linux-user/elfload.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'linux-user') diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 0836e72..a640507 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -1024,6 +1024,8 @@ static uint32_t get_elf_hwcap(void) GET_FEATURE_REG_EQU(CP0_Config0, CP0C0_AR, CP0C0_AR_LENGTH, 2, HWCAP_MIPS_R6); GET_FEATURE_REG_SET(CP0_Config3, 1 << CP0C3_MSAP, HWCAP_MIPS_MSA); + GET_FEATURE_INSN(ASE_LMMI, HWCAP_LOONGSON_MMI); + GET_FEATURE_INSN(ASE_LEXT, HWCAP_LOONGSON_EXT); return hwcaps; } -- cgit v1.1 From 8494645797ac3c61d8693ac4164a87c8790a8717 Mon Sep 17 00:00:00 2001 From: Andreas Schwab Date: Thu, 12 Nov 2020 12:45:16 +0100 Subject: linux-user: Implement copy_file_range Signed-off-by: Andreas Schwab Reviewed-by: Laurent Vivier Message-Id: [lv: copy back offset only if there is no error] Signed-off-by: Laurent Vivier --- linux-user/syscall.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) (limited to 'linux-user') diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 7bf99be..6091a44 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -813,6 +813,12 @@ safe_syscall5(int, mq_timedsend, int, mqdes, const char *, msg_ptr, safe_syscall5(int, mq_timedreceive, int, mqdes, char *, msg_ptr, size_t, len, unsigned *, prio, const struct timespec *, timeout) #endif +#if defined(TARGET_NR_copy_file_range) && defined(__NR_copy_file_range) +safe_syscall6(ssize_t, copy_file_range, int, infd, loff_t *, pinoff, + int, outfd, loff_t *, poutoff, size_t, length, + unsigned int, flags) +#endif + /* We do ioctl like this rather than via safe_syscall3 to preserve the * "third argument might be integer or pointer or not present" behaviour of * the libc function. @@ -13065,6 +13071,42 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, return get_errno(membarrier(arg1, arg2)); #endif +#if defined(TARGET_NR_copy_file_range) && defined(__NR_copy_file_range) + case TARGET_NR_copy_file_range: + { + loff_t inoff, outoff; + loff_t *pinoff = NULL, *poutoff = NULL; + + if (arg2) { + if (get_user_u64(inoff, arg2)) { + return -TARGET_EFAULT; + } + pinoff = &inoff; + } + if (arg4) { + if (get_user_u64(outoff, arg4)) { + return -TARGET_EFAULT; + } + poutoff = &outoff; + } + ret = get_errno(safe_copy_file_range(arg1, pinoff, arg3, poutoff, + arg5, arg6)); + if (!is_error(ret) && ret > 0) { + if (arg2) { + if (put_user_u64(inoff, arg2)) { + return -TARGET_EFAULT; + } + } + if (arg4) { + if (put_user_u64(outoff, arg4)) { + return -TARGET_EFAULT; + } + } + } + } + return ret; +#endif + default: qemu_log_mask(LOG_UNIMP, "Unsupported syscall: %d\n", num); return -TARGET_ENOSYS; -- cgit v1.1 From 6addf06a3c4dad68d8d7032e31714e81b438c7d9 Mon Sep 17 00:00:00 2001 From: Shu-Chun Weng Date: Mon, 28 Sep 2020 18:48:01 -0700 Subject: linux-user: Add most IFTUN ioctls The three options handling `struct sock_fprog` (TUNATTACHFILTER, TUNDETACHFILTER, and TUNGETFILTER) are not implemented. Linux kernel keeps a user space pointer in them which we cannot correctly handle. Signed-off-by: Josh Kunz Signed-off-by: Shu-Chun Weng Reviewed-by: Laurent Vivier Message-Id: <20200929014801.655524-1-scw@google.com> [lv: use 0 size in unlock_user()] Signed-off-by: Laurent Vivier --- linux-user/ioctls.h | 46 ++++++++++++++++++++++++++++++++++++++++++++++ linux-user/syscall.c | 37 +++++++++++++++++++++++++++++++++++++ linux-user/syscall_defs.h | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 115 insertions(+) (limited to 'linux-user') diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h index 8efb4d3..661b5da 100644 --- a/linux-user/ioctls.h +++ b/linux-user/ioctls.h @@ -720,3 +720,49 @@ IOCTL(KCOV_DISABLE, 0, TYPE_NULL) IOCTL(KCOV_INIT_TRACE, IOC_R, TYPE_ULONG) #endif + + IOCTL(TUNSETDEBUG, IOC_W, TYPE_INT) + IOCTL(TUNSETIFF, IOC_RW, MK_PTR(MK_STRUCT(STRUCT_short_ifreq))) + IOCTL(TUNSETPERSIST, IOC_W, TYPE_INT) + IOCTL(TUNSETOWNER, IOC_W, TYPE_INT) + IOCTL(TUNSETLINK, IOC_W, TYPE_INT) + IOCTL(TUNSETGROUP, IOC_W, TYPE_INT) + IOCTL(TUNGETFEATURES, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(TUNSETOFFLOAD, IOC_W, TYPE_LONG) + IOCTL_SPECIAL(TUNSETTXFILTER, IOC_W, do_ioctl_TUNSETTXFILTER, + /* + * We can't represent `struct tun_filter` in thunk so leaving + * it uninterpreted. do_ioctl_TUNSETTXFILTER will do the + * conversion. + */ + TYPE_PTRVOID) + IOCTL(TUNGETIFF, IOC_R, MK_PTR(MK_STRUCT(STRUCT_short_ifreq))) + IOCTL(TUNGETSNDBUF, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(TUNSETSNDBUF, IOC_W, MK_PTR(TYPE_INT)) + /* + * TUNATTACHFILTER and TUNDETACHFILTER are not supported. Linux kernel keeps a + * user pointer in TUNATTACHFILTER, which we are not able to correctly handle. + */ + IOCTL(TUNGETVNETHDRSZ, IOC_R, MK_PTR(TYPE_INT)) + IOCTL(TUNSETVNETHDRSZ, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(TUNSETQUEUE, IOC_W, MK_PTR(MK_STRUCT(STRUCT_short_ifreq))) + IOCTL(TUNSETIFINDEX , IOC_W, MK_PTR(TYPE_INT)) + /* TUNGETFILTER is not supported: see TUNATTACHFILTER. */ + IOCTL(TUNSETVNETLE, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(TUNGETVNETLE, IOC_R, MK_PTR(TYPE_INT)) +#ifdef TUNSETVNETBE + IOCTL(TUNSETVNETBE, IOC_W, MK_PTR(TYPE_INT)) + IOCTL(TUNGETVNETBE, IOC_R, MK_PTR(TYPE_INT)) +#endif +#ifdef TUNSETSTEERINGEBPF + IOCTL(TUNSETSTEERINGEBPF, IOC_W, MK_PTR(TYPE_INT)) +#endif +#ifdef TUNSETFILTEREBPF + IOCTL(TUNSETFILTEREBPF, IOC_W, MK_PTR(TYPE_INT)) +#endif +#ifdef TUNSETCARRIER + IOCTL(TUNSETCARRIER, IOC_W, MK_PTR(TYPE_INT)) +#endif +#ifdef TUNGETDEVNETNS + IOCTL(TUNGETDEVNETNS, IOC_R, TYPE_NULL) +#endif diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 6091a44..d182890 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -56,6 +56,7 @@ #include #include #include +#include #include #include #ifdef CONFIG_TIMERFD @@ -5709,6 +5710,42 @@ static abi_long do_ioctl_drm_i915(const IOCTLEntry *ie, uint8_t *buf_temp, #endif +static abi_long do_ioctl_TUNSETTXFILTER(const IOCTLEntry *ie, uint8_t *buf_temp, + int fd, int cmd, abi_long arg) +{ + struct tun_filter *filter = (struct tun_filter *)buf_temp; + struct tun_filter *target_filter; + char *target_addr; + + assert(ie->access == IOC_W); + + target_filter = lock_user(VERIFY_READ, arg, sizeof(*target_filter), 1); + if (!target_filter) { + return -TARGET_EFAULT; + } + filter->flags = tswap16(target_filter->flags); + filter->count = tswap16(target_filter->count); + unlock_user(target_filter, arg, 0); + + if (filter->count) { + if (offsetof(struct tun_filter, addr) + filter->count * ETH_ALEN > + MAX_STRUCT_SIZE) { + return -TARGET_EFAULT; + } + + target_addr = lock_user(VERIFY_READ, + arg + offsetof(struct tun_filter, addr), + filter->count * ETH_ALEN, 1); + if (!target_addr) { + return -TARGET_EFAULT; + } + memcpy(filter->addr, target_addr, filter->count * ETH_ALEN); + unlock_user(target_addr, arg + offsetof(struct tun_filter, addr), 0); + } + + return get_errno(safe_ioctl(fd, ie->host_cmd, filter)); +} + IOCTLEntry ioctl_entries[] = { #define IOCTL(cmd, access, ...) \ { TARGET_ ## cmd, cmd, #cmd, access, 0, { __VA_ARGS__ } }, diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index b934d0b..a00bfc2 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -929,6 +929,38 @@ struct target_rtc_pll_info { #define TARGET_SIOCGIWNAME 0x8B01 /* get name == wireless protocol */ +/* From */ + +#define TARGET_TUNSETDEBUG TARGET_IOW('T', 201, int) +#define TARGET_TUNSETIFF TARGET_IOW('T', 202, int) +#define TARGET_TUNSETPERSIST TARGET_IOW('T', 203, int) +#define TARGET_TUNSETOWNER TARGET_IOW('T', 204, int) +#define TARGET_TUNSETLINK TARGET_IOW('T', 205, int) +#define TARGET_TUNSETGROUP TARGET_IOW('T', 206, int) +#define TARGET_TUNGETFEATURES TARGET_IOR('T', 207, unsigned int) +#define TARGET_TUNSETOFFLOAD TARGET_IOW('T', 208, unsigned int) +#define TARGET_TUNSETTXFILTER TARGET_IOW('T', 209, unsigned int) +#define TARGET_TUNGETIFF TARGET_IOR('T', 210, unsigned int) +#define TARGET_TUNGETSNDBUF TARGET_IOR('T', 211, int) +#define TARGET_TUNSETSNDBUF TARGET_IOW('T', 212, int) +/* + * TUNATTACHFILTER and TUNDETACHFILTER are not supported. Linux kernel keeps a + * user pointer in TUNATTACHFILTER, which we are not able to correctly handle. + */ +#define TARGET_TUNGETVNETHDRSZ TARGET_IOR('T', 215, int) +#define TARGET_TUNSETVNETHDRSZ TARGET_IOW('T', 216, int) +#define TARGET_TUNSETQUEUE TARGET_IOW('T', 217, int) +#define TARGET_TUNSETIFINDEX TARGET_IOW('T', 218, unsigned int) +/* TUNGETFILTER is not supported: see TUNATTACHFILTER. */ +#define TARGET_TUNSETVNETLE TARGET_IOW('T', 220, int) +#define TARGET_TUNGETVNETLE TARGET_IOR('T', 221, int) +#define TARGET_TUNSETVNETBE TARGET_IOW('T', 222, int) +#define TARGET_TUNGETVNETBE TARGET_IOR('T', 223, int) +#define TARGET_TUNSETSTEERINGEBPF TARGET_IOR('T', 224, int) +#define TARGET_TUNSETFILTEREBPF TARGET_IOR('T', 225, int) +#define TARGET_TUNSETCARRIER TARGET_IOW('T', 226, int) +#define TARGET_TUNGETDEVNETNS TARGET_IO('T', 227) + /* From */ #define TARGET_RNDGETENTCNT TARGET_IOR('R', 0x00, int) -- cgit v1.1 From 246ff44295d0153d1d272b4d4a77c4bf9cc6ad66 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 6 Nov 2020 15:27:35 +0000 Subject: linux-user/sparc: Correct sparc64_get/set_context() FPU handling The handling of the FPU state in sparc64_get_context() and sparc64_set_context() is not the same as what the kernel actually does: we unconditionally read and write the FP registers and the FSR, GSR and FPRS, but the kernel logic is more complicated: * in get_context the kernel has code for saving FPU registers, but it is hidden inside an "if (fenab) condition and the fenab flag is always set to 0 (inside an "#if 1" which has been in the kernel for over 15 years). So the effect is that the FPU state part is always written as zeroes. * in set_context the kernel looks at the fenab field in the structure from the guest, and only restores the state if it is set; it also looks at the structure's FPRS to see whether either the upper or lower or both halves of the register file have valid data. Bring our implementations into line with the kernel: * in get_context: - clear the entire target_ucontext at the top of the function (as the kernel does) - then don't write the FPU state, so those fields remain zero - this fixes Coverity issue CID 1432305 by deleting the code it was complaining about * in set_context: - check the fenab and the fpsr to decide which parts of the FPU data to restore, if any - instead of setting the FPU registers by doing two 32-bit loads and filling in the .upper and .lower parts of the CPU_Double union separately, just do a 64-bit load of the whole register at once. This fixes Coverity issue CID 1432303 because we now access the dregs[] part of the mcfpu_fregs union rather than the sregs[] part (which is not large enough to actually cover the whole of the data, so we were accessing off the end of sregs[]) We change both functions in a single commit to avoid potentially breaking bisection. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-Id: <20201106152738.26026-2-peter.maydell@linaro.org> [lv: fix FPRS_DU loop s/31/32/] Signed-off-by: Laurent Vivier --- linux-user/sparc/signal.c | 74 +++++++++++++++++++++++++++-------------------- 1 file changed, 43 insertions(+), 31 deletions(-) (limited to 'linux-user') diff --git a/linux-user/sparc/signal.c b/linux-user/sparc/signal.c index d12adc8..0057b48 100644 --- a/linux-user/sparc/signal.c +++ b/linux-user/sparc/signal.c @@ -402,8 +402,10 @@ void sparc64_set_context(CPUSPARCState *env) abi_ulong ucp_addr; struct target_ucontext *ucp; target_mc_gregset_t *grp; + target_mc_fpu_t *fpup; abi_ulong pc, npc, tstate; unsigned int i; + unsigned char fenab; ucp_addr = env->regwptr[WREG_O0]; if (!lock_user_struct(VERIFY_READ, ucp, ucp_addr, 1)) { @@ -467,26 +469,42 @@ void sparc64_set_context(CPUSPARCState *env) __get_user(env->regwptr[WREG_FP], &(ucp->tuc_mcontext.mc_fp)); __get_user(env->regwptr[WREG_I7], &(ucp->tuc_mcontext.mc_i7)); - /* FIXME this does not match how the kernel handles the FPU in - * its sparc64_set_context implementation. In particular the FPU - * is only restored if fenab is non-zero in: - * __get_user(fenab, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_enab)); - */ - __get_user(env->fprs, &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fprs)); - { - uint32_t *src = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs; - for (i = 0; i < 64; i++, src++) { - if (i & 1) { - __get_user(env->fpr[i/2].l.lower, src); - } else { - __get_user(env->fpr[i/2].l.upper, src); + fpup = &ucp->tuc_mcontext.mc_fpregs; + + __get_user(fenab, &(fpup->mcfpu_enab)); + if (fenab) { + abi_ulong fprs; + + /* + * We use the FPRS from the guest only in deciding whether + * to restore the upper, lower, or both banks of the FPU regs. + * The kernel here writes the FPU register data into the + * process's current_thread_info state and unconditionally + * clears FPRS and TSTATE_PEF: this disables the FPU so that the + * next FPU-disabled trap will copy the data out of + * current_thread_info and into the real FPU registers. + * QEMU doesn't need to handle lazy-FPU-state-restoring like that, + * so we always load the data directly into the FPU registers + * and leave FPRS and TSTATE_PEF alone (so the FPU stays enabled). + * Note that because we (and the kernel) always write zeroes for + * the fenab and fprs in sparc64_get_context() none of this code + * will execute unless the guest manually constructed or changed + * the context structure. + */ + __get_user(fprs, &(fpup->mcfpu_fprs)); + if (fprs & FPRS_DL) { + for (i = 0; i < 16; i++) { + __get_user(env->fpr[i].ll, &(fpup->mcfpu_fregs.dregs[i])); + } + } + if (fprs & FPRS_DU) { + for (i = 16; i < 32; i++) { + __get_user(env->fpr[i].ll, &(fpup->mcfpu_fregs.dregs[i])); } } + __get_user(env->fsr, &(fpup->mcfpu_fsr)); + __get_user(env->gsr, &(fpup->mcfpu_gsr)); } - __get_user(env->fsr, - &(ucp->tuc_mcontext.mc_fpregs.mcfpu_fsr)); - __get_user(env->gsr, - &(ucp->tuc_mcontext.mc_fpregs.mcfpu_gsr)); unlock_user_struct(ucp, ucp_addr, 0); return; do_sigsegv: @@ -509,7 +527,9 @@ void sparc64_get_context(CPUSPARCState *env) if (!lock_user_struct(VERIFY_WRITE, ucp, ucp_addr, 0)) { goto do_sigsegv; } - + + memset(ucp, 0, sizeof(*ucp)); + mcp = &ucp->tuc_mcontext; grp = &mcp->mc_gregs; @@ -572,19 +592,11 @@ void sparc64_get_context(CPUSPARCState *env) __put_user(env->regwptr[WREG_FP], &(mcp->mc_fp)); __put_user(env->regwptr[WREG_I7], &(mcp->mc_i7)); - { - uint32_t *dst = ucp->tuc_mcontext.mc_fpregs.mcfpu_fregs.sregs; - for (i = 0; i < 64; i++, dst++) { - if (i & 1) { - __put_user(env->fpr[i/2].l.lower, dst); - } else { - __put_user(env->fpr[i/2].l.upper, dst); - } - } - } - __put_user(env->fsr, &(mcp->mc_fpregs.mcfpu_fsr)); - __put_user(env->gsr, &(mcp->mc_fpregs.mcfpu_gsr)); - __put_user(env->fprs, &(mcp->mc_fpregs.mcfpu_fprs)); + /* + * We don't write out the FPU state. This matches the kernel's + * implementation (which has the code for doing this but + * hidden behind an "if (fenab)" where fenab is always 0). + */ if (err) goto do_sigsegv; -- cgit v1.1 From 309abce23658c0142430440c7ad1be2a02170ed0 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 6 Nov 2020 15:27:36 +0000 Subject: linux-user/sparc: Remove unneeded checks of 'err' from sparc64_get_context() Unlike the kernel macros, our __get_user() and __put_user() do not return a failure code. Kernel code typically has a style of err |= __get_user(...); err |= __get_user(...); and then checking err at the end. In sparc64_get_context() our version of the code dropped the accumulating into err but left the "if (err) goto do_sigsegv" checks, which will never be taken. Delete unnecessary if()s. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-Id: <20201106152738.26026-3-peter.maydell@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/sparc/signal.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'linux-user') diff --git a/linux-user/sparc/signal.c b/linux-user/sparc/signal.c index 0057b48..58b48af 100644 --- a/linux-user/sparc/signal.c +++ b/linux-user/sparc/signal.c @@ -555,8 +555,6 @@ void sparc64_get_context(CPUSPARCState *env) for (i = 0; i < TARGET_NSIG_WORDS; i++, dst++, src++) { __put_user(*src, dst); } - if (err) - goto do_sigsegv; } /* XXX: tstate must be saved properly */ @@ -598,8 +596,6 @@ void sparc64_get_context(CPUSPARCState *env) * hidden behind an "if (fenab)" where fenab is always 0). */ - if (err) - goto do_sigsegv; unlock_user_struct(ucp, ucp_addr, 1); return; do_sigsegv: -- cgit v1.1 From 0ad20314f1e11acaeedcb14135b178a5711766f5 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 6 Nov 2020 15:27:37 +0000 Subject: linux-user/sparc: Don't restore %g7 in sparc64_set_context() The kernel does not restore the g7 register in sparc64_set_context(); neither should we. (We still save it in sparc64_get_context().) Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-Id: <20201106152738.26026-4-peter.maydell@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/sparc/signal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-user') diff --git a/linux-user/sparc/signal.c b/linux-user/sparc/signal.c index 58b48af..d92e096 100644 --- a/linux-user/sparc/signal.c +++ b/linux-user/sparc/signal.c @@ -447,7 +447,7 @@ void sparc64_set_context(CPUSPARCState *env) __get_user(env->gregs[4], (&(*grp)[SPARC_MC_G4])); __get_user(env->gregs[5], (&(*grp)[SPARC_MC_G5])); __get_user(env->gregs[6], (&(*grp)[SPARC_MC_G6])); - __get_user(env->gregs[7], (&(*grp)[SPARC_MC_G7])); + /* Skip g7 as that's the thread register in userspace */ /* * Note that unlike the kernel, we didn't need to mess with the -- cgit v1.1 From 7a5805a08f942325b373643099f784cdac65c9ea Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 6 Nov 2020 15:27:38 +0000 Subject: linux-user/sparc: Handle tstate in sparc64_get/set_context() Correctly implement save/restore of the tstate field in sparc64_get_context() and sparc64_set_context(): * Don't use the CWP value from the guest in set_context * Construct and save a tstate value rather than leaving it as zero in get_context To do this we factor out the "calculate TSTATE value from CPU state" code from sparc_cpu_do_interrupt() into its own sparc64_tstate() function; that in turn requires us to move some of the function prototypes out from inside a CPU_NO_IO_DEFS ifdef guard. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-Id: <20201106152738.26026-5-peter.maydell@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/sparc/signal.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'linux-user') diff --git a/linux-user/sparc/signal.c b/linux-user/sparc/signal.c index d92e096..d27b7a3 100644 --- a/linux-user/sparc/signal.c +++ b/linux-user/sparc/signal.c @@ -438,9 +438,9 @@ void sparc64_set_context(CPUSPARCState *env) env->npc = npc; __get_user(env->y, &((*grp)[SPARC_MC_Y])); __get_user(tstate, &((*grp)[SPARC_MC_TSTATE])); + /* Honour TSTATE_ASI, TSTATE_ICC and TSTATE_XCC only */ env->asi = (tstate >> 24) & 0xff; - cpu_put_ccr(env, tstate >> 32); - cpu_put_cwp64(env, tstate & 0x1f); + cpu_put_ccr(env, (tstate >> 32) & 0xff); __get_user(env->gregs[1], (&(*grp)[SPARC_MC_G1])); __get_user(env->gregs[2], (&(*grp)[SPARC_MC_G2])); __get_user(env->gregs[3], (&(*grp)[SPARC_MC_G3])); @@ -557,8 +557,7 @@ void sparc64_get_context(CPUSPARCState *env) } } - /* XXX: tstate must be saved properly */ - // __put_user(env->tstate, &((*grp)[SPARC_MC_TSTATE])); + __put_user(sparc64_tstate(env), &((*grp)[SPARC_MC_TSTATE])); __put_user(env->pc, &((*grp)[SPARC_MC_PC])); __put_user(env->npc, &((*grp)[SPARC_MC_NPC])); __put_user(env->y, &((*grp)[SPARC_MC_Y])); -- cgit v1.1