Unverified Commit 57d7713a authored by Charlie Jenkins's avatar Charlie Jenkins Committed by Palmer Dabbelt
Browse files

selftests: riscv: Fix vector tests



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: default avatarCharlie Jenkins <charlie@rivosinc.com>
Tested-by: default avatarYangyu Chen <cyy@cyyself.name>
Link: https://lore.kernel.org/r/20241113-xtheadvector-v11-12-236c22791ef9@rivosinc.com


Signed-off-by: default avatarPalmer Dabbelt <palmer@rivosinc.com>
parent 7fa00fd6
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
vstate_exec_nolibc
vstate_prctl
v_initval_nolibc
v_initval
v_exec_initval_nolibc
+13 −4
Original line number Diff line number Diff line
@@ -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 −0
Original line number Diff line number Diff line
// 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 −0
Original line number Diff line number Diff line
// 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 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
#include <stdbool.h>

bool is_vector_supported(void);

int launch_test(char *next_program, int test_inherit);
Loading