diff options
-rw-r--r-- | fpu/softfloat-parts.c.inc | 4 | ||||
-rw-r--r-- | fpu/softfloat.c | 54 | ||||
-rw-r--r-- | include/tcg/tcg.h | 6 | ||||
-rw-r--r-- | linux-user/fd-trans.h | 10 | ||||
-rw-r--r-- | linux-user/gen-vdso.c | 16 | ||||
-rw-r--r-- | linux-user/main.c | 2 | ||||
-rw-r--r-- | linux-user/mips/target_signal.h | 1 | ||||
-rw-r--r-- | linux-user/syscall.c | 26 | ||||
-rw-r--r-- | linux-user/syscall_defs.h | 4 | ||||
-rw-r--r-- | tcg/tcg.c | 9 | ||||
-rw-r--r-- | tests/tcg/multiarch/Makefile.target | 1 | ||||
-rw-r--r-- | tests/tcg/multiarch/fnmsub.c | 37 |
12 files changed, 137 insertions, 33 deletions
diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index 171bfd0..5e0438f 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -708,10 +708,6 @@ static FloatPartsN *partsN(muladd_scalbn)(FloatPartsN *a, FloatPartsN *b, return_normal: a->exp += scale; finish_sign: - if (flags & float_muladd_negate_result) { - a->sign ^= 1; - } - /* * All result types except for "return the default NaN * because this is an Invalid Operation" go through here; diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 34c962d..8094358 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -1731,11 +1731,8 @@ static float64 float64_round_pack_canonical(FloatParts64 *p, return float64_pack_raw(p); } -static float64 float64r32_round_pack_canonical(FloatParts64 *p, - float_status *s) +static float64 float64r32_pack_raw(FloatParts64 *p) { - parts_uncanon(p, s, &float32_params); - /* * In parts_uncanon, we placed the fraction for float32 at the lsb. * We need to adjust the fraction higher so that the least N bits are @@ -1776,6 +1773,13 @@ static float64 float64r32_round_pack_canonical(FloatParts64 *p, return float64_pack_raw(p); } +static float64 float64r32_round_pack_canonical(FloatParts64 *p, + float_status *s) +{ + parts_uncanon(p, s, &float32_params); + return float64r32_pack_raw(p); +} + static void float128_unpack_canonical(FloatParts128 *p, float128 f, float_status *s) { @@ -2240,7 +2244,12 @@ float16_muladd_scalbn(float16 a, float16 b, float16 c, float16_unpack_canonical(&pc, c, status); pr = parts_muladd_scalbn(&pa, &pb, &pc, scale, flags, status); - return float16_round_pack_canonical(pr, status); + /* Round before applying negate result. */ + parts_uncanon(pr, status, &float16_params); + if ((flags & float_muladd_negate_result) && !is_nan(pr->cls)) { + pr->sign ^= 1; + } + return float16_pack_raw(pr); } float16 float16_muladd(float16 a, float16 b, float16 c, @@ -2260,7 +2269,12 @@ float32_muladd_scalbn(float32 a, float32 b, float32 c, float32_unpack_canonical(&pc, c, status); pr = parts_muladd_scalbn(&pa, &pb, &pc, scale, flags, status); - return float32_round_pack_canonical(pr, status); + /* Round before applying negate result. */ + parts_uncanon(pr, status, &float32_params); + if ((flags & float_muladd_negate_result) && !is_nan(pr->cls)) { + pr->sign ^= 1; + } + return float32_pack_raw(pr); } float64 QEMU_SOFTFLOAT_ATTR @@ -2274,7 +2288,12 @@ float64_muladd_scalbn(float64 a, float64 b, float64 c, float64_unpack_canonical(&pc, c, status); pr = parts_muladd_scalbn(&pa, &pb, &pc, scale, flags, status); - return float64_round_pack_canonical(pr, status); + /* Round before applying negate result. */ + parts_uncanon(pr, status, &float64_params); + if ((flags & float_muladd_negate_result) && !is_nan(pr->cls)) { + pr->sign ^= 1; + } + return float64_pack_raw(pr); } static bool force_soft_fma; @@ -2428,7 +2447,12 @@ float64 float64r32_muladd(float64 a, float64 b, float64 c, float64_unpack_canonical(&pc, c, status); pr = parts_muladd_scalbn(&pa, &pb, &pc, 0, flags, status); - return float64r32_round_pack_canonical(pr, status); + /* Round before applying negate result. */ + parts_uncanon(pr, status, &float32_params); + if ((flags & float_muladd_negate_result) && !is_nan(pr->cls)) { + pr->sign ^= 1; + } + return float64r32_pack_raw(pr); } bfloat16 QEMU_FLATTEN bfloat16_muladd(bfloat16 a, bfloat16 b, bfloat16 c, @@ -2441,7 +2465,12 @@ bfloat16 QEMU_FLATTEN bfloat16_muladd(bfloat16 a, bfloat16 b, bfloat16 c, bfloat16_unpack_canonical(&pc, c, status); pr = parts_muladd_scalbn(&pa, &pb, &pc, 0, flags, status); - return bfloat16_round_pack_canonical(pr, status); + /* Round before applying negate result. */ + parts_uncanon(pr, status, &bfloat16_params); + if ((flags & float_muladd_negate_result) && !is_nan(pr->cls)) { + pr->sign ^= 1; + } + return bfloat16_pack_raw(pr); } float128 QEMU_FLATTEN float128_muladd(float128 a, float128 b, float128 c, @@ -2454,7 +2483,12 @@ float128 QEMU_FLATTEN float128_muladd(float128 a, float128 b, float128 c, float128_unpack_canonical(&pc, c, status); pr = parts_muladd_scalbn(&pa, &pb, &pc, 0, flags, status); - return float128_round_pack_canonical(pr, status); + /* Round before applying negate result. */ + parts_uncanon(pr, status, &float128_params); + if ((flags & float_muladd_negate_result) && !is_nan(pr->cls)) { + pr->sign ^= 1; + } + return float128_pack_raw(pr); } /* diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h index 125323f..0c2a319 100644 --- a/include/tcg/tcg.h +++ b/include/tcg/tcg.h @@ -357,7 +357,7 @@ static inline TCGRegSet output_pref(const TCGOp *op, unsigned i) } struct TCGContext { - uint8_t *pool_cur, *pool_end; + uintptr_t pool_cur, pool_end; TCGPool *pool_first, *pool_current, *pool_first_large; int nb_labels; int nb_globals; @@ -706,7 +706,7 @@ size_t tcg_nb_tbs(void); static inline void *tcg_malloc(int size) { TCGContext *s = tcg_ctx; - uint8_t *ptr, *ptr_end; + uintptr_t ptr, ptr_end; /* ??? This is a weak placeholder for minimum malloc alignment. */ size = QEMU_ALIGN_UP(size, 8); @@ -717,7 +717,7 @@ static inline void *tcg_malloc(int size) return tcg_malloc_internal(tcg_ctx, size); } else { s->pool_cur = ptr_end; - return ptr; + return (void *)ptr; } } diff --git a/linux-user/fd-trans.h b/linux-user/fd-trans.h index 910faaf..e14f960 100644 --- a/linux-user/fd-trans.h +++ b/linux-user/fd-trans.h @@ -36,6 +36,16 @@ static inline void fd_trans_init(void) qemu_mutex_init(&target_fd_trans_lock); } +static inline void fd_trans_prefork(void) +{ + qemu_mutex_lock(&target_fd_trans_lock); +} + +static inline void fd_trans_postfork(void) +{ + qemu_mutex_unlock(&target_fd_trans_lock); +} + static inline TargetFdDataFunc fd_trans_target_to_host_data(int fd) { if (fd < 0) { diff --git a/linux-user/gen-vdso.c b/linux-user/gen-vdso.c index fce9d5c..aeaa927 100644 --- a/linux-user/gen-vdso.c +++ b/linux-user/gen-vdso.c @@ -113,9 +113,21 @@ int main(int argc, char **argv) * We expect the vdso to be small, on the order of one page, * therefore we do not expect a partial read. */ - fseek(inf, 0, SEEK_END); + if (fseek(inf, 0, SEEK_END) < 0) { + goto perror_inf; + } total_len = ftell(inf); - fseek(inf, 0, SEEK_SET); + if (total_len < 0) { + goto perror_inf; + } + if (fseek(inf, 0, SEEK_SET) < 0) { + goto perror_inf; + } + + if (total_len < EI_NIDENT) { + fprintf(stderr, "%s: file too small (truncated?)\n", inf_name); + return EXIT_FAILURE; + } buf = malloc(total_len); if (buf == NULL) { diff --git a/linux-user/main.c b/linux-user/main.c index a9142ee..f4f2007 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -149,12 +149,14 @@ void fork_start(void) cpu_list_lock(); qemu_plugin_user_prefork_lock(); gdbserver_fork_start(); + fd_trans_prefork(); } void fork_end(pid_t pid) { bool child = pid == 0; + fd_trans_postfork(); qemu_plugin_user_postfork(child); mmap_fork_end(child); if (child) { diff --git a/linux-user/mips/target_signal.h b/linux-user/mips/target_signal.h index fa542c1..4481426 100644 --- a/linux-user/mips/target_signal.h +++ b/linux-user/mips/target_signal.h @@ -64,7 +64,6 @@ typedef struct target_sigaltstack { #define TARGET_SA_NODEFER 0x40000000 #define TARGET_SA_RESTART 0x10000000 #define TARGET_SA_RESETHAND 0x80000000 -#define TARGET_SA_RESTORER 0x04000000 /* Only for O32 */ #define TARGET_MINSIGSTKSZ 2048 diff --git a/linux-user/syscall.c b/linux-user/syscall.c index fc37028..91360a0 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -790,6 +790,10 @@ safe_syscall6(ssize_t, copy_file_range, int, infd, loff_t *, pinoff, int, outfd, loff_t *, poutoff, size_t, length, unsigned int, flags) #endif +#if defined(TARGET_NR_fchmodat2) && defined(__NR_fchmodat2) +safe_syscall4(int, fchmodat2, int, dfd, const char *, filename, + unsigned short, mode, 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 @@ -6743,10 +6747,9 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp, int pid_child = ret; pid_fd = pidfd_open(pid_child, 0); if (pid_fd >= 0) { - fcntl(pid_fd, F_SETFD, fcntl(pid_fd, F_GETFL) - | FD_CLOEXEC); + qemu_set_cloexec(pid_fd); } else { - pid_fd = 0; + pid_fd = 0; } #endif put_user_u32(pid_fd, parent_tidptr); @@ -10714,6 +10717,15 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, unlock_user(p, arg2, 0); return ret; #endif +#if defined(TARGET_NR_fchmodat2) && defined(__NR_fchmodat2) + case TARGET_NR_fchmodat2: + if (!(p = lock_user_string(arg2))) { + return -TARGET_EFAULT; + } + ret = get_errno(safe_fchmodat2(arg1, p, arg3, arg4)); + unlock_user(p, arg2, 0); + return ret; +#endif case TARGET_NR_getpriority: /* Note that negative values are valid for getpriority, so we must differentiate based on errno settings. */ @@ -11630,10 +11642,14 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, case TARGET_NR_nanosleep: { struct timespec req, rem; - target_to_host_timespec(&req, arg1); + if (target_to_host_timespec(&req, arg1)) { + return -TARGET_EFAULT; + } ret = get_errno(safe_nanosleep(&req, &rem)); if (is_error(ret) && arg2) { - host_to_target_timespec(arg2, &rem); + if (host_to_target_timespec(arg2, &rem)) { + return -TARGET_EFAULT; + } } } return ret; diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 5d22759..df26a2d 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -515,10 +515,6 @@ struct target_sigaction { abi_ulong _sa_handler; #endif target_sigset_t sa_mask; -#ifdef TARGET_ARCH_HAS_SA_RESTORER - /* ??? This is always present, but ignored unless O32. */ - abi_ulong sa_restorer; -#endif }; #else struct target_old_sigaction { @@ -1331,8 +1331,9 @@ void *tcg_malloc_internal(TCGContext *s, int size) p = s->pool_current; if (!p) { p = s->pool_first; - if (!p) + if (!p) { goto new_pool; + } } else { if (!p->next) { new_pool: @@ -1351,8 +1352,8 @@ void *tcg_malloc_internal(TCGContext *s, int size) } } s->pool_current = p; - s->pool_cur = p->data + size; - s->pool_end = p->data + p->size; + s->pool_cur = (uintptr_t)p->data + size; + s->pool_end = (uintptr_t)p->data + p->size; return p->data; } @@ -1364,7 +1365,7 @@ void tcg_pool_reset(TCGContext *s) g_free(p); } s->pool_first_large = NULL; - s->pool_cur = s->pool_end = NULL; + s->pool_cur = s->pool_end = 0; s->pool_current = NULL; } diff --git a/tests/tcg/multiarch/Makefile.target b/tests/tcg/multiarch/Makefile.target index 45c9cfe..bfdf719 100644 --- a/tests/tcg/multiarch/Makefile.target +++ b/tests/tcg/multiarch/Makefile.target @@ -29,6 +29,7 @@ run-float_%: float_% $(call run-test,$<, $(QEMU) $(QEMU_OPTS) $<) $(call conditional-diff-out,$<,$(SRC_PATH)/tests/tcg/$(TARGET_NAME)/$<.ref) +fnmsub: LDFLAGS+=-lm testthread: LDFLAGS+=-lpthread diff --git a/tests/tcg/multiarch/fnmsub.c b/tests/tcg/multiarch/fnmsub.c new file mode 100644 index 0000000..15dd41d --- /dev/null +++ b/tests/tcg/multiarch/fnmsub.c @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include <stdio.h> +#include <math.h> +#include <fenv.h> + +union U { + double d; + unsigned long long l; +}; + +union U x = { .l = 0x4ff0000000000000ULL }; +union U y = { .l = 0x2ff0000000000000ULL }; +union U r; + +int main() +{ +#ifdef FE_DOWNWARD + fesetround(FE_DOWNWARD); + +#if defined(__loongarch__) + asm("fnmsub.d %0, %1, %1, %2" : "=f"(r.d) : "f"(x.d), "f"(y.d)); +#elif defined(__powerpc64__) + asm("fnmsub %0,%1,%1,%2" : "=f"(r.d) : "f"(x.d), "f"(y.d)); +#elif defined(__s390x__) && 0 /* need -march=z14 */ + asm("vfnms %0,%1,%1,%2,0,3" : "=f"(r.d) : "f"(x.d), "f"(y.d)); +#else + r.d = -fma(x.d, x.d, -y.d); +#endif + + if (r.l != 0xdfefffffffffffffULL) { + printf("r = %.18a (%016llx)\n", r.d, r.l); + return 1; + } +#endif + return 0; +} |