Message ID | 20240403-vector_sigreturn_tests-v1-1-2e68b7a3b8d7@rivosinc.com |
---|---|
State | Accepted |
Commit | 9d5328eeb18597749b18f42ff7df1c9f485d3c3c |
Headers | show |
Series | riscv: selftests: Add signal handling vector tests | expand |
On Thu, Apr 4, 2024 at 1:47 PM Björn Töpel <bjorn@kernel.org> wrote: > > Charlie Jenkins <charlie@rivosinc.com> writes: > > > Add two tests to check vector save/restore when a signal is received > > during a vector routine. One test ensures that a value is not clobbered > > during signal handling. The other verifies that vector registers > > modified in the signal handler are properly reflected when the signal > > handling is complete. > > > > Signed-off-by: Charlie Jenkins <charlie@rivosinc.com> > > Nice! > > Reviewed-by: Björn Töpel <bjorn@rivosinc.com> Thanks! Reviewed-by: Andy Chiu <andy.chiu@sifive.com> Tested-by: Andy Chiu <andy.chiu@sifive.com>
On Wed, 03 Apr 2024 16:50:29 PDT (-0700), Charlie Jenkins wrote: > Add two tests to check vector save/restore when a signal is received > during a vector routine. One test ensures that a value is not clobbered > during signal handling. The other verifies that vector registers > modified in the signal handler are properly reflected when the signal > handling is complete. > > Signed-off-by: Charlie Jenkins <charlie@rivosinc.com> > --- > These tests came about to highlight the bug fixed in > https://lore.kernel.org/lkml/20240403072638.567446-1-bjorn@kernel.org/ > and will only pass with that fix applied. Thaks. I'm just staging this, I have a testcase too that I keep forgetting to post because I haven't gotten in into the selftests sanely yet... #include "../../kselftest.h" #include <signal.h> #include <stdlib.h> #include <asm/ptrace.h> #include <stdint.h> #define ITERATIONS (1 << 24) #define RISCV_V_MAGIC 0x53465457 struct __riscv_ctx_hdr { __u32 magic; __u32 size; }; struct __riscv_extra_ext_header { __u32 __padding[129] __attribute__((aligned(16))); /* * Reserved for expansion of sigcontext structure. Currently zeroed * upon signal, and must be zero upon sigreturn. */ __u32 reserved; struct __riscv_ctx_hdr hdr; }; struct __riscv_v_ext_state { unsigned long vstart; unsigned long vl; unsigned long vtype; unsigned long vcsr; unsigned long vlenb; void *datap; /* * In signal handler, datap will be set a correct user stack offset * and vector registers will be copied to the address of datap * pointer. */ }; /* The beginning of the actual state. */ int count; void handler(int, siginfo_t *si, void *ucontext_void) { ucontext_t *ucontext = ucontext_void; /* Skip over the SEGV by just jumping to a0. */ ucontext->uc_mcontext.__gregs[REG_PC] = ucontext->uc_mcontext.__gregs[REG_A0]; /* Increment the first element of v0. */ { struct __riscv_extra_ext_header *ext; struct __riscv_v_ext_state *v_ext_state; uint32_t val; /* Find the vector context. */ ext = (void *)(&ucontext->uc_mcontext.__fpregs); if (ext->hdr.magic != RISCV_V_MAGIC) { fprintf(stderr, "bad vector magic: %x\n", ext->hdr.magic); abort(); } v_ext_state = (void *)((char *)(ext) + sizeof(*ext)); /* Actually do the increment. */ memcpy(&val, v_ext_state->datap, sizeof(val)); val++; memcpy(v_ext_state->datap, &val, sizeof(val)); } /* Count the delivered signal, to make sure we don't miss any. */ count++; } void sigill(int, siginfo_t *si, void *ucontext_void) { fprintf(stderr, "SIGILL after %d iterations\n", count); abort(); } void check_signal(void) { int check = rand(); int out; __asm__ volatile ( "vsetvli a0, %2, e32, ta, ma\n\t" "vmv.s.x v0, %1\n\t" "la a0, 1f\n\t" "lw t0, 0(x0)\n\t" "1:\n\t" "vmv.x.s %0, v0" : "=&r"(out) : "r"(check-1), "r"(1) : "a0" #ifdef __riscv_vector , "v0" #endif ); if (out != check) { fprintf(stderr, "out: %d\ncheck: %d\n", out, check); abort(); } } int main(void) { struct sigaction sa_segv, sa_ill; memset(&sa_segv, 0, sizeof(sa_segv)); sa_segv.sa_sigaction = &handler; sa_segv.sa_flags = SA_SIGINFO; sigaction(SIGSEGV, &sa_segv, NULL); memset(&sa_ill, 0, sizeof(sa_ill)); sa_ill.sa_sigaction = &sigill; sa_ill.sa_flags = SA_SIGINFO; sigaction(SIGILL, &sa_ill, NULL); count = 0; for (int i = 0; i < ITERATIONS; ++i) check_signal(); if (count != ITERATIONS) { fprintf(stderr, "count: %d\n", count); abort(); } return 0; } > --- > tools/testing/selftests/riscv/Makefile | 2 +- > tools/testing/selftests/riscv/sigreturn/.gitignore | 1 + > tools/testing/selftests/riscv/sigreturn/Makefile | 12 ++++ > .../testing/selftests/riscv/sigreturn/sigreturn.c | 82 ++++++++++++++++++++++ > 4 files changed, 96 insertions(+), 1 deletion(-) > > diff --git a/tools/testing/selftests/riscv/Makefile b/tools/testing/selftests/riscv/Makefile > index 4a9ff515a3a0..7ce03d832b64 100644 > --- a/tools/testing/selftests/riscv/Makefile > +++ b/tools/testing/selftests/riscv/Makefile > @@ -5,7 +5,7 @@ > ARCH ?= $(shell uname -m 2>/dev/null || echo not) > > ifneq (,$(filter $(ARCH),riscv)) > -RISCV_SUBTARGETS ?= hwprobe vector mm > +RISCV_SUBTARGETS ?= hwprobe vector mm sigreturn > else > RISCV_SUBTARGETS := > endif > diff --git a/tools/testing/selftests/riscv/sigreturn/.gitignore b/tools/testing/selftests/riscv/sigreturn/.gitignore > new file mode 100644 > index 000000000000..35002b8ae780 > --- /dev/null > +++ b/tools/testing/selftests/riscv/sigreturn/.gitignore > @@ -0,0 +1 @@ > +sigreturn > diff --git a/tools/testing/selftests/riscv/sigreturn/Makefile b/tools/testing/selftests/riscv/sigreturn/Makefile > new file mode 100644 > index 000000000000..eb8bac9279a8 > --- /dev/null > +++ b/tools/testing/selftests/riscv/sigreturn/Makefile > @@ -0,0 +1,12 @@ > +# SPDX-License-Identifier: GPL-2.0 > +# Copyright (C) 2021 ARM Limited > +# Originally tools/testing/arm64/abi/Makefile > + > +CFLAGS += -I$(top_srcdir)/tools/include > + > +TEST_GEN_PROGS := sigreturn > + > +include ../../lib.mk > + > +$(OUTPUT)/sigreturn: sigreturn.c > + $(CC) -static -o$@ $(CFLAGS) $(LDFLAGS) $^ > diff --git a/tools/testing/selftests/riscv/sigreturn/sigreturn.c b/tools/testing/selftests/riscv/sigreturn/sigreturn.c > new file mode 100644 > index 000000000000..62397d5934f1 > --- /dev/null > +++ b/tools/testing/selftests/riscv/sigreturn/sigreturn.c > @@ -0,0 +1,82 @@ > +// SPDX-License-Identifier: GPL-2.0-only > +#include <signal.h> > +#include <stdio.h> > +#include <stdlib.h> > +#include <ucontext.h> > +#include <linux/ptrace.h> > +#include "../../kselftest_harness.h" > + > +#define RISCV_V_MAGIC 0x53465457 > +#define DEFAULT_VALUE 2 > +#define SIGNAL_HANDLER_OVERRIDE 3 > + > +static void simple_handle(int sig_no, siginfo_t *info, void *vcontext) > +{ > + ucontext_t *context = vcontext; > + > + context->uc_mcontext.__gregs[REG_PC] = context->uc_mcontext.__gregs[REG_PC] + 4; > +} > + > +static void vector_override(int sig_no, siginfo_t *info, void *vcontext) > +{ > + ucontext_t *context = vcontext; > + > + // vector state > + struct __riscv_extra_ext_header *ext; > + struct __riscv_v_ext_state *v_ext_state; > + > + /* Find the vector context. */ > + ext = (void *)(&context->uc_mcontext.__fpregs); > + if (ext->hdr.magic != RISCV_V_MAGIC) { > + fprintf(stderr, "bad vector magic: %x\n", ext->hdr.magic); > + abort(); > + } > + > + v_ext_state = (void *)((char *)(ext) + sizeof(*ext)); > + > + *(int *)v_ext_state->datap = SIGNAL_HANDLER_OVERRIDE; > + > + context->uc_mcontext.__gregs[REG_PC] = context->uc_mcontext.__gregs[REG_PC] + 4; > +} > + > +static int vector_sigreturn(int data, void (*handler)(int, siginfo_t *, void *)) > +{ > + int after_sigreturn; > + struct sigaction sig_action = { > + .sa_sigaction = handler, > + .sa_flags = SA_SIGINFO > + }; > + > + sigaction(SIGSEGV, &sig_action, 0); > + > + asm(".option push \n\ > + .option arch, +v \n\ > + vsetivli x0, 1, e32, ta, ma \n\ > + vmv.s.x v0, %1 \n\ > + # Generate SIGSEGV \n\ > + lw a0, 0(x0) \n\ > + vmv.x.s %0, v0 \n\ > + .option pop" : "=r" (after_sigreturn) : "r" (data)); > + > + return after_sigreturn; > +} > + > +TEST(vector_restore) > +{ > + int result; > + > + result = vector_sigreturn(DEFAULT_VALUE, &simple_handle); > + > + EXPECT_EQ(DEFAULT_VALUE, result); > +} > + > +TEST(vector_restore_signal_handler_override) > +{ > + int result; > + > + result = vector_sigreturn(DEFAULT_VALUE, &vector_override); > + > + EXPECT_EQ(SIGNAL_HANDLER_OVERRIDE, result); > +} > + > +TEST_HARNESS_MAIN > > --- > base-commit: 4cece764965020c22cff7665b18a012006359095 > change-id: 20240403-vector_sigreturn_tests-8118f0ac54fa
Hello: This patch was applied to riscv/linux.git (for-next) by Palmer Dabbelt <palmer@rivosinc.com>: On Wed, 03 Apr 2024 16:50:29 -0700 you wrote: > Add two tests to check vector save/restore when a signal is received > during a vector routine. One test ensures that a value is not clobbered > during signal handling. The other verifies that vector registers > modified in the signal handler are properly reflected when the signal > handling is complete. > > Signed-off-by: Charlie Jenkins <charlie@rivosinc.com> > > [...] Here is the summary with links: - riscv: selftests: Add signal handling vector tests https://git.kernel.org/riscv/c/b2a2e892cdbc You are awesome, thank you!
diff --git a/tools/testing/selftests/riscv/Makefile b/tools/testing/selftests/riscv/Makefile index 4a9ff515a3a0..7ce03d832b64 100644 --- a/tools/testing/selftests/riscv/Makefile +++ b/tools/testing/selftests/riscv/Makefile @@ -5,7 +5,7 @@ ARCH ?= $(shell uname -m 2>/dev/null || echo not) ifneq (,$(filter $(ARCH),riscv)) -RISCV_SUBTARGETS ?= hwprobe vector mm +RISCV_SUBTARGETS ?= hwprobe vector mm sigreturn else RISCV_SUBTARGETS := endif diff --git a/tools/testing/selftests/riscv/sigreturn/.gitignore b/tools/testing/selftests/riscv/sigreturn/.gitignore new file mode 100644 index 000000000000..35002b8ae780 --- /dev/null +++ b/tools/testing/selftests/riscv/sigreturn/.gitignore @@ -0,0 +1 @@ +sigreturn diff --git a/tools/testing/selftests/riscv/sigreturn/Makefile b/tools/testing/selftests/riscv/sigreturn/Makefile new file mode 100644 index 000000000000..eb8bac9279a8 --- /dev/null +++ b/tools/testing/selftests/riscv/sigreturn/Makefile @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0 +# Copyright (C) 2021 ARM Limited +# Originally tools/testing/arm64/abi/Makefile + +CFLAGS += -I$(top_srcdir)/tools/include + +TEST_GEN_PROGS := sigreturn + +include ../../lib.mk + +$(OUTPUT)/sigreturn: sigreturn.c + $(CC) -static -o$@ $(CFLAGS) $(LDFLAGS) $^ diff --git a/tools/testing/selftests/riscv/sigreturn/sigreturn.c b/tools/testing/selftests/riscv/sigreturn/sigreturn.c new file mode 100644 index 000000000000..62397d5934f1 --- /dev/null +++ b/tools/testing/selftests/riscv/sigreturn/sigreturn.c @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <ucontext.h> +#include <linux/ptrace.h> +#include "../../kselftest_harness.h" + +#define RISCV_V_MAGIC 0x53465457 +#define DEFAULT_VALUE 2 +#define SIGNAL_HANDLER_OVERRIDE 3 + +static void simple_handle(int sig_no, siginfo_t *info, void *vcontext) +{ + ucontext_t *context = vcontext; + + context->uc_mcontext.__gregs[REG_PC] = context->uc_mcontext.__gregs[REG_PC] + 4; +} + +static void vector_override(int sig_no, siginfo_t *info, void *vcontext) +{ + ucontext_t *context = vcontext; + + // vector state + struct __riscv_extra_ext_header *ext; + struct __riscv_v_ext_state *v_ext_state; + + /* Find the vector context. */ + ext = (void *)(&context->uc_mcontext.__fpregs); + if (ext->hdr.magic != RISCV_V_MAGIC) { + fprintf(stderr, "bad vector magic: %x\n", ext->hdr.magic); + abort(); + } + + v_ext_state = (void *)((char *)(ext) + sizeof(*ext)); + + *(int *)v_ext_state->datap = SIGNAL_HANDLER_OVERRIDE; + + context->uc_mcontext.__gregs[REG_PC] = context->uc_mcontext.__gregs[REG_PC] + 4; +} + +static int vector_sigreturn(int data, void (*handler)(int, siginfo_t *, void *)) +{ + int after_sigreturn; + struct sigaction sig_action = { + .sa_sigaction = handler, + .sa_flags = SA_SIGINFO + }; + + sigaction(SIGSEGV, &sig_action, 0); + + asm(".option push \n\ + .option arch, +v \n\ + vsetivli x0, 1, e32, ta, ma \n\ + vmv.s.x v0, %1 \n\ + # Generate SIGSEGV \n\ + lw a0, 0(x0) \n\ + vmv.x.s %0, v0 \n\ + .option pop" : "=r" (after_sigreturn) : "r" (data)); + + return after_sigreturn; +} + +TEST(vector_restore) +{ + int result; + + result = vector_sigreturn(DEFAULT_VALUE, &simple_handle); + + EXPECT_EQ(DEFAULT_VALUE, result); +} + +TEST(vector_restore_signal_handler_override) +{ + int result; + + result = vector_sigreturn(DEFAULT_VALUE, &vector_override); + + EXPECT_EQ(SIGNAL_HANDLER_OVERRIDE, result); +} + +TEST_HARNESS_MAIN
Add two tests to check vector save/restore when a signal is received during a vector routine. One test ensures that a value is not clobbered during signal handling. The other verifies that vector registers modified in the signal handler are properly reflected when the signal handling is complete. Signed-off-by: Charlie Jenkins <charlie@rivosinc.com> --- These tests came about to highlight the bug fixed in https://lore.kernel.org/lkml/20240403072638.567446-1-bjorn@kernel.org/ and will only pass with that fix applied. --- tools/testing/selftests/riscv/Makefile | 2 +- tools/testing/selftests/riscv/sigreturn/.gitignore | 1 + tools/testing/selftests/riscv/sigreturn/Makefile | 12 ++++ .../testing/selftests/riscv/sigreturn/sigreturn.c | 82 ++++++++++++++++++++++ 4 files changed, 96 insertions(+), 1 deletion(-) --- base-commit: 4cece764965020c22cff7665b18a012006359095 change-id: 20240403-vector_sigreturn_tests-8118f0ac54fa