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
>
>
next prev parent 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