From: Nicholas Piggin <npiggin@gmail.com>
To: qemu-riscv@nongnu.org
Cc: Nicholas Piggin <npiggin@gmail.com>,
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: [PATCH v3 4/5] linux-user/riscv: Add vector state to signal context
Date: Sun, 22 Mar 2026 00:13:42 +1000 [thread overview]
Message-ID: <20260321141345.599105-5-npiggin@gmail.com> (raw)
In-Reply-To: <20260321141345.599105-1-npiggin@gmail.com>
This enables vector state to be saved and restored across signals.
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
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-21 14:15 UTC|newest]
Thread overview: 18+ 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 ` Nicholas Piggin [this message]
2026-03-25 3:45 ` [PATCH v3 4/5] linux-user/riscv: Add vector state to signal context Alistair Francis
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
2026-03-27 11:12 ` Michael Tokarev
2026-04-01 4:31 ` Alistair Francis
2026-04-03 19:57 ` Michael Tokarev
2026-04-15 8:17 ` Heinrich Schuchardt
2026-04-16 1:11 ` Alistair Francis
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=20260321141345.599105-5-npiggin@gmail.com \
--to=npiggin@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=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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.