Skip to content

Commit

Permalink
selftests: riscv: Fix vector tests
Browse files Browse the repository at this point in the history
Overhaul the riscv vector tests to use kselftest_harness to help the
test cases correctly report the results and decouple the individual test
cases from each other. With this refactoring, only run the test cases if
vector is reported and properly report the test case as skipped
otherwise. The v_initval_nolibc test was previously not checking if
vector was supported and used a function (malloc) which invalidates
the state of the vector registers.

Signed-off-by: Charlie Jenkins <charlie@rivosinc.com>
Tested-by: Yangyu Chen <cyy@cyyself.name>
Link: https://lore.kernel.org/r/20241113-xtheadvector-v11-12-236c22791ef9@rivosinc.com
Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
  • Loading branch information
Charlie Jenkins authored and Palmer Dabbelt committed Jan 18, 2025
1 parent 7fa00fd commit 57d7713
Show file tree
Hide file tree
Showing 8 changed files with 337 additions and 193 deletions.
3 changes: 2 additions & 1 deletion tools/testing/selftests/riscv/vector/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
vstate_exec_nolibc
vstate_prctl
v_initval_nolibc
v_initval
v_exec_initval_nolibc
17 changes: 13 additions & 4 deletions tools/testing/selftests/riscv/vector/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,27 @@
# Copyright (C) 2021 ARM Limited
# Originally tools/testing/arm64/abi/Makefile

TEST_GEN_PROGS := vstate_prctl v_initval_nolibc
TEST_GEN_PROGS_EXTENDED := vstate_exec_nolibc
TEST_GEN_PROGS := v_initval vstate_prctl
TEST_GEN_PROGS_EXTENDED := vstate_exec_nolibc v_exec_initval_nolibc

include ../../lib.mk

$(OUTPUT)/vstate_prctl: vstate_prctl.c ../hwprobe/sys_hwprobe.S
$(OUTPUT)/sys_hwprobe.o: ../hwprobe/sys_hwprobe.S
$(CC) -static -c -o$@ $(CFLAGS) $^

$(OUTPUT)/v_helpers.o: v_helpers.c
$(CC) -static -c -o$@ $(CFLAGS) $^

$(OUTPUT)/vstate_prctl: vstate_prctl.c $(OUTPUT)/sys_hwprobe.o $(OUTPUT)/v_helpers.o
$(CC) -static -o$@ $(CFLAGS) $(LDFLAGS) $^

$(OUTPUT)/vstate_exec_nolibc: vstate_exec_nolibc.c
$(CC) -nostdlib -static -include ../../../../include/nolibc/nolibc.h \
-Wall $(CFLAGS) $(LDFLAGS) $^ -o $@ -lgcc

$(OUTPUT)/v_initval_nolibc: v_initval_nolibc.c
$(OUTPUT)/v_initval: v_initval.c $(OUTPUT)/sys_hwprobe.o $(OUTPUT)/v_helpers.o
$(CC) -static -o$@ $(CFLAGS) $(LDFLAGS) $^

$(OUTPUT)/v_exec_initval_nolibc: v_exec_initval_nolibc.c
$(CC) -nostdlib -static -include ../../../../include/nolibc/nolibc.h \
-Wall $(CFLAGS) $(LDFLAGS) $^ -o $@ -lgcc
85 changes: 85 additions & 0 deletions tools/testing/selftests/riscv/vector/v_exec_initval_nolibc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Get values of vector registers as soon as the program starts to test if
* is properly cleaning the values before starting a new program. Vector
* registers are caller saved, so no function calls may happen before reading
* the values. To further ensure consistency, this file is compiled without
* libc and without auto-vectorization.
*
* To be "clean" all values must be either all ones or all zeroes.
*/

#define __stringify_1(x...) #x
#define __stringify(x...) __stringify_1(x)

int main(int argc, char **argv)
{
char prev_value = 0, value;
unsigned long vl;
int first = 1;

asm volatile (
".option push\n\t"
".option arch, +v\n\t"
"vsetvli %[vl], x0, e8, m1, ta, ma\n\t"
".option pop\n\t"
: [vl] "=r" (vl)
);

#define CHECK_VECTOR_REGISTER(register) ({ \
for (int i = 0; i < vl; i++) { \
asm volatile ( \
".option push\n\t" \
".option arch, +v\n\t" \
"vmv.x.s %0, " __stringify(register) "\n\t" \
"vsrl.vi " __stringify(register) ", " __stringify(register) ", 8\n\t" \
".option pop\n\t" \
: "=r" (value)); \
if (first) { \
first = 0; \
} else if (value != prev_value || !(value == 0x00 || value == 0xff)) { \
printf("Register " __stringify(register) \
" values not clean! value: %u\n", value); \
exit(-1); \
} \
prev_value = value; \
} \
})

CHECK_VECTOR_REGISTER(v0);
CHECK_VECTOR_REGISTER(v1);
CHECK_VECTOR_REGISTER(v2);
CHECK_VECTOR_REGISTER(v3);
CHECK_VECTOR_REGISTER(v4);
CHECK_VECTOR_REGISTER(v5);
CHECK_VECTOR_REGISTER(v6);
CHECK_VECTOR_REGISTER(v7);
CHECK_VECTOR_REGISTER(v8);
CHECK_VECTOR_REGISTER(v9);
CHECK_VECTOR_REGISTER(v10);
CHECK_VECTOR_REGISTER(v11);
CHECK_VECTOR_REGISTER(v12);
CHECK_VECTOR_REGISTER(v13);
CHECK_VECTOR_REGISTER(v14);
CHECK_VECTOR_REGISTER(v15);
CHECK_VECTOR_REGISTER(v16);
CHECK_VECTOR_REGISTER(v17);
CHECK_VECTOR_REGISTER(v18);
CHECK_VECTOR_REGISTER(v19);
CHECK_VECTOR_REGISTER(v20);
CHECK_VECTOR_REGISTER(v21);
CHECK_VECTOR_REGISTER(v22);
CHECK_VECTOR_REGISTER(v23);
CHECK_VECTOR_REGISTER(v24);
CHECK_VECTOR_REGISTER(v25);
CHECK_VECTOR_REGISTER(v26);
CHECK_VECTOR_REGISTER(v27);
CHECK_VECTOR_REGISTER(v28);
CHECK_VECTOR_REGISTER(v29);
CHECK_VECTOR_REGISTER(v30);
CHECK_VECTOR_REGISTER(v31);

#undef CHECK_VECTOR_REGISTER

return 0;
}
57 changes: 57 additions & 0 deletions tools/testing/selftests/riscv/vector/v_helpers.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// SPDX-License-Identifier: GPL-2.0-only

#include "../hwprobe/hwprobe.h"
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>

bool is_vector_supported(void)
{
struct riscv_hwprobe pair;

pair.key = RISCV_HWPROBE_KEY_IMA_EXT_0;
riscv_hwprobe(&pair, 1, 0, NULL, 0);
return pair.value & RISCV_HWPROBE_EXT_ZVE32X;
}

int launch_test(char *next_program, int test_inherit)
{
char *exec_argv[3], *exec_envp[1];
int rc, pid, status;

pid = fork();
if (pid < 0) {
printf("fork failed %d", pid);
return -1;
}

if (!pid) {
exec_argv[0] = next_program;
exec_argv[1] = test_inherit != 0 ? "x" : NULL;
exec_argv[2] = NULL;
exec_envp[0] = NULL;
/* launch the program again to check inherit */
rc = execve(next_program, exec_argv, exec_envp);
if (rc) {
perror("execve");
printf("child execve failed %d\n", rc);
exit(-1);
}
}

rc = waitpid(-1, &status, 0);
if (rc < 0) {
printf("waitpid failed\n");
return -3;
}

if ((WIFEXITED(status) && WEXITSTATUS(status) == -1) ||
WIFSIGNALED(status)) {
printf("child exited abnormally\n");
return -4;
}

return WEXITSTATUS(status);
}
6 changes: 6 additions & 0 deletions tools/testing/selftests/riscv/vector/v_helpers.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <stdbool.h>

bool is_vector_supported(void);

int launch_test(char *next_program, int test_inherit);
16 changes: 16 additions & 0 deletions tools/testing/selftests/riscv/vector/v_initval.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: GPL-2.0-only

#include "../../kselftest_harness.h"
#include "v_helpers.h"

#define NEXT_PROGRAM "./v_exec_initval_nolibc"

TEST(v_initval)
{
if (!is_vector_supported())
SKIP(return, "Vector not supported");

ASSERT_EQ(0, launch_test(NEXT_PROGRAM, 0));
}

TEST_HARNESS_MAIN
68 changes: 0 additions & 68 deletions tools/testing/selftests/riscv/vector/v_initval_nolibc.c

This file was deleted.

Loading

0 comments on commit 57d7713

Please sign in to comment.