Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions tools/testing/selftests/riscv/sigreturn/sigreturn.c
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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;
Expand Down
111 changes: 107 additions & 4 deletions tools/testing/selftests/riscv/vector/vstate_ptrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;

Expand All @@ -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;
Expand Down Expand Up @@ -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");

Expand All @@ -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();
}
Loading