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 <kselftest.h>
10 #include <signal.h>
11 #include <ucontext.h>
12 #include <sys/prctl.h>
13
14 #include "test_signals_utils.h"
15 #include "testcases.h"
16
17 struct fake_sigframe sf;
18 static unsigned int vls[SVE_VQ_MAX];
19 unsigned int nvls = 0;
20
sve_get_vls(struct tdescr * td)21 static bool sve_get_vls(struct tdescr *td)
22 {
23 int vq, vl;
24
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;
32
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);
44 td->result = KSFT_SKIP;
45 return false;
46 }
47
48 return true;
49 }
50
fake_sigreturn_sve_change_vl(struct tdescr * td,siginfo_t * si,ucontext_t * uc)51 static int fake_sigreturn_sve_change_vl(struct tdescr *td,
52 siginfo_t *si, ucontext_t *uc)
53 {
54 size_t resv_sz, offset;
55 struct _aarch64_ctx *head = GET_SF_RESV_HEAD(sf);
56 struct sve_context *sve;
57
58 /* Get a signal context with a SVE frame in it */
59 if (!get_current_context(td, &sf.uc, sizeof(sf.uc)))
60 return 1;
61
62 resv_sz = GET_SF_RESV_SIZE(sf);
63 head = get_header(head, SVE_MAGIC, resv_sz, &offset);
64 if (!head) {
65 fprintf(stderr, "No SVE context\n");
66 return 1;
67 }
68
69 if (head->size != sizeof(struct sve_context)) {
70 fprintf(stderr, "SVE register state active, skipping\n");
71 return 1;
72 }
73
74 sve = (struct sve_context *)head;
75
76 /* No changes are supported; init left us at minimum VL so go to max */
77 fprintf(stderr, "Attempting to change VL from %d to %d\n",
78 sve->vl, vls[0]);
79 sve->vl = vls[0];
80
81 fake_sigreturn(&sf, sizeof(sf), 0);
82
83 return 1;
84 }
85
86 struct tdescr tde = {
87 .name = "FAKE_SIGRETURN_SVE_CHANGE",
88 .descr = "Attempt to change SVE VL",
89 .feats_required = FEAT_SVE,
90 .sig_ok = SIGSEGV,
91 .timeout = 3,
92 .init = sve_get_vls,
93 .run = fake_sigreturn_sve_change_vl,
94 };
95