1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2021 ARM Limited
4  *
5  * Verify that both the streaming SVE and ZA register context in
6  * signal frames is set up as expected when enabled simultaneously.
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 static union {
17 	ucontext_t uc;
18 	char buf[1024 * 128];
19 } context;
20 static unsigned int vls[SVE_VQ_MAX];
21 unsigned int nvls = 0;
22 
23 static bool sme_get_vls(struct tdescr *td)
24 {
25 	int vq, vl;
26 
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;
40 
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 	}
52 
53 	return true;
54 }
55 
56 static void setup_regs(void)
57 {
58 	/* smstart sm; real data is TODO */
59 	asm volatile(".inst 0xd503437f" : : : );
60 
61 	/* smstart za; real data is TODO */
62 	asm volatile(".inst 0xd503457f" : : : );
63 }
64 
65 static char zeros[ZA_SIG_REGS_SIZE(SVE_VQ_MAX)];
66 
67 static int do_one_sme_vl(struct tdescr *td, siginfo_t *si, ucontext_t *uc,
68 			 unsigned int vl)
69 {
70 	size_t offset;
71 	struct _aarch64_ctx *head = GET_BUF_RESV_HEAD(context);
72 	struct _aarch64_ctx *regs;
73 	struct sve_context *ssve;
74 	struct za_context *za;
75 	int ret;
76 
77 	fprintf(stderr, "Testing VL %d\n", vl);
78 
79 	ret = prctl(PR_SME_SET_VL, vl);
80 	if (ret != vl) {
81 		fprintf(stderr, "Failed to set VL, got %d\n", ret);
82 		return 1;
83 	}
84 
85 	/*
86 	 * Get a signal context which should have the SVE and ZA
87 	 * frames in it.
88 	 */
89 	setup_regs();
90 	if (!get_current_context(td, &context.uc, sizeof(context)))
91 		return 1;
92 
93 	regs = get_header(head, SVE_MAGIC, GET_BUF_RESV_SIZE(context),
94 			  &offset);
95 	if (!regs) {
96 		fprintf(stderr, "No SVE context\n");
97 		return 1;
98 	}
99 
100 	ssve = (struct sve_context *)regs;
101 	if (ssve->vl != vl) {
102 		fprintf(stderr, "Got SSVE VL %d, expected %d\n", ssve->vl, vl);
103 		return 1;
104 	}
105 
106 	if (!(ssve->flags & SVE_SIG_FLAG_SM)) {
107 		fprintf(stderr, "SVE_SIG_FLAG_SM not set in SVE record\n");
108 		return 1;
109 	}
110 
111 	fprintf(stderr, "Got expected SSVE size %u and VL %d\n",
112 		regs->size, ssve->vl);
113 
114 	regs = get_header(head, ZA_MAGIC, GET_BUF_RESV_SIZE(context),
115 			  &offset);
116 	if (!regs) {
117 		fprintf(stderr, "No ZA context\n");
118 		return 1;
119 	}
120 
121 	za = (struct za_context *)regs;
122 	if (za->vl != vl) {
123 		fprintf(stderr, "Got ZA VL %d, expected %d\n", za->vl, vl);
124 		return 1;
125 	}
126 
127 	fprintf(stderr, "Got expected ZA size %u and VL %d\n",
128 		regs->size, za->vl);
129 
130 	/* We didn't load any data into ZA so it should be all zeros */
131 	if (memcmp(zeros, (char *)za + ZA_SIG_REGS_OFFSET,
132 		   ZA_SIG_REGS_SIZE(sve_vq_from_vl(za->vl))) != 0) {
133 		fprintf(stderr, "ZA data invalid\n");
134 		return 1;
135 	}
136 
137 	return 0;
138 }
139 
140 static int sme_regs(struct tdescr *td, siginfo_t *si, ucontext_t *uc)
141 {
142 	int i;
143 
144 	for (i = 0; i < nvls; i++) {
145 		if (do_one_sme_vl(td, si, uc, vls[i]))
146 			return 1;
147 	}
148 
149 	td->pass = 1;
150 
151 	return 0;
152 }
153 
154 struct tdescr tde = {
155 	.name = "Streaming SVE registers",
156 	.descr = "Check that we get the right Streaming SVE registers reported",
157 	.feats_required = FEAT_SME,
158 	.timeout = 3,
159 	.init = sme_get_vls,
160 	.run = sme_regs,
161 };
162