public inbox for qemu-devel@nongnu.org
 help / color / mirror / Atom feed
From: Alistair Francis <alistair23@gmail.com>
To: Nicholas Piggin <npiggin@gmail.com>
Cc: qemu-riscv@nongnu.org, qemu-devel@nongnu.org,
	 Laurent Vivier <laurent@vivier.eu>,
	Pierrick Bouvier <pierrick.bouvier@linaro.org>,
	 Palmer Dabbelt <palmer@dabbelt.com>,
	Alistair Francis <alistair.francis@wdc.com>,
	 Weiwei Li <liwei1518@gmail.com>,
	Daniel Henrique Barboza <dbarboza@ventanamicro.com>,
	 Liu Zhiwei <zhiwei_liu@linux.alibaba.com>,
	 Richard Henderson <richard.henderson@linaro.org>,
	Joel Stanley <joel@jms.id.au>
Subject: Re: [PATCH v3 4/5] linux-user/riscv: Add vector state to signal context
Date: Wed, 25 Mar 2026 13:45:39 +1000	[thread overview]
Message-ID: <CAKmqyKPnQ_ozznZFi6EKZfiY9XxJwQEPhXhYrpBEDY1Qd17vvQ@mail.gmail.com> (raw)
In-Reply-To: <20260321141345.599105-5-npiggin@gmail.com>

On Sun, Mar 22, 2026 at 12:16 AM Nicholas Piggin <npiggin@gmail.com> wrote:
>
> This enables vector state to be saved and restored across signals.
>
> Signed-off-by: Nicholas Piggin <npiggin@gmail.com>

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  linux-user/riscv/signal.c    | 175 +++++++++++++++++++++++++++++++++--
>  target/riscv/cpu.h           |   4 +
>  target/riscv/csr.c           |   7 +-
>  target/riscv/vector_helper.c |  19 +++-
>  4 files changed, 191 insertions(+), 14 deletions(-)
>
> diff --git a/linux-user/riscv/signal.c b/linux-user/riscv/signal.c
> index e20b9ac177..2e1a1a5027 100644
> --- a/linux-user/riscv/signal.c
> +++ b/linux-user/riscv/signal.c
> @@ -41,7 +41,17 @@ struct target_fp_state {
>      uint32_t fcsr;
>  };
>
> +struct target_v_ext_state {
> +    abi_ulong vstart;
> +    abi_ulong vl;
> +    abi_ulong vtype;
> +    abi_ulong vcsr;
> +    abi_ulong vlenb;
> +    abi_ptr   datap;
> +};
> +
>  /* The Magic number for signal context frame header. */
> +#define RISCV_V_MAGIC   0x53465457
>  #define END_MAGIC       0x0
>
>  /* The size of END signal context header. */
> @@ -106,6 +116,130 @@ static abi_ulong get_sigframe(struct target_sigaction *ka,
>      return sp;
>  }
>
> +static unsigned int get_v_state_hdr_size(CPURISCVState *env)
> +{
> +    return sizeof(struct target_ctx_hdr) +
> +           sizeof(struct target_v_ext_state);
> +}
> +
> +static unsigned int get_v_state_data_size(CPURISCVState *env)
> +{
> +    RISCVCPU *cpu = env_archcpu(env);
> +    return cpu->cfg.vlenb * 32;
> +}
> +
> +static struct target_ctx_hdr *save_v_state(CPURISCVState *env,
> +                                           struct target_ctx_hdr *hdr)
> +{
> +    RISCVCPU *cpu = env_archcpu(env);
> +    target_ulong vlenb = cpu->cfg.vlenb;
> +    uint32_t riscv_v_sc_size = get_v_state_hdr_size(env) +
> +                               get_v_state_data_size(env);
> +    struct target_v_ext_state *vs;
> +    abi_ulong vcsr;
> +    abi_ptr datap;
> +    void *host_datap;
> +
> +#ifdef CONFIG_DEBUG_REMAP
> +    /*
> +     * The host pointers are derived from lock_user, not g2h, so
> +     * h2g can not be used when CONFIG_DEBUG_REMAP=y.
> +     */
> +    qemu_log_mask(LOG_UNIMP, "signal: sigcontext can not save V state "
> +                             "when CONFIG_DEBUG_REMAP=y\n");
> +    return hdr;
> +#endif
> +
> +    vs = (struct target_v_ext_state *)(hdr + 1);
> +    vcsr = riscv_csr_read(env, CSR_VCSR);
> +    host_datap = (vs + 1);
> +    datap = h2g(host_datap);
> +
> +    __put_user(RISCV_V_MAGIC, &hdr->magic);
> +    __put_user(riscv_v_sc_size, &hdr->size);
> +
> +    __put_user(env->vstart, &vs->vstart);
> +    __put_user(env->vl, &vs->vl);
> +    __put_user(env->vtype, &vs->vtype);
> +    __put_user(vcsr, &vs->vcsr);
> +    __put_user(vlenb, &vs->vlenb);
> +    __put_user(datap, &vs->datap);
> +
> +    for (int i = 0; i < 32; i++) {
> +        for (int j = 0; j < vlenb; j += 8) {
> +            size_t idx = (i * vlenb + j);
> +            __put_user(env->vreg[idx / 8],
> +                       (uint64_t *)(host_datap + idx));
> +        }
> +    }
> +
> +    return (void *)hdr + riscv_v_sc_size;
> +}
> +
> +static bool restore_v_state(CPURISCVState *env,
> +                            struct target_ctx_hdr *hdr)
> +{
> +    RISCVCPU *cpu = env_archcpu(env);
> +    target_ulong vlenb;
> +    target_ulong vcsr, vl, vtype, vstart;
> +    struct target_v_ext_state *vs;
> +    uint32_t size;
> +    abi_ptr datap;
> +    void *host_datap;
> +
> +    if (!riscv_has_ext(env, RVV)) {
> +        qemu_log_mask(LOG_GUEST_ERROR, "signal: sigcontext has V state but "
> +                                       "CPU does not support V extension\n");
> +        return false;
> +    }
> +
> +    __get_user(size, &hdr->size);
> +    if (size < get_v_state_hdr_size(env)) {
> +        qemu_log_mask(LOG_GUEST_ERROR, "signal: sigcontext V state header "
> +                                       "size is too small (%u)\n", size);
> +        return false;
> +    }
> +
> +    vs = (struct target_v_ext_state *)(hdr + 1);
> +
> +    __get_user(vstart, &vs->vstart);
> +    __get_user(vl, &vs->vl);
> +    __get_user(vtype, &vs->vtype);
> +    __get_user(vcsr, &vs->vcsr);
> +
> +    riscv_cpu_set_vstart(env, vstart);
> +    riscv_cpu_vsetvl(env, vl, vtype, 0);
> +    riscv_csr_write(env, CSR_VCSR, vcsr);
> +
> +    __get_user(vlenb, &vs->vlenb);
> +
> +    if (vlenb != cpu->cfg.vlenb) {
> +        qemu_log_mask(LOG_GUEST_ERROR, "signal: sigcontext has invalid "
> +                                       "vlenb\n");
> +        return false;
> +    }
> +
> +    __get_user(datap, &vs->datap);
> +
> +    host_datap = lock_user(VERIFY_READ, datap, vlenb * 32, true);
> +    if (!host_datap) {
> +        qemu_log_mask(LOG_GUEST_ERROR, "signal: sigcontext has V state but "
> +                                       "datap pointer is invalid\n");
> +        return false;
> +    }
> +
> +    for (int i = 0; i < 32; i++) {
> +        for (int j = 0; j < vlenb; j += 8) {
> +            size_t idx = (i * vlenb + j);
> +            __get_user(env->vreg[idx / 8],
> +                       (uint64_t *)(host_datap + idx));
> +        }
> +    }
> +    unlock_user(host_datap, datap, 0);
> +
> +    return true;
> +}
> +
>  static void setup_sigcontext(struct target_sigcontext *sc, CPURISCVState *env)
>  {
>      struct target_ctx_hdr *hdr;
> @@ -126,6 +260,9 @@ static void setup_sigcontext(struct target_sigcontext *sc, CPURISCVState *env)
>      __put_user(0, &sc->sc_extdesc.reserved);
>
>      hdr = &sc->sc_extdesc.hdr;
> +    if (riscv_has_ext(env, RVV)) {
> +        hdr = save_v_state(env, hdr);
> +    }
>      __put_user(END_MAGIC, &hdr->magic);
>      __put_user(END_HDR_SIZE, &hdr->size);
>  }
> @@ -152,17 +289,24 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
>  {
>      abi_ulong frame_addr;
>      struct target_rt_sigframe *frame;
> +    size_t frame_size = sizeof(*frame);
>
> -    frame_addr = get_sigframe(ka, env, sizeof(*frame));
> +    if (riscv_has_ext(env, RVV)) {
> +        frame_size += get_v_state_hdr_size(env) +
> +                      get_v_state_data_size(env);
> +    }
> +
> +    frame_addr = get_sigframe(ka, env, frame_size);
>      trace_user_setup_rt_frame(env, frame_addr);
>
> -    if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
> +    frame = lock_user(VERIFY_WRITE, frame_addr, frame_size, 0);
> +    if (!frame) {
>          goto badframe;
>      }
>
>      setup_ucontext(&frame->uc, env, set);
>      frame->info = *info;
> -    unlock_user_struct(frame, frame_addr, 1);
> +    unlock_user(frame, frame_addr, frame_size);
>
>      env->pc = ka->_sa_handler;
>      env->gpr[xSP] = frame_addr;
> @@ -174,7 +318,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
>      return;
>
>  badframe:
> -    unlock_user_struct(frame, frame_addr, 1);
> +    unlock_user(frame, frame_addr, frame_size);
>      if (sig == TARGET_SIGSEGV) {
>          ka->_sa_handler = TARGET_SIG_DFL;
>      }
> @@ -211,6 +355,11 @@ static bool restore_sigcontext(CPURISCVState *env, struct target_sigcontext *sc)
>      __get_user(magic, &hdr->magic);
>      while (magic != END_MAGIC) {
>          switch (magic) {
> +        case RISCV_V_MAGIC:
> +            if (!restore_v_state(env, hdr)) {
> +                return false;
> +            }
> +            break;
>          default:
>              qemu_log_mask(LOG_GUEST_ERROR, "signal: unknown extended state in "
>                                             "sigcontext, magic=0x%08x\n", magic);
> @@ -258,11 +407,23 @@ static bool restore_ucontext(CPURISCVState *env, struct target_ucontext *uc)
>  long do_rt_sigreturn(CPURISCVState *env)
>  {
>      struct target_rt_sigframe *frame;
> +    size_t frame_size = sizeof(*frame);
>      abi_ulong frame_addr;
>
> +    if (riscv_has_ext(env, RVV)) {
> +        /*
> +         * userspace may have set up a discontiguous V state data area,
> +         * so need to map that region separately once the address is
> +         * known, from datap.
> +         */
> +        frame_size += get_v_state_hdr_size(env);
> +    }
> +
>      frame_addr = env->gpr[xSP];
>      trace_user_do_sigreturn(env, frame_addr);
> -    if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
> +
> +    frame = lock_user(VERIFY_READ, frame_addr, frame_size, 1);
> +    if (!frame) {
>          goto badframe;
>      }
>
> @@ -272,11 +433,11 @@ long do_rt_sigreturn(CPURISCVState *env)
>
>      target_restore_altstack(&frame->uc.uc_stack, env);
>
> -    unlock_user_struct(frame, frame_addr, 0);
> +    unlock_user(frame, frame_addr, 0);
>      return -QEMU_ESIGRETURN;
>
>  badframe:
> -    unlock_user_struct(frame, frame_addr, 0);
> +    unlock_user(frame, frame_addr, 0);
>      force_sig(TARGET_SIGSEGV);
>      return 0;
>  }
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index 35d1f6362c..e1eca79197 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -668,6 +668,10 @@ G_NORETURN void riscv_raise_exception(CPURISCVState *env,
>  target_ulong riscv_cpu_get_fflags(CPURISCVState *env);
>  void riscv_cpu_set_fflags(CPURISCVState *env, target_ulong);
>
> +void riscv_cpu_set_vstart(CPURISCVState *env, target_ulong val);
> +target_ulong riscv_cpu_vsetvl(CPURISCVState *env, target_ulong s1,
> +                              target_ulong s2, target_ulong x0);
> +
>  #ifndef CONFIG_USER_ONLY
>  void cpu_set_exception_base(int vp_index, target_ulong address);
>  #endif
> diff --git a/target/riscv/csr.c b/target/riscv/csr.c
> index 5064483917..8a6fd11fb5 100644
> --- a/target/riscv/csr.c
> +++ b/target/riscv/csr.c
> @@ -991,11 +991,8 @@ static RISCVException write_vstart(CPURISCVState *env, int csrno,
>  #if !defined(CONFIG_USER_ONLY)
>      env->mstatus |= MSTATUS_VS;
>  #endif
> -    /*
> -     * The vstart CSR is defined to have only enough writable bits
> -     * to hold the largest element index, i.e. lg2(VLEN) bits.
> -     */
> -    env->vstart = val & ~(~0ULL << ctzl(riscv_cpu_cfg(env)->vlenb << 3));
> +    riscv_cpu_set_vstart(env, val);
> +
>      return RISCV_EXCP_NONE;
>  }
>
> diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c
> index caa8dd9c12..bceefe019b 100644
> --- a/target/riscv/vector_helper.c
> +++ b/target/riscv/vector_helper.c
> @@ -33,8 +33,17 @@
>  #include "vector_internals.h"
>  #include <math.h>
>
> -target_ulong HELPER(vsetvl)(CPURISCVState *env, target_ulong s1,
> -                            target_ulong s2, target_ulong x0)
> +void riscv_cpu_set_vstart(CPURISCVState *env, target_ulong val)
> +{
> +    /*
> +     * The vstart CSR is defined to have only enough writable bits
> +     * to hold the largest element index, i.e. lg2(VLEN) bits.
> +     */
> +    env->vstart = val & ~(~0ULL << ctzl(riscv_cpu_cfg(env)->vlenb << 3));
> +}
> +
> +target_ulong riscv_cpu_vsetvl(CPURISCVState *env, target_ulong s1,
> +                              target_ulong s2, target_ulong x0)
>  {
>      int vlmax, vl;
>      RISCVCPU *cpu = env_archcpu(env);
> @@ -99,6 +108,12 @@ target_ulong HELPER(vsetvl)(CPURISCVState *env, target_ulong s1,
>      return vl;
>  }
>
> +target_ulong HELPER(vsetvl)(CPURISCVState *env, target_ulong s1,
> +                            target_ulong s2, target_ulong x0)
> +{
> +    return riscv_cpu_vsetvl(env, s1, s2, x0);
> +}
> +
>  /*
>   * Get the maximum number of elements can be operated.
>   *
> --
> 2.51.0
>
>


  reply	other threads:[~2026-03-25  3:46 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-21 14:13 [PATCH v3 0/5] linux-user/riscv: add vector state to signal context Nicholas Piggin
2026-03-21 14:13 ` [PATCH v3 1/5] tests/tcg/riscv64: Add a user signal handling test Nicholas Piggin
2026-03-25  3:07   ` Alistair Francis
2026-03-21 14:13 ` [PATCH v3 2/5] linux-user/riscv: Allow restore_sigcontext to return error Nicholas Piggin
2026-03-25  3:07   ` Alistair Francis
2026-03-21 14:13 ` [PATCH v3 3/5] linux-user/riscv: Add extended state to sigcontext Nicholas Piggin
2026-03-25  3:14   ` Alistair Francis
2026-03-21 14:13 ` [PATCH v3 4/5] linux-user/riscv: Add vector state to signal context Nicholas Piggin
2026-03-25  3:45   ` Alistair Francis [this message]
2026-03-21 14:13 ` [PATCH v3 5/5] tests/tcg/riscv64: Add vector state to signal test Nicholas Piggin
2026-03-25  3:49   ` Alistair Francis
2026-03-25  4:45 ` [PATCH v3 0/5] linux-user/riscv: add vector state to signal context Alistair Francis
2026-03-26  6:22   ` Nicholas Piggin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CAKmqyKPnQ_ozznZFi6EKZfiY9XxJwQEPhXhYrpBEDY1Qd17vvQ@mail.gmail.com \
    --to=alistair23@gmail.com \
    --cc=alistair.francis@wdc.com \
    --cc=dbarboza@ventanamicro.com \
    --cc=joel@jms.id.au \
    --cc=laurent@vivier.eu \
    --cc=liwei1518@gmail.com \
    --cc=npiggin@gmail.com \
    --cc=palmer@dabbelt.com \
    --cc=pierrick.bouvier@linaro.org \
    --cc=qemu-devel@nongnu.org \
    --cc=qemu-riscv@nongnu.org \
    --cc=richard.henderson@linaro.org \
    --cc=zhiwei_liu@linux.alibaba.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox