Commit 5225b656 authored by Andre Przywara's avatar Andre Przywara Committed by Will Deacon

kselftest/arm64: signal: fix/refactor SVE vector length enumeration

Currently a number of SVE/SME related tests have almost identical
functions to enumerate all supported vector lengths. However over time
the copy&pasted code has diverged, allowing some bugs to creep in:
- fake_sigreturn_sme_change_vl reports a failure, not a SKIP if only
  one vector length is supported (but the SVE version is fine)
- fake_sigreturn_sme_change_vl tries to set the SVE vector length, not
  the SME one (but the other SME tests are fine)
- za_no_regs keeps iterating forever if only one vector length is
  supported (but za_regs is correct)

Since those bugs seem to be mostly copy&paste ones, let's consolidate
the enumeration loop into one shared function, and just call that from
each test. That should fix the above bugs, and prevent similar issues
from happening again.

Fixes: 4963aeb3 ("kselftest/arm64: signal: Add SME signal handling tests")
Signed-off-by: default avatarAndre Przywara <andre.przywara@arm.com>
Reviewed-by: default avatarMark Brown <broonie@kernel.org>
Link: https://lore.kernel.org/r/20240821164401.3598545-1-andre.przywara@arm.comSigned-off-by: default avatarWill Deacon <will@kernel.org>
parent 7c626ce4
......@@ -23,7 +23,7 @@ $(TEST_GEN_PROGS): $(PROGS)
# Common test-unit targets to build common-layout test-cases executables
# Needs secondary expansion to properly include the testcase c-file in pre-reqs
COMMON_SOURCES := test_signals.c test_signals_utils.c testcases/testcases.c \
signals.S
signals.S sve_helpers.c
COMMON_HEADERS := test_signals.h test_signals_utils.h testcases/testcases.h
.SECONDEXPANSION:
......
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2024 ARM Limited
*
* Common helper functions for SVE and SME functionality.
*/
#include <stdbool.h>
#include <kselftest.h>
#include <asm/sigcontext.h>
#include <sys/prctl.h>
unsigned int vls[SVE_VQ_MAX];
unsigned int nvls;
int sve_fill_vls(bool use_sme, int min_vls)
{
int vq, vl;
int pr_set_vl = use_sme ? PR_SME_SET_VL : PR_SVE_SET_VL;
int len_mask = use_sme ? PR_SME_VL_LEN_MASK : PR_SVE_VL_LEN_MASK;
/*
* Enumerate up to SVE_VQ_MAX vector lengths
*/
for (vq = SVE_VQ_MAX; vq > 0; --vq) {
vl = prctl(pr_set_vl, vq * 16);
if (vl == -1)
return KSFT_FAIL;
vl &= len_mask;
/*
* Unlike SVE, SME does not require the minimum vector length
* to be implemented, or the VLs to be consecutive, so any call
* to the prctl might return the single implemented VL, which
* might be larger than 16. So to avoid this loop never
* terminating, bail out here when we find a higher VL than
* we asked for.
* See the ARM ARM, DDI 0487K.a, B1.4.2: I_QQRNR and I_NWYBP.
*/
if (vq < sve_vq_from_vl(vl))
break;
/* Skip missing VLs */
vq = sve_vq_from_vl(vl);
vls[nvls++] = vl;
}
if (nvls < min_vls) {
fprintf(stderr, "Only %d VL supported\n", nvls);
return KSFT_SKIP;
}
return KSFT_PASS;
}
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2024 ARM Limited
*
* Common helper functions for SVE and SME functionality.
*/
#ifndef __SVE_HELPERS_H__
#define __SVE_HELPERS_H__
#include <stdbool.h>
#define VLS_USE_SVE false
#define VLS_USE_SME true
extern unsigned int vls[];
extern unsigned int nvls;
int sve_fill_vls(bool use_sme, int min_vls);
#endif
......@@ -6,44 +6,28 @@
* handler, this is not supported and is expected to segfault.
*/
#include <kselftest.h>
#include <signal.h>
#include <ucontext.h>
#include <sys/prctl.h>
#include "test_signals_utils.h"
#include "sve_helpers.h"
#include "testcases.h"
struct fake_sigframe sf;
static unsigned int vls[SVE_VQ_MAX];
unsigned int nvls = 0;
static bool sme_get_vls(struct tdescr *td)
{
int vq, vl;
int res = sve_fill_vls(VLS_USE_SME, 2);
/*
* Enumerate up to SVE_VQ_MAX vector lengths
*/
for (vq = SVE_VQ_MAX; vq > 0; --vq) {
vl = prctl(PR_SVE_SET_VL, vq * 16);
if (vl == -1)
return false;
if (!res)
return true;
vl &= PR_SME_VL_LEN_MASK;
if (res == KSFT_SKIP)
td->result = KSFT_SKIP;
/* Skip missing VLs */
vq = sve_vq_from_vl(vl);
vls[nvls++] = vl;
}
/* We need at least two VLs */
if (nvls < 2) {
fprintf(stderr, "Only %d VL supported\n", nvls);
return false;
}
return true;
return false;
}
static int fake_sigreturn_ssve_change_vl(struct tdescr *td,
......
......@@ -12,40 +12,22 @@
#include <sys/prctl.h>
#include "test_signals_utils.h"
#include "sve_helpers.h"
#include "testcases.h"
struct fake_sigframe sf;
static unsigned int vls[SVE_VQ_MAX];
unsigned int nvls = 0;
static bool sve_get_vls(struct tdescr *td)
{
int vq, vl;
int res = sve_fill_vls(VLS_USE_SVE, 2);
/*
* Enumerate up to SVE_VQ_MAX vector lengths
*/
for (vq = SVE_VQ_MAX; vq > 0; --vq) {
vl = prctl(PR_SVE_SET_VL, vq * 16);
if (vl == -1)
return false;
if (!res)
return true;
vl &= PR_SVE_VL_LEN_MASK;
/* Skip missing VLs */
vq = sve_vq_from_vl(vl);
vls[nvls++] = vl;
}
/* We need at least two VLs */
if (nvls < 2) {
fprintf(stderr, "Only %d VL supported\n", nvls);
if (res == KSFT_SKIP)
td->result = KSFT_SKIP;
return false;
}
return true;
return false;
}
static int fake_sigreturn_sve_change_vl(struct tdescr *td,
......
......@@ -6,51 +6,31 @@
* set up as expected.
*/
#include <kselftest.h>
#include <signal.h>
#include <ucontext.h>
#include <sys/prctl.h>
#include "test_signals_utils.h"
#include "sve_helpers.h"
#include "testcases.h"
static union {
ucontext_t uc;
char buf[1024 * 64];
} context;
static unsigned int vls[SVE_VQ_MAX];
unsigned int nvls = 0;
static bool sme_get_vls(struct tdescr *td)
{
int vq, vl;
int res = sve_fill_vls(VLS_USE_SME, 1);
/*
* Enumerate up to SVE_VQ_MAX vector lengths
*/
for (vq = SVE_VQ_MAX; vq > 0; --vq) {
vl = prctl(PR_SME_SET_VL, vq * 16);
if (vl == -1)
return false;
vl &= PR_SME_VL_LEN_MASK;
/* Did we find the lowest supported VL? */
if (vq < sve_vq_from_vl(vl))
break;
if (!res)
return true;
/* Skip missing VLs */
vq = sve_vq_from_vl(vl);
vls[nvls++] = vl;
}
/* We need at least one VL */
if (nvls < 1) {
fprintf(stderr, "Only %d VL supported\n", nvls);
return false;
}
if (res == KSFT_SKIP)
td->result = KSFT_SKIP;
return true;
return false;
}
static void setup_ssve_regs(void)
......
......@@ -6,51 +6,31 @@
* signal frames is set up as expected when enabled simultaneously.
*/
#include <kselftest.h>
#include <signal.h>
#include <ucontext.h>
#include <sys/prctl.h>
#include "test_signals_utils.h"
#include "sve_helpers.h"
#include "testcases.h"
static union {
ucontext_t uc;
char buf[1024 * 128];
} context;
static unsigned int vls[SVE_VQ_MAX];
unsigned int nvls = 0;
static bool sme_get_vls(struct tdescr *td)
{
int vq, vl;
int res = sve_fill_vls(VLS_USE_SME, 1);
/*
* Enumerate up to SVE_VQ_MAX vector lengths
*/
for (vq = SVE_VQ_MAX; vq > 0; --vq) {
vl = prctl(PR_SME_SET_VL, vq * 16);
if (vl == -1)
return false;
vl &= PR_SME_VL_LEN_MASK;
/* Did we find the lowest supported VL? */
if (vq < sve_vq_from_vl(vl))
break;
if (!res)
return true;
/* Skip missing VLs */
vq = sve_vq_from_vl(vl);
vls[nvls++] = vl;
}
/* We need at least one VL */
if (nvls < 1) {
fprintf(stderr, "Only %d VL supported\n", nvls);
return false;
}
if (res == KSFT_SKIP)
td->result = KSFT_SKIP;
return true;
return false;
}
static void setup_regs(void)
......
......@@ -6,47 +6,31 @@
* expected.
*/
#include <kselftest.h>
#include <signal.h>
#include <ucontext.h>
#include <sys/prctl.h>
#include "test_signals_utils.h"
#include "sve_helpers.h"
#include "testcases.h"
static union {
ucontext_t uc;
char buf[1024 * 64];
} context;
static unsigned int vls[SVE_VQ_MAX];
unsigned int nvls = 0;
static bool sve_get_vls(struct tdescr *td)
{
int vq, vl;
int res = sve_fill_vls(VLS_USE_SVE, 1);
/*
* Enumerate up to SVE_VQ_MAX vector lengths
*/
for (vq = SVE_VQ_MAX; vq > 0; --vq) {
vl = prctl(PR_SVE_SET_VL, vq * 16);
if (vl == -1)
return false;
vl &= PR_SVE_VL_LEN_MASK;
/* Skip missing VLs */
vq = sve_vq_from_vl(vl);
if (!res)
return true;
vls[nvls++] = vl;
}
/* We need at least one VL */
if (nvls < 1) {
fprintf(stderr, "Only %d VL supported\n", nvls);
return false;
}
if (res == KSFT_SKIP)
td->result = KSFT_SKIP;
return true;
return false;
}
static void setup_sve_regs(void)
......
......@@ -6,47 +6,31 @@
* expected.
*/
#include <kselftest.h>
#include <signal.h>
#include <ucontext.h>
#include <sys/prctl.h>
#include "test_signals_utils.h"
#include "sve_helpers.h"
#include "testcases.h"
static union {
ucontext_t uc;
char buf[1024 * 128];
} context;
static unsigned int vls[SVE_VQ_MAX];
unsigned int nvls = 0;
static bool sme_get_vls(struct tdescr *td)
{
int vq, vl;
int res = sve_fill_vls(VLS_USE_SME, 1);
/*
* Enumerate up to SME_VQ_MAX vector lengths
*/
for (vq = SVE_VQ_MAX; vq > 0; --vq) {
vl = prctl(PR_SME_SET_VL, vq * 16);
if (vl == -1)
return false;
vl &= PR_SME_VL_LEN_MASK;
/* Skip missing VLs */
vq = sve_vq_from_vl(vl);
if (!res)
return true;
vls[nvls++] = vl;
}
/* We need at least one VL */
if (nvls < 1) {
fprintf(stderr, "Only %d VL supported\n", nvls);
return false;
}
if (res == KSFT_SKIP)
td->result = KSFT_SKIP;
return true;
return false;
}
static int do_one_sme_vl(struct tdescr *td, siginfo_t *si, ucontext_t *uc,
......
......@@ -6,51 +6,31 @@
* expected.
*/
#include <kselftest.h>
#include <signal.h>
#include <ucontext.h>
#include <sys/prctl.h>
#include "test_signals_utils.h"
#include "sve_helpers.h"
#include "testcases.h"
static union {
ucontext_t uc;
char buf[1024 * 128];
} context;
static unsigned int vls[SVE_VQ_MAX];
unsigned int nvls = 0;
static bool sme_get_vls(struct tdescr *td)
{
int vq, vl;
int res = sve_fill_vls(VLS_USE_SME, 1);
/*
* Enumerate up to SME_VQ_MAX vector lengths
*/
for (vq = SVE_VQ_MAX; vq > 0; --vq) {
vl = prctl(PR_SME_SET_VL, vq * 16);
if (vl == -1)
return false;
vl &= PR_SME_VL_LEN_MASK;
/* Did we find the lowest supported VL? */
if (vq < sve_vq_from_vl(vl))
break;
if (!res)
return true;
/* Skip missing VLs */
vq = sve_vq_from_vl(vl);
vls[nvls++] = vl;
}
/* We need at least one VL */
if (nvls < 1) {
fprintf(stderr, "Only %d VL supported\n", nvls);
return false;
}
if (res == KSFT_SKIP)
td->result = KSFT_SKIP;
return true;
return false;
}
static void setup_za_regs(void)
......
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