* [PATCH v7 0/6] riscv: optimize mode switch latency for Vector
@ 2026-11-11 18:43 ` Andy Chiu
0 siblings, 0 replies; 20+ messages in thread
From: Andy Chiu @ 2026-11-11 18:43 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
linux-riscv
Cc: andybnac, Andy Chiu, dfustini, greentime.hu, linux-kernel, olof
This series provide several optimizations targeting system call latency
regarding vector context management. Before the series, the kernel
handled user's vector context in an conservative way, where registers
were null out and VS is tracked as DIRTY. This introduce excess context
saving and restoring when there is a context swicth. Also, the kernel
turned off Vector at the exception entry, making all in-kernel vector
usecase take the serialization cost, which includes context switch and
user copies. The cost is not easy to hide as vector code are usually sit
right after enabling V.
Since vector register are set to a known state at syscall exit, the
series set VS to INIT at syscall entry and null out the vector register
at the exit, skipping unnecessary saves and restores. The series also
introduce riscv_novstateopt, when unset, enables vector in the kernel
mode, and do not perform register nulling on the syscall fast path,
where there is no context switch or kernel-mode vector during the
syscall.
With the whole series, nginx request throughput vs base on a four-core
Ascalon-S, by served page size (* = statistically distinct):
86B 1KB 2KB 4KB 8KB 16KB 32KB
v5 +0.79%* +1.36%* +2.33%* +2.02%* +0.14% +0.93% +2.42%*
v6 +0.33%* -0.23% +2.88%* +2.19%* +1.02% +1.14% +1.40%*
This series depends on [1], which is now queued in the
linux-riscv/fixes. For those who prefer git, the series is also available
at [3].
Patch summary:
- New patches: 2, 6
- Modified patches: 3
- Unchanged patches: 1, 4, 5
Changelog v7:
- Resend the series based on unmerged patches from v6
- Rearange patches so that it does not introduce bug mid-series (2,3)
- Add a KVM patch that skips duplicate context operations on host vector
context (6)
Changelog v6:
- Refactor the context switch of preemptible kernel-mode vector (2)
- Address checkpatch warnings by reformatting patch 7
- Drive the optimization with an alternative instead of
CONFIG_RISCV_VSTATE_OPT, enable it by default (8)
- Link to v5: https://lore.kernel.org/all/20260810172255.1532787-1-tchiu@tenstorrent.com/
Changelog v5:
- Rebase on top of the kvm fix
- Do not read sstatus in vector context swicth (1)
- Add a test for vectorized user copy (2)
- Enable vector in the kernel-mode and skip nulling at syscall fast
path, gurad the optimization in a new config (7)
- Link to v4: https://patchwork.kernel.org/project/linux-riscv/cover/20260528190927.886558-1-tchiu@tenstorrent.com/
Changelog v4:
- Fix a build warning (1)
- Prevent setting INIT when it is already and provide performance
meassurements (2)
- Address comments from sashiko (4)
- Link to v3: https://lore.kernel.org/all/20260521162521.188629-1-tchiu@tenstorrent.com/
Changelog v3:
- Refactor function names. (1, 2)
- Merge daichengrong's patch, with a fix and optimzation. (2)
- Fix ptrace GETREGSET failure. (3)
- Strengthen ptrace SETREGSET semantics and add a test to cover it. (3,
4)
- Fix a potential ABI break in signal and add a test to prevent future
breaks. (3, 4)
- Link to v2: https://lore.kernel.org/linux-riscv/20260402043414.2421916-1-andybnac@gmail.com/
Changelog v2: rebase on top of for-next
[1] https://patch.msgid.link/20261020-vector_fpu_regs_status_rmw_fix-v2-1-474a59155e96@intel.com
[3] https://github.com/tchiu-TT/linux/commits/vctxopt/v7/
Andy Chiu (5):
riscv: vector: refactor vector context operations
riscv: introduce riscv_v_ucontext_save() for signal and ptrace
selftests: riscv: Extend vector tests for sigreturn and ptrace
riscv: vector: optimize vstate operations
riscv: KVM: do not save host vector context for vcpu
daichengrong (1):
riscv: clarify vector state semantics on syscall and context switch
.../admin-guide/kernel-parameters.txt | 13 ++
arch/riscv/include/asm/alternative-macros.h | 6 +
arch/riscv/include/asm/alternative.h | 3 -
arch/riscv/include/asm/cpufeature-macros.h | 6 +-
arch/riscv/include/asm/kvm_vcpu_vector.h | 17 ++-
arch/riscv/include/asm/vector.h | 68 +++++++----
arch/riscv/kernel/cpufeature.c | 18 +++
arch/riscv/kernel/entry.S | 15 ++-
arch/riscv/kernel/kernel_mode_vector.c | 4 +
arch/riscv/kernel/process.c | 3 +
arch/riscv/kernel/ptrace.c | 13 +-
arch/riscv/kernel/signal.c | 11 +-
arch/riscv/kernel/vector.c | 56 ++++++++-
arch/riscv/kvm/vcpu.c | 5 +-
arch/riscv/kvm/vcpu_vector.c | 22 +---
.../selftests/riscv/sigreturn/sigreturn.c | 71 +++++++++++
.../selftests/riscv/vector/vstate_ptrace.c | 111 +++++++++++++++++-
17 files changed, 364 insertions(+), 78 deletions(-)
base-commit: d1a8d411533d6be16ac79796c02a9bfc7d7958f1
--
2.43.0
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH v7 0/6] riscv: optimize mode switch latency for Vector
@ 2026-11-11 18:43 ` Andy Chiu
0 siblings, 0 replies; 20+ messages in thread
From: Andy Chiu @ 2026-11-11 18:43 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
linux-riscv
Cc: andybnac, Andy Chiu, dfustini, greentime.hu, linux-kernel, olof
This series provide several optimizations targeting system call latency
regarding vector context management. Before the series, the kernel
handled user's vector context in an conservative way, where registers
were null out and VS is tracked as DIRTY. This introduce excess context
saving and restoring when there is a context swicth. Also, the kernel
turned off Vector at the exception entry, making all in-kernel vector
usecase take the serialization cost, which includes context switch and
user copies. The cost is not easy to hide as vector code are usually sit
right after enabling V.
Since vector register are set to a known state at syscall exit, the
series set VS to INIT at syscall entry and null out the vector register
at the exit, skipping unnecessary saves and restores. The series also
introduce riscv_novstateopt, when unset, enables vector in the kernel
mode, and do not perform register nulling on the syscall fast path,
where there is no context switch or kernel-mode vector during the
syscall.
With the whole series, nginx request throughput vs base on a four-core
Ascalon-S, by served page size (* = statistically distinct):
86B 1KB 2KB 4KB 8KB 16KB 32KB
v5 +0.79%* +1.36%* +2.33%* +2.02%* +0.14% +0.93% +2.42%*
v6 +0.33%* -0.23% +2.88%* +2.19%* +1.02% +1.14% +1.40%*
This series depends on [1], which is now queued in the
linux-riscv/fixes. For those who prefer git, the series is also available
at [3].
Patch summary:
- New patches: 2, 6
- Modified patches: 3
- Unchanged patches: 1, 4, 5
Changelog v7:
- Resend the series based on unmerged patches from v6
- Rearange patches so that it does not introduce bug mid-series (2,3)
- Add a KVM patch that skips duplicate context operations on host vector
context (6)
Changelog v6:
- Refactor the context switch of preemptible kernel-mode vector (2)
- Address checkpatch warnings by reformatting patch 7
- Drive the optimization with an alternative instead of
CONFIG_RISCV_VSTATE_OPT, enable it by default (8)
- Link to v5: https://lore.kernel.org/all/20260810172255.1532787-1-tchiu@tenstorrent.com/
Changelog v5:
- Rebase on top of the kvm fix
- Do not read sstatus in vector context swicth (1)
- Add a test for vectorized user copy (2)
- Enable vector in the kernel-mode and skip nulling at syscall fast
path, gurad the optimization in a new config (7)
- Link to v4: https://patchwork.kernel.org/project/linux-riscv/cover/20260528190927.886558-1-tchiu@tenstorrent.com/
Changelog v4:
- Fix a build warning (1)
- Prevent setting INIT when it is already and provide performance
meassurements (2)
- Address comments from sashiko (4)
- Link to v3: https://lore.kernel.org/all/20260521162521.188629-1-tchiu@tenstorrent.com/
Changelog v3:
- Refactor function names. (1, 2)
- Merge daichengrong's patch, with a fix and optimzation. (2)
- Fix ptrace GETREGSET failure. (3)
- Strengthen ptrace SETREGSET semantics and add a test to cover it. (3,
4)
- Fix a potential ABI break in signal and add a test to prevent future
breaks. (3, 4)
- Link to v2: https://lore.kernel.org/linux-riscv/20260402043414.2421916-1-andybnac@gmail.com/
Changelog v2: rebase on top of for-next
[1] https://patch.msgid.link/20261020-vector_fpu_regs_status_rmw_fix-v2-1-474a59155e96@intel.com
[3] https://github.com/tchiu-TT/linux/commits/vctxopt/v7/
Andy Chiu (5):
riscv: vector: refactor vector context operations
riscv: introduce riscv_v_ucontext_save() for signal and ptrace
selftests: riscv: Extend vector tests for sigreturn and ptrace
riscv: vector: optimize vstate operations
riscv: KVM: do not save host vector context for vcpu
daichengrong (1):
riscv: clarify vector state semantics on syscall and context switch
.../admin-guide/kernel-parameters.txt | 13 ++
arch/riscv/include/asm/alternative-macros.h | 6 +
arch/riscv/include/asm/alternative.h | 3 -
arch/riscv/include/asm/cpufeature-macros.h | 6 +-
arch/riscv/include/asm/kvm_vcpu_vector.h | 17 ++-
arch/riscv/include/asm/vector.h | 68 +++++++----
arch/riscv/kernel/cpufeature.c | 18 +++
arch/riscv/kernel/entry.S | 15 ++-
arch/riscv/kernel/kernel_mode_vector.c | 4 +
arch/riscv/kernel/process.c | 3 +
arch/riscv/kernel/ptrace.c | 13 +-
arch/riscv/kernel/signal.c | 11 +-
arch/riscv/kernel/vector.c | 56 ++++++++-
arch/riscv/kvm/vcpu.c | 5 +-
arch/riscv/kvm/vcpu_vector.c | 22 +---
.../selftests/riscv/sigreturn/sigreturn.c | 71 +++++++++++
.../selftests/riscv/vector/vstate_ptrace.c | 111 +++++++++++++++++-
17 files changed, 364 insertions(+), 78 deletions(-)
base-commit: d1a8d411533d6be16ac79796c02a9bfc7d7958f1
--
2.43.0
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH v7 1/6] riscv: vector: refactor vector context operations
2026-11-11 18:43 ` Andy Chiu
(?)
@ 2026-11-11 18:43 ` Andy Chiu
-1 siblings, 0 replies; 20+ messages in thread
From: Andy Chiu @ 2026-11-11 18:43 UTC (permalink / raw)
To: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, kvm, kvm-riscv, linux-riscv
Cc: andybnac, Andy Chiu, dfustini, greentime.hu, Aurelien Jarno,
Yong-Xuan Wang, daichengrong, Troy Mitchell
Lift riscv_v_{enable,disable} out of __*vstate_{save,restore,discard} so
that we can reuse some functions without repeatedly turning on/off
vector.
Also, refactor and document about the user context save in preempt_v to
make code more readable.
Signed-off-by: Andy Chiu <tchiu@tenstorrent.com>
---
Changelog v5:
- rebase on top of the kvm fix[1]
Changelog v4:
- fix an unused variable warning (Olof)
Changelog v3:
- new patch since v3
---
arch/riscv/include/asm/kvm_vcpu_vector.h | 8 ++++++--
arch/riscv/include/asm/vector.h | 15 ++++++++-------
arch/riscv/kernel/kernel_mode_vector.c | 4 ++++
arch/riscv/kvm/vcpu.c | 2 +-
arch/riscv/kvm/vcpu_vector.c | 6 +++---
5 files changed, 22 insertions(+), 13 deletions(-)
diff --git a/arch/riscv/include/asm/kvm_vcpu_vector.h b/arch/riscv/include/asm/kvm_vcpu_vector.h
index 50d4789b9cac..60fa28030944 100644
--- a/arch/riscv/include/asm/kvm_vcpu_vector.h
+++ b/arch/riscv/include/asm/kvm_vcpu_vector.h
@@ -16,14 +16,18 @@
#ifdef CONFIG_RISCV_ISA_V
#include <asm/kvm_host.h>
-static __always_inline void __kvm_riscv_vector_save(struct kvm_cpu_context *context)
+static __always_inline void kvm_riscv_vector_save(struct kvm_cpu_context *context)
{
+ riscv_v_enable();
__riscv_v_vstate_save(&context->vector, context->vector.datap);
+ riscv_v_disable();
}
-static __always_inline void __kvm_riscv_vector_restore(struct kvm_cpu_context *context)
+static __always_inline void kvm_riscv_vector_restore(struct kvm_cpu_context *context)
{
+ riscv_v_enable();
__riscv_v_vstate_restore(&context->vector, context->vector.datap);
+ riscv_v_disable();
}
void kvm_riscv_vcpu_vector_reset(struct kvm_vcpu *vcpu);
diff --git a/arch/riscv/include/asm/vector.h b/arch/riscv/include/asm/vector.h
index 3381a535abb4..8c88a2258e61 100644
--- a/arch/riscv/include/asm/vector.h
+++ b/arch/riscv/include/asm/vector.h
@@ -203,7 +203,6 @@ static inline void __riscv_v_vstate_save(struct __riscv_v_ext_state *save_to,
{
unsigned long vl;
- riscv_v_enable();
__vstate_csr_save(save_to);
if (has_xtheadvector()) {
asm volatile (
@@ -232,7 +231,6 @@ static inline void __riscv_v_vstate_save(struct __riscv_v_ext_state *save_to,
".option pop\n\t"
: "=&r" (vl), "+r" (datap) : : "memory");
}
- riscv_v_disable();
}
static inline void __riscv_v_vstate_restore(struct __riscv_v_ext_state *restore_from,
@@ -240,7 +238,6 @@ static inline void __riscv_v_vstate_restore(struct __riscv_v_ext_state *restore_
{
unsigned long vl;
- riscv_v_enable();
if (has_xtheadvector()) {
asm volatile (
"mv t0, %0\n\t"
@@ -269,14 +266,12 @@ static inline void __riscv_v_vstate_restore(struct __riscv_v_ext_state *restore_
: "=&r" (vl), "+r" (datap) : : "memory");
}
__vstate_csr_restore(restore_from);
- riscv_v_disable();
}
static inline void __riscv_v_vstate_discard(void)
{
unsigned long vl, vtype_inval = 1UL << (BITS_PER_LONG - 1);
- riscv_v_enable();
if (has_xtheadvector())
asm volatile (THEAD_VSETVLI_T4X0E8M8D1 : : : "t4");
else
@@ -296,14 +291,14 @@ static inline void __riscv_v_vstate_discard(void)
"vsetvl %0, x0, %1\n\t"
".option pop\n\t"
: "=&r" (vl) : "r" (vtype_inval));
-
- riscv_v_disable();
}
static inline void riscv_v_vstate_discard(struct pt_regs *regs)
{
if (riscv_v_vstate_query(regs)) {
+ riscv_v_enable();
__riscv_v_vstate_discard();
+ riscv_v_disable();
__riscv_v_vstate_dirty(regs);
}
}
@@ -312,7 +307,9 @@ static inline void riscv_v_vstate_save(struct __riscv_v_ext_state *vstate,
struct pt_regs *regs)
{
if (__riscv_v_vstate_check(regs->status, DIRTY)) {
+ riscv_v_enable();
__riscv_v_vstate_save(vstate, vstate->datap);
+ riscv_v_disable();
__riscv_v_vstate_clean(regs);
}
}
@@ -323,7 +320,9 @@ static inline void riscv_v_vstate_restore(struct __riscv_v_ext_state *vstate,
WARN_ON_ONCE(preemptible());
if (riscv_v_vstate_query(regs)) {
+ riscv_v_enable();
__riscv_v_vstate_restore(vstate, vstate->datap);
+ riscv_v_disable();
__riscv_v_vstate_clean(regs);
}
}
@@ -385,8 +384,10 @@ static inline void __switch_to_vector(struct task_struct *prev,
riscv_v_disable();
prev->thread.riscv_v_flags |= RISCV_PREEMPT_V_IN_SCHEDULE;
} else if (riscv_preempt_v_dirty(prev)) {
+ riscv_v_enable();
__riscv_v_vstate_save(&prev->thread.kernel_vstate,
prev->thread.kernel_vstate.datap);
+ riscv_v_disable();
riscv_preempt_v_clear_dirty(prev);
}
} else {
diff --git a/arch/riscv/kernel/kernel_mode_vector.c b/arch/riscv/kernel/kernel_mode_vector.c
index b9481a3e40e3..280180114899 100644
--- a/arch/riscv/kernel/kernel_mode_vector.c
+++ b/arch/riscv/kernel/kernel_mode_vector.c
@@ -171,7 +171,9 @@ static int riscv_v_start_kernel_context(void)
WARN_ON(riscv_v_ctx_get_depth() == 0);
get_cpu_vector_context();
if (riscv_preempt_v_dirty(current)) {
+ riscv_v_enable();
__riscv_v_vstate_save(kvstate, kvstate->datap);
+ riscv_v_disable();
riscv_preempt_v_clear_dirty(current);
}
riscv_preempt_v_set_restore(current);
@@ -215,7 +217,9 @@ asmlinkage void riscv_v_context_nesting_end(struct pt_regs *regs)
depth = riscv_v_ctx_get_depth();
if (depth == 0) {
if (riscv_preempt_v_restore(current)) {
+ riscv_v_enable();
__riscv_v_vstate_restore(vstate, vstate->datap);
+ riscv_v_disable();
__riscv_v_vstate_clean(regs);
riscv_preempt_v_reset_flags();
}
diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c
index dd786f758eb7..caf6e0ad72ef 100644
--- a/arch/riscv/kvm/vcpu.c
+++ b/arch/riscv/kvm/vcpu.c
@@ -825,7 +825,7 @@ static void noinstr kvm_riscv_vcpu_enter_exit(struct kvm_vcpu *vcpu,
if (current->thread.riscv_v_flags & RISCV_V_VCPU_NEED_RESTORE) {
current->thread.riscv_v_flags &= ~RISCV_V_VCPU_NEED_RESTORE;
current->thread.riscv_v_flags |= RISCV_V_VCPU_CTX;
- __kvm_riscv_vector_restore(gcntx);
+ kvm_riscv_vector_restore(gcntx);
gcntx->sstatus = (gcntx->sstatus & ~SR_VS) | SR_VS_CLEAN;
}
diff --git a/arch/riscv/kvm/vcpu_vector.c b/arch/riscv/kvm/vcpu_vector.c
index fefc2857f753..730c32f7de50 100644
--- a/arch/riscv/kvm/vcpu_vector.c
+++ b/arch/riscv/kvm/vcpu_vector.c
@@ -47,7 +47,7 @@ void kvm_riscv_vcpu_guest_vector_save(struct kvm_cpu_context *cntx,
{
if ((cntx->sstatus & SR_VS) == SR_VS_DIRTY) {
if (riscv_isa_extension_available(isa, V))
- __kvm_riscv_vector_save(cntx);
+ kvm_riscv_vector_save(cntx);
kvm_riscv_vcpu_vector_clean(cntx);
}
}
@@ -65,13 +65,13 @@ void kvm_riscv_vcpu_host_vector_save(struct kvm_cpu_context *cntx)
{
/* No need to check host sstatus as it can be modified outside */
if (!kvm_riscv_isa_check_host(V))
- __kvm_riscv_vector_save(cntx);
+ kvm_riscv_vector_save(cntx);
}
void kvm_riscv_vcpu_host_vector_restore(struct kvm_cpu_context *cntx)
{
if (!kvm_riscv_isa_check_host(V))
- __kvm_riscv_vector_restore(cntx);
+ kvm_riscv_vector_restore(cntx);
riscv_v_flags_set(riscv_v_flags() & ~(RISCV_V_VCPU_CTX | RISCV_V_VCPU_NEED_RESTORE));
}
--
2.43.0
--
kvm-riscv mailing list
kvm-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kvm-riscv
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v7 1/6] riscv: vector: refactor vector context operations
@ 2026-11-11 18:43 ` Andy Chiu
0 siblings, 0 replies; 20+ messages in thread
From: Andy Chiu @ 2026-11-11 18:43 UTC (permalink / raw)
To: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, kvm, kvm-riscv, linux-riscv
Cc: andybnac, Andy Chiu, dfustini, greentime.hu, Aurelien Jarno,
Yong-Xuan Wang, daichengrong, Troy Mitchell
Lift riscv_v_{enable,disable} out of __*vstate_{save,restore,discard} so
that we can reuse some functions without repeatedly turning on/off
vector.
Also, refactor and document about the user context save in preempt_v to
make code more readable.
Signed-off-by: Andy Chiu <tchiu@tenstorrent.com>
---
Changelog v5:
- rebase on top of the kvm fix[1]
Changelog v4:
- fix an unused variable warning (Olof)
Changelog v3:
- new patch since v3
---
arch/riscv/include/asm/kvm_vcpu_vector.h | 8 ++++++--
arch/riscv/include/asm/vector.h | 15 ++++++++-------
arch/riscv/kernel/kernel_mode_vector.c | 4 ++++
arch/riscv/kvm/vcpu.c | 2 +-
arch/riscv/kvm/vcpu_vector.c | 6 +++---
5 files changed, 22 insertions(+), 13 deletions(-)
diff --git a/arch/riscv/include/asm/kvm_vcpu_vector.h b/arch/riscv/include/asm/kvm_vcpu_vector.h
index 50d4789b9cac..60fa28030944 100644
--- a/arch/riscv/include/asm/kvm_vcpu_vector.h
+++ b/arch/riscv/include/asm/kvm_vcpu_vector.h
@@ -16,14 +16,18 @@
#ifdef CONFIG_RISCV_ISA_V
#include <asm/kvm_host.h>
-static __always_inline void __kvm_riscv_vector_save(struct kvm_cpu_context *context)
+static __always_inline void kvm_riscv_vector_save(struct kvm_cpu_context *context)
{
+ riscv_v_enable();
__riscv_v_vstate_save(&context->vector, context->vector.datap);
+ riscv_v_disable();
}
-static __always_inline void __kvm_riscv_vector_restore(struct kvm_cpu_context *context)
+static __always_inline void kvm_riscv_vector_restore(struct kvm_cpu_context *context)
{
+ riscv_v_enable();
__riscv_v_vstate_restore(&context->vector, context->vector.datap);
+ riscv_v_disable();
}
void kvm_riscv_vcpu_vector_reset(struct kvm_vcpu *vcpu);
diff --git a/arch/riscv/include/asm/vector.h b/arch/riscv/include/asm/vector.h
index 3381a535abb4..8c88a2258e61 100644
--- a/arch/riscv/include/asm/vector.h
+++ b/arch/riscv/include/asm/vector.h
@@ -203,7 +203,6 @@ static inline void __riscv_v_vstate_save(struct __riscv_v_ext_state *save_to,
{
unsigned long vl;
- riscv_v_enable();
__vstate_csr_save(save_to);
if (has_xtheadvector()) {
asm volatile (
@@ -232,7 +231,6 @@ static inline void __riscv_v_vstate_save(struct __riscv_v_ext_state *save_to,
".option pop\n\t"
: "=&r" (vl), "+r" (datap) : : "memory");
}
- riscv_v_disable();
}
static inline void __riscv_v_vstate_restore(struct __riscv_v_ext_state *restore_from,
@@ -240,7 +238,6 @@ static inline void __riscv_v_vstate_restore(struct __riscv_v_ext_state *restore_
{
unsigned long vl;
- riscv_v_enable();
if (has_xtheadvector()) {
asm volatile (
"mv t0, %0\n\t"
@@ -269,14 +266,12 @@ static inline void __riscv_v_vstate_restore(struct __riscv_v_ext_state *restore_
: "=&r" (vl), "+r" (datap) : : "memory");
}
__vstate_csr_restore(restore_from);
- riscv_v_disable();
}
static inline void __riscv_v_vstate_discard(void)
{
unsigned long vl, vtype_inval = 1UL << (BITS_PER_LONG - 1);
- riscv_v_enable();
if (has_xtheadvector())
asm volatile (THEAD_VSETVLI_T4X0E8M8D1 : : : "t4");
else
@@ -296,14 +291,14 @@ static inline void __riscv_v_vstate_discard(void)
"vsetvl %0, x0, %1\n\t"
".option pop\n\t"
: "=&r" (vl) : "r" (vtype_inval));
-
- riscv_v_disable();
}
static inline void riscv_v_vstate_discard(struct pt_regs *regs)
{
if (riscv_v_vstate_query(regs)) {
+ riscv_v_enable();
__riscv_v_vstate_discard();
+ riscv_v_disable();
__riscv_v_vstate_dirty(regs);
}
}
@@ -312,7 +307,9 @@ static inline void riscv_v_vstate_save(struct __riscv_v_ext_state *vstate,
struct pt_regs *regs)
{
if (__riscv_v_vstate_check(regs->status, DIRTY)) {
+ riscv_v_enable();
__riscv_v_vstate_save(vstate, vstate->datap);
+ riscv_v_disable();
__riscv_v_vstate_clean(regs);
}
}
@@ -323,7 +320,9 @@ static inline void riscv_v_vstate_restore(struct __riscv_v_ext_state *vstate,
WARN_ON_ONCE(preemptible());
if (riscv_v_vstate_query(regs)) {
+ riscv_v_enable();
__riscv_v_vstate_restore(vstate, vstate->datap);
+ riscv_v_disable();
__riscv_v_vstate_clean(regs);
}
}
@@ -385,8 +384,10 @@ static inline void __switch_to_vector(struct task_struct *prev,
riscv_v_disable();
prev->thread.riscv_v_flags |= RISCV_PREEMPT_V_IN_SCHEDULE;
} else if (riscv_preempt_v_dirty(prev)) {
+ riscv_v_enable();
__riscv_v_vstate_save(&prev->thread.kernel_vstate,
prev->thread.kernel_vstate.datap);
+ riscv_v_disable();
riscv_preempt_v_clear_dirty(prev);
}
} else {
diff --git a/arch/riscv/kernel/kernel_mode_vector.c b/arch/riscv/kernel/kernel_mode_vector.c
index b9481a3e40e3..280180114899 100644
--- a/arch/riscv/kernel/kernel_mode_vector.c
+++ b/arch/riscv/kernel/kernel_mode_vector.c
@@ -171,7 +171,9 @@ static int riscv_v_start_kernel_context(void)
WARN_ON(riscv_v_ctx_get_depth() == 0);
get_cpu_vector_context();
if (riscv_preempt_v_dirty(current)) {
+ riscv_v_enable();
__riscv_v_vstate_save(kvstate, kvstate->datap);
+ riscv_v_disable();
riscv_preempt_v_clear_dirty(current);
}
riscv_preempt_v_set_restore(current);
@@ -215,7 +217,9 @@ asmlinkage void riscv_v_context_nesting_end(struct pt_regs *regs)
depth = riscv_v_ctx_get_depth();
if (depth == 0) {
if (riscv_preempt_v_restore(current)) {
+ riscv_v_enable();
__riscv_v_vstate_restore(vstate, vstate->datap);
+ riscv_v_disable();
__riscv_v_vstate_clean(regs);
riscv_preempt_v_reset_flags();
}
diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c
index dd786f758eb7..caf6e0ad72ef 100644
--- a/arch/riscv/kvm/vcpu.c
+++ b/arch/riscv/kvm/vcpu.c
@@ -825,7 +825,7 @@ static void noinstr kvm_riscv_vcpu_enter_exit(struct kvm_vcpu *vcpu,
if (current->thread.riscv_v_flags & RISCV_V_VCPU_NEED_RESTORE) {
current->thread.riscv_v_flags &= ~RISCV_V_VCPU_NEED_RESTORE;
current->thread.riscv_v_flags |= RISCV_V_VCPU_CTX;
- __kvm_riscv_vector_restore(gcntx);
+ kvm_riscv_vector_restore(gcntx);
gcntx->sstatus = (gcntx->sstatus & ~SR_VS) | SR_VS_CLEAN;
}
diff --git a/arch/riscv/kvm/vcpu_vector.c b/arch/riscv/kvm/vcpu_vector.c
index fefc2857f753..730c32f7de50 100644
--- a/arch/riscv/kvm/vcpu_vector.c
+++ b/arch/riscv/kvm/vcpu_vector.c
@@ -47,7 +47,7 @@ void kvm_riscv_vcpu_guest_vector_save(struct kvm_cpu_context *cntx,
{
if ((cntx->sstatus & SR_VS) == SR_VS_DIRTY) {
if (riscv_isa_extension_available(isa, V))
- __kvm_riscv_vector_save(cntx);
+ kvm_riscv_vector_save(cntx);
kvm_riscv_vcpu_vector_clean(cntx);
}
}
@@ -65,13 +65,13 @@ void kvm_riscv_vcpu_host_vector_save(struct kvm_cpu_context *cntx)
{
/* No need to check host sstatus as it can be modified outside */
if (!kvm_riscv_isa_check_host(V))
- __kvm_riscv_vector_save(cntx);
+ kvm_riscv_vector_save(cntx);
}
void kvm_riscv_vcpu_host_vector_restore(struct kvm_cpu_context *cntx)
{
if (!kvm_riscv_isa_check_host(V))
- __kvm_riscv_vector_restore(cntx);
+ kvm_riscv_vector_restore(cntx);
riscv_v_flags_set(riscv_v_flags() & ~(RISCV_V_VCPU_CTX | RISCV_V_VCPU_NEED_RESTORE));
}
--
2.43.0
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v7 1/6] riscv: vector: refactor vector context operations
@ 2026-11-11 18:43 ` Andy Chiu
0 siblings, 0 replies; 20+ messages in thread
From: Andy Chiu @ 2026-11-11 18:43 UTC (permalink / raw)
To: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, kvm, kvm-riscv, linux-riscv
Cc: andybnac, Andy Chiu, dfustini, greentime.hu, Aurelien Jarno,
Yong-Xuan Wang, daichengrong, Troy Mitchell
Lift riscv_v_{enable,disable} out of __*vstate_{save,restore,discard} so
that we can reuse some functions without repeatedly turning on/off
vector.
Also, refactor and document about the user context save in preempt_v to
make code more readable.
Signed-off-by: Andy Chiu <tchiu@tenstorrent.com>
---
Changelog v5:
- rebase on top of the kvm fix[1]
Changelog v4:
- fix an unused variable warning (Olof)
Changelog v3:
- new patch since v3
---
arch/riscv/include/asm/kvm_vcpu_vector.h | 8 ++++++--
arch/riscv/include/asm/vector.h | 15 ++++++++-------
arch/riscv/kernel/kernel_mode_vector.c | 4 ++++
arch/riscv/kvm/vcpu.c | 2 +-
arch/riscv/kvm/vcpu_vector.c | 6 +++---
5 files changed, 22 insertions(+), 13 deletions(-)
diff --git a/arch/riscv/include/asm/kvm_vcpu_vector.h b/arch/riscv/include/asm/kvm_vcpu_vector.h
index 50d4789b9cac..60fa28030944 100644
--- a/arch/riscv/include/asm/kvm_vcpu_vector.h
+++ b/arch/riscv/include/asm/kvm_vcpu_vector.h
@@ -16,14 +16,18 @@
#ifdef CONFIG_RISCV_ISA_V
#include <asm/kvm_host.h>
-static __always_inline void __kvm_riscv_vector_save(struct kvm_cpu_context *context)
+static __always_inline void kvm_riscv_vector_save(struct kvm_cpu_context *context)
{
+ riscv_v_enable();
__riscv_v_vstate_save(&context->vector, context->vector.datap);
+ riscv_v_disable();
}
-static __always_inline void __kvm_riscv_vector_restore(struct kvm_cpu_context *context)
+static __always_inline void kvm_riscv_vector_restore(struct kvm_cpu_context *context)
{
+ riscv_v_enable();
__riscv_v_vstate_restore(&context->vector, context->vector.datap);
+ riscv_v_disable();
}
void kvm_riscv_vcpu_vector_reset(struct kvm_vcpu *vcpu);
diff --git a/arch/riscv/include/asm/vector.h b/arch/riscv/include/asm/vector.h
index 3381a535abb4..8c88a2258e61 100644
--- a/arch/riscv/include/asm/vector.h
+++ b/arch/riscv/include/asm/vector.h
@@ -203,7 +203,6 @@ static inline void __riscv_v_vstate_save(struct __riscv_v_ext_state *save_to,
{
unsigned long vl;
- riscv_v_enable();
__vstate_csr_save(save_to);
if (has_xtheadvector()) {
asm volatile (
@@ -232,7 +231,6 @@ static inline void __riscv_v_vstate_save(struct __riscv_v_ext_state *save_to,
".option pop\n\t"
: "=&r" (vl), "+r" (datap) : : "memory");
}
- riscv_v_disable();
}
static inline void __riscv_v_vstate_restore(struct __riscv_v_ext_state *restore_from,
@@ -240,7 +238,6 @@ static inline void __riscv_v_vstate_restore(struct __riscv_v_ext_state *restore_
{
unsigned long vl;
- riscv_v_enable();
if (has_xtheadvector()) {
asm volatile (
"mv t0, %0\n\t"
@@ -269,14 +266,12 @@ static inline void __riscv_v_vstate_restore(struct __riscv_v_ext_state *restore_
: "=&r" (vl), "+r" (datap) : : "memory");
}
__vstate_csr_restore(restore_from);
- riscv_v_disable();
}
static inline void __riscv_v_vstate_discard(void)
{
unsigned long vl, vtype_inval = 1UL << (BITS_PER_LONG - 1);
- riscv_v_enable();
if (has_xtheadvector())
asm volatile (THEAD_VSETVLI_T4X0E8M8D1 : : : "t4");
else
@@ -296,14 +291,14 @@ static inline void __riscv_v_vstate_discard(void)
"vsetvl %0, x0, %1\n\t"
".option pop\n\t"
: "=&r" (vl) : "r" (vtype_inval));
-
- riscv_v_disable();
}
static inline void riscv_v_vstate_discard(struct pt_regs *regs)
{
if (riscv_v_vstate_query(regs)) {
+ riscv_v_enable();
__riscv_v_vstate_discard();
+ riscv_v_disable();
__riscv_v_vstate_dirty(regs);
}
}
@@ -312,7 +307,9 @@ static inline void riscv_v_vstate_save(struct __riscv_v_ext_state *vstate,
struct pt_regs *regs)
{
if (__riscv_v_vstate_check(regs->status, DIRTY)) {
+ riscv_v_enable();
__riscv_v_vstate_save(vstate, vstate->datap);
+ riscv_v_disable();
__riscv_v_vstate_clean(regs);
}
}
@@ -323,7 +320,9 @@ static inline void riscv_v_vstate_restore(struct __riscv_v_ext_state *vstate,
WARN_ON_ONCE(preemptible());
if (riscv_v_vstate_query(regs)) {
+ riscv_v_enable();
__riscv_v_vstate_restore(vstate, vstate->datap);
+ riscv_v_disable();
__riscv_v_vstate_clean(regs);
}
}
@@ -385,8 +384,10 @@ static inline void __switch_to_vector(struct task_struct *prev,
riscv_v_disable();
prev->thread.riscv_v_flags |= RISCV_PREEMPT_V_IN_SCHEDULE;
} else if (riscv_preempt_v_dirty(prev)) {
+ riscv_v_enable();
__riscv_v_vstate_save(&prev->thread.kernel_vstate,
prev->thread.kernel_vstate.datap);
+ riscv_v_disable();
riscv_preempt_v_clear_dirty(prev);
}
} else {
diff --git a/arch/riscv/kernel/kernel_mode_vector.c b/arch/riscv/kernel/kernel_mode_vector.c
index b9481a3e40e3..280180114899 100644
--- a/arch/riscv/kernel/kernel_mode_vector.c
+++ b/arch/riscv/kernel/kernel_mode_vector.c
@@ -171,7 +171,9 @@ static int riscv_v_start_kernel_context(void)
WARN_ON(riscv_v_ctx_get_depth() == 0);
get_cpu_vector_context();
if (riscv_preempt_v_dirty(current)) {
+ riscv_v_enable();
__riscv_v_vstate_save(kvstate, kvstate->datap);
+ riscv_v_disable();
riscv_preempt_v_clear_dirty(current);
}
riscv_preempt_v_set_restore(current);
@@ -215,7 +217,9 @@ asmlinkage void riscv_v_context_nesting_end(struct pt_regs *regs)
depth = riscv_v_ctx_get_depth();
if (depth == 0) {
if (riscv_preempt_v_restore(current)) {
+ riscv_v_enable();
__riscv_v_vstate_restore(vstate, vstate->datap);
+ riscv_v_disable();
__riscv_v_vstate_clean(regs);
riscv_preempt_v_reset_flags();
}
diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c
index dd786f758eb7..caf6e0ad72ef 100644
--- a/arch/riscv/kvm/vcpu.c
+++ b/arch/riscv/kvm/vcpu.c
@@ -825,7 +825,7 @@ static void noinstr kvm_riscv_vcpu_enter_exit(struct kvm_vcpu *vcpu,
if (current->thread.riscv_v_flags & RISCV_V_VCPU_NEED_RESTORE) {
current->thread.riscv_v_flags &= ~RISCV_V_VCPU_NEED_RESTORE;
current->thread.riscv_v_flags |= RISCV_V_VCPU_CTX;
- __kvm_riscv_vector_restore(gcntx);
+ kvm_riscv_vector_restore(gcntx);
gcntx->sstatus = (gcntx->sstatus & ~SR_VS) | SR_VS_CLEAN;
}
diff --git a/arch/riscv/kvm/vcpu_vector.c b/arch/riscv/kvm/vcpu_vector.c
index fefc2857f753..730c32f7de50 100644
--- a/arch/riscv/kvm/vcpu_vector.c
+++ b/arch/riscv/kvm/vcpu_vector.c
@@ -47,7 +47,7 @@ void kvm_riscv_vcpu_guest_vector_save(struct kvm_cpu_context *cntx,
{
if ((cntx->sstatus & SR_VS) == SR_VS_DIRTY) {
if (riscv_isa_extension_available(isa, V))
- __kvm_riscv_vector_save(cntx);
+ kvm_riscv_vector_save(cntx);
kvm_riscv_vcpu_vector_clean(cntx);
}
}
@@ -65,13 +65,13 @@ void kvm_riscv_vcpu_host_vector_save(struct kvm_cpu_context *cntx)
{
/* No need to check host sstatus as it can be modified outside */
if (!kvm_riscv_isa_check_host(V))
- __kvm_riscv_vector_save(cntx);
+ kvm_riscv_vector_save(cntx);
}
void kvm_riscv_vcpu_host_vector_restore(struct kvm_cpu_context *cntx)
{
if (!kvm_riscv_isa_check_host(V))
- __kvm_riscv_vector_restore(cntx);
+ kvm_riscv_vector_restore(cntx);
riscv_v_flags_set(riscv_v_flags() & ~(RISCV_V_VCPU_CTX | RISCV_V_VCPU_NEED_RESTORE));
}
--
2.43.0
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v7 2/6] riscv: introduce riscv_v_ucontext_save() for signal and ptrace
2026-11-11 18:43 ` Andy Chiu
(?)
(?)
@ 2026-11-11 18:43 ` Andy Chiu
-1 siblings, 0 replies; 20+ messages in thread
From: Andy Chiu @ 2026-11-11 18:43 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Oleg Nesterov, linux-riscv
Cc: andybnac, Andy Chiu, dfustini, greentime.hu, Aurelien Jarno,
Yong-Xuan Wang, Anup Patel, daichengrong, Guobin Zhang,
Troy Mitchell, Deepak Gupta, Sergey Matyukevich
Add a centralized user context saving function for the next patch. As we
are preparing for the optimization that skip saving on VS==INITIAL, user
context saving in ptrace and signal both need to account for such case,
and they are handled in a similar way.
This is a preparatory patch, the next patch folds in the actual handling
for exporting the user context when VS is at INITIAL state.
Signed-off-by: Andy Chiu <tchiu@tenstorrent.com>
---
Changelog v7:
- new patch since v7 (splited out from v6 to maintain git bisectability)
---
arch/riscv/include/asm/vector.h | 2 ++
arch/riscv/kernel/ptrace.c | 6 +-----
arch/riscv/kernel/signal.c | 4 +---
arch/riscv/kernel/vector.c | 12 ++++++++++++
4 files changed, 16 insertions(+), 8 deletions(-)
diff --git a/arch/riscv/include/asm/vector.h b/arch/riscv/include/asm/vector.h
index 8c88a2258e61..7cd20f661596 100644
--- a/arch/riscv/include/asm/vector.h
+++ b/arch/riscv/include/asm/vector.h
@@ -52,6 +52,7 @@ void riscv_v_thread_free(struct task_struct *tsk);
void __init riscv_v_setup_ctx_cache(void);
void riscv_v_thread_alloc(struct task_struct *tsk);
void __init update_regset_vector_info(unsigned long size);
+void riscv_v_ucontext_save(struct task_struct *tsk);
static inline u32 riscv_v_flags(void)
{
@@ -434,6 +435,7 @@ static inline bool riscv_v_vstate_ctrl_user_allowed(void) { return false; }
#define riscv_v_thread_alloc(tsk) do {} while (0)
#define get_cpu_vector_context() do {} while (0)
#define put_cpu_vector_context() do {} while (0)
+#define riscv_v_ucontext_save(tsk) do {} while (0)
#define riscv_v_vstate_set_restore(task, regs) do {} while (0)
#endif /* CONFIG_RISCV_ISA_V */
diff --git a/arch/riscv/kernel/ptrace.c b/arch/riscv/kernel/ptrace.c
index a0055743d3ba..88442ac4f6ae 100644
--- a/arch/riscv/kernel/ptrace.c
+++ b/arch/riscv/kernel/ptrace.c
@@ -109,11 +109,7 @@ static int riscv_vr_get(struct task_struct *target,
* Ensure the vector registers have been saved to the memory before
* copying them to membuf.
*/
- if (target == current) {
- get_cpu_vector_context();
- riscv_v_vstate_save(¤t->thread.vstate, task_pt_regs(current));
- put_cpu_vector_context();
- }
+ riscv_v_ucontext_save(target);
ptrace_vstate.vstart = vstate->vstart;
ptrace_vstate.vl = vstate->vl;
diff --git a/arch/riscv/kernel/signal.c b/arch/riscv/kernel/signal.c
index 6f6f3315bc09..50c77bcf2b09 100644
--- a/arch/riscv/kernel/signal.c
+++ b/arch/riscv/kernel/signal.c
@@ -89,9 +89,7 @@ static long save_v_state(struct pt_regs *regs, void __user *sc_vec)
/* datap is designed to be 16 byte aligned for better performance */
WARN_ON(!IS_ALIGNED((unsigned long)datap, 16));
- get_cpu_vector_context();
- riscv_v_vstate_save(¤t->thread.vstate, regs);
- put_cpu_vector_context();
+ riscv_v_ucontext_save(current);
/* Copy everything of vstate but datap. */
err = __copy_to_user(&state->v_state, ¤t->thread.vstate,
diff --git a/arch/riscv/kernel/vector.c b/arch/riscv/kernel/vector.c
index b112166d51e9..924baa71af7e 100644
--- a/arch/riscv/kernel/vector.c
+++ b/arch/riscv/kernel/vector.c
@@ -29,6 +29,18 @@ static struct kmem_cache *riscv_v_kernel_cachep;
unsigned long riscv_v_vsize __read_mostly;
EXPORT_SYMBOL_GPL(riscv_v_vsize);
+void riscv_v_ucontext_save(struct task_struct *tsk)
+{
+ struct __riscv_v_ext_state *vstate = &tsk->thread.vstate;
+ struct pt_regs *regs = task_pt_regs(tsk);
+
+ if (tsk == current) {
+ get_cpu_vector_context();
+ riscv_v_vstate_save(vstate, regs);
+ put_cpu_vector_context();
+ }
+}
+
int riscv_v_setup_vsize(void)
{
unsigned long this_vsize;
--
2.43.0
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v7 3/6] riscv: clarify vector state semantics on syscall and context switch
2026-11-11 18:43 ` Andy Chiu
` (2 preceding siblings ...)
(?)
@ 2026-11-11 18:43 ` Andy Chiu
2026-11-12 12:12 ` kernel test robot
-1 siblings, 1 reply; 20+ messages in thread
From: Andy Chiu @ 2026-11-11 18:43 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Oleg Nesterov, linux-riscv
Cc: andybnac, daichengrong, gdb, Andy Chiu, dfustini, greentime.hu,
Yong-Xuan Wang, Aurelien Jarno, Anup Patel, Guobin Zhang,
Troy Mitchell, Deepak Gupta, Sergey Matyukevich
From: daichengrong <daichengrong@iscas.ac.cn>
The RISC-V vector specification states that executing a system call
causes all caller-saved vector registers (v0-v31, vl, vtype) and vstart
to become unspecified.
Currently, after calling riscv_v_vstate_discard(), the vector state
may still be marked as DIRTY, which can mislead the context switch
logic into treating the registers as containing valid user data.
This patch clarifies and tightens the kernel-side semantics:
1. On syscall entry, the kernel checks the vector state via sstatus
and set it to INIT if not already, indicating that the vector
registers no longer contain meaningful user data. Context
invalidation is required on restore.
If the state is already set to INIT, it means that the user has not
touched vector since the last invalidation. So no further action is
required on restore.
2. During context switch, the vector state is saved only if the state is
DIRTY. (no change)
3. On restore, if invalidation is required, the vector registers are
overwritten with a known initial value and the state is set to INIT.
4. Ptrace writes (PTRACE_SETREGSET) during a syscall stop are silently
dropped (returning 0). Returning an error like EINVAL would break
debbugers like GDB, which disables the optional regset on receiving
such error. On the otherhand, ptrace reads at a syscall stop always
returns the nulled context.
Performance improvements on Blackhole x280:
Latency of getpid() with different status.VS upon syscall entry in ns:
status.VS Before Patch After Patch Improvement
DIRTY 235.9 242.4 +6.5 (+2.7%) # regress
INIT 234.8 174.4 -60.4 (-25.7%)
OFF 178.2 174.5 -3.7 (-2.1%)
Context switch latencies in us:
Metric Before Patch After Patch Improvement
Mean Latency 14.19 11.62 -2.57 (-18.1%)
Median Latency 13.51 11.01 -2.50 (-18.5%)
Max Latency 27.76 21.92 -5.84 (-21.0%)
Min Latency 8.99 8.12 -0.87 (-9.7%)
The metrics on context switch latencies are obtained by running the
following command 100 times:
$ taskset 0x2 ./lat_ctx_v -N 10000 -s 512 2
The program lat_ctx_v is a modified lat_ctx where benchmark processes
(parent/child) do a `vsetvli` to dirtify VS before making each write
syscall.
CC: gdb@sourceware.org
Signed-off-by: daichengrong <daichengrong@iscas.ac.cn>
Co-developed-by: Andy Chiu <tchiu@tenstorrent.com>
Signed-off-by: Andy Chiu <tchiu@tenstorrent.com>
---
Changelog v7:
- Fold the next patch from v6 into this to prevent exposing breaks in
signal and ptrace.
Changelog v4:
- Provide performance meassurement (Olof)
- Aggregate riscv_v_{enable,disable} for better performance (reduces to
~240 ns/call when the user touches vector)
- Do not invalidate again if user doesn't touch vector
Changelog v3:
- rename vstate_on to vstate_init to prevent confusion
- set context as clean at first-use trap to return zero'ed context
- reduce context nulling operations by defering __vstate_discard to
exit_to_user_mode_prepare.
---
arch/riscv/include/asm/vector.h | 45 ++++++++++++++++++---------------
arch/riscv/kernel/ptrace.c | 7 ++++-
arch/riscv/kernel/signal.c | 7 ++++-
arch/riscv/kernel/vector.c | 29 +++++++++++++++++++--
4 files changed, 64 insertions(+), 24 deletions(-)
diff --git a/arch/riscv/include/asm/vector.h b/arch/riscv/include/asm/vector.h
index 7cd20f661596..e83f9e0046a9 100644
--- a/arch/riscv/include/asm/vector.h
+++ b/arch/riscv/include/asm/vector.h
@@ -40,6 +40,15 @@
_res; \
})
+#define __riscv_v_vstate_check_gt(_val, TYPE) ({ \
+ bool _res; \
+ if (has_xtheadvector()) \
+ _res = ((_val) & SR_VS_THEAD) > SR_VS_##TYPE##_THEAD; \
+ else \
+ _res = ((_val) & SR_VS) > SR_VS_##TYPE; \
+ _res; \
+})
+
extern unsigned long riscv_v_vsize;
int riscv_v_setup_vsize(void);
bool insn_is_vector(u32 insn_buf);
@@ -101,7 +110,7 @@ static inline void riscv_v_vstate_off(struct pt_regs *regs)
regs->status = __riscv_v_vstate_or(regs->status, OFF);
}
-static inline void riscv_v_vstate_on(struct pt_regs *regs)
+static inline void riscv_v_vstate_init(struct pt_regs *regs)
{
regs->status = __riscv_v_vstate_or(regs->status, INITIAL);
}
@@ -294,16 +303,6 @@ static inline void __riscv_v_vstate_discard(void)
: "=&r" (vl) : "r" (vtype_inval));
}
-static inline void riscv_v_vstate_discard(struct pt_regs *regs)
-{
- if (riscv_v_vstate_query(regs)) {
- riscv_v_enable();
- __riscv_v_vstate_discard();
- riscv_v_disable();
- __riscv_v_vstate_dirty(regs);
- }
-}
-
static inline void riscv_v_vstate_save(struct __riscv_v_ext_state *vstate,
struct pt_regs *regs)
{
@@ -319,21 +318,26 @@ static inline void riscv_v_vstate_restore(struct __riscv_v_ext_state *vstate,
struct pt_regs *regs)
{
WARN_ON_ONCE(preemptible());
-
- if (riscv_v_vstate_query(regs)) {
- riscv_v_enable();
+ riscv_v_enable();
+ if (__riscv_v_vstate_check(regs->status, INITIAL))
+ __riscv_v_vstate_discard();
+ else if (__riscv_v_vstate_check(regs->status, CLEAN))
__riscv_v_vstate_restore(vstate, vstate->datap);
- riscv_v_disable();
- __riscv_v_vstate_clean(regs);
- }
+ riscv_v_disable();
}
static inline void riscv_v_vstate_set_restore(struct task_struct *task,
struct pt_regs *regs)
{
- if (riscv_v_vstate_query(regs)) {
+ if (riscv_v_vstate_query(regs))
set_tsk_thread_flag(task, TIF_RISCV_V_DEFER_RESTORE);
- riscv_v_vstate_on(regs);
+}
+
+static inline void riscv_v_vstate_discard(struct pt_regs *regs)
+{
+ if (__riscv_v_vstate_check_gt(regs->status, INITIAL)) {
+ riscv_v_vstate_set_restore(current, regs);
+ riscv_v_vstate_init(regs);
}
}
@@ -404,6 +408,7 @@ static inline void __switch_to_vector(struct task_struct *prev,
riscv_preempt_v_set_restore(next);
}
} else {
+ /* VS is never DIRTY at this point, there's no need to alter vstate here */
riscv_v_vstate_set_restore(next, task_pt_regs(next));
}
}
@@ -429,7 +434,7 @@ static inline bool riscv_v_vstate_ctrl_user_allowed(void) { return false; }
#define riscv_v_vstate_restore(vstate, regs) do {} while (0)
#define __switch_to_vector(__prev, __next) do {} while (0)
#define riscv_v_vstate_off(regs) do {} while (0)
-#define riscv_v_vstate_on(regs) do {} while (0)
+#define riscv_v_vstate_init(regs) do {} while (0)
#define riscv_v_thread_free(tsk) do {} while (0)
#define riscv_v_setup_ctx_cache() do {} while (0)
#define riscv_v_thread_alloc(tsk) do {} while (0)
diff --git a/arch/riscv/kernel/ptrace.c b/arch/riscv/kernel/ptrace.c
index 88442ac4f6ae..d329518cceb6 100644
--- a/arch/riscv/kernel/ptrace.c
+++ b/arch/riscv/kernel/ptrace.c
@@ -218,13 +218,18 @@ static int riscv_vr_set(struct task_struct *target,
int ret;
struct __riscv_v_ext_state *vstate = &target->thread.vstate;
struct __riscv_v_regset_state ptrace_vstate;
+ struct pt_regs *regs = task_pt_regs(target);
if (!(has_vector() || has_xtheadvector()))
return -EINVAL;
- if (!riscv_v_vstate_query(task_pt_regs(target)))
+ if (!riscv_v_vstate_query(regs))
return -ENODATA;
+ /* Silently drop the modification to tracee as no vreg lives across a syscall */
+ if (__riscv_v_vstate_check(regs->status, INITIAL))
+ return 0;
+
/* Copy rest of the vstate except datap */
memset(&ptrace_vstate, 0, sizeof(ptrace_vstate));
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &ptrace_vstate, 0,
diff --git a/arch/riscv/kernel/signal.c b/arch/riscv/kernel/signal.c
index 50c77bcf2b09..dc785aca1cc4 100644
--- a/arch/riscv/kernel/signal.c
+++ b/arch/riscv/kernel/signal.c
@@ -119,10 +119,15 @@ static long __restore_v_state(struct pt_regs *regs, void __user *sc_vec)
/*
* Mark the vstate as clean prior performing the actual copy,
* to avoid getting the vstate incorrectly clobbered by the
- * discarded vector state.
+ * discarded vector state.
+ *
+ * This also allows user to modify vregs through the signal
+ * interface at a syscall stop. e.g. to support user space
+ * context switching.
*/
preempt_disable();
riscv_v_vstate_set_restore(current, regs);
+ __riscv_v_vstate_clean(regs);
preempt_enable();
/* Copy everything of __sc_riscv_v_state except datap. */
diff --git a/arch/riscv/kernel/vector.c b/arch/riscv/kernel/vector.c
index 924baa71af7e..6fd541f5d5cb 100644
--- a/arch/riscv/kernel/vector.c
+++ b/arch/riscv/kernel/vector.c
@@ -29,15 +29,40 @@ static struct kmem_cache *riscv_v_kernel_cachep;
unsigned long riscv_v_vsize __read_mostly;
EXPORT_SYMBOL_GPL(riscv_v_vsize);
+/*
+ * Context memory is not coherent to register when sstatus.vs is set to INITIAL. This function
+ * take the INITIAL state into consideration and reflect the nulled state into context memory.
+ * Assume the target task is not actively running when tsk != current
+ */
void riscv_v_ucontext_save(struct task_struct *tsk)
{
struct __riscv_v_ext_state *vstate = &tsk->thread.vstate;
struct pt_regs *regs = task_pt_regs(tsk);
+ /*
+ * Do not set vstate as clean when it is INITIAL, otherwise we lose track of the nulled
+ * state in ptrace.
+ */
if (tsk == current) {
get_cpu_vector_context();
- riscv_v_vstate_save(vstate, regs);
+ if (__riscv_v_vstate_check(regs->status, INITIAL)) {
+ riscv_v_enable();
+ __riscv_v_vstate_discard();
+ __riscv_v_vstate_save(vstate, vstate->datap);
+ riscv_v_disable();
+ } else {
+ riscv_v_vstate_save(vstate, regs);
+ }
put_cpu_vector_context();
+ } else if (__riscv_v_vstate_check(regs->status, INITIAL)) {
+ /*
+ * If we are not current and VS == INITIAL, null out the context memory for tsk
+ * using kernel mode vector.
+ */
+ kernel_vector_begin();
+ __riscv_v_vstate_discard();
+ __riscv_v_vstate_save(vstate, vstate->datap);
+ kernel_vector_end();
}
}
@@ -233,7 +258,7 @@ bool riscv_v_first_use_handler(struct pt_regs *regs)
return true;
}
- riscv_v_vstate_on(regs);
+ __riscv_v_vstate_clean(regs);
riscv_v_vstate_set_restore(current, regs);
return true;
--
2.43.0
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v7 4/6] selftests: riscv: Extend vector tests for sigreturn and ptrace
2026-11-11 18:43 ` Andy Chiu
@ 2026-11-11 18:43 ` Andy Chiu
-1 siblings, 0 replies; 20+ messages in thread
From: Andy Chiu @ 2026-11-11 18:43 UTC (permalink / raw)
To: Shuah Khan, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, linux-kselftest, linux-riscv
Cc: andybnac, Andy Chiu, dfustini, greentime.hu, Andrew Morton,
Bala-Vignesh-Reddy, Wei Yang, Yong-Xuan Wang
Add new test cases to verify the vector state restorations at syscall
stops for ptrace and signal interfaces. Specifically:
1. Signal handler should read all ones at syscall stop and modifying
context should success.
2. Ptrace should read all ones but any modification to NT_RISCV_VECTOR
is silently dropped.
Signed-off-by: Andy Chiu <tchiu@tenstorrent.com>
---
Changelog v4:
- remove timer dependency from the signal delivery (Sashiko)
- solve 2 memory leaks in ptrace (Sashiko)
Changelog v3:
- new patch since v3
---
.../selftests/riscv/sigreturn/sigreturn.c | 71 +++++++++++
.../selftests/riscv/vector/vstate_ptrace.c | 111 +++++++++++++++++-
2 files changed, 178 insertions(+), 4 deletions(-)
diff --git a/tools/testing/selftests/riscv/sigreturn/sigreturn.c b/tools/testing/selftests/riscv/sigreturn/sigreturn.c
index e10873d95fed..647249dbd7e6 100644
--- a/tools/testing/selftests/riscv/sigreturn/sigreturn.c
+++ b/tools/testing/selftests/riscv/sigreturn/sigreturn.c
@@ -7,6 +7,7 @@
#include "kselftest_harness.h"
#define RISCV_V_MAGIC 0x53465457
+#define END_MAGIC 0
#define DEFAULT_VALUE 2
#define SIGNAL_HANDLER_OVERRIDE 3
@@ -61,6 +62,76 @@ static int vector_sigreturn(int data, void (*handler)(int, siginfo_t *, void *))
return after_sigreturn;
}
+#define V_TEST_PATTERN_SIGNAL 0x98
+int nulled_val;
+static void sigalrm_handler(int sig, siginfo_t *info, void *vcontext)
+{
+ ucontext_t *context = vcontext;
+ struct __riscv_extra_ext_header *ext;
+ struct __riscv_ctx_hdr *hdr;
+ uint8_t *ext_ptr;
+
+ /* Find the vector context */
+ ext = (void *)(&context->uc_mcontext.__fpregs);
+ ext_ptr = (uint8_t *)ext;
+ hdr = &ext->hdr;
+
+ while (hdr->magic != END_MAGIC) {
+ if (hdr->magic == RISCV_V_MAGIC) {
+ struct __riscv_v_ext_state *v_state = (struct __riscv_v_ext_state *)(hdr + 1);
+ /* Assume a valid datap */
+ nulled_val = *(int *)v_state->datap;
+ /* Fill all vector registers with magic pattern */
+ memset(v_state->datap, V_TEST_PATTERN_SIGNAL, v_state->vlenb * 32);
+ /*
+ * We must also set the vector configuration so that when
+ * userspace reads v0, it uses a valid element width (e8).
+ */
+ v_state->vl = v_state->vlenb;
+ v_state->vtype = 0; /* e8, m1, tu, mu */
+ break;
+ }
+ /* Move to the next extension header */
+ ext_ptr += hdr->size;
+ hdr = (struct __riscv_ctx_hdr *)ext_ptr;
+ }
+}
+
+TEST(test_signal_syscall_ucontext) {
+ struct sigaction sa;
+
+ /* Make sure we get V in ucontext by executing vsetvli */
+ asm volatile (
+ ".option push\n\t"
+ ".option arch, +v\n\t"
+ "vsetivli x0, 1, e32, m1, ta, ma\n\t"
+ ".option pop\n\t" : : :);
+
+ sa.sa_flags = SA_SIGINFO;
+ sa.sa_sigaction = sigalrm_handler;
+ sigemptyset(&sa.sa_mask);
+ if (sigaction(SIGALRM, &sa, NULL) == -1)
+ ksft_exit_fail_msg("Failed to register signal handler\n");
+
+ raise(SIGALRM);
+ /*
+ * If the kernel successfully parsed and restored our modified ucontext,
+ * v0 will contain V_TEST_PATTERN_SIGNAL.
+ */
+ unsigned char v0_val;
+
+ asm volatile(
+ ".option push\n\t"
+ ".option arch, +zve32x\n\t"
+ "vmv.x.s %0, v0\n\t"
+ ".option pop\n\t"
+ : "=r" (v0_val)
+ );
+
+ EXPECT_EQ(v0_val, V_TEST_PATTERN_SIGNAL);
+ EXPECT_EQ(nulled_val, -1);
+}
+
TEST(vector_restore)
{
int result;
diff --git a/tools/testing/selftests/riscv/vector/vstate_ptrace.c b/tools/testing/selftests/riscv/vector/vstate_ptrace.c
index 1479abc0c9cb..863a16f6e1a3 100644
--- a/tools/testing/selftests/riscv/vector/vstate_ptrace.c
+++ b/tools/testing/selftests/riscv/vector/vstate_ptrace.c
@@ -21,6 +21,41 @@ static long do_ptrace(enum __ptrace_request op, pid_t pid, long type, size_t siz
return ptrace(op, pid, type, &v_iovec);
}
+static int do_child_syscall_stop(void)
+{
+ int out;
+
+ if (ptrace(PTRACE_TRACEME, -1, NULL, NULL)) {
+ ksft_perror("PTRACE_TRACEME failed\n");
+ return EXIT_FAILURE;
+ }
+
+ raise(SIGSTOP);
+
+ asm volatile (".option push\n\t"
+ ".option arch, +v\n\t"
+ "vsetivli x0, 1, e32, m1, ta, ma\n\t"
+ "vmv.s.x v31, %[in]\n\t"
+ ".option pop\n\t"
+ :
+ : [in] "r" (child_set_val));
+
+ getpid();
+
+ asm volatile (".option push\n\t"
+ ".option arch, +v\n\t"
+ "vsetivli x0, 1, e32, m1, ta, ma\n\t"
+ "vmv.x.s %[out], v31\n\t"
+ ".option pop\n\t"
+ : [out] "=r" (out)
+ :);
+
+ if (out != -1)
+ return EXIT_FAILURE;
+
+ return EXIT_SUCCESS;
+}
+
static int do_child(void)
{
int out;
@@ -59,7 +94,7 @@ static void do_parent(pid_t child)
goto out;
} else if (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGTRAP)) {
size_t size;
- void *data, *v31;
+ void *vctx, *v31;
struct __riscv_v_regset_state *v_regset_hdr;
struct user_regs_struct *gpreg;
@@ -73,9 +108,11 @@ static void do_parent(pid_t child)
goto out;
ksft_print_msg("vlenb %ld\n", v_regset_hdr->vlenb);
- data = realloc(data, size + v_regset_hdr->vlenb * 32);
- if (!data)
+ vctx = realloc(data, size + v_regset_hdr->vlenb * 32);
+ if (!vctx)
goto out;
+ data = vctx;
+
v_regset_hdr = (struct __riscv_v_regset_state *)data;
v31 = (void *)(data + size + v_regset_hdr->vlenb * 31);
size += v_regset_hdr->vlenb * 32;
@@ -109,11 +146,65 @@ static void do_parent(pid_t child)
free(data);
}
+static void do_parent_syscall_stop(pid_t child)
+{
+ int status;
+ void *data = NULL;
+
+ while (waitpid(child, &status, 0)) {
+ if (WIFEXITED(status)) {
+ ksft_test_result(WEXITSTATUS(status) == 0,
+ "SETREGSET vector at syscall stop\n");
+ goto out;
+ } else if (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGSTOP)) {
+ /* Attach to the child at syscall stop */
+ ptrace(PTRACE_SYSCALL, child, NULL, NULL);
+ continue;
+ } else if (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGTRAP)) {
+ size_t size;
+ void *vctx, *v31;
+ struct __riscv_v_regset_state *v_regset_hdr;
+
+ size = sizeof(*v_regset_hdr);
+ data = malloc(size);
+ if (!data)
+ goto out;
+ v_regset_hdr = (struct __riscv_v_regset_state *)data;
+
+ if (do_ptrace(PTRACE_GETREGSET, child, NT_RISCV_VECTOR, size, data))
+ goto out;
+
+ ksft_print_msg("vlenb %ld\n", v_regset_hdr->vlenb);
+ vctx = realloc(data, size + v_regset_hdr->vlenb * 32);
+ if (!vctx)
+ goto out;
+ data = vctx;
+
+ v_regset_hdr = (struct __riscv_v_regset_state *)data;
+ v31 = (void *)(data + size + v_regset_hdr->vlenb * 31);
+ size += v_regset_hdr->vlenb * 32;
+
+ if (do_ptrace(PTRACE_GETREGSET, child, NT_RISCV_VECTOR, size, data))
+ goto out;
+
+ ksft_test_result(*(int *)v31 == -1, "GETREGSET vector at syscall stop\n");
+
+ *(int *)v31 = parent_set_val;
+ if (do_ptrace(PTRACE_SETREGSET, child, NT_RISCV_VECTOR, size, data))
+ goto out;
+ }
+ ptrace(PTRACE_CONT, child, NULL, NULL);
+ }
+
+out:
+ free(data);
+}
+
int main(void)
{
pid_t child;
- ksft_set_plan(2);
+ ksft_set_plan(4);
if (!is_vector_supported() && !is_xtheadvector_supported())
ksft_exit_skip("Vector not supported\n");
@@ -130,5 +221,17 @@ int main(void)
do_parent(child);
+ parent_set_val = 0x53355457;
+ child_set_val = 0x49504F21;
+
+ child = fork();
+ if (child < 0)
+ ksft_exit_fail_msg("Fork failed %d\n", child);
+
+ if (!child)
+ return do_child_syscall_stop();
+
+ do_parent_syscall_stop(child);
+
ksft_finished();
}
--
2.43.0
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v7 4/6] selftests: riscv: Extend vector tests for sigreturn and ptrace
@ 2026-11-11 18:43 ` Andy Chiu
0 siblings, 0 replies; 20+ messages in thread
From: Andy Chiu @ 2026-11-11 18:43 UTC (permalink / raw)
To: Shuah Khan, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, linux-kselftest, linux-riscv
Cc: andybnac, Andy Chiu, dfustini, greentime.hu, Andrew Morton,
Bala-Vignesh-Reddy, Wei Yang, Yong-Xuan Wang
Add new test cases to verify the vector state restorations at syscall
stops for ptrace and signal interfaces. Specifically:
1. Signal handler should read all ones at syscall stop and modifying
context should success.
2. Ptrace should read all ones but any modification to NT_RISCV_VECTOR
is silently dropped.
Signed-off-by: Andy Chiu <tchiu@tenstorrent.com>
---
Changelog v4:
- remove timer dependency from the signal delivery (Sashiko)
- solve 2 memory leaks in ptrace (Sashiko)
Changelog v3:
- new patch since v3
---
.../selftests/riscv/sigreturn/sigreturn.c | 71 +++++++++++
.../selftests/riscv/vector/vstate_ptrace.c | 111 +++++++++++++++++-
2 files changed, 178 insertions(+), 4 deletions(-)
diff --git a/tools/testing/selftests/riscv/sigreturn/sigreturn.c b/tools/testing/selftests/riscv/sigreturn/sigreturn.c
index e10873d95fed..647249dbd7e6 100644
--- a/tools/testing/selftests/riscv/sigreturn/sigreturn.c
+++ b/tools/testing/selftests/riscv/sigreturn/sigreturn.c
@@ -7,6 +7,7 @@
#include "kselftest_harness.h"
#define RISCV_V_MAGIC 0x53465457
+#define END_MAGIC 0
#define DEFAULT_VALUE 2
#define SIGNAL_HANDLER_OVERRIDE 3
@@ -61,6 +62,76 @@ static int vector_sigreturn(int data, void (*handler)(int, siginfo_t *, void *))
return after_sigreturn;
}
+#define V_TEST_PATTERN_SIGNAL 0x98
+int nulled_val;
+static void sigalrm_handler(int sig, siginfo_t *info, void *vcontext)
+{
+ ucontext_t *context = vcontext;
+ struct __riscv_extra_ext_header *ext;
+ struct __riscv_ctx_hdr *hdr;
+ uint8_t *ext_ptr;
+
+ /* Find the vector context */
+ ext = (void *)(&context->uc_mcontext.__fpregs);
+ ext_ptr = (uint8_t *)ext;
+ hdr = &ext->hdr;
+
+ while (hdr->magic != END_MAGIC) {
+ if (hdr->magic == RISCV_V_MAGIC) {
+ struct __riscv_v_ext_state *v_state = (struct __riscv_v_ext_state *)(hdr + 1);
+ /* Assume a valid datap */
+ nulled_val = *(int *)v_state->datap;
+ /* Fill all vector registers with magic pattern */
+ memset(v_state->datap, V_TEST_PATTERN_SIGNAL, v_state->vlenb * 32);
+ /*
+ * We must also set the vector configuration so that when
+ * userspace reads v0, it uses a valid element width (e8).
+ */
+ v_state->vl = v_state->vlenb;
+ v_state->vtype = 0; /* e8, m1, tu, mu */
+ break;
+ }
+ /* Move to the next extension header */
+ ext_ptr += hdr->size;
+ hdr = (struct __riscv_ctx_hdr *)ext_ptr;
+ }
+}
+
+TEST(test_signal_syscall_ucontext) {
+ struct sigaction sa;
+
+ /* Make sure we get V in ucontext by executing vsetvli */
+ asm volatile (
+ ".option push\n\t"
+ ".option arch, +v\n\t"
+ "vsetivli x0, 1, e32, m1, ta, ma\n\t"
+ ".option pop\n\t" : : :);
+
+ sa.sa_flags = SA_SIGINFO;
+ sa.sa_sigaction = sigalrm_handler;
+ sigemptyset(&sa.sa_mask);
+ if (sigaction(SIGALRM, &sa, NULL) == -1)
+ ksft_exit_fail_msg("Failed to register signal handler\n");
+
+ raise(SIGALRM);
+ /*
+ * If the kernel successfully parsed and restored our modified ucontext,
+ * v0 will contain V_TEST_PATTERN_SIGNAL.
+ */
+ unsigned char v0_val;
+
+ asm volatile(
+ ".option push\n\t"
+ ".option arch, +zve32x\n\t"
+ "vmv.x.s %0, v0\n\t"
+ ".option pop\n\t"
+ : "=r" (v0_val)
+ );
+
+ EXPECT_EQ(v0_val, V_TEST_PATTERN_SIGNAL);
+ EXPECT_EQ(nulled_val, -1);
+}
+
TEST(vector_restore)
{
int result;
diff --git a/tools/testing/selftests/riscv/vector/vstate_ptrace.c b/tools/testing/selftests/riscv/vector/vstate_ptrace.c
index 1479abc0c9cb..863a16f6e1a3 100644
--- a/tools/testing/selftests/riscv/vector/vstate_ptrace.c
+++ b/tools/testing/selftests/riscv/vector/vstate_ptrace.c
@@ -21,6 +21,41 @@ static long do_ptrace(enum __ptrace_request op, pid_t pid, long type, size_t siz
return ptrace(op, pid, type, &v_iovec);
}
+static int do_child_syscall_stop(void)
+{
+ int out;
+
+ if (ptrace(PTRACE_TRACEME, -1, NULL, NULL)) {
+ ksft_perror("PTRACE_TRACEME failed\n");
+ return EXIT_FAILURE;
+ }
+
+ raise(SIGSTOP);
+
+ asm volatile (".option push\n\t"
+ ".option arch, +v\n\t"
+ "vsetivli x0, 1, e32, m1, ta, ma\n\t"
+ "vmv.s.x v31, %[in]\n\t"
+ ".option pop\n\t"
+ :
+ : [in] "r" (child_set_val));
+
+ getpid();
+
+ asm volatile (".option push\n\t"
+ ".option arch, +v\n\t"
+ "vsetivli x0, 1, e32, m1, ta, ma\n\t"
+ "vmv.x.s %[out], v31\n\t"
+ ".option pop\n\t"
+ : [out] "=r" (out)
+ :);
+
+ if (out != -1)
+ return EXIT_FAILURE;
+
+ return EXIT_SUCCESS;
+}
+
static int do_child(void)
{
int out;
@@ -59,7 +94,7 @@ static void do_parent(pid_t child)
goto out;
} else if (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGTRAP)) {
size_t size;
- void *data, *v31;
+ void *vctx, *v31;
struct __riscv_v_regset_state *v_regset_hdr;
struct user_regs_struct *gpreg;
@@ -73,9 +108,11 @@ static void do_parent(pid_t child)
goto out;
ksft_print_msg("vlenb %ld\n", v_regset_hdr->vlenb);
- data = realloc(data, size + v_regset_hdr->vlenb * 32);
- if (!data)
+ vctx = realloc(data, size + v_regset_hdr->vlenb * 32);
+ if (!vctx)
goto out;
+ data = vctx;
+
v_regset_hdr = (struct __riscv_v_regset_state *)data;
v31 = (void *)(data + size + v_regset_hdr->vlenb * 31);
size += v_regset_hdr->vlenb * 32;
@@ -109,11 +146,65 @@ static void do_parent(pid_t child)
free(data);
}
+static void do_parent_syscall_stop(pid_t child)
+{
+ int status;
+ void *data = NULL;
+
+ while (waitpid(child, &status, 0)) {
+ if (WIFEXITED(status)) {
+ ksft_test_result(WEXITSTATUS(status) == 0,
+ "SETREGSET vector at syscall stop\n");
+ goto out;
+ } else if (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGSTOP)) {
+ /* Attach to the child at syscall stop */
+ ptrace(PTRACE_SYSCALL, child, NULL, NULL);
+ continue;
+ } else if (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGTRAP)) {
+ size_t size;
+ void *vctx, *v31;
+ struct __riscv_v_regset_state *v_regset_hdr;
+
+ size = sizeof(*v_regset_hdr);
+ data = malloc(size);
+ if (!data)
+ goto out;
+ v_regset_hdr = (struct __riscv_v_regset_state *)data;
+
+ if (do_ptrace(PTRACE_GETREGSET, child, NT_RISCV_VECTOR, size, data))
+ goto out;
+
+ ksft_print_msg("vlenb %ld\n", v_regset_hdr->vlenb);
+ vctx = realloc(data, size + v_regset_hdr->vlenb * 32);
+ if (!vctx)
+ goto out;
+ data = vctx;
+
+ v_regset_hdr = (struct __riscv_v_regset_state *)data;
+ v31 = (void *)(data + size + v_regset_hdr->vlenb * 31);
+ size += v_regset_hdr->vlenb * 32;
+
+ if (do_ptrace(PTRACE_GETREGSET, child, NT_RISCV_VECTOR, size, data))
+ goto out;
+
+ ksft_test_result(*(int *)v31 == -1, "GETREGSET vector at syscall stop\n");
+
+ *(int *)v31 = parent_set_val;
+ if (do_ptrace(PTRACE_SETREGSET, child, NT_RISCV_VECTOR, size, data))
+ goto out;
+ }
+ ptrace(PTRACE_CONT, child, NULL, NULL);
+ }
+
+out:
+ free(data);
+}
+
int main(void)
{
pid_t child;
- ksft_set_plan(2);
+ ksft_set_plan(4);
if (!is_vector_supported() && !is_xtheadvector_supported())
ksft_exit_skip("Vector not supported\n");
@@ -130,5 +221,17 @@ int main(void)
do_parent(child);
+ parent_set_val = 0x53355457;
+ child_set_val = 0x49504F21;
+
+ child = fork();
+ if (child < 0)
+ ksft_exit_fail_msg("Fork failed %d\n", child);
+
+ if (!child)
+ return do_child_syscall_stop();
+
+ do_parent_syscall_stop(child);
+
ksft_finished();
}
--
2.43.0
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v7 5/6] riscv: vector: optimize vstate operations
2026-11-11 18:43 ` Andy Chiu
@ 2026-11-11 18:43 ` Andy Chiu
-1 siblings, 0 replies; 20+ messages in thread
From: Andy Chiu @ 2026-11-11 18:43 UTC (permalink / raw)
To: Jonathan Corbet, Shuah Khan, Randy Dunlap, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, linux-doc,
linux-riscv
Cc: andybnac, Andy Chiu, dfustini, greentime.hu,
Mike Rapoport (Microsoft), Arnd Bergmann, Karl Mehltretter,
Borislav Petkov (AMD), Dapeng Mi, Marco Elver, Ethan Nelson-Moore,
Jeff Layton, Jisheng Zhang, Conor Dooley, Yong-Xuan Wang,
Anup Patel, Aurelien Jarno, daichengrong, Troy Mitchell,
Guobin Zhang, Guodong Xu, Andrew Jones, Charlie Jenkins,
Atish Patra, Deepak Gupta, Hui Wang, Pincheng Wang, Zong Li,
Vivian Wang, Rui Qi, Yunhui Cui, Samuel Holland, Zishun Yi,
Sergey Matyukevich
Introduce the riscv_novstateopt to control the optimization of vector
state operations in the kernel space.
The optimization enables vector in kernel mode and bypasses vector
register nulling for user space on the syscall fast path when the boot
argument "riscv_novstateopt" is not set
Enabling this optimization yields the following performance benefits:
- Cut 80 cycles latency for getpid on Ascalon.
- 1.1% ~ 4.09% request throughput improvment on nginx workload with web
serving size under 4KB
Signed-off-by: Andy Chiu <tchiu@tenstorrent.com>
---
Changelog v6:
- upgrade it to use alternative and change default to enable the
optimization
Changelog v5:
- new patch since v5
---
.../admin-guide/kernel-parameters.txt | 13 +++++++++++++
arch/riscv/include/asm/alternative-macros.h | 6 ++++++
arch/riscv/include/asm/alternative.h | 3 ---
arch/riscv/include/asm/cpufeature-macros.h | 6 ++++--
arch/riscv/include/asm/vector.h | 16 +++++++++++++++-
arch/riscv/kernel/cpufeature.c | 18 ++++++++++++++++++
arch/riscv/kernel/entry.S | 15 +++++++++++++--
arch/riscv/kernel/process.c | 3 +++
arch/riscv/kernel/vector.c | 17 +++++++++++++++--
9 files changed, 87 insertions(+), 10 deletions(-)
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 0b3c140babd9..e1146ee6ab1e 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -6722,6 +6722,19 @@ Kernel parameters
fcfi Disable user forward CFI ABI to userspace even if the
landing pad extension is available.
+ riscv_novstateopt [RISCV,EARLY]
+ Disable the vector state optimization. By default the
+ kernel keeps Vector enabled while running in kernel
+ space, rather than toggling sstatus.VS on every use of
+ the kernel-mode vector, and skips nulling the vector
+ registers for user space. Pass this option to restore the
+ conservative behavior, which catches illegal use of
+ Vector in kernel code. The optimization roughly cuts
+ 30 ns of getpid() latency on a Blackhole x280 and gives
+ a 4.09% request throughput improvement for an nginx
+ workload serving a 2KB web page on a four-core
+ Ascalon-S.
+
ro [KNL] Mount root device read-only on boot
rodata= [KNL,EARLY]
diff --git a/arch/riscv/include/asm/alternative-macros.h b/arch/riscv/include/asm/alternative-macros.h
index 629d884578da..45d9ae1e0aa8 100644
--- a/arch/riscv/include/asm/alternative-macros.h
+++ b/arch/riscv/include/asm/alternative-macros.h
@@ -2,6 +2,12 @@
#ifndef __ASM_ALTERNATIVE_MACROS_H
#define __ASM_ALTERNATIVE_MACROS_H
+#include <linux/wordpart.h>
+#define PATCH_ID_CPUFEATURE_ID(p) lower_16_bits(p)
+#define PATCH_ID_CPUFEATURE_VALUE(p) upper_16_bits(p)
+
+#define RISCV_CPUFEAT_VSTATEOPT 0x1
+
#ifdef __ASSEMBLER__
.macro ALT_ENTRY oldptr newptr vendor_id patch_id new_len
diff --git a/arch/riscv/include/asm/alternative.h b/arch/riscv/include/asm/alternative.h
index 6be7b2b6ade9..bc2ecaa9125a 100644
--- a/arch/riscv/include/asm/alternative.h
+++ b/arch/riscv/include/asm/alternative.h
@@ -16,9 +16,6 @@
#include <linux/stddef.h>
#include <asm/hwcap.h>
-#define PATCH_ID_CPUFEATURE_ID(p) lower_16_bits(p)
-#define PATCH_ID_CPUFEATURE_VALUE(p) upper_16_bits(p)
-
#define RISCV_ALTERNATIVES_BOOT 0 /* alternatives applied during regular boot */
#define RISCV_ALTERNATIVES_MODULE 1 /* alternatives applied during module-init */
#define RISCV_ALTERNATIVES_EARLY_BOOT 2 /* alternatives applied before mmu start */
diff --git a/arch/riscv/include/asm/cpufeature-macros.h b/arch/riscv/include/asm/cpufeature-macros.h
index adaf9e3fb25c..7bd900899bb0 100644
--- a/arch/riscv/include/asm/cpufeature-macros.h
+++ b/arch/riscv/include/asm/cpufeature-macros.h
@@ -45,14 +45,16 @@ static __always_inline bool __riscv_has_extension_unlikely(const unsigned long v
static __always_inline bool riscv_has_extension_unlikely(const unsigned long ext)
{
- compiletime_assert(ext < RISCV_ISA_EXT_MAX, "ext must be < RISCV_ISA_EXT_MAX");
+ int realext = PATCH_ID_CPUFEATURE_ID(ext);
+ compiletime_assert(realext < RISCV_ISA_EXT_MAX, "ext must be < RISCV_ISA_EXT_MAX");
return __riscv_has_extension_unlikely(STANDARD_EXT, ext);
}
static __always_inline bool riscv_has_extension_likely(const unsigned long ext)
{
- compiletime_assert(ext < RISCV_ISA_EXT_MAX, "ext must be < RISCV_ISA_EXT_MAX");
+ int realext = PATCH_ID_CPUFEATURE_ID(ext);
+ compiletime_assert(realext < RISCV_ISA_EXT_MAX, "ext must be < RISCV_ISA_EXT_MAX");
return __riscv_has_extension_likely(STANDARD_EXT, ext);
}
diff --git a/arch/riscv/include/asm/vector.h b/arch/riscv/include/asm/vector.h
index e83f9e0046a9..745ac3ca67b7 100644
--- a/arch/riscv/include/asm/vector.h
+++ b/arch/riscv/include/asm/vector.h
@@ -49,6 +49,7 @@
_res; \
})
+extern bool riscv_v_vstate_opt;
extern unsigned long riscv_v_vsize;
int riscv_v_setup_vsize(void);
bool insn_is_vector(u32 insn_buf);
@@ -78,6 +79,11 @@ static __always_inline bool has_vector(void)
return riscv_has_extension_unlikely(RISCV_ISA_EXT_ZVE32X);
}
+static __always_inline bool has_vstate_opt(void)
+{
+ return riscv_has_extension_likely((RISCV_CPUFEAT_VSTATEOPT << 16) | RISCV_ISA_EXT_ZVE32X);
+}
+
static __always_inline bool has_xtheadvector_no_alternatives(void)
{
if (IS_ENABLED(CONFIG_RISCV_ISA_XTHEADVECTOR))
@@ -122,6 +128,9 @@ static inline bool riscv_v_vstate_query(struct pt_regs *regs)
static __always_inline void riscv_v_enable(void)
{
+ if (has_vstate_opt())
+ return;
+
if (has_xtheadvector())
csr_set(CSR_SSTATUS, SR_VS_THEAD);
else
@@ -130,6 +139,9 @@ static __always_inline void riscv_v_enable(void)
static __always_inline void riscv_v_disable(void)
{
+ if (has_vstate_opt())
+ return;
+
if (has_xtheadvector())
csr_clear(CSR_SSTATUS, SR_VS_THEAD);
else
@@ -336,7 +348,8 @@ static inline void riscv_v_vstate_set_restore(struct task_struct *task,
static inline void riscv_v_vstate_discard(struct pt_regs *regs)
{
if (__riscv_v_vstate_check_gt(regs->status, INITIAL)) {
- riscv_v_vstate_set_restore(current, regs);
+ if (!has_vstate_opt())
+ riscv_v_vstate_set_restore(current, regs);
riscv_v_vstate_init(regs);
}
}
@@ -422,6 +435,7 @@ struct pt_regs;
static inline int riscv_v_setup_vsize(void) { return -EOPNOTSUPP; }
static __always_inline bool has_vector(void) { return false; }
+static __always_inline bool has_vstate_opt(void) { return false; }
static __always_inline bool insn_is_vector(u32 insn_buf) { return false; }
static __always_inline bool has_xtheadvector_no_alternatives(void) { return false; }
static __always_inline bool has_xtheadvector(void) { return false; }
diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
index 72bce616491f..041f6a35fba3 100644
--- a/arch/riscv/kernel/cpufeature.c
+++ b/arch/riscv/kernel/cpufeature.c
@@ -1294,6 +1294,19 @@ void riscv_clear_hypervisor_csr(void)
csr_clear(CSR_HSTATUS, HSTATUS_HU);
}
+/*
+ * Leaving Vector enabled while in the kernel relies on the vstate alternatives
+ * being patched in. It can be turned off on the command line to catch illegal
+ * use of Vector in kernel code.
+ */
+bool riscv_v_vstate_opt = true;
+static int __init riscv_novstateopt_setup(char *__unused)
+{
+ riscv_v_vstate_opt = false;
+ return 0;
+}
+early_param("riscv_novstateopt", riscv_novstateopt_setup);
+
/*
* Alternative patch sites consider 48 bits when determining when to patch
* the old instruction sequence with the new. These bits are broken into a
@@ -1322,6 +1335,11 @@ static bool riscv_cpufeature_patch_check(u16 id, u16 value)
* then the alternative cannot be applied.
*/
return riscv_cboz_block_size <= (1U << value);
+ case RISCV_ISA_EXT_ZVE32X:
+ if (value == RISCV_CPUFEAT_VSTATEOPT)
+ return riscv_v_vstate_opt;
+
+ return true;
}
return false;
diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S
index 628b85e3915a..bb4787711f2c 100644
--- a/arch/riscv/kernel/entry.S
+++ b/arch/riscv/kernel/entry.S
@@ -6,6 +6,7 @@
#include <linux/init.h>
#include <linux/linkage.h>
+#include <linux/stringify.h>
#include <asm/alternative-macros.h>
#include <asm/asm.h>
@@ -175,10 +176,13 @@ SYM_CODE_START(handle_exception)
* Disable user-mode memory access as it should only be set in the
* actual user copy routines.
*
- * Disable the FPU/Vector to detect illegal usage of floating point
+ * Disable the FPU to detect illegal usage of floating point
* or vector in kernel space.
*/
- li t0, SR_SUM | SR_FS_VS
+ li t0, SR_SUM | SR_FS
+ ALTERNATIVE(__stringify(ori t0, t0, SR_VS), "nop", 0,
+ (RISCV_CPUFEAT_VSTATEOPT << 16) | RISCV_ISA_EXT_ZVE32X,
+ CONFIG_RISCV_ISA_V)
#ifdef CONFIG_64BIT
li t1, SR_ELP
or t0, t0, t1
@@ -186,6 +190,13 @@ SYM_CODE_START(handle_exception)
REG_L s0, TASK_TI_USER_SP(tp)
csrrc s1, CSR_STATUS, t0
+ ALTERNATIVE("j .Lskip_v_enable", __stringify(andi t0, s1, SR_VS), 0,
+ (RISCV_CPUFEAT_VSTATEOPT << 16) | RISCV_ISA_EXT_ZVE32X,
+ CONFIG_RISCV_ISA_V)
+ bnez t0, .Lskip_v_enable
+ li a0, SR_VS_INITIAL
+ csrs CSR_STATUS, a0
+.Lskip_v_enable:
save_userssp s2, s1
csrr s2, CSR_EPC
csrr s3, CSR_TVAL
diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c
index 34c1d498d1ca..27146b3fa738 100644
--- a/arch/riscv/kernel/process.c
+++ b/arch/riscv/kernel/process.c
@@ -258,6 +258,9 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
/* Supervisor/Machine, irqs on: */
childregs->status = SR_PP | SR_PIE;
+ if (has_vstate_opt())
+ riscv_v_vstate_init(childregs);
+
p->thread.s[0] = (unsigned long)args->fn;
p->thread.s[1] = (unsigned long)args->fn_arg;
p->thread.ra = (unsigned long)ret_from_fork_kernel_asm;
diff --git a/arch/riscv/kernel/vector.c b/arch/riscv/kernel/vector.c
index 6fd541f5d5cb..eec9deff8da7 100644
--- a/arch/riscv/kernel/vector.c
+++ b/arch/riscv/kernel/vector.c
@@ -12,6 +12,7 @@
#include <linux/prctl.h>
#include <asm/thread_info.h>
+#include <asm/cpufeature.h>
#include <asm/processor.h>
#include <asm/insn.h>
#include <asm/vector.h>
@@ -69,6 +70,16 @@ void riscv_v_ucontext_save(struct task_struct *tsk)
int riscv_v_setup_vsize(void)
{
unsigned long this_vsize;
+ bool v_always_on = false;
+
+ /*
+ * has_vstate_opt() cannot be used here if called from riscv_fill_hwcap(), before
+ * apply_boot_alternatives(),
+ */
+ if (__riscv_isa_extension_available(NULL, RISCV_ISA_EXT_ZVE32X) && riscv_v_vstate_opt) {
+ v_always_on = true;
+ csr_set(CSR_SSTATUS, SR_VS_INITIAL);
+ }
/*
* There are 32 vector registers with vlenb length.
@@ -81,9 +92,11 @@ int riscv_v_setup_vsize(void)
return 0;
}
- riscv_v_enable();
+ if (!v_always_on)
+ riscv_v_enable();
this_vsize = csr_read(CSR_VLENB) * 32;
- riscv_v_disable();
+ if (!v_always_on)
+ riscv_v_disable();
if (!riscv_v_vsize) {
riscv_v_vsize = this_vsize;
--
2.43.0
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v7 5/6] riscv: vector: optimize vstate operations
@ 2026-11-11 18:43 ` Andy Chiu
0 siblings, 0 replies; 20+ messages in thread
From: Andy Chiu @ 2026-11-11 18:43 UTC (permalink / raw)
To: Jonathan Corbet, Shuah Khan, Randy Dunlap, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, linux-doc,
linux-riscv
Cc: andybnac, Andy Chiu, dfustini, greentime.hu,
Mike Rapoport (Microsoft), Arnd Bergmann, Karl Mehltretter,
Borislav Petkov (AMD), Dapeng Mi, Marco Elver, Ethan Nelson-Moore,
Jeff Layton, Jisheng Zhang, Conor Dooley, Yong-Xuan Wang,
Anup Patel, Aurelien Jarno, daichengrong, Troy Mitchell,
Guobin Zhang, Guodong Xu, Andrew Jones, Charlie Jenkins,
Atish Patra, Deepak Gupta, Hui Wang, Pincheng Wang, Zong Li,
Vivian Wang, Rui Qi, Yunhui Cui, Samuel Holland, Zishun Yi,
Sergey Matyukevich
Introduce the riscv_novstateopt to control the optimization of vector
state operations in the kernel space.
The optimization enables vector in kernel mode and bypasses vector
register nulling for user space on the syscall fast path when the boot
argument "riscv_novstateopt" is not set
Enabling this optimization yields the following performance benefits:
- Cut 80 cycles latency for getpid on Ascalon.
- 1.1% ~ 4.09% request throughput improvment on nginx workload with web
serving size under 4KB
Signed-off-by: Andy Chiu <tchiu@tenstorrent.com>
---
Changelog v6:
- upgrade it to use alternative and change default to enable the
optimization
Changelog v5:
- new patch since v5
---
.../admin-guide/kernel-parameters.txt | 13 +++++++++++++
arch/riscv/include/asm/alternative-macros.h | 6 ++++++
arch/riscv/include/asm/alternative.h | 3 ---
arch/riscv/include/asm/cpufeature-macros.h | 6 ++++--
arch/riscv/include/asm/vector.h | 16 +++++++++++++++-
arch/riscv/kernel/cpufeature.c | 18 ++++++++++++++++++
arch/riscv/kernel/entry.S | 15 +++++++++++++--
arch/riscv/kernel/process.c | 3 +++
arch/riscv/kernel/vector.c | 17 +++++++++++++++--
9 files changed, 87 insertions(+), 10 deletions(-)
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 0b3c140babd9..e1146ee6ab1e 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -6722,6 +6722,19 @@ Kernel parameters
fcfi Disable user forward CFI ABI to userspace even if the
landing pad extension is available.
+ riscv_novstateopt [RISCV,EARLY]
+ Disable the vector state optimization. By default the
+ kernel keeps Vector enabled while running in kernel
+ space, rather than toggling sstatus.VS on every use of
+ the kernel-mode vector, and skips nulling the vector
+ registers for user space. Pass this option to restore the
+ conservative behavior, which catches illegal use of
+ Vector in kernel code. The optimization roughly cuts
+ 30 ns of getpid() latency on a Blackhole x280 and gives
+ a 4.09% request throughput improvement for an nginx
+ workload serving a 2KB web page on a four-core
+ Ascalon-S.
+
ro [KNL] Mount root device read-only on boot
rodata= [KNL,EARLY]
diff --git a/arch/riscv/include/asm/alternative-macros.h b/arch/riscv/include/asm/alternative-macros.h
index 629d884578da..45d9ae1e0aa8 100644
--- a/arch/riscv/include/asm/alternative-macros.h
+++ b/arch/riscv/include/asm/alternative-macros.h
@@ -2,6 +2,12 @@
#ifndef __ASM_ALTERNATIVE_MACROS_H
#define __ASM_ALTERNATIVE_MACROS_H
+#include <linux/wordpart.h>
+#define PATCH_ID_CPUFEATURE_ID(p) lower_16_bits(p)
+#define PATCH_ID_CPUFEATURE_VALUE(p) upper_16_bits(p)
+
+#define RISCV_CPUFEAT_VSTATEOPT 0x1
+
#ifdef __ASSEMBLER__
.macro ALT_ENTRY oldptr newptr vendor_id patch_id new_len
diff --git a/arch/riscv/include/asm/alternative.h b/arch/riscv/include/asm/alternative.h
index 6be7b2b6ade9..bc2ecaa9125a 100644
--- a/arch/riscv/include/asm/alternative.h
+++ b/arch/riscv/include/asm/alternative.h
@@ -16,9 +16,6 @@
#include <linux/stddef.h>
#include <asm/hwcap.h>
-#define PATCH_ID_CPUFEATURE_ID(p) lower_16_bits(p)
-#define PATCH_ID_CPUFEATURE_VALUE(p) upper_16_bits(p)
-
#define RISCV_ALTERNATIVES_BOOT 0 /* alternatives applied during regular boot */
#define RISCV_ALTERNATIVES_MODULE 1 /* alternatives applied during module-init */
#define RISCV_ALTERNATIVES_EARLY_BOOT 2 /* alternatives applied before mmu start */
diff --git a/arch/riscv/include/asm/cpufeature-macros.h b/arch/riscv/include/asm/cpufeature-macros.h
index adaf9e3fb25c..7bd900899bb0 100644
--- a/arch/riscv/include/asm/cpufeature-macros.h
+++ b/arch/riscv/include/asm/cpufeature-macros.h
@@ -45,14 +45,16 @@ static __always_inline bool __riscv_has_extension_unlikely(const unsigned long v
static __always_inline bool riscv_has_extension_unlikely(const unsigned long ext)
{
- compiletime_assert(ext < RISCV_ISA_EXT_MAX, "ext must be < RISCV_ISA_EXT_MAX");
+ int realext = PATCH_ID_CPUFEATURE_ID(ext);
+ compiletime_assert(realext < RISCV_ISA_EXT_MAX, "ext must be < RISCV_ISA_EXT_MAX");
return __riscv_has_extension_unlikely(STANDARD_EXT, ext);
}
static __always_inline bool riscv_has_extension_likely(const unsigned long ext)
{
- compiletime_assert(ext < RISCV_ISA_EXT_MAX, "ext must be < RISCV_ISA_EXT_MAX");
+ int realext = PATCH_ID_CPUFEATURE_ID(ext);
+ compiletime_assert(realext < RISCV_ISA_EXT_MAX, "ext must be < RISCV_ISA_EXT_MAX");
return __riscv_has_extension_likely(STANDARD_EXT, ext);
}
diff --git a/arch/riscv/include/asm/vector.h b/arch/riscv/include/asm/vector.h
index e83f9e0046a9..745ac3ca67b7 100644
--- a/arch/riscv/include/asm/vector.h
+++ b/arch/riscv/include/asm/vector.h
@@ -49,6 +49,7 @@
_res; \
})
+extern bool riscv_v_vstate_opt;
extern unsigned long riscv_v_vsize;
int riscv_v_setup_vsize(void);
bool insn_is_vector(u32 insn_buf);
@@ -78,6 +79,11 @@ static __always_inline bool has_vector(void)
return riscv_has_extension_unlikely(RISCV_ISA_EXT_ZVE32X);
}
+static __always_inline bool has_vstate_opt(void)
+{
+ return riscv_has_extension_likely((RISCV_CPUFEAT_VSTATEOPT << 16) | RISCV_ISA_EXT_ZVE32X);
+}
+
static __always_inline bool has_xtheadvector_no_alternatives(void)
{
if (IS_ENABLED(CONFIG_RISCV_ISA_XTHEADVECTOR))
@@ -122,6 +128,9 @@ static inline bool riscv_v_vstate_query(struct pt_regs *regs)
static __always_inline void riscv_v_enable(void)
{
+ if (has_vstate_opt())
+ return;
+
if (has_xtheadvector())
csr_set(CSR_SSTATUS, SR_VS_THEAD);
else
@@ -130,6 +139,9 @@ static __always_inline void riscv_v_enable(void)
static __always_inline void riscv_v_disable(void)
{
+ if (has_vstate_opt())
+ return;
+
if (has_xtheadvector())
csr_clear(CSR_SSTATUS, SR_VS_THEAD);
else
@@ -336,7 +348,8 @@ static inline void riscv_v_vstate_set_restore(struct task_struct *task,
static inline void riscv_v_vstate_discard(struct pt_regs *regs)
{
if (__riscv_v_vstate_check_gt(regs->status, INITIAL)) {
- riscv_v_vstate_set_restore(current, regs);
+ if (!has_vstate_opt())
+ riscv_v_vstate_set_restore(current, regs);
riscv_v_vstate_init(regs);
}
}
@@ -422,6 +435,7 @@ struct pt_regs;
static inline int riscv_v_setup_vsize(void) { return -EOPNOTSUPP; }
static __always_inline bool has_vector(void) { return false; }
+static __always_inline bool has_vstate_opt(void) { return false; }
static __always_inline bool insn_is_vector(u32 insn_buf) { return false; }
static __always_inline bool has_xtheadvector_no_alternatives(void) { return false; }
static __always_inline bool has_xtheadvector(void) { return false; }
diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
index 72bce616491f..041f6a35fba3 100644
--- a/arch/riscv/kernel/cpufeature.c
+++ b/arch/riscv/kernel/cpufeature.c
@@ -1294,6 +1294,19 @@ void riscv_clear_hypervisor_csr(void)
csr_clear(CSR_HSTATUS, HSTATUS_HU);
}
+/*
+ * Leaving Vector enabled while in the kernel relies on the vstate alternatives
+ * being patched in. It can be turned off on the command line to catch illegal
+ * use of Vector in kernel code.
+ */
+bool riscv_v_vstate_opt = true;
+static int __init riscv_novstateopt_setup(char *__unused)
+{
+ riscv_v_vstate_opt = false;
+ return 0;
+}
+early_param("riscv_novstateopt", riscv_novstateopt_setup);
+
/*
* Alternative patch sites consider 48 bits when determining when to patch
* the old instruction sequence with the new. These bits are broken into a
@@ -1322,6 +1335,11 @@ static bool riscv_cpufeature_patch_check(u16 id, u16 value)
* then the alternative cannot be applied.
*/
return riscv_cboz_block_size <= (1U << value);
+ case RISCV_ISA_EXT_ZVE32X:
+ if (value == RISCV_CPUFEAT_VSTATEOPT)
+ return riscv_v_vstate_opt;
+
+ return true;
}
return false;
diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S
index 628b85e3915a..bb4787711f2c 100644
--- a/arch/riscv/kernel/entry.S
+++ b/arch/riscv/kernel/entry.S
@@ -6,6 +6,7 @@
#include <linux/init.h>
#include <linux/linkage.h>
+#include <linux/stringify.h>
#include <asm/alternative-macros.h>
#include <asm/asm.h>
@@ -175,10 +176,13 @@ SYM_CODE_START(handle_exception)
* Disable user-mode memory access as it should only be set in the
* actual user copy routines.
*
- * Disable the FPU/Vector to detect illegal usage of floating point
+ * Disable the FPU to detect illegal usage of floating point
* or vector in kernel space.
*/
- li t0, SR_SUM | SR_FS_VS
+ li t0, SR_SUM | SR_FS
+ ALTERNATIVE(__stringify(ori t0, t0, SR_VS), "nop", 0,
+ (RISCV_CPUFEAT_VSTATEOPT << 16) | RISCV_ISA_EXT_ZVE32X,
+ CONFIG_RISCV_ISA_V)
#ifdef CONFIG_64BIT
li t1, SR_ELP
or t0, t0, t1
@@ -186,6 +190,13 @@ SYM_CODE_START(handle_exception)
REG_L s0, TASK_TI_USER_SP(tp)
csrrc s1, CSR_STATUS, t0
+ ALTERNATIVE("j .Lskip_v_enable", __stringify(andi t0, s1, SR_VS), 0,
+ (RISCV_CPUFEAT_VSTATEOPT << 16) | RISCV_ISA_EXT_ZVE32X,
+ CONFIG_RISCV_ISA_V)
+ bnez t0, .Lskip_v_enable
+ li a0, SR_VS_INITIAL
+ csrs CSR_STATUS, a0
+.Lskip_v_enable:
save_userssp s2, s1
csrr s2, CSR_EPC
csrr s3, CSR_TVAL
diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c
index 34c1d498d1ca..27146b3fa738 100644
--- a/arch/riscv/kernel/process.c
+++ b/arch/riscv/kernel/process.c
@@ -258,6 +258,9 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
/* Supervisor/Machine, irqs on: */
childregs->status = SR_PP | SR_PIE;
+ if (has_vstate_opt())
+ riscv_v_vstate_init(childregs);
+
p->thread.s[0] = (unsigned long)args->fn;
p->thread.s[1] = (unsigned long)args->fn_arg;
p->thread.ra = (unsigned long)ret_from_fork_kernel_asm;
diff --git a/arch/riscv/kernel/vector.c b/arch/riscv/kernel/vector.c
index 6fd541f5d5cb..eec9deff8da7 100644
--- a/arch/riscv/kernel/vector.c
+++ b/arch/riscv/kernel/vector.c
@@ -12,6 +12,7 @@
#include <linux/prctl.h>
#include <asm/thread_info.h>
+#include <asm/cpufeature.h>
#include <asm/processor.h>
#include <asm/insn.h>
#include <asm/vector.h>
@@ -69,6 +70,16 @@ void riscv_v_ucontext_save(struct task_struct *tsk)
int riscv_v_setup_vsize(void)
{
unsigned long this_vsize;
+ bool v_always_on = false;
+
+ /*
+ * has_vstate_opt() cannot be used here if called from riscv_fill_hwcap(), before
+ * apply_boot_alternatives(),
+ */
+ if (__riscv_isa_extension_available(NULL, RISCV_ISA_EXT_ZVE32X) && riscv_v_vstate_opt) {
+ v_always_on = true;
+ csr_set(CSR_SSTATUS, SR_VS_INITIAL);
+ }
/*
* There are 32 vector registers with vlenb length.
@@ -81,9 +92,11 @@ int riscv_v_setup_vsize(void)
return 0;
}
- riscv_v_enable();
+ if (!v_always_on)
+ riscv_v_enable();
this_vsize = csr_read(CSR_VLENB) * 32;
- riscv_v_disable();
+ if (!v_always_on)
+ riscv_v_disable();
if (!riscv_v_vsize) {
riscv_v_vsize = this_vsize;
--
2.43.0
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v7 6/6] riscv: KVM: do not save host vector context for vcpu
2026-11-11 18:43 ` Andy Chiu
(?)
@ 2026-11-11 18:43 ` Andy Chiu
-1 siblings, 0 replies; 20+ messages in thread
From: Andy Chiu @ 2026-11-11 18:43 UTC (permalink / raw)
To: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, kvm, kvm-riscv, linux-riscv
Cc: andybnac, Andy Chiu, dfustini, greentime.hu
Host's vector contexts are already managed in per-thread's struct by
regular context switch routines. Saving and restoring the context in
preempt-notifier is redundant.
Signed-off-by: Andy Chiu <tchiu@tenstorrent.com>
---
Note: I haven't been able to get a statistically significant result on
how this help/regress KVM performance running a nginx server in guest.
I am happy to carry out a test again and post the number if there is any
suggestions on what workload can benefit from this, thanks!
Changelog v7:
- new patch since v7
---
arch/riscv/include/asm/kvm_vcpu_vector.h | 9 ++-------
arch/riscv/kvm/vcpu.c | 3 +--
arch/riscv/kvm/vcpu_vector.c | 20 ++------------------
3 files changed, 5 insertions(+), 27 deletions(-)
diff --git a/arch/riscv/include/asm/kvm_vcpu_vector.h b/arch/riscv/include/asm/kvm_vcpu_vector.h
index 60fa28030944..06409c870a06 100644
--- a/arch/riscv/include/asm/kvm_vcpu_vector.h
+++ b/arch/riscv/include/asm/kvm_vcpu_vector.h
@@ -35,8 +35,7 @@ void kvm_riscv_vcpu_guest_vector_save(struct kvm_cpu_context *cntx,
unsigned long *isa);
void kvm_riscv_vcpu_guest_vector_restore(struct kvm_cpu_context *cntx,
unsigned long *isa);
-void kvm_riscv_vcpu_host_vector_save(struct kvm_cpu_context *cntx);
-void kvm_riscv_vcpu_host_vector_restore(struct kvm_cpu_context *cntx);
+void kvm_riscv_vcpu_host_vector_restore(void);
int kvm_riscv_vcpu_alloc_vector_context(struct kvm_vcpu *vcpu);
void kvm_riscv_vcpu_free_vector_context(struct kvm_vcpu *vcpu);
void kvm_riscv_register_vctx_callback(void (*func)(void));
@@ -77,11 +76,7 @@ static inline void kvm_riscv_vcpu_guest_vector_restore(struct kvm_cpu_context *c
{
}
-static inline void kvm_riscv_vcpu_host_vector_save(struct kvm_cpu_context *cntx)
-{
-}
-
-static inline void kvm_riscv_vcpu_host_vector_restore(struct kvm_cpu_context *cntx)
+static inline void kvm_riscv_vcpu_host_vector_restore(void)
{
}
diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c
index caf6e0ad72ef..d9d31851ee62 100644
--- a/arch/riscv/kvm/vcpu.c
+++ b/arch/riscv/kvm/vcpu.c
@@ -650,7 +650,6 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
kvm_riscv_vcpu_guest_fp_restore(&vcpu->arch.guest_context,
vcpu->arch.isa);
get_cpu_vector_context();
- kvm_riscv_vcpu_host_vector_save(&vcpu->arch.host_context);
kvm_riscv_vcpu_guest_vector_restore(&vcpu->arch.guest_context,
vcpu->arch.isa);
put_cpu_vector_context();
@@ -677,7 +676,7 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
get_cpu_vector_context();
kvm_riscv_vcpu_guest_vector_save(&vcpu->arch.guest_context,
vcpu->arch.isa);
- kvm_riscv_vcpu_host_vector_restore(&vcpu->arch.host_context);
+ kvm_riscv_vcpu_host_vector_restore();
put_cpu_vector_context();
if (kvm_riscv_nacl_available()) {
diff --git a/arch/riscv/kvm/vcpu_vector.c b/arch/riscv/kvm/vcpu_vector.c
index 730c32f7de50..6129a6e18404 100644
--- a/arch/riscv/kvm/vcpu_vector.c
+++ b/arch/riscv/kvm/vcpu_vector.c
@@ -61,17 +61,9 @@ void kvm_riscv_vcpu_guest_vector_restore(struct kvm_cpu_context *cntx,
}
}
-void kvm_riscv_vcpu_host_vector_save(struct kvm_cpu_context *cntx)
+void kvm_riscv_vcpu_host_vector_restore(void)
{
- /* No need to check host sstatus as it can be modified outside */
- if (!kvm_riscv_isa_check_host(V))
- kvm_riscv_vector_save(cntx);
-}
-
-void kvm_riscv_vcpu_host_vector_restore(struct kvm_cpu_context *cntx)
-{
- if (!kvm_riscv_isa_check_host(V))
- kvm_riscv_vector_restore(cntx);
+ riscv_v_vstate_set_restore(current, task_pt_regs(current));
riscv_v_flags_set(riscv_v_flags() & ~(RISCV_V_VCPU_CTX | RISCV_V_VCPU_NEED_RESTORE));
}
@@ -81,20 +73,12 @@ int kvm_riscv_vcpu_alloc_vector_context(struct kvm_vcpu *vcpu)
if (!vcpu->arch.guest_context.vector.datap)
return -ENOMEM;
- vcpu->arch.host_context.vector.datap = kzalloc(riscv_v_vsize, GFP_KERNEL_ACCOUNT);
- if (!vcpu->arch.host_context.vector.datap) {
- kfree(vcpu->arch.guest_context.vector.datap);
- vcpu->arch.guest_context.vector.datap = NULL;
- return -ENOMEM;
- }
-
return 0;
}
void kvm_riscv_vcpu_free_vector_context(struct kvm_vcpu *vcpu)
{
kfree(vcpu->arch.guest_context.vector.datap);
- kfree(vcpu->arch.host_context.vector.datap);
}
void kvm_riscv_vcpu_flush_vector(void)
--
2.43.0
--
kvm-riscv mailing list
kvm-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kvm-riscv
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v7 6/6] riscv: KVM: do not save host vector context for vcpu
@ 2026-11-11 18:43 ` Andy Chiu
0 siblings, 0 replies; 20+ messages in thread
From: Andy Chiu @ 2026-11-11 18:43 UTC (permalink / raw)
To: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, kvm, kvm-riscv, linux-riscv
Cc: andybnac, Andy Chiu, dfustini, greentime.hu
Host's vector contexts are already managed in per-thread's struct by
regular context switch routines. Saving and restoring the context in
preempt-notifier is redundant.
Signed-off-by: Andy Chiu <tchiu@tenstorrent.com>
---
Note: I haven't been able to get a statistically significant result on
how this help/regress KVM performance running a nginx server in guest.
I am happy to carry out a test again and post the number if there is any
suggestions on what workload can benefit from this, thanks!
Changelog v7:
- new patch since v7
---
arch/riscv/include/asm/kvm_vcpu_vector.h | 9 ++-------
arch/riscv/kvm/vcpu.c | 3 +--
arch/riscv/kvm/vcpu_vector.c | 20 ++------------------
3 files changed, 5 insertions(+), 27 deletions(-)
diff --git a/arch/riscv/include/asm/kvm_vcpu_vector.h b/arch/riscv/include/asm/kvm_vcpu_vector.h
index 60fa28030944..06409c870a06 100644
--- a/arch/riscv/include/asm/kvm_vcpu_vector.h
+++ b/arch/riscv/include/asm/kvm_vcpu_vector.h
@@ -35,8 +35,7 @@ void kvm_riscv_vcpu_guest_vector_save(struct kvm_cpu_context *cntx,
unsigned long *isa);
void kvm_riscv_vcpu_guest_vector_restore(struct kvm_cpu_context *cntx,
unsigned long *isa);
-void kvm_riscv_vcpu_host_vector_save(struct kvm_cpu_context *cntx);
-void kvm_riscv_vcpu_host_vector_restore(struct kvm_cpu_context *cntx);
+void kvm_riscv_vcpu_host_vector_restore(void);
int kvm_riscv_vcpu_alloc_vector_context(struct kvm_vcpu *vcpu);
void kvm_riscv_vcpu_free_vector_context(struct kvm_vcpu *vcpu);
void kvm_riscv_register_vctx_callback(void (*func)(void));
@@ -77,11 +76,7 @@ static inline void kvm_riscv_vcpu_guest_vector_restore(struct kvm_cpu_context *c
{
}
-static inline void kvm_riscv_vcpu_host_vector_save(struct kvm_cpu_context *cntx)
-{
-}
-
-static inline void kvm_riscv_vcpu_host_vector_restore(struct kvm_cpu_context *cntx)
+static inline void kvm_riscv_vcpu_host_vector_restore(void)
{
}
diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c
index caf6e0ad72ef..d9d31851ee62 100644
--- a/arch/riscv/kvm/vcpu.c
+++ b/arch/riscv/kvm/vcpu.c
@@ -650,7 +650,6 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
kvm_riscv_vcpu_guest_fp_restore(&vcpu->arch.guest_context,
vcpu->arch.isa);
get_cpu_vector_context();
- kvm_riscv_vcpu_host_vector_save(&vcpu->arch.host_context);
kvm_riscv_vcpu_guest_vector_restore(&vcpu->arch.guest_context,
vcpu->arch.isa);
put_cpu_vector_context();
@@ -677,7 +676,7 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
get_cpu_vector_context();
kvm_riscv_vcpu_guest_vector_save(&vcpu->arch.guest_context,
vcpu->arch.isa);
- kvm_riscv_vcpu_host_vector_restore(&vcpu->arch.host_context);
+ kvm_riscv_vcpu_host_vector_restore();
put_cpu_vector_context();
if (kvm_riscv_nacl_available()) {
diff --git a/arch/riscv/kvm/vcpu_vector.c b/arch/riscv/kvm/vcpu_vector.c
index 730c32f7de50..6129a6e18404 100644
--- a/arch/riscv/kvm/vcpu_vector.c
+++ b/arch/riscv/kvm/vcpu_vector.c
@@ -61,17 +61,9 @@ void kvm_riscv_vcpu_guest_vector_restore(struct kvm_cpu_context *cntx,
}
}
-void kvm_riscv_vcpu_host_vector_save(struct kvm_cpu_context *cntx)
+void kvm_riscv_vcpu_host_vector_restore(void)
{
- /* No need to check host sstatus as it can be modified outside */
- if (!kvm_riscv_isa_check_host(V))
- kvm_riscv_vector_save(cntx);
-}
-
-void kvm_riscv_vcpu_host_vector_restore(struct kvm_cpu_context *cntx)
-{
- if (!kvm_riscv_isa_check_host(V))
- kvm_riscv_vector_restore(cntx);
+ riscv_v_vstate_set_restore(current, task_pt_regs(current));
riscv_v_flags_set(riscv_v_flags() & ~(RISCV_V_VCPU_CTX | RISCV_V_VCPU_NEED_RESTORE));
}
@@ -81,20 +73,12 @@ int kvm_riscv_vcpu_alloc_vector_context(struct kvm_vcpu *vcpu)
if (!vcpu->arch.guest_context.vector.datap)
return -ENOMEM;
- vcpu->arch.host_context.vector.datap = kzalloc(riscv_v_vsize, GFP_KERNEL_ACCOUNT);
- if (!vcpu->arch.host_context.vector.datap) {
- kfree(vcpu->arch.guest_context.vector.datap);
- vcpu->arch.guest_context.vector.datap = NULL;
- return -ENOMEM;
- }
-
return 0;
}
void kvm_riscv_vcpu_free_vector_context(struct kvm_vcpu *vcpu)
{
kfree(vcpu->arch.guest_context.vector.datap);
- kfree(vcpu->arch.host_context.vector.datap);
}
void kvm_riscv_vcpu_flush_vector(void)
--
2.43.0
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v7 6/6] riscv: KVM: do not save host vector context for vcpu
@ 2026-11-11 18:43 ` Andy Chiu
0 siblings, 0 replies; 20+ messages in thread
From: Andy Chiu @ 2026-11-11 18:43 UTC (permalink / raw)
To: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, kvm, kvm-riscv, linux-riscv
Cc: andybnac, Andy Chiu, dfustini, greentime.hu
Host's vector contexts are already managed in per-thread's struct by
regular context switch routines. Saving and restoring the context in
preempt-notifier is redundant.
Signed-off-by: Andy Chiu <tchiu@tenstorrent.com>
---
Note: I haven't been able to get a statistically significant result on
how this help/regress KVM performance running a nginx server in guest.
I am happy to carry out a test again and post the number if there is any
suggestions on what workload can benefit from this, thanks!
Changelog v7:
- new patch since v7
---
arch/riscv/include/asm/kvm_vcpu_vector.h | 9 ++-------
arch/riscv/kvm/vcpu.c | 3 +--
arch/riscv/kvm/vcpu_vector.c | 20 ++------------------
3 files changed, 5 insertions(+), 27 deletions(-)
diff --git a/arch/riscv/include/asm/kvm_vcpu_vector.h b/arch/riscv/include/asm/kvm_vcpu_vector.h
index 60fa28030944..06409c870a06 100644
--- a/arch/riscv/include/asm/kvm_vcpu_vector.h
+++ b/arch/riscv/include/asm/kvm_vcpu_vector.h
@@ -35,8 +35,7 @@ void kvm_riscv_vcpu_guest_vector_save(struct kvm_cpu_context *cntx,
unsigned long *isa);
void kvm_riscv_vcpu_guest_vector_restore(struct kvm_cpu_context *cntx,
unsigned long *isa);
-void kvm_riscv_vcpu_host_vector_save(struct kvm_cpu_context *cntx);
-void kvm_riscv_vcpu_host_vector_restore(struct kvm_cpu_context *cntx);
+void kvm_riscv_vcpu_host_vector_restore(void);
int kvm_riscv_vcpu_alloc_vector_context(struct kvm_vcpu *vcpu);
void kvm_riscv_vcpu_free_vector_context(struct kvm_vcpu *vcpu);
void kvm_riscv_register_vctx_callback(void (*func)(void));
@@ -77,11 +76,7 @@ static inline void kvm_riscv_vcpu_guest_vector_restore(struct kvm_cpu_context *c
{
}
-static inline void kvm_riscv_vcpu_host_vector_save(struct kvm_cpu_context *cntx)
-{
-}
-
-static inline void kvm_riscv_vcpu_host_vector_restore(struct kvm_cpu_context *cntx)
+static inline void kvm_riscv_vcpu_host_vector_restore(void)
{
}
diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c
index caf6e0ad72ef..d9d31851ee62 100644
--- a/arch/riscv/kvm/vcpu.c
+++ b/arch/riscv/kvm/vcpu.c
@@ -650,7 +650,6 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
kvm_riscv_vcpu_guest_fp_restore(&vcpu->arch.guest_context,
vcpu->arch.isa);
get_cpu_vector_context();
- kvm_riscv_vcpu_host_vector_save(&vcpu->arch.host_context);
kvm_riscv_vcpu_guest_vector_restore(&vcpu->arch.guest_context,
vcpu->arch.isa);
put_cpu_vector_context();
@@ -677,7 +676,7 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
get_cpu_vector_context();
kvm_riscv_vcpu_guest_vector_save(&vcpu->arch.guest_context,
vcpu->arch.isa);
- kvm_riscv_vcpu_host_vector_restore(&vcpu->arch.host_context);
+ kvm_riscv_vcpu_host_vector_restore();
put_cpu_vector_context();
if (kvm_riscv_nacl_available()) {
diff --git a/arch/riscv/kvm/vcpu_vector.c b/arch/riscv/kvm/vcpu_vector.c
index 730c32f7de50..6129a6e18404 100644
--- a/arch/riscv/kvm/vcpu_vector.c
+++ b/arch/riscv/kvm/vcpu_vector.c
@@ -61,17 +61,9 @@ void kvm_riscv_vcpu_guest_vector_restore(struct kvm_cpu_context *cntx,
}
}
-void kvm_riscv_vcpu_host_vector_save(struct kvm_cpu_context *cntx)
+void kvm_riscv_vcpu_host_vector_restore(void)
{
- /* No need to check host sstatus as it can be modified outside */
- if (!kvm_riscv_isa_check_host(V))
- kvm_riscv_vector_save(cntx);
-}
-
-void kvm_riscv_vcpu_host_vector_restore(struct kvm_cpu_context *cntx)
-{
- if (!kvm_riscv_isa_check_host(V))
- kvm_riscv_vector_restore(cntx);
+ riscv_v_vstate_set_restore(current, task_pt_regs(current));
riscv_v_flags_set(riscv_v_flags() & ~(RISCV_V_VCPU_CTX | RISCV_V_VCPU_NEED_RESTORE));
}
@@ -81,20 +73,12 @@ int kvm_riscv_vcpu_alloc_vector_context(struct kvm_vcpu *vcpu)
if (!vcpu->arch.guest_context.vector.datap)
return -ENOMEM;
- vcpu->arch.host_context.vector.datap = kzalloc(riscv_v_vsize, GFP_KERNEL_ACCOUNT);
- if (!vcpu->arch.host_context.vector.datap) {
- kfree(vcpu->arch.guest_context.vector.datap);
- vcpu->arch.guest_context.vector.datap = NULL;
- return -ENOMEM;
- }
-
return 0;
}
void kvm_riscv_vcpu_free_vector_context(struct kvm_vcpu *vcpu)
{
kfree(vcpu->arch.guest_context.vector.datap);
- kfree(vcpu->arch.host_context.vector.datap);
}
void kvm_riscv_vcpu_flush_vector(void)
--
2.43.0
^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [PATCH v7 1/6] riscv: vector: refactor vector context operations
2026-11-11 18:43 ` Andy Chiu
(?)
(?)
@ 2026-11-11 19:30 ` sashiko-bot
-1 siblings, 0 replies; 20+ messages in thread
From: sashiko-bot @ 2026-11-11 19:30 UTC (permalink / raw)
To: Andy Chiu, kvm
Thank you for your contribution! Sashiko AI review found 2 potential
issues to consider:
- [High] riscv: kvm: unrenamed __kvm_riscv_vector_restore() stub breaks
!ISA_V build
- [Low] riscv: vector: commit message describes preempt_v changes not in
diff
--
commit 7053b3ce403daff58cb731616963dcc0c16f7edb
Author: Andy Chiu <tchiu@tenstorrent.com>
riscv: vector: refactor vector context operations
This commit lifts riscv_v_enable() and riscv_v_disable() out of the
low-level __riscv_v_vstate_{save,restore,discard}() helpers into their
callers and renames the KVM vector save/restore helpers.
> Also, refactor and document about the user context save in preempt_v to
> make code more readable.
[Severity: Low]
This isn't a bug, but the preempt_v refactoring and comment described here
are not in this patch; they were already included in commit b5060a4aa33d
("RISC-V: KVM: fix vcpu vector context handling for kernel-mode vector").
> diff --git a/arch/riscv/include/asm/kvm_vcpu_vector.h b/arch/riscv/include/asm/kvm_vcpu_vector.h
> index 50d4789b9cac9..60fa280309444 100644
> --- a/arch/riscv/include/asm/kvm_vcpu_vector.h
> +++ b/arch/riscv/include/asm/kvm_vcpu_vector.h
> @@ -16,14 +16,18 @@
> #ifdef CONFIG_RISCV_ISA_V
> #include <asm/kvm_host.h>
>
> -static __always_inline void __kvm_riscv_vector_save(struct kvm_cpu_context *context)
> +static __always_inline void kvm_riscv_vector_save(struct kvm_cpu_context *context)
> {
> + riscv_v_enable();
> __riscv_v_vstate_save(&context->vector, context->vector.datap);
> + riscv_v_disable();
> }
>
> -static __always_inline void __kvm_riscv_vector_restore(struct kvm_cpu_context *context)
> +static __always_inline void kvm_riscv_vector_restore(struct kvm_cpu_context *context)
> {
> + riscv_v_enable();
> __riscv_v_vstate_restore(&context->vector, context->vector.datap);
> + riscv_v_disable();
> }
[ ... ]
> diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c
> index dd786f758eb76..caf6e0ad72efd 100644
> --- a/arch/riscv/kvm/vcpu.c
> +++ b/arch/riscv/kvm/vcpu.c
> @@ -825,7 +825,7 @@ static void noinstr kvm_riscv_vcpu_enter_exit(struct kvm_vcpu *vcpu,
> if (current->thread.riscv_v_flags & RISCV_V_VCPU_NEED_RESTORE) {
> current->thread.riscv_v_flags &= ~RISCV_V_VCPU_NEED_RESTORE;
> current->thread.riscv_v_flags |= RISCV_V_VCPU_CTX;
> - __kvm_riscv_vector_restore(gcntx);
> + kvm_riscv_vector_restore(gcntx);
> gcntx->sstatus = (gcntx->sstatus & ~SR_VS) | SR_VS_CLEAN;
> }
[Severity: High]
Does this break the build when CONFIG_KVM is enabled and CONFIG_RISCV_ISA_V
is disabled? The stub in the #else branch of
arch/riscv/include/asm/kvm_vcpu_vector.h is still named
__kvm_riscv_vector_restore(), so kvm_riscv_vcpu_enter_exit() calls an
undeclared function.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261111184359.1239821-1-tchiu@tenstorrent.com?part=1
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v7 6/6] riscv: KVM: do not save host vector context for vcpu
2026-11-11 18:43 ` Andy Chiu
(?)
(?)
@ 2026-11-11 20:03 ` sashiko-bot
-1 siblings, 0 replies; 20+ messages in thread
From: sashiko-bot @ 2026-11-11 20:03 UTC (permalink / raw)
To: Andy Chiu, kvm
Thank you for your contribution! Sashiko AI review found 2 potential
issues to consider:
- [High] riscv: KVM: build failure in kvm_riscv_vcpu_enter_exit() when
!CONFIG_RISCV_ISA_V
- [High] riscv: KVM: guest CSR_VCSR state leaks to host in
kvm_riscv_vcpu_host_vector_restore()
--
commit e0f5ce69db9b4e847c776901421a3c6de8e57845
Author: Andy Chiu <tchiu@tenstorrent.com>
riscv: KVM: do not save host vector context for vcpu
This commit removes the per-vCPU host vector context buffer and replaces the
explicit host vector context save and restore in kvm_arch_vcpu_load() and
kvm_arch_vcpu_put() with deferred thread vector state restoration.
> diff --git a/arch/riscv/include/asm/kvm_vcpu_vector.h b/arch/riscv/include/asm/kvm_vcpu_vector.h
> index 60fa280309444..06409c870a069 100644
> --- a/arch/riscv/include/asm/kvm_vcpu_vector.h
> +++ b/arch/riscv/include/asm/kvm_vcpu_vector.h
[ ... ]
> @@ -77,11 +76,7 @@ static inline void kvm_riscv_vcpu_guest_vector_restore(struct kvm_cpu_context *c
> {
> }
>
> -static inline void kvm_riscv_vcpu_host_vector_save(struct kvm_cpu_context *cntx)
> -{
> -}
> -
> -static inline void kvm_riscv_vcpu_host_vector_restore(struct kvm_cpu_context *cntx)
> +static inline void kvm_riscv_vcpu_host_vector_restore(void)
> {
> }
[Severity: High]
Does building with CONFIG_KVM enabled and CONFIG_RISCV_ISA_V disabled fail in
kvm_riscv_vcpu_enter_exit()?
Earlier in the series, commit "riscv: vector: refactor vector context
operations" renamed __kvm_riscv_vector_restore() to
kvm_riscv_vector_restore() under #ifdef CONFIG_RISCV_ISA_V and at the call
site in kvm_riscv_vcpu_enter_exit(), which is compiled unconditionally, but
the !CONFIG_RISCV_ISA_V stub in arch/riscv/include/asm/kvm_vcpu_vector.h is
still named __kvm_riscv_vector_restore().
[ ... ]
> diff --git a/arch/riscv/kvm/vcpu_vector.c b/arch/riscv/kvm/vcpu_vector.c
> index 730c32f7de504..6129a6e184049 100644
> --- a/arch/riscv/kvm/vcpu_vector.c
> +++ b/arch/riscv/kvm/vcpu_vector.c
> @@ -61,17 +61,9 @@ void kvm_riscv_vcpu_guest_vector_restore(struct kvm_cpu_context *cntx,
> }
> }
>
> -void kvm_riscv_vcpu_host_vector_save(struct kvm_cpu_context *cntx)
> +void kvm_riscv_vcpu_host_vector_restore(void)
> {
> - /* No need to check host sstatus as it can be modified outside */
> - if (!kvm_riscv_isa_check_host(V))
> - kvm_riscv_vector_save(cntx);
> -}
> -
> -void kvm_riscv_vcpu_host_vector_restore(struct kvm_cpu_context *cntx)
> -{
> - if (!kvm_riscv_isa_check_host(V))
> - kvm_riscv_vector_restore(cntx);
> + riscv_v_vstate_set_restore(current, task_pt_regs(current));
> riscv_v_flags_set(riscv_v_flags() & ~(RISCV_V_VCPU_CTX | RISCV_V_VCPU_NEED_RESTORE));
> }
[Severity: High]
Can the guest's CSR_VCSR value leak into host userspace after exiting the
guest?
When the host task enters ioctl(KVM_RUN) via do_trap_ecall_u(),
riscv_v_vstate_discard() sets task_pt_regs(current)->status to SR_VS_INITIAL
(or leaves it at SR_VS_OFF if the task has not used vector instructions).
While running the vCPU, kvm_riscv_vcpu_enter_exit() ->
kvm_riscv_vector_restore() loads the guest's vcsr into hardware CSR_VCSR (or
CSR_VXRM and CSR_VXSAT on XTheadVector), and the guest can also modify it
directly.
On vCPU put, kvm_riscv_vcpu_host_vector_restore() now only schedules a
deferred restore via riscv_v_vstate_set_restore(). When returning to host
userspace with SR_VS_INITIAL, riscv_v_vstate_restore() calls
__riscv_v_vstate_discard(), which resets v0..v31, vl, vtype, and vstart, but
never writes CSR_VCSR:
arch/riscv/include/asm/vector.h:riscv_v_vstate_restore() {
...
riscv_v_enable();
if (__riscv_v_vstate_check(regs->status, INITIAL))
__riscv_v_vstate_discard();
else if (__riscv_v_vstate_check(regs->status, CLEAN))
__riscv_v_vstate_restore(vstate, vstate->datap);
riscv_v_disable();
...
}
This leaves the guest's CSR_VCSR active in hardware when host userspace
resumes (and across riscv_v_ucontext_save() on signal delivery or ptrace), or
for the next task that hits __riscv_v_vstate_discard() on that CPU if the VMM
task had SR_VS_OFF.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261111184359.1239821-1-tchiu@tenstorrent.com?part=6
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v7 5/6] riscv: vector: optimize vstate operations
2026-11-11 18:43 ` Andy Chiu
@ 2026-11-11 23:00 ` Conor Dooley
-1 siblings, 0 replies; 20+ messages in thread
From: Conor Dooley @ 2026-11-11 23:00 UTC (permalink / raw)
To: Andy Chiu
Cc: Jonathan Corbet, Shuah Khan, Randy Dunlap, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, linux-doc,
linux-riscv, andybnac, dfustini, greentime.hu,
Mike Rapoport (Microsoft), Arnd Bergmann, Karl Mehltretter,
Borislav Petkov (AMD), Dapeng Mi, Marco Elver, Ethan Nelson-Moore,
Jeff Layton, Jisheng Zhang, Conor Dooley, Yong-Xuan Wang,
Anup Patel, Aurelien Jarno, daichengrong, Troy Mitchell,
Guobin Zhang, Guodong Xu, Andrew Jones, Charlie Jenkins,
Atish Patra, Deepak Gupta, Hui Wang, Pincheng Wang, Zong Li,
Vivian Wang, Rui Qi, Yunhui Cui, Samuel Holland, Zishun Yi,
Sergey Matyukevich
[-- Attachment #1: Type: text/plain, Size: 14393 bytes --]
On Wed, Nov 11, 2026 at 12:43:27PM -0600, Andy Chiu wrote:
> Introduce the riscv_novstateopt to control the optimization of vector
> state operations in the kernel space.
>
> The optimization enables vector in kernel mode and bypasses vector
> register nulling for user space on the syscall fast path when the boot
> argument "riscv_novstateopt" is not set
>
> Enabling this optimization yields the following performance benefits:
> - Cut 80 cycles latency for getpid on Ascalon.
> - 1.1% ~ 4.09% request throughput improvment on nginx workload with web
> serving size under 4KB
>
> Signed-off-by: Andy Chiu <tchiu@tenstorrent.com>
> ---
> Changelog v6:
> - upgrade it to use alternative and change default to enable the
> optimization
Why? Argument for the default being like this needs to be in the commit
message.
> Changelog v5:
> - new patch since v5
> ---
> .../admin-guide/kernel-parameters.txt | 13 +++++++++++++
> arch/riscv/include/asm/alternative-macros.h | 6 ++++++
> arch/riscv/include/asm/alternative.h | 3 ---
> arch/riscv/include/asm/cpufeature-macros.h | 6 ++++--
> arch/riscv/include/asm/vector.h | 16 +++++++++++++++-
> arch/riscv/kernel/cpufeature.c | 18 ++++++++++++++++++
> arch/riscv/kernel/entry.S | 15 +++++++++++++--
> arch/riscv/kernel/process.c | 3 +++
> arch/riscv/kernel/vector.c | 17 +++++++++++++++--
> 9 files changed, 87 insertions(+), 10 deletions(-)
>
> diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
> index 0b3c140babd9..e1146ee6ab1e 100644
> --- a/Documentation/admin-guide/kernel-parameters.txt
> +++ b/Documentation/admin-guide/kernel-parameters.txt
> @@ -6722,6 +6722,19 @@ Kernel parameters
> fcfi Disable user forward CFI ABI to userspace even if the
> landing pad extension is available.
>
> + riscv_novstateopt [RISCV,EARLY]
> + Disable the vector state optimization. By default the
> + kernel keeps Vector enabled while running in kernel
> + space, rather than toggling sstatus.VS on every use of
> + the kernel-mode vector, and skips nulling the vector
> + registers for user space. Pass this option to restore the
> + conservative behavior, which catches illegal use of
> + Vector in kernel code. The optimization roughly cuts
> + 30 ns of getpid() latency on a Blackhole x280 and gives
> + a 4.09% request throughput improvement for an nginx
> + workload serving a 2KB web page on a four-core
> + Ascalon-S.
> +
> ro [KNL] Mount root device read-only on boot
>
> rodata= [KNL,EARLY]
> diff --git a/arch/riscv/include/asm/alternative-macros.h b/arch/riscv/include/asm/alternative-macros.h
> index 629d884578da..45d9ae1e0aa8 100644
> --- a/arch/riscv/include/asm/alternative-macros.h
> +++ b/arch/riscv/include/asm/alternative-macros.h
> @@ -2,6 +2,12 @@
> #ifndef __ASM_ALTERNATIVE_MACROS_H
> #define __ASM_ALTERNATIVE_MACROS_H
>
> +#include <linux/wordpart.h>
> +#define PATCH_ID_CPUFEATURE_ID(p) lower_16_bits(p)
> +#define PATCH_ID_CPUFEATURE_VALUE(p) upper_16_bits(p)
> +
> +#define RISCV_CPUFEAT_VSTATEOPT 0x1
This isn't a cpu feature at all though, so it should not be named like that.
> +
> #ifdef __ASSEMBLER__
>
> .macro ALT_ENTRY oldptr newptr vendor_id patch_id new_len
> diff --git a/arch/riscv/include/asm/alternative.h b/arch/riscv/include/asm/alternative.h
> index 6be7b2b6ade9..bc2ecaa9125a 100644
> --- a/arch/riscv/include/asm/alternative.h
> +++ b/arch/riscv/include/asm/alternative.h
> @@ -16,9 +16,6 @@
> #include <linux/stddef.h>
> #include <asm/hwcap.h>
>
> -#define PATCH_ID_CPUFEATURE_ID(p) lower_16_bits(p)
> -#define PATCH_ID_CPUFEATURE_VALUE(p) upper_16_bits(p)
> -
> #define RISCV_ALTERNATIVES_BOOT 0 /* alternatives applied during regular boot */
> #define RISCV_ALTERNATIVES_MODULE 1 /* alternatives applied during module-init */
> #define RISCV_ALTERNATIVES_EARLY_BOOT 2 /* alternatives applied before mmu start */
> diff --git a/arch/riscv/include/asm/cpufeature-macros.h b/arch/riscv/include/asm/cpufeature-macros.h
> index adaf9e3fb25c..7bd900899bb0 100644
> --- a/arch/riscv/include/asm/cpufeature-macros.h
> +++ b/arch/riscv/include/asm/cpufeature-macros.h
> @@ -45,14 +45,16 @@ static __always_inline bool __riscv_has_extension_unlikely(const unsigned long v
>
> static __always_inline bool riscv_has_extension_unlikely(const unsigned long ext)
> {
> - compiletime_assert(ext < RISCV_ISA_EXT_MAX, "ext must be < RISCV_ISA_EXT_MAX");
> + int realext = PATCH_ID_CPUFEATURE_ID(ext);
> + compiletime_assert(realext < RISCV_ISA_EXT_MAX, "ext must be < RISCV_ISA_EXT_MAX");
>
> return __riscv_has_extension_unlikely(STANDARD_EXT, ext);
> }
Please don't abuse riscv_has_extension_*() for things that are not
extensions. I don't mind if you do something that wraps
__riscv_has_extension_*() to make use of the underlying infrastructure
but I am against muddying the standard extension space with linux internal
stuff - particularly in this manner because this:
> +static __always_inline bool has_vstate_opt(void)
> +{
> + return riscv_has_extension_likely((RISCV_CPUFEAT_VSTATEOPT << 16) | RISCV_ISA_EXT_ZVE32X);
> +}
is incredibly confusing and error prone.
Recently enough I talked about something very very similar with Jisheng,
in the context of using an alternative for misaligned access, and I
said:
| ...I'd rather see __riscv_has_extension_*() get renamed
| to __riscv_has_cap*(), so that things like unaligned access speed get a
| different namespace to standard and vendor extensions. IOW you'd end up
| with
|
| static __always_inline bool riscv_has_extension_unlikely(const unsigned long ext)
| {
| compiletime_assert(ext < RISCV_ISA_EXT_MAX, "ext must be < RISCV_ISA_EXT_MAX");
|
| return __riscv_has_cap_unlikely(STANDARD_EXT, ext);
| }
|
| static __always_inline bool riscv_has_vendor_extension_unlikely(const unsigned long vendor,
| const unsigned long ext)
| {
| if (!IS_ENABLED(CONFIG_RISCV_ISA_VENDOR_EXT))
| return false;
|
| return __riscv_has_cap_unlikely(vendor, ext + RISCV_VENDOR_EXT_ALTERNATIVES_BASE);
| }
|
| static __always_inline bool riscv_has_cap_unlikely(const unsigned long cap)
| {
| return __riscv_has_cap_unlikely(LINUX_CAP, cap);
| }
|
| Currently standard extensions use 0 as the vendor, perhaps we could then
| use -1 (the value is an unsigned long) for non extension related caps?
What's here, with this realext business definitely looks like a hack.
Doing what I suggest above allows you to have a real key that you can
set, just like the vendor extensions do. You can call a function from
riscv_fill_hwcap() to populate the bitmap and modify
_apply_alternatives() to additionally patch this sort of thing.
Cheers,
Conor.
pw-bot: changes-requested
>
> static __always_inline bool riscv_has_extension_likely(const unsigned long ext)
> {
> - compiletime_assert(ext < RISCV_ISA_EXT_MAX, "ext must be < RISCV_ISA_EXT_MAX");
> + int realext = PATCH_ID_CPUFEATURE_ID(ext);
> + compiletime_assert(realext < RISCV_ISA_EXT_MAX, "ext must be < RISCV_ISA_EXT_MAX");
>
> return __riscv_has_extension_likely(STANDARD_EXT, ext);
> }
> diff --git a/arch/riscv/include/asm/vector.h b/arch/riscv/include/asm/vector.h
> index e83f9e0046a9..745ac3ca67b7 100644
> --- a/arch/riscv/include/asm/vector.h
> +++ b/arch/riscv/include/asm/vector.h
> @@ -49,6 +49,7 @@
> _res; \
> })
>
> +extern bool riscv_v_vstate_opt;
> extern unsigned long riscv_v_vsize;
> int riscv_v_setup_vsize(void);
> bool insn_is_vector(u32 insn_buf);
> @@ -78,6 +79,11 @@ static __always_inline bool has_vector(void)
> return riscv_has_extension_unlikely(RISCV_ISA_EXT_ZVE32X);
> }
>
> +static __always_inline bool has_vstate_opt(void)
> +{
> + return riscv_has_extension_likely((RISCV_CPUFEAT_VSTATEOPT << 16) | RISCV_ISA_EXT_ZVE32X);
> +}
> +
> static __always_inline bool has_xtheadvector_no_alternatives(void)
> {
> if (IS_ENABLED(CONFIG_RISCV_ISA_XTHEADVECTOR))
> @@ -122,6 +128,9 @@ static inline bool riscv_v_vstate_query(struct pt_regs *regs)
>
> static __always_inline void riscv_v_enable(void)
> {
> + if (has_vstate_opt())
> + return;
> +
> if (has_xtheadvector())
> csr_set(CSR_SSTATUS, SR_VS_THEAD);
> else
> @@ -130,6 +139,9 @@ static __always_inline void riscv_v_enable(void)
>
> static __always_inline void riscv_v_disable(void)
> {
> + if (has_vstate_opt())
> + return;
> +
> if (has_xtheadvector())
> csr_clear(CSR_SSTATUS, SR_VS_THEAD);
> else
> @@ -336,7 +348,8 @@ static inline void riscv_v_vstate_set_restore(struct task_struct *task,
> static inline void riscv_v_vstate_discard(struct pt_regs *regs)
> {
> if (__riscv_v_vstate_check_gt(regs->status, INITIAL)) {
> - riscv_v_vstate_set_restore(current, regs);
> + if (!has_vstate_opt())
> + riscv_v_vstate_set_restore(current, regs);
> riscv_v_vstate_init(regs);
> }
> }
> @@ -422,6 +435,7 @@ struct pt_regs;
>
> static inline int riscv_v_setup_vsize(void) { return -EOPNOTSUPP; }
> static __always_inline bool has_vector(void) { return false; }
> +static __always_inline bool has_vstate_opt(void) { return false; }
> static __always_inline bool insn_is_vector(u32 insn_buf) { return false; }
> static __always_inline bool has_xtheadvector_no_alternatives(void) { return false; }
> static __always_inline bool has_xtheadvector(void) { return false; }
> diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
> index 72bce616491f..041f6a35fba3 100644
> --- a/arch/riscv/kernel/cpufeature.c
> +++ b/arch/riscv/kernel/cpufeature.c
> @@ -1294,6 +1294,19 @@ void riscv_clear_hypervisor_csr(void)
> csr_clear(CSR_HSTATUS, HSTATUS_HU);
> }
>
> +/*
> + * Leaving Vector enabled while in the kernel relies on the vstate alternatives
> + * being patched in. It can be turned off on the command line to catch illegal
> + * use of Vector in kernel code.
> + */
> +bool riscv_v_vstate_opt = true;
> +static int __init riscv_novstateopt_setup(char *__unused)
> +{
> + riscv_v_vstate_opt = false;
> + return 0;
> +}
> +early_param("riscv_novstateopt", riscv_novstateopt_setup);
> +
> /*
> * Alternative patch sites consider 48 bits when determining when to patch
> * the old instruction sequence with the new. These bits are broken into a
> @@ -1322,6 +1335,11 @@ static bool riscv_cpufeature_patch_check(u16 id, u16 value)
> * then the alternative cannot be applied.
> */
> return riscv_cboz_block_size <= (1U << value);
> + case RISCV_ISA_EXT_ZVE32X:
> + if (value == RISCV_CPUFEAT_VSTATEOPT)
> + return riscv_v_vstate_opt;
> +
> + return true;
> }
>
> return false;
> diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S
> index 628b85e3915a..bb4787711f2c 100644
> --- a/arch/riscv/kernel/entry.S
> +++ b/arch/riscv/kernel/entry.S
> @@ -6,6 +6,7 @@
>
> #include <linux/init.h>
> #include <linux/linkage.h>
> +#include <linux/stringify.h>
>
> #include <asm/alternative-macros.h>
> #include <asm/asm.h>
> @@ -175,10 +176,13 @@ SYM_CODE_START(handle_exception)
> * Disable user-mode memory access as it should only be set in the
> * actual user copy routines.
> *
> - * Disable the FPU/Vector to detect illegal usage of floating point
> + * Disable the FPU to detect illegal usage of floating point
> * or vector in kernel space.
> */
> - li t0, SR_SUM | SR_FS_VS
> + li t0, SR_SUM | SR_FS
> + ALTERNATIVE(__stringify(ori t0, t0, SR_VS), "nop", 0,
> + (RISCV_CPUFEAT_VSTATEOPT << 16) | RISCV_ISA_EXT_ZVE32X,
> + CONFIG_RISCV_ISA_V)
> #ifdef CONFIG_64BIT
> li t1, SR_ELP
> or t0, t0, t1
> @@ -186,6 +190,13 @@ SYM_CODE_START(handle_exception)
>
> REG_L s0, TASK_TI_USER_SP(tp)
> csrrc s1, CSR_STATUS, t0
> + ALTERNATIVE("j .Lskip_v_enable", __stringify(andi t0, s1, SR_VS), 0,
> + (RISCV_CPUFEAT_VSTATEOPT << 16) | RISCV_ISA_EXT_ZVE32X,
> + CONFIG_RISCV_ISA_V)
> + bnez t0, .Lskip_v_enable
> + li a0, SR_VS_INITIAL
> + csrs CSR_STATUS, a0
> +.Lskip_v_enable:
> save_userssp s2, s1
> csrr s2, CSR_EPC
> csrr s3, CSR_TVAL
> diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c
> index 34c1d498d1ca..27146b3fa738 100644
> --- a/arch/riscv/kernel/process.c
> +++ b/arch/riscv/kernel/process.c
> @@ -258,6 +258,9 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
> /* Supervisor/Machine, irqs on: */
> childregs->status = SR_PP | SR_PIE;
>
> + if (has_vstate_opt())
> + riscv_v_vstate_init(childregs);
> +
> p->thread.s[0] = (unsigned long)args->fn;
> p->thread.s[1] = (unsigned long)args->fn_arg;
> p->thread.ra = (unsigned long)ret_from_fork_kernel_asm;
> diff --git a/arch/riscv/kernel/vector.c b/arch/riscv/kernel/vector.c
> index 6fd541f5d5cb..eec9deff8da7 100644
> --- a/arch/riscv/kernel/vector.c
> +++ b/arch/riscv/kernel/vector.c
> @@ -12,6 +12,7 @@
> #include <linux/prctl.h>
>
> #include <asm/thread_info.h>
> +#include <asm/cpufeature.h>
> #include <asm/processor.h>
> #include <asm/insn.h>
> #include <asm/vector.h>
> @@ -69,6 +70,16 @@ void riscv_v_ucontext_save(struct task_struct *tsk)
> int riscv_v_setup_vsize(void)
> {
> unsigned long this_vsize;
> + bool v_always_on = false;
> +
> + /*
> + * has_vstate_opt() cannot be used here if called from riscv_fill_hwcap(), before
> + * apply_boot_alternatives(),
> + */
> + if (__riscv_isa_extension_available(NULL, RISCV_ISA_EXT_ZVE32X) && riscv_v_vstate_opt) {
> + v_always_on = true;
> + csr_set(CSR_SSTATUS, SR_VS_INITIAL);
> + }
>
> /*
> * There are 32 vector registers with vlenb length.
> @@ -81,9 +92,11 @@ int riscv_v_setup_vsize(void)
> return 0;
> }
>
> - riscv_v_enable();
> + if (!v_always_on)
> + riscv_v_enable();
> this_vsize = csr_read(CSR_VLENB) * 32;
> - riscv_v_disable();
> + if (!v_always_on)
> + riscv_v_disable();
>
> if (!riscv_v_vsize) {
> riscv_v_vsize = this_vsize;
> --
> 2.43.0
>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v7 5/6] riscv: vector: optimize vstate operations
@ 2026-11-11 23:00 ` Conor Dooley
0 siblings, 0 replies; 20+ messages in thread
From: Conor Dooley @ 2026-11-11 23:00 UTC (permalink / raw)
To: Andy Chiu
Cc: Jonathan Corbet, Shuah Khan, Randy Dunlap, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, linux-doc,
linux-riscv, andybnac, dfustini, greentime.hu,
Mike Rapoport (Microsoft), Arnd Bergmann, Karl Mehltretter,
Borislav Petkov (AMD), Dapeng Mi, Marco Elver, Ethan Nelson-Moore,
Jeff Layton, Jisheng Zhang, Conor Dooley, Yong-Xuan Wang,
Anup Patel, Aurelien Jarno, daichengrong, Troy Mitchell,
Guobin Zhang, Guodong Xu, Andrew Jones, Charlie Jenkins,
Atish Patra, Deepak Gupta, Hui Wang, Pincheng Wang, Zong Li,
Vivian Wang, Rui Qi, Yunhui Cui, Samuel Holland, Zishun Yi,
Sergey Matyukevich
[-- Attachment #1.1: Type: text/plain, Size: 14393 bytes --]
On Wed, Nov 11, 2026 at 12:43:27PM -0600, Andy Chiu wrote:
> Introduce the riscv_novstateopt to control the optimization of vector
> state operations in the kernel space.
>
> The optimization enables vector in kernel mode and bypasses vector
> register nulling for user space on the syscall fast path when the boot
> argument "riscv_novstateopt" is not set
>
> Enabling this optimization yields the following performance benefits:
> - Cut 80 cycles latency for getpid on Ascalon.
> - 1.1% ~ 4.09% request throughput improvment on nginx workload with web
> serving size under 4KB
>
> Signed-off-by: Andy Chiu <tchiu@tenstorrent.com>
> ---
> Changelog v6:
> - upgrade it to use alternative and change default to enable the
> optimization
Why? Argument for the default being like this needs to be in the commit
message.
> Changelog v5:
> - new patch since v5
> ---
> .../admin-guide/kernel-parameters.txt | 13 +++++++++++++
> arch/riscv/include/asm/alternative-macros.h | 6 ++++++
> arch/riscv/include/asm/alternative.h | 3 ---
> arch/riscv/include/asm/cpufeature-macros.h | 6 ++++--
> arch/riscv/include/asm/vector.h | 16 +++++++++++++++-
> arch/riscv/kernel/cpufeature.c | 18 ++++++++++++++++++
> arch/riscv/kernel/entry.S | 15 +++++++++++++--
> arch/riscv/kernel/process.c | 3 +++
> arch/riscv/kernel/vector.c | 17 +++++++++++++++--
> 9 files changed, 87 insertions(+), 10 deletions(-)
>
> diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
> index 0b3c140babd9..e1146ee6ab1e 100644
> --- a/Documentation/admin-guide/kernel-parameters.txt
> +++ b/Documentation/admin-guide/kernel-parameters.txt
> @@ -6722,6 +6722,19 @@ Kernel parameters
> fcfi Disable user forward CFI ABI to userspace even if the
> landing pad extension is available.
>
> + riscv_novstateopt [RISCV,EARLY]
> + Disable the vector state optimization. By default the
> + kernel keeps Vector enabled while running in kernel
> + space, rather than toggling sstatus.VS on every use of
> + the kernel-mode vector, and skips nulling the vector
> + registers for user space. Pass this option to restore the
> + conservative behavior, which catches illegal use of
> + Vector in kernel code. The optimization roughly cuts
> + 30 ns of getpid() latency on a Blackhole x280 and gives
> + a 4.09% request throughput improvement for an nginx
> + workload serving a 2KB web page on a four-core
> + Ascalon-S.
> +
> ro [KNL] Mount root device read-only on boot
>
> rodata= [KNL,EARLY]
> diff --git a/arch/riscv/include/asm/alternative-macros.h b/arch/riscv/include/asm/alternative-macros.h
> index 629d884578da..45d9ae1e0aa8 100644
> --- a/arch/riscv/include/asm/alternative-macros.h
> +++ b/arch/riscv/include/asm/alternative-macros.h
> @@ -2,6 +2,12 @@
> #ifndef __ASM_ALTERNATIVE_MACROS_H
> #define __ASM_ALTERNATIVE_MACROS_H
>
> +#include <linux/wordpart.h>
> +#define PATCH_ID_CPUFEATURE_ID(p) lower_16_bits(p)
> +#define PATCH_ID_CPUFEATURE_VALUE(p) upper_16_bits(p)
> +
> +#define RISCV_CPUFEAT_VSTATEOPT 0x1
This isn't a cpu feature at all though, so it should not be named like that.
> +
> #ifdef __ASSEMBLER__
>
> .macro ALT_ENTRY oldptr newptr vendor_id patch_id new_len
> diff --git a/arch/riscv/include/asm/alternative.h b/arch/riscv/include/asm/alternative.h
> index 6be7b2b6ade9..bc2ecaa9125a 100644
> --- a/arch/riscv/include/asm/alternative.h
> +++ b/arch/riscv/include/asm/alternative.h
> @@ -16,9 +16,6 @@
> #include <linux/stddef.h>
> #include <asm/hwcap.h>
>
> -#define PATCH_ID_CPUFEATURE_ID(p) lower_16_bits(p)
> -#define PATCH_ID_CPUFEATURE_VALUE(p) upper_16_bits(p)
> -
> #define RISCV_ALTERNATIVES_BOOT 0 /* alternatives applied during regular boot */
> #define RISCV_ALTERNATIVES_MODULE 1 /* alternatives applied during module-init */
> #define RISCV_ALTERNATIVES_EARLY_BOOT 2 /* alternatives applied before mmu start */
> diff --git a/arch/riscv/include/asm/cpufeature-macros.h b/arch/riscv/include/asm/cpufeature-macros.h
> index adaf9e3fb25c..7bd900899bb0 100644
> --- a/arch/riscv/include/asm/cpufeature-macros.h
> +++ b/arch/riscv/include/asm/cpufeature-macros.h
> @@ -45,14 +45,16 @@ static __always_inline bool __riscv_has_extension_unlikely(const unsigned long v
>
> static __always_inline bool riscv_has_extension_unlikely(const unsigned long ext)
> {
> - compiletime_assert(ext < RISCV_ISA_EXT_MAX, "ext must be < RISCV_ISA_EXT_MAX");
> + int realext = PATCH_ID_CPUFEATURE_ID(ext);
> + compiletime_assert(realext < RISCV_ISA_EXT_MAX, "ext must be < RISCV_ISA_EXT_MAX");
>
> return __riscv_has_extension_unlikely(STANDARD_EXT, ext);
> }
Please don't abuse riscv_has_extension_*() for things that are not
extensions. I don't mind if you do something that wraps
__riscv_has_extension_*() to make use of the underlying infrastructure
but I am against muddying the standard extension space with linux internal
stuff - particularly in this manner because this:
> +static __always_inline bool has_vstate_opt(void)
> +{
> + return riscv_has_extension_likely((RISCV_CPUFEAT_VSTATEOPT << 16) | RISCV_ISA_EXT_ZVE32X);
> +}
is incredibly confusing and error prone.
Recently enough I talked about something very very similar with Jisheng,
in the context of using an alternative for misaligned access, and I
said:
| ...I'd rather see __riscv_has_extension_*() get renamed
| to __riscv_has_cap*(), so that things like unaligned access speed get a
| different namespace to standard and vendor extensions. IOW you'd end up
| with
|
| static __always_inline bool riscv_has_extension_unlikely(const unsigned long ext)
| {
| compiletime_assert(ext < RISCV_ISA_EXT_MAX, "ext must be < RISCV_ISA_EXT_MAX");
|
| return __riscv_has_cap_unlikely(STANDARD_EXT, ext);
| }
|
| static __always_inline bool riscv_has_vendor_extension_unlikely(const unsigned long vendor,
| const unsigned long ext)
| {
| if (!IS_ENABLED(CONFIG_RISCV_ISA_VENDOR_EXT))
| return false;
|
| return __riscv_has_cap_unlikely(vendor, ext + RISCV_VENDOR_EXT_ALTERNATIVES_BASE);
| }
|
| static __always_inline bool riscv_has_cap_unlikely(const unsigned long cap)
| {
| return __riscv_has_cap_unlikely(LINUX_CAP, cap);
| }
|
| Currently standard extensions use 0 as the vendor, perhaps we could then
| use -1 (the value is an unsigned long) for non extension related caps?
What's here, with this realext business definitely looks like a hack.
Doing what I suggest above allows you to have a real key that you can
set, just like the vendor extensions do. You can call a function from
riscv_fill_hwcap() to populate the bitmap and modify
_apply_alternatives() to additionally patch this sort of thing.
Cheers,
Conor.
pw-bot: changes-requested
>
> static __always_inline bool riscv_has_extension_likely(const unsigned long ext)
> {
> - compiletime_assert(ext < RISCV_ISA_EXT_MAX, "ext must be < RISCV_ISA_EXT_MAX");
> + int realext = PATCH_ID_CPUFEATURE_ID(ext);
> + compiletime_assert(realext < RISCV_ISA_EXT_MAX, "ext must be < RISCV_ISA_EXT_MAX");
>
> return __riscv_has_extension_likely(STANDARD_EXT, ext);
> }
> diff --git a/arch/riscv/include/asm/vector.h b/arch/riscv/include/asm/vector.h
> index e83f9e0046a9..745ac3ca67b7 100644
> --- a/arch/riscv/include/asm/vector.h
> +++ b/arch/riscv/include/asm/vector.h
> @@ -49,6 +49,7 @@
> _res; \
> })
>
> +extern bool riscv_v_vstate_opt;
> extern unsigned long riscv_v_vsize;
> int riscv_v_setup_vsize(void);
> bool insn_is_vector(u32 insn_buf);
> @@ -78,6 +79,11 @@ static __always_inline bool has_vector(void)
> return riscv_has_extension_unlikely(RISCV_ISA_EXT_ZVE32X);
> }
>
> +static __always_inline bool has_vstate_opt(void)
> +{
> + return riscv_has_extension_likely((RISCV_CPUFEAT_VSTATEOPT << 16) | RISCV_ISA_EXT_ZVE32X);
> +}
> +
> static __always_inline bool has_xtheadvector_no_alternatives(void)
> {
> if (IS_ENABLED(CONFIG_RISCV_ISA_XTHEADVECTOR))
> @@ -122,6 +128,9 @@ static inline bool riscv_v_vstate_query(struct pt_regs *regs)
>
> static __always_inline void riscv_v_enable(void)
> {
> + if (has_vstate_opt())
> + return;
> +
> if (has_xtheadvector())
> csr_set(CSR_SSTATUS, SR_VS_THEAD);
> else
> @@ -130,6 +139,9 @@ static __always_inline void riscv_v_enable(void)
>
> static __always_inline void riscv_v_disable(void)
> {
> + if (has_vstate_opt())
> + return;
> +
> if (has_xtheadvector())
> csr_clear(CSR_SSTATUS, SR_VS_THEAD);
> else
> @@ -336,7 +348,8 @@ static inline void riscv_v_vstate_set_restore(struct task_struct *task,
> static inline void riscv_v_vstate_discard(struct pt_regs *regs)
> {
> if (__riscv_v_vstate_check_gt(regs->status, INITIAL)) {
> - riscv_v_vstate_set_restore(current, regs);
> + if (!has_vstate_opt())
> + riscv_v_vstate_set_restore(current, regs);
> riscv_v_vstate_init(regs);
> }
> }
> @@ -422,6 +435,7 @@ struct pt_regs;
>
> static inline int riscv_v_setup_vsize(void) { return -EOPNOTSUPP; }
> static __always_inline bool has_vector(void) { return false; }
> +static __always_inline bool has_vstate_opt(void) { return false; }
> static __always_inline bool insn_is_vector(u32 insn_buf) { return false; }
> static __always_inline bool has_xtheadvector_no_alternatives(void) { return false; }
> static __always_inline bool has_xtheadvector(void) { return false; }
> diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
> index 72bce616491f..041f6a35fba3 100644
> --- a/arch/riscv/kernel/cpufeature.c
> +++ b/arch/riscv/kernel/cpufeature.c
> @@ -1294,6 +1294,19 @@ void riscv_clear_hypervisor_csr(void)
> csr_clear(CSR_HSTATUS, HSTATUS_HU);
> }
>
> +/*
> + * Leaving Vector enabled while in the kernel relies on the vstate alternatives
> + * being patched in. It can be turned off on the command line to catch illegal
> + * use of Vector in kernel code.
> + */
> +bool riscv_v_vstate_opt = true;
> +static int __init riscv_novstateopt_setup(char *__unused)
> +{
> + riscv_v_vstate_opt = false;
> + return 0;
> +}
> +early_param("riscv_novstateopt", riscv_novstateopt_setup);
> +
> /*
> * Alternative patch sites consider 48 bits when determining when to patch
> * the old instruction sequence with the new. These bits are broken into a
> @@ -1322,6 +1335,11 @@ static bool riscv_cpufeature_patch_check(u16 id, u16 value)
> * then the alternative cannot be applied.
> */
> return riscv_cboz_block_size <= (1U << value);
> + case RISCV_ISA_EXT_ZVE32X:
> + if (value == RISCV_CPUFEAT_VSTATEOPT)
> + return riscv_v_vstate_opt;
> +
> + return true;
> }
>
> return false;
> diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S
> index 628b85e3915a..bb4787711f2c 100644
> --- a/arch/riscv/kernel/entry.S
> +++ b/arch/riscv/kernel/entry.S
> @@ -6,6 +6,7 @@
>
> #include <linux/init.h>
> #include <linux/linkage.h>
> +#include <linux/stringify.h>
>
> #include <asm/alternative-macros.h>
> #include <asm/asm.h>
> @@ -175,10 +176,13 @@ SYM_CODE_START(handle_exception)
> * Disable user-mode memory access as it should only be set in the
> * actual user copy routines.
> *
> - * Disable the FPU/Vector to detect illegal usage of floating point
> + * Disable the FPU to detect illegal usage of floating point
> * or vector in kernel space.
> */
> - li t0, SR_SUM | SR_FS_VS
> + li t0, SR_SUM | SR_FS
> + ALTERNATIVE(__stringify(ori t0, t0, SR_VS), "nop", 0,
> + (RISCV_CPUFEAT_VSTATEOPT << 16) | RISCV_ISA_EXT_ZVE32X,
> + CONFIG_RISCV_ISA_V)
> #ifdef CONFIG_64BIT
> li t1, SR_ELP
> or t0, t0, t1
> @@ -186,6 +190,13 @@ SYM_CODE_START(handle_exception)
>
> REG_L s0, TASK_TI_USER_SP(tp)
> csrrc s1, CSR_STATUS, t0
> + ALTERNATIVE("j .Lskip_v_enable", __stringify(andi t0, s1, SR_VS), 0,
> + (RISCV_CPUFEAT_VSTATEOPT << 16) | RISCV_ISA_EXT_ZVE32X,
> + CONFIG_RISCV_ISA_V)
> + bnez t0, .Lskip_v_enable
> + li a0, SR_VS_INITIAL
> + csrs CSR_STATUS, a0
> +.Lskip_v_enable:
> save_userssp s2, s1
> csrr s2, CSR_EPC
> csrr s3, CSR_TVAL
> diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c
> index 34c1d498d1ca..27146b3fa738 100644
> --- a/arch/riscv/kernel/process.c
> +++ b/arch/riscv/kernel/process.c
> @@ -258,6 +258,9 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
> /* Supervisor/Machine, irqs on: */
> childregs->status = SR_PP | SR_PIE;
>
> + if (has_vstate_opt())
> + riscv_v_vstate_init(childregs);
> +
> p->thread.s[0] = (unsigned long)args->fn;
> p->thread.s[1] = (unsigned long)args->fn_arg;
> p->thread.ra = (unsigned long)ret_from_fork_kernel_asm;
> diff --git a/arch/riscv/kernel/vector.c b/arch/riscv/kernel/vector.c
> index 6fd541f5d5cb..eec9deff8da7 100644
> --- a/arch/riscv/kernel/vector.c
> +++ b/arch/riscv/kernel/vector.c
> @@ -12,6 +12,7 @@
> #include <linux/prctl.h>
>
> #include <asm/thread_info.h>
> +#include <asm/cpufeature.h>
> #include <asm/processor.h>
> #include <asm/insn.h>
> #include <asm/vector.h>
> @@ -69,6 +70,16 @@ void riscv_v_ucontext_save(struct task_struct *tsk)
> int riscv_v_setup_vsize(void)
> {
> unsigned long this_vsize;
> + bool v_always_on = false;
> +
> + /*
> + * has_vstate_opt() cannot be used here if called from riscv_fill_hwcap(), before
> + * apply_boot_alternatives(),
> + */
> + if (__riscv_isa_extension_available(NULL, RISCV_ISA_EXT_ZVE32X) && riscv_v_vstate_opt) {
> + v_always_on = true;
> + csr_set(CSR_SSTATUS, SR_VS_INITIAL);
> + }
>
> /*
> * There are 32 vector registers with vlenb length.
> @@ -81,9 +92,11 @@ int riscv_v_setup_vsize(void)
> return 0;
> }
>
> - riscv_v_enable();
> + if (!v_always_on)
> + riscv_v_enable();
> this_vsize = csr_read(CSR_VLENB) * 32;
> - riscv_v_disable();
> + if (!v_always_on)
> + riscv_v_disable();
>
> if (!riscv_v_vsize) {
> riscv_v_vsize = this_vsize;
> --
> 2.43.0
>
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
[-- Attachment #2: Type: text/plain, Size: 161 bytes --]
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v7 3/6] riscv: clarify vector state semantics on syscall and context switch
2026-11-11 18:43 ` [PATCH v7 3/6] riscv: clarify vector state semantics on syscall and context switch Andy Chiu
@ 2026-11-12 12:12 ` kernel test robot
0 siblings, 0 replies; 20+ messages in thread
From: kernel test robot @ 2026-11-12 12:12 UTC (permalink / raw)
To: Andy Chiu, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Oleg Nesterov, linux-riscv
Cc: oe-kbuild-all, andybnac, daichengrong, gdb, Andy Chiu, dfustini,
greentime.hu, Yong-Xuan Wang, Aurelien Jarno, Anup Patel,
Guobin Zhang, Troy Mitchell, Deepak Gupta, Sergey Matyukevich
Hi Andy,
kernel test robot noticed the following build errors:
[auto build test ERROR on d1a8d411533d6be16ac79796c02a9bfc7d7958f1]
url: https://github.com/intel-lab-lkp/linux/commits/Andy-Chiu/riscv-vector-refactor-vector-context-operations/20261111-124323
base: d1a8d411533d6be16ac79796c02a9bfc7d7958f1
patch link: https://lore.kernel.org/r/20261111184359.1239821-4-tchiu%40tenstorrent.com
patch subject: [PATCH v7 3/6] riscv: clarify vector state semantics on syscall and context switch
config: riscv-allnoconfig (https://download.01.org/0day-ci/archive/20261112/202611122049.91BrkXTs-lkp@intel.com/config)
compiler: riscv64-linux-gcc (GCC) 16.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20261112/202611122049.91BrkXTs-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202611122049.91BrkXTs-lkp@intel.com/
All errors (new ones prefixed by >>):
arch/riscv/kernel/signal.c: In function '__restore_v_state':
>> arch/riscv/kernel/signal.c:130:9: error: implicit declaration of function '__riscv_v_vstate_clean'; did you mean 'riscv_v_vstate_query'? [-Wimplicit-function-declaration]
130 | __riscv_v_vstate_clean(regs);
| ^~~~~~~~~~~~~~~~~~~~~~
| riscv_v_vstate_query
vim +130 arch/riscv/kernel/signal.c
107
108 /*
109 * Restore Vector extension context from the user's signal frame. This function
110 * assumes a valid extension header. So magic and size checking must be done by
111 * the caller.
112 */
113 static long __restore_v_state(struct pt_regs *regs, void __user *sc_vec)
114 {
115 long err;
116 struct __sc_riscv_v_state __user *state = sc_vec;
117 void __user *datap;
118
119 /*
120 * Mark the vstate as clean prior performing the actual copy,
121 * to avoid getting the vstate incorrectly clobbered by the
122 * discarded vector state.
123 *
124 * This also allows user to modify vregs through the signal
125 * interface at a syscall stop. e.g. to support user space
126 * context switching.
127 */
128 preempt_disable();
129 riscv_v_vstate_set_restore(current, regs);
> 130 __riscv_v_vstate_clean(regs);
131 preempt_enable();
132
133 /* Copy everything of __sc_riscv_v_state except datap. */
134 err = __copy_from_user(¤t->thread.vstate, &state->v_state,
135 offsetof(struct __riscv_v_ext_state, datap));
136 if (unlikely(err))
137 return err;
138
139 /* Copy the pointer datap itself. */
140 err = __get_user(datap, &state->v_state.datap);
141 if (unlikely(err))
142 return err;
143 /*
144 * Copy the whole vector content from user space datap. Use
145 * copy_from_user to prevent information leak.
146 */
147 return copy_from_user(current->thread.vstate.datap, datap, riscv_v_vsize);
148 }
149
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v7 3/6] riscv: clarify vector state semantics on syscall and context switch
@ 2026-11-12 12:12 ` kernel test robot
0 siblings, 0 replies; 20+ messages in thread
From: kernel test robot @ 2026-11-12 12:12 UTC (permalink / raw)
To: Andy Chiu, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Oleg Nesterov, linux-riscv
Cc: oe-kbuild-all, andybnac, daichengrong, gdb, Andy Chiu, dfustini,
greentime.hu, Yong-Xuan Wang, Aurelien Jarno, Anup Patel,
Guobin Zhang, Troy Mitchell, Deepak Gupta, Sergey Matyukevich
Hi Andy,
kernel test robot noticed the following build errors:
[auto build test ERROR on d1a8d411533d6be16ac79796c02a9bfc7d7958f1]
url: https://github.com/intel-lab-lkp/linux/commits/Andy-Chiu/riscv-vector-refactor-vector-context-operations/20261111-124323
base: d1a8d411533d6be16ac79796c02a9bfc7d7958f1
patch link: https://lore.kernel.org/r/20261111184359.1239821-4-tchiu%40tenstorrent.com
patch subject: [PATCH v7 3/6] riscv: clarify vector state semantics on syscall and context switch
config: riscv-allnoconfig (https://download.01.org/0day-ci/archive/20261112/202611122049.91BrkXTs-lkp@intel.com/config)
compiler: riscv64-linux-gcc (GCC) 16.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20261112/202611122049.91BrkXTs-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202611122049.91BrkXTs-lkp@intel.com/
All errors (new ones prefixed by >>):
arch/riscv/kernel/signal.c: In function '__restore_v_state':
>> arch/riscv/kernel/signal.c:130:9: error: implicit declaration of function '__riscv_v_vstate_clean'; did you mean 'riscv_v_vstate_query'? [-Wimplicit-function-declaration]
130 | __riscv_v_vstate_clean(regs);
| ^~~~~~~~~~~~~~~~~~~~~~
| riscv_v_vstate_query
vim +130 arch/riscv/kernel/signal.c
107
108 /*
109 * Restore Vector extension context from the user's signal frame. This function
110 * assumes a valid extension header. So magic and size checking must be done by
111 * the caller.
112 */
113 static long __restore_v_state(struct pt_regs *regs, void __user *sc_vec)
114 {
115 long err;
116 struct __sc_riscv_v_state __user *state = sc_vec;
117 void __user *datap;
118
119 /*
120 * Mark the vstate as clean prior performing the actual copy,
121 * to avoid getting the vstate incorrectly clobbered by the
122 * discarded vector state.
123 *
124 * This also allows user to modify vregs through the signal
125 * interface at a syscall stop. e.g. to support user space
126 * context switching.
127 */
128 preempt_disable();
129 riscv_v_vstate_set_restore(current, regs);
> 130 __riscv_v_vstate_clean(regs);
131 preempt_enable();
132
133 /* Copy everything of __sc_riscv_v_state except datap. */
134 err = __copy_from_user(¤t->thread.vstate, &state->v_state,
135 offsetof(struct __riscv_v_ext_state, datap));
136 if (unlikely(err))
137 return err;
138
139 /* Copy the pointer datap itself. */
140 err = __get_user(datap, &state->v_state.datap);
141 if (unlikely(err))
142 return err;
143 /*
144 * Copy the whole vector content from user space datap. Use
145 * copy_from_user to prevent information leak.
146 */
147 return copy_from_user(current->thread.vstate.datap, datap, riscv_v_vsize);
148 }
149
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 20+ messages in thread
end of thread, other threads:[~2026-11-12 12:13 UTC | newest]
Thread overview: 20+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-11 18:43 [PATCH v7 0/6] riscv: optimize mode switch latency for Vector Andy Chiu
2026-11-11 18:43 ` Andy Chiu
2026-11-11 18:43 ` [PATCH v7 1/6] riscv: vector: refactor vector context operations Andy Chiu
2026-11-11 18:43 ` Andy Chiu
2026-11-11 18:43 ` Andy Chiu
2026-11-11 19:30 ` sashiko-bot
2026-11-11 18:43 ` [PATCH v7 2/6] riscv: introduce riscv_v_ucontext_save() for signal and ptrace Andy Chiu
2026-11-11 18:43 ` [PATCH v7 3/6] riscv: clarify vector state semantics on syscall and context switch Andy Chiu
2026-11-12 12:12 ` kernel test robot
2026-11-12 12:12 ` kernel test robot
2026-11-11 18:43 ` [PATCH v7 4/6] selftests: riscv: Extend vector tests for sigreturn and ptrace Andy Chiu
2026-11-11 18:43 ` Andy Chiu
2026-11-11 18:43 ` [PATCH v7 5/6] riscv: vector: optimize vstate operations Andy Chiu
2026-11-11 18:43 ` Andy Chiu
2026-11-11 23:00 ` Conor Dooley
2026-11-11 23:00 ` Conor Dooley
2026-11-11 18:43 ` [PATCH v7 6/6] riscv: KVM: do not save host vector context for vcpu Andy Chiu
2026-11-11 18:43 ` Andy Chiu
2026-11-11 18:43 ` Andy Chiu
2026-11-11 20:03 ` sashiko-bot
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.