Skip to content

Commit 5225b65

Browse files
Andre-ARMwilldeacon
authored andcommitted
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: 4963aeb ("kselftest/arm64: signal: Add SME signal handling tests") Signed-off-by: Andre Przywara <[email protected]> Reviewed-by: Mark Brown <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Will Deacon <[email protected]>
1 parent 7c626ce commit 5225b65

File tree

10 files changed

+132
-181
lines changed

10 files changed

+132
-181
lines changed

tools/testing/selftests/arm64/signal/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ $(TEST_GEN_PROGS): $(PROGS)
2323
# Common test-unit targets to build common-layout test-cases executables
2424
# Needs secondary expansion to properly include the testcase c-file in pre-reqs
2525
COMMON_SOURCES := test_signals.c test_signals_utils.c testcases/testcases.c \
26-
signals.S
26+
signals.S sve_helpers.c
2727
COMMON_HEADERS := test_signals.h test_signals_utils.h testcases/testcases.h
2828

2929
.SECONDEXPANSION:
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Copyright (C) 2024 ARM Limited
4+
*
5+
* Common helper functions for SVE and SME functionality.
6+
*/
7+
8+
#include <stdbool.h>
9+
#include <kselftest.h>
10+
#include <asm/sigcontext.h>
11+
#include <sys/prctl.h>
12+
13+
unsigned int vls[SVE_VQ_MAX];
14+
unsigned int nvls;
15+
16+
int sve_fill_vls(bool use_sme, int min_vls)
17+
{
18+
int vq, vl;
19+
int pr_set_vl = use_sme ? PR_SME_SET_VL : PR_SVE_SET_VL;
20+
int len_mask = use_sme ? PR_SME_VL_LEN_MASK : PR_SVE_VL_LEN_MASK;
21+
22+
/*
23+
* Enumerate up to SVE_VQ_MAX vector lengths
24+
*/
25+
for (vq = SVE_VQ_MAX; vq > 0; --vq) {
26+
vl = prctl(pr_set_vl, vq * 16);
27+
if (vl == -1)
28+
return KSFT_FAIL;
29+
30+
vl &= len_mask;
31+
32+
/*
33+
* Unlike SVE, SME does not require the minimum vector length
34+
* to be implemented, or the VLs to be consecutive, so any call
35+
* to the prctl might return the single implemented VL, which
36+
* might be larger than 16. So to avoid this loop never
37+
* terminating, bail out here when we find a higher VL than
38+
* we asked for.
39+
* See the ARM ARM, DDI 0487K.a, B1.4.2: I_QQRNR and I_NWYBP.
40+
*/
41+
if (vq < sve_vq_from_vl(vl))
42+
break;
43+
44+
/* Skip missing VLs */
45+
vq = sve_vq_from_vl(vl);
46+
47+
vls[nvls++] = vl;
48+
}
49+
50+
if (nvls < min_vls) {
51+
fprintf(stderr, "Only %d VL supported\n", nvls);
52+
return KSFT_SKIP;
53+
}
54+
55+
return KSFT_PASS;
56+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
/*
3+
* Copyright (C) 2024 ARM Limited
4+
*
5+
* Common helper functions for SVE and SME functionality.
6+
*/
7+
8+
#ifndef __SVE_HELPERS_H__
9+
#define __SVE_HELPERS_H__
10+
11+
#include <stdbool.h>
12+
13+
#define VLS_USE_SVE false
14+
#define VLS_USE_SME true
15+
16+
extern unsigned int vls[];
17+
extern unsigned int nvls;
18+
19+
int sve_fill_vls(bool use_sme, int min_vls);
20+
21+
#endif

tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_sme_change_vl.c

Lines changed: 8 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,44 +6,28 @@
66
* handler, this is not supported and is expected to segfault.
77
*/
88

9+
#include <kselftest.h>
910
#include <signal.h>
1011
#include <ucontext.h>
1112
#include <sys/prctl.h>
1213

1314
#include "test_signals_utils.h"
15+
#include "sve_helpers.h"
1416
#include "testcases.h"
1517

1618
struct fake_sigframe sf;
17-
static unsigned int vls[SVE_VQ_MAX];
18-
unsigned int nvls = 0;
1919

2020
static bool sme_get_vls(struct tdescr *td)
2121
{
22-
int vq, vl;
22+
int res = sve_fill_vls(VLS_USE_SME, 2);
2323

24-
/*
25-
* Enumerate up to SVE_VQ_MAX vector lengths
26-
*/
27-
for (vq = SVE_VQ_MAX; vq > 0; --vq) {
28-
vl = prctl(PR_SVE_SET_VL, vq * 16);
29-
if (vl == -1)
30-
return false;
24+
if (!res)
25+
return true;
3126

32-
vl &= PR_SME_VL_LEN_MASK;
27+
if (res == KSFT_SKIP)
28+
td->result = KSFT_SKIP;
3329

34-
/* Skip missing VLs */
35-
vq = sve_vq_from_vl(vl);
36-
37-
vls[nvls++] = vl;
38-
}
39-
40-
/* We need at least two VLs */
41-
if (nvls < 2) {
42-
fprintf(stderr, "Only %d VL supported\n", nvls);
43-
return false;
44-
}
45-
46-
return true;
30+
return false;
4731
}
4832

4933
static int fake_sigreturn_ssve_change_vl(struct tdescr *td,

tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_sve_change_vl.c

Lines changed: 6 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -12,40 +12,22 @@
1212
#include <sys/prctl.h>
1313

1414
#include "test_signals_utils.h"
15+
#include "sve_helpers.h"
1516
#include "testcases.h"
1617

1718
struct fake_sigframe sf;
18-
static unsigned int vls[SVE_VQ_MAX];
19-
unsigned int nvls = 0;
2019

2120
static bool sve_get_vls(struct tdescr *td)
2221
{
23-
int vq, vl;
22+
int res = sve_fill_vls(VLS_USE_SVE, 2);
2423

25-
/*
26-
* Enumerate up to SVE_VQ_MAX vector lengths
27-
*/
28-
for (vq = SVE_VQ_MAX; vq > 0; --vq) {
29-
vl = prctl(PR_SVE_SET_VL, vq * 16);
30-
if (vl == -1)
31-
return false;
24+
if (!res)
25+
return true;
3226

33-
vl &= PR_SVE_VL_LEN_MASK;
34-
35-
/* Skip missing VLs */
36-
vq = sve_vq_from_vl(vl);
37-
38-
vls[nvls++] = vl;
39-
}
40-
41-
/* We need at least two VLs */
42-
if (nvls < 2) {
43-
fprintf(stderr, "Only %d VL supported\n", nvls);
27+
if (res == KSFT_SKIP)
4428
td->result = KSFT_SKIP;
45-
return false;
46-
}
4729

48-
return true;
30+
return false;
4931
}
5032

5133
static int fake_sigreturn_sve_change_vl(struct tdescr *td,

tools/testing/selftests/arm64/signal/testcases/ssve_regs.c

Lines changed: 8 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -6,51 +6,31 @@
66
* set up as expected.
77
*/
88

9+
#include <kselftest.h>
910
#include <signal.h>
1011
#include <ucontext.h>
1112
#include <sys/prctl.h>
1213

1314
#include "test_signals_utils.h"
15+
#include "sve_helpers.h"
1416
#include "testcases.h"
1517

1618
static union {
1719
ucontext_t uc;
1820
char buf[1024 * 64];
1921
} context;
20-
static unsigned int vls[SVE_VQ_MAX];
21-
unsigned int nvls = 0;
2222

2323
static bool sme_get_vls(struct tdescr *td)
2424
{
25-
int vq, vl;
25+
int res = sve_fill_vls(VLS_USE_SME, 1);
2626

27-
/*
28-
* Enumerate up to SVE_VQ_MAX vector lengths
29-
*/
30-
for (vq = SVE_VQ_MAX; vq > 0; --vq) {
31-
vl = prctl(PR_SME_SET_VL, vq * 16);
32-
if (vl == -1)
33-
return false;
34-
35-
vl &= PR_SME_VL_LEN_MASK;
36-
37-
/* Did we find the lowest supported VL? */
38-
if (vq < sve_vq_from_vl(vl))
39-
break;
27+
if (!res)
28+
return true;
4029

41-
/* Skip missing VLs */
42-
vq = sve_vq_from_vl(vl);
43-
44-
vls[nvls++] = vl;
45-
}
46-
47-
/* We need at least one VL */
48-
if (nvls < 1) {
49-
fprintf(stderr, "Only %d VL supported\n", nvls);
50-
return false;
51-
}
30+
if (res == KSFT_SKIP)
31+
td->result = KSFT_SKIP;
5232

53-
return true;
33+
return false;
5434
}
5535

5636
static void setup_ssve_regs(void)

tools/testing/selftests/arm64/signal/testcases/ssve_za_regs.c

Lines changed: 8 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -6,51 +6,31 @@
66
* signal frames is set up as expected when enabled simultaneously.
77
*/
88

9+
#include <kselftest.h>
910
#include <signal.h>
1011
#include <ucontext.h>
1112
#include <sys/prctl.h>
1213

1314
#include "test_signals_utils.h"
15+
#include "sve_helpers.h"
1416
#include "testcases.h"
1517

1618
static union {
1719
ucontext_t uc;
1820
char buf[1024 * 128];
1921
} context;
20-
static unsigned int vls[SVE_VQ_MAX];
21-
unsigned int nvls = 0;
2222

2323
static bool sme_get_vls(struct tdescr *td)
2424
{
25-
int vq, vl;
25+
int res = sve_fill_vls(VLS_USE_SME, 1);
2626

27-
/*
28-
* Enumerate up to SVE_VQ_MAX vector lengths
29-
*/
30-
for (vq = SVE_VQ_MAX; vq > 0; --vq) {
31-
vl = prctl(PR_SME_SET_VL, vq * 16);
32-
if (vl == -1)
33-
return false;
34-
35-
vl &= PR_SME_VL_LEN_MASK;
36-
37-
/* Did we find the lowest supported VL? */
38-
if (vq < sve_vq_from_vl(vl))
39-
break;
27+
if (!res)
28+
return true;
4029

41-
/* Skip missing VLs */
42-
vq = sve_vq_from_vl(vl);
43-
44-
vls[nvls++] = vl;
45-
}
46-
47-
/* We need at least one VL */
48-
if (nvls < 1) {
49-
fprintf(stderr, "Only %d VL supported\n", nvls);
50-
return false;
51-
}
30+
if (res == KSFT_SKIP)
31+
td->result = KSFT_SKIP;
5232

53-
return true;
33+
return false;
5434
}
5535

5636
static void setup_regs(void)

tools/testing/selftests/arm64/signal/testcases/sve_regs.c

Lines changed: 8 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,47 +6,31 @@
66
* expected.
77
*/
88

9+
#include <kselftest.h>
910
#include <signal.h>
1011
#include <ucontext.h>
1112
#include <sys/prctl.h>
1213

1314
#include "test_signals_utils.h"
15+
#include "sve_helpers.h"
1416
#include "testcases.h"
1517

1618
static union {
1719
ucontext_t uc;
1820
char buf[1024 * 64];
1921
} context;
20-
static unsigned int vls[SVE_VQ_MAX];
21-
unsigned int nvls = 0;
2222

2323
static bool sve_get_vls(struct tdescr *td)
2424
{
25-
int vq, vl;
25+
int res = sve_fill_vls(VLS_USE_SVE, 1);
2626

27-
/*
28-
* Enumerate up to SVE_VQ_MAX vector lengths
29-
*/
30-
for (vq = SVE_VQ_MAX; vq > 0; --vq) {
31-
vl = prctl(PR_SVE_SET_VL, vq * 16);
32-
if (vl == -1)
33-
return false;
34-
35-
vl &= PR_SVE_VL_LEN_MASK;
36-
37-
/* Skip missing VLs */
38-
vq = sve_vq_from_vl(vl);
27+
if (!res)
28+
return true;
3929

40-
vls[nvls++] = vl;
41-
}
42-
43-
/* We need at least one VL */
44-
if (nvls < 1) {
45-
fprintf(stderr, "Only %d VL supported\n", nvls);
46-
return false;
47-
}
30+
if (res == KSFT_SKIP)
31+
td->result = KSFT_SKIP;
4832

49-
return true;
33+
return false;
5034
}
5135

5236
static void setup_sve_regs(void)

0 commit comments

Comments
 (0)