Skip to content

Commit d25ac50

Browse files
brooniectmarinas
authored andcommitted
kselftest/arm64: signal: Verify that signals can't change the SVE vector length
We do not support changing the SVE vector length as part of signal return, verify that this is the case if the system supports multiple vector lengths. Signed-off-by: Mark Brown <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Catalin Marinas <[email protected]>
1 parent c1f67a1 commit d25ac50

File tree

1 file changed

+92
-0
lines changed

1 file changed

+92
-0
lines changed
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Copyright (C) 2021 ARM Limited
4+
*
5+
* Attempt to change the SVE vector length in a signal hander, this is not
6+
* supported and is expected to segfault.
7+
*/
8+
9+
#include <signal.h>
10+
#include <ucontext.h>
11+
#include <sys/prctl.h>
12+
13+
#include "test_signals_utils.h"
14+
#include "testcases.h"
15+
16+
struct fake_sigframe sf;
17+
static unsigned int vls[SVE_VQ_MAX];
18+
unsigned int nvls = 0;
19+
20+
static bool sve_get_vls(struct tdescr *td)
21+
{
22+
int vq, vl;
23+
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;
31+
32+
vl &= PR_SVE_VL_LEN_MASK;
33+
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;
47+
}
48+
49+
static int fake_sigreturn_sve_change_vl(struct tdescr *td,
50+
siginfo_t *si, ucontext_t *uc)
51+
{
52+
size_t resv_sz, offset;
53+
struct _aarch64_ctx *head = GET_SF_RESV_HEAD(sf);
54+
struct sve_context *sve;
55+
56+
/* Get a signal context with a SVE frame in it */
57+
if (!get_current_context(td, &sf.uc))
58+
return 1;
59+
60+
resv_sz = GET_SF_RESV_SIZE(sf);
61+
head = get_header(head, SVE_MAGIC, resv_sz, &offset);
62+
if (!head) {
63+
fprintf(stderr, "No SVE context\n");
64+
return 1;
65+
}
66+
67+
if (head->size != sizeof(struct sve_context)) {
68+
fprintf(stderr, "SVE register state active, skipping\n");
69+
return 1;
70+
}
71+
72+
sve = (struct sve_context *)head;
73+
74+
/* No changes are supported; init left us at minimum VL so go to max */
75+
fprintf(stderr, "Attempting to change VL from %d to %d\n",
76+
sve->vl, vls[0]);
77+
sve->vl = vls[0];
78+
79+
fake_sigreturn(&sf, sizeof(sf), 0);
80+
81+
return 1;
82+
}
83+
84+
struct tdescr tde = {
85+
.name = "FAKE_SIGRETURN_SVE_CHANGE",
86+
.descr = "Attempt to change SVE VL",
87+
.feats_required = FEAT_SVE,
88+
.sig_ok = SIGSEGV,
89+
.timeout = 3,
90+
.init = sve_get_vls,
91+
.run = fake_sigreturn_sve_change_vl,
92+
};

0 commit comments

Comments
 (0)