diff options
-rw-r--r-- | linux-user/include/host/ppc/host-signal.h | 38 | ||||
-rw-r--r-- | linux-user/include/host/ppc64/host-signal.h | 42 | ||||
-rw-r--r-- | target/ppc/fpu_helper.c | 93 | ||||
-rw-r--r-- | util/aio-posix.c | 32 | ||||
-rw-r--r-- | util/aio-posix.h | 1 | ||||
-rw-r--r-- | util/fdmon-io_uring.c | 4 |
6 files changed, 147 insertions, 63 deletions
diff --git a/linux-user/include/host/ppc/host-signal.h b/linux-user/include/host/ppc/host-signal.h deleted file mode 100644 index b80384d135..0000000000 --- a/linux-user/include/host/ppc/host-signal.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * host-signal.h: signal info dependent on the host architecture - * - * Copyright (c) 2003-2005 Fabrice Bellard - * Copyright (c) 2021 Linaro Limited - * - * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. - * See the COPYING file in the top-level directory. - */ - -#ifndef PPC_HOST_SIGNAL_H -#define PPC_HOST_SIGNAL_H - -/* The third argument to a SA_SIGINFO handler is ucontext_t. */ -typedef ucontext_t host_sigcontext; - -static inline uintptr_t host_signal_pc(host_sigcontext *uc) -{ - return uc->uc_mcontext.regs->nip; -} - -static inline void host_signal_set_pc(host_sigcontext *uc, uintptr_t pc) -{ - uc->uc_mcontext.regs->nip = pc; -} - -static inline void *host_signal_mask(host_sigcontext *uc) -{ - return &uc->uc_sigmask; -} - -static inline bool host_signal_write(siginfo_t *info, host_sigcontext *uc) -{ - return uc->uc_mcontext.regs->trap != 0x400 - && (uc->uc_mcontext.regs->dsisr & 0x02000000); -} - -#endif diff --git a/linux-user/include/host/ppc64/host-signal.h b/linux-user/include/host/ppc64/host-signal.h index a353c22a90..c4ea866472 100644 --- a/linux-user/include/host/ppc64/host-signal.h +++ b/linux-user/include/host/ppc64/host-signal.h @@ -1 +1,41 @@ -#include "../ppc/host-signal.h" +/* + * host-signal.h: signal info dependent on the host architecture + * + * Copyright (c) 2003-2005 Fabrice Bellard + * Copyright (c) 2021 Linaro Limited + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef PPC_HOST_SIGNAL_H +#define PPC_HOST_SIGNAL_H + +/* Needed for PT_* constants */ +#include <asm/ptrace.h> + +/* The third argument to a SA_SIGINFO handler is ucontext_t. */ +typedef ucontext_t host_sigcontext; + +static inline uintptr_t host_signal_pc(host_sigcontext *uc) +{ + return uc->uc_mcontext.gp_regs[PT_NIP]; +} + +static inline void host_signal_set_pc(host_sigcontext *uc, uintptr_t pc) +{ + uc->uc_mcontext.gp_regs[PT_NIP] = pc; +} + +static inline void *host_signal_mask(host_sigcontext *uc) +{ + return &uc->uc_sigmask; +} + +static inline bool host_signal_write(siginfo_t *info, host_sigcontext *uc) +{ + return uc->uc_mcontext.gp_regs[PT_TRAP] != 0x400 + && (uc->uc_mcontext.gp_regs[PT_DSISR] & 0x02000000); +} + +#endif diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c index bd12db960a..7e8be99cc0 100644 --- a/target/ppc/fpu_helper.c +++ b/target/ppc/fpu_helper.c @@ -2691,11 +2691,35 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ do_float_check_status(env, GETPC()); \ } -VSX_CVT_FP_TO_FP(xscvdpsp, 1, float64, float32, VsrD(0), VsrW(0), 1) VSX_CVT_FP_TO_FP(xscvspdp, 1, float32, float64, VsrW(0), VsrD(0), 1) -VSX_CVT_FP_TO_FP(xvcvdpsp, 2, float64, float32, VsrD(i), VsrW(2 * i), 0) VSX_CVT_FP_TO_FP(xvcvspdp, 2, float32, float64, VsrW(2 * i), VsrD(i), 0) +#define VSX_CVT_FP_TO_FP2(op, nels, stp, ttp, sfprf) \ +void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ +{ \ + ppc_vsr_t t = { }; \ + int i; \ + \ + for (i = 0; i < nels; i++) { \ + t.VsrW(2 * i) = stp##_to_##ttp(xb->VsrD(i), &env->fp_status); \ + if (unlikely(stp##_is_signaling_nan(xb->VsrD(i), \ + &env->fp_status))) { \ + float_invalid_op_vxsnan(env, GETPC()); \ + t.VsrW(2 * i) = ttp##_snan_to_qnan(t.VsrW(2 * i)); \ + } \ + if (sfprf) { \ + helper_compute_fprf_##ttp(env, t.VsrW(2 * i)); \ + } \ + t.VsrW(2 * i + 1) = t.VsrW(2 * i); \ + } \ + \ + *xt = t; \ + do_float_check_status(env, GETPC()); \ +} + +VSX_CVT_FP_TO_FP2(xvcvdpsp, 2, float64, float32, 0) +VSX_CVT_FP_TO_FP2(xscvdpsp, 1, float64, float32, 1) + /* * VSX_CVT_FP_TO_FP_VECTOR - VSX floating point/floating point conversion * op - instruction mnemonic @@ -2891,16 +2915,10 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ VSX_CVT_FP_TO_INT(xscvdpsxds, 1, float64, int64, VsrD(0), VsrD(0), \ 0x8000000000000000ULL) -VSX_CVT_FP_TO_INT(xscvdpsxws, 1, float64, int32, VsrD(0), VsrW(1), \ - 0x80000000U) VSX_CVT_FP_TO_INT(xscvdpuxds, 1, float64, uint64, VsrD(0), VsrD(0), 0ULL) -VSX_CVT_FP_TO_INT(xscvdpuxws, 1, float64, uint32, VsrD(0), VsrW(1), 0U) VSX_CVT_FP_TO_INT(xvcvdpsxds, 2, float64, int64, VsrD(i), VsrD(i), \ 0x8000000000000000ULL) -VSX_CVT_FP_TO_INT(xvcvdpsxws, 2, float64, int32, VsrD(i), VsrW(2 * i), \ - 0x80000000U) VSX_CVT_FP_TO_INT(xvcvdpuxds, 2, float64, uint64, VsrD(i), VsrD(i), 0ULL) -VSX_CVT_FP_TO_INT(xvcvdpuxws, 2, float64, uint32, VsrD(i), VsrW(2 * i), 0U) VSX_CVT_FP_TO_INT(xvcvspsxds, 2, float32, int64, VsrW(2 * i), VsrD(i), \ 0x8000000000000000ULL) VSX_CVT_FP_TO_INT(xvcvspsxws, 4, float32, int32, VsrW(i), VsrW(i), 0x80000000U) @@ -2908,6 +2926,45 @@ VSX_CVT_FP_TO_INT(xvcvspuxds, 2, float32, uint64, VsrW(2 * i), VsrD(i), 0ULL) VSX_CVT_FP_TO_INT(xvcvspuxws, 4, float32, uint32, VsrW(i), VsrW(i), 0U) /* + * Likewise, except that the result is duplicated into both subwords. + * Power ISA v3.1 has Programming Notes for these insns: + * Previous versions of the architecture allowed the contents of + * word 0 of the result register to be undefined. However, all + * processors that support this instruction write the result into + * words 0 and 1 (and words 2 and 3) of the result register, as + * is required by this version of the architecture. + */ +#define VSX_CVT_FP_TO_INT2(op, nels, stp, ttp, rnan) \ +void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ +{ \ + int all_flags = env->fp_status.float_exception_flags, flags; \ + ppc_vsr_t t = { }; \ + int i; \ + \ + for (i = 0; i < nels; i++) { \ + env->fp_status.float_exception_flags = 0; \ + t.VsrW(2 * i) = stp##_to_##ttp##_round_to_zero(xb->VsrD(i), \ + &env->fp_status); \ + flags = env->fp_status.float_exception_flags; \ + if (unlikely(flags & float_flag_invalid)) { \ + t.VsrW(2 * i) = float_invalid_cvt(env, flags, t.VsrW(2 * i), \ + rnan, 0, GETPC()); \ + } \ + t.VsrW(2 * i + 1) = t.VsrW(2 * i); \ + all_flags |= flags; \ + } \ + \ + *xt = t; \ + env->fp_status.float_exception_flags = all_flags; \ + do_float_check_status(env, GETPC()); \ +} + +VSX_CVT_FP_TO_INT2(xscvdpsxws, 1, float64, int32, 0x80000000U) +VSX_CVT_FP_TO_INT2(xscvdpuxws, 1, float64, uint32, 0U) +VSX_CVT_FP_TO_INT2(xvcvdpsxws, 2, float64, int32, 0x80000000U) +VSX_CVT_FP_TO_INT2(xvcvdpuxws, 2, float64, uint32, 0U) + +/* * VSX_CVT_FP_TO_INT_VECTOR - VSX floating point to integer conversion * op - instruction mnemonic * stp - source type (float32 or float64) @@ -2980,11 +3037,27 @@ VSX_CVT_INT_TO_FP(xvcvsxddp, 2, int64, float64, VsrD(i), VsrD(i), 0, 0) VSX_CVT_INT_TO_FP(xvcvuxddp, 2, uint64, float64, VsrD(i), VsrD(i), 0, 0) VSX_CVT_INT_TO_FP(xvcvsxwdp, 2, int32, float64, VsrW(2 * i), VsrD(i), 0, 0) VSX_CVT_INT_TO_FP(xvcvuxwdp, 2, uint64, float64, VsrW(2 * i), VsrD(i), 0, 0) -VSX_CVT_INT_TO_FP(xvcvsxdsp, 2, int64, float32, VsrD(i), VsrW(2 * i), 0, 0) -VSX_CVT_INT_TO_FP(xvcvuxdsp, 2, uint64, float32, VsrD(i), VsrW(2 * i), 0, 0) VSX_CVT_INT_TO_FP(xvcvsxwsp, 4, int32, float32, VsrW(i), VsrW(i), 0, 0) VSX_CVT_INT_TO_FP(xvcvuxwsp, 4, uint32, float32, VsrW(i), VsrW(i), 0, 0) +#define VSX_CVT_INT_TO_FP2(op, stp, ttp) \ +void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ +{ \ + ppc_vsr_t t = { }; \ + int i; \ + \ + for (i = 0; i < 2; i++) { \ + t.VsrW(2 * i) = stp##_to_##ttp(xb->VsrD(i), &env->fp_status); \ + t.VsrW(2 * i + 1) = t.VsrW(2 * i); \ + } \ + \ + *xt = t; \ + do_float_check_status(env, GETPC()); \ +} + +VSX_CVT_INT_TO_FP2(xvcvsxdsp, int64, float32) +VSX_CVT_INT_TO_FP2(xvcvuxdsp, uint64, float32) + /* * VSX_CVT_INT_TO_FP_VECTOR - VSX integer to floating point conversion * op - instruction mnemonic diff --git a/util/aio-posix.c b/util/aio-posix.c index 7b9f629218..be0182a3c6 100644 --- a/util/aio-posix.c +++ b/util/aio-posix.c @@ -23,15 +23,6 @@ #include "trace.h" #include "aio-posix.h" -/* - * G_IO_IN and G_IO_OUT are not appropriate revents values for polling, since - * the handler may not need to access the file descriptor. For example, the - * handler doesn't need to read from an EventNotifier if it polled a memory - * location and a read syscall would be slow. Define our own unique revents - * value to indicate that polling determined this AioHandler is ready. - */ -#define REVENTS_POLL_READY 0 - /* Stop userspace polling on a handler if it isn't active for some time */ #define POLL_IDLE_INTERVAL_NS (7 * NANOSECONDS_PER_SECOND) @@ -49,6 +40,14 @@ void aio_add_ready_handler(AioHandlerList *ready_list, QLIST_INSERT_HEAD(ready_list, node, node_ready); } +static void aio_add_poll_ready_handler(AioHandlerList *ready_list, + AioHandler *node) +{ + QLIST_SAFE_REMOVE(node, node_ready); /* remove from nested parent's list */ + node->poll_ready = true; + QLIST_INSERT_HEAD(ready_list, node, node_ready); +} + static AioHandler *find_aio_handler(AioContext *ctx, int fd) { AioHandler *node; @@ -76,6 +75,7 @@ static bool aio_remove_fd_handler(AioContext *ctx, AioHandler *node) } node->pfd.revents = 0; + node->poll_ready = false; /* If the fd monitor has already marked it deleted, leave it alone */ if (QLIST_IS_INSERTED(node, node_deleted)) { @@ -247,7 +247,7 @@ static bool poll_set_started(AioContext *ctx, AioHandlerList *ready_list, /* Poll one last time in case ->io_poll_end() raced with the event */ if (!started && node->io_poll(node->opaque)) { - aio_add_ready_handler(ready_list, node, REVENTS_POLL_READY); + aio_add_poll_ready_handler(ready_list, node); progress = true; } } @@ -282,6 +282,7 @@ bool aio_pending(AioContext *ctx) QLIST_FOREACH_RCU(node, &ctx->aio_handlers, node) { int revents; + /* TODO should this check poll ready? */ revents = node->pfd.revents & node->pfd.events; if (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR) && node->io_read && aio_node_check(ctx, node->is_external)) { @@ -323,11 +324,15 @@ static void aio_free_deleted_handlers(AioContext *ctx) static bool aio_dispatch_handler(AioContext *ctx, AioHandler *node) { bool progress = false; + bool poll_ready; int revents; revents = node->pfd.revents & node->pfd.events; node->pfd.revents = 0; + poll_ready = node->poll_ready; + node->poll_ready = false; + /* * Start polling AioHandlers when they become ready because activity is * likely to continue. Note that starvation is theoretically possible when @@ -344,7 +349,7 @@ static bool aio_dispatch_handler(AioContext *ctx, AioHandler *node) QLIST_INSERT_HEAD(&ctx->poll_aio_handlers, node, node_poll); } if (!QLIST_IS_INSERTED(node, node_deleted) && - revents == 0 && + poll_ready && revents == 0 && aio_node_check(ctx, node->is_external) && node->io_poll_ready) { node->io_poll_ready(node->opaque); @@ -432,7 +437,7 @@ static bool run_poll_handlers_once(AioContext *ctx, QLIST_FOREACH_SAFE(node, &ctx->poll_aio_handlers, node_poll, tmp) { if (aio_node_check(ctx, node->is_external) && node->io_poll(node->opaque)) { - aio_add_ready_handler(ready_list, node, REVENTS_POLL_READY); + aio_add_poll_ready_handler(ready_list, node); node->poll_idle_timeout = now + POLL_IDLE_INTERVAL_NS; @@ -491,8 +496,7 @@ static bool remove_idle_poll_handlers(AioContext *ctx, * this causes progress. */ if (node->io_poll(node->opaque)) { - aio_add_ready_handler(ready_list, node, - REVENTS_POLL_READY); + aio_add_poll_ready_handler(ready_list, node); progress = true; } } diff --git a/util/aio-posix.h b/util/aio-posix.h index 7f2c37a684..80b927c7f4 100644 --- a/util/aio-posix.h +++ b/util/aio-posix.h @@ -37,6 +37,7 @@ struct AioHandler { unsigned flags; /* see fdmon-io_uring.c */ #endif int64_t poll_idle_timeout; /* when to stop userspace polling */ + bool poll_ready; /* has polling detected an event? */ bool is_external; }; diff --git a/util/fdmon-io_uring.c b/util/fdmon-io_uring.c index 1461dfa407..ab43052dd7 100644 --- a/util/fdmon-io_uring.c +++ b/util/fdmon-io_uring.c @@ -179,7 +179,11 @@ static void add_poll_remove_sqe(AioContext *ctx, AioHandler *node) { struct io_uring_sqe *sqe = get_sqe(ctx); +#ifdef LIBURING_HAVE_DATA64 + io_uring_prep_poll_remove(sqe, (__u64)(uintptr_t)node); +#else io_uring_prep_poll_remove(sqe, node); +#endif } /* Add a timeout that self-cancels when another cqe becomes ready */ |