Commit 82f97bcd authored by Mark Brown's avatar Mark Brown Committed by Catalin Marinas

kselftest/arm64: Validate setting via FPSIMD and read via SVE regsets

Currently we validate that we can set the floating point state via the SVE
regset and read the data via the FPSIMD regset but we do not valiate that
the opposite case works as expected. Add a test that covers this case,
noting that when reading via SVE regset the kernel has the option of
returning either SVE or FPSIMD data so we need to accept both formats.
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
Reviewed-by: default avatarShuah Khan <skhan@linuxfoundation.org>
Link: https://lore.kernel.org/r/20220404090613.181272-4-broonie@kernel.orgSigned-off-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
parent 1fb1e285
......@@ -44,7 +44,7 @@ static const struct vec_type vec_types[] = {
},
};
#define VL_TESTS (((SVE_VQ_MAX - SVE_VQ_MIN) + 1) * 3)
#define VL_TESTS (((SVE_VQ_MAX - SVE_VQ_MIN) + 1) * 4)
#define FLAG_TESTS 2
#define FPSIMD_TESTS 2
......@@ -78,6 +78,15 @@ static int get_fpsimd(pid_t pid, struct user_fpsimd_state *fpsimd)
return ptrace(PTRACE_GETREGSET, pid, NT_PRFPREG, &iov);
}
static int set_fpsimd(pid_t pid, struct user_fpsimd_state *fpsimd)
{
struct iovec iov;
iov.iov_base = fpsimd;
iov.iov_len = sizeof(*fpsimd);
return ptrace(PTRACE_SETREGSET, pid, NT_PRFPREG, &iov);
}
static struct user_sve_header *get_sve(pid_t pid, const struct vec_type *type,
void **buf, size_t *size)
{
......@@ -473,6 +482,115 @@ static void ptrace_set_sve_get_fpsimd_data(pid_t child,
free(write_buf);
}
/* Validate attempting to set FPSIMD data and read it via the SVE regset */
static void ptrace_set_fpsimd_get_sve_data(pid_t child,
const struct vec_type *type,
unsigned int vl)
{
void *read_buf = NULL;
unsigned char *p;
struct user_sve_header *read_sve;
unsigned int vq = sve_vq_from_vl(vl);
struct user_fpsimd_state write_fpsimd;
int ret, i, j;
size_t read_sve_size = 0;
size_t expected_size;
int errors = 0;
if (__BYTE_ORDER == __BIG_ENDIAN) {
ksft_test_result_skip("Big endian not supported\n");
return;
}
for (i = 0; i < 32; ++i) {
p = (unsigned char *)&write_fpsimd.vregs[i];
for (j = 0; j < sizeof(write_fpsimd.vregs[i]); ++j)
p[j] = j;
}
ret = set_fpsimd(child, &write_fpsimd);
if (ret != 0) {
ksft_test_result_fail("Failed to set FPSIMD state: %d\n)",
ret);
return;
}
if (!get_sve(child, type, (void **)&read_buf, &read_sve_size)) {
ksft_test_result_fail("Failed to read %s VL %u data\n",
type->name, vl);
return;
}
read_sve = read_buf;
if (read_sve->vl != vl) {
ksft_test_result_fail("Child VL != expected VL %d\n",
read_sve->vl, vl);
goto out;
}
/* The kernel may return either SVE or FPSIMD format */
switch (read_sve->flags & SVE_PT_REGS_MASK) {
case SVE_PT_REGS_FPSIMD:
expected_size = SVE_PT_FPSIMD_SIZE(vq, SVE_PT_REGS_FPSIMD);
if (read_sve_size < expected_size) {
ksft_test_result_fail("Read %d bytes, expected %d\n",
read_sve_size, expected_size);
goto out;
}
ret = memcmp(&write_fpsimd, read_buf + SVE_PT_FPSIMD_OFFSET,
sizeof(write_fpsimd));
if (ret != 0) {
ksft_print_msg("Read FPSIMD data mismatch\n");
errors++;
}
break;
case SVE_PT_REGS_SVE:
expected_size = SVE_PT_SVE_SIZE(vq, SVE_PT_REGS_SVE);
if (read_sve_size < expected_size) {
ksft_test_result_fail("Read %d bytes, expected %d\n",
read_sve_size, expected_size);
goto out;
}
for (i = 0; i < __SVE_NUM_ZREGS; i++) {
__uint128_t tmp = 0;
/*
* Z regs are stored endianness invariant, this won't
* work for big endian
*/
memcpy(&tmp, read_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),
sizeof(tmp));
if (tmp != write_fpsimd.vregs[i]) {
ksft_print_msg("Mismatch in FPSIMD for %s VL %u Z%d/V%d\n",
type->name, vl, i, i);
errors++;
}
}
check_u32(vl, "FPSR", &write_fpsimd.fpsr,
read_buf + SVE_PT_SVE_FPSR_OFFSET(vq), &errors);
check_u32(vl, "FPCR", &write_fpsimd.fpcr,
read_buf + SVE_PT_SVE_FPCR_OFFSET(vq), &errors);
break;
default:
ksft_print_msg("Unexpected regs type %d\n",
read_sve->flags & SVE_PT_REGS_MASK);
errors++;
break;
}
ksft_test_result(errors == 0, "Set FPSIMD, read via SVE for %s VL %u\n",
type->name, vl);
out:
free(read_buf);
}
static int do_parent(pid_t child)
{
int ret = EXIT_FAILURE;
......@@ -578,11 +696,14 @@ static int do_parent(pid_t child)
if (vl_supported) {
ptrace_set_sve_get_sve_data(child, &vec_types[i], vl);
ptrace_set_sve_get_fpsimd_data(child, &vec_types[i], vl);
ptrace_set_fpsimd_get_sve_data(child, &vec_types[i], vl);
} else {
ksft_test_result_skip("%s set SVE get SVE for VL %d\n",
vec_types[i].name, vl);
ksft_test_result_skip("%s set SVE get FPSIMD for VL %d\n",
vec_types[i].name, vl);
ksft_test_result_skip("%s set FPSIMD get SVE for VL %d\n",
vec_types[i].name, vl);
}
}
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment