]>
Commit | Line | Data |
---|---|---|
16582a51 LM |
1 | /* This testcase is part of GDB, the GNU debugger. |
2 | ||
1d506c26 | 3 | Copyright 2023-2024 Free Software Foundation, Inc. |
16582a51 LM |
4 | |
5 | This program is free software; you can redistribute it and/or modify | |
6 | it under the terms of the GNU General Public License as published by | |
7 | the Free Software Foundation; either version 3 of the License, or | |
8 | (at your option) any later version. | |
9 | ||
10 | This program is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | GNU General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU General Public License | |
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | |
17 | ||
18 | /* Exercise AArch64's Scalable Vector/Matrix Extension signal frame handling | |
19 | for GDB. */ | |
20 | ||
21 | #include <stdio.h> | |
22 | #include <sys/auxv.h> | |
23 | #include <sys/prctl.h> | |
24 | #include <stdlib.h> | |
25 | #include <string.h> | |
26 | #include <signal.h> | |
27 | #include <unistd.h> | |
28 | ||
29 | #ifndef HWCAP_SVE | |
30 | #define HWCAP_SVE (1 << 22) | |
31 | #endif | |
32 | ||
33 | #ifndef HWCAP2_SME | |
34 | #define HWCAP2_SME (1 << 23) | |
35 | #endif | |
36 | ||
c6727038 LM |
37 | #ifndef HWCAP2_SME2 |
38 | #define HWCAP2_SME2 (1UL << 37) | |
39 | #define HWCAP2_SME2P1 (1UL << 38) | |
40 | #endif | |
41 | ||
16582a51 LM |
42 | #ifndef PR_SVE_SET_VL |
43 | #define PR_SVE_SET_VL 50 | |
44 | #define PR_SVE_GET_VL 51 | |
45 | #define PR_SVE_VL_LEN_MASK 0xffff | |
46 | #endif | |
47 | ||
48 | #ifndef PR_SME_SET_VL | |
49 | #define PR_SME_SET_VL 63 | |
50 | #define PR_SME_GET_VL 64 | |
51 | #define PR_SME_VL_LEN_MASK 0xffff | |
52 | #endif | |
53 | ||
54 | static int count = 0; | |
55 | ||
56 | static void | |
57 | handler (int sig) | |
58 | { | |
59 | count++; /* handler */ | |
60 | } | |
61 | ||
62 | static void | |
63 | enable_za () | |
64 | { | |
65 | /* smstart za */ | |
66 | __asm __volatile (".word 0xD503457F"); | |
67 | } | |
68 | ||
69 | static void | |
70 | disable_za () | |
71 | { | |
72 | /* smstop za */ | |
73 | __asm __volatile (".word 0xD503447F"); | |
74 | } | |
75 | ||
76 | static void | |
77 | enable_sm () | |
78 | { | |
79 | /* smstart sm */ | |
80 | __asm __volatile (".word 0xD503437F"); | |
81 | } | |
82 | ||
83 | static void | |
84 | disable_sm () | |
85 | { | |
86 | /* smstop sm */ | |
87 | __asm __volatile (".word 0xD503427F"); | |
88 | } | |
89 | ||
90 | static void | |
91 | initialize_fpsimd_state () | |
92 | { | |
93 | char buffer[16]; | |
94 | ||
95 | for (int i = 0; i < 16; i++) | |
96 | buffer[i] = 0x55; | |
97 | ||
98 | __asm __volatile ("mov x0, %0\n\t" \ | |
99 | : : "r" (buffer)); | |
100 | ||
101 | __asm __volatile ("ldr q0, [x0]"); | |
102 | __asm __volatile ("ldr q1, [x0]"); | |
103 | __asm __volatile ("ldr q2, [x0]"); | |
104 | __asm __volatile ("ldr q3, [x0]"); | |
105 | __asm __volatile ("ldr q4, [x0]"); | |
106 | __asm __volatile ("ldr q5, [x0]"); | |
107 | __asm __volatile ("ldr q6, [x0]"); | |
108 | __asm __volatile ("ldr q7, [x0]"); | |
109 | __asm __volatile ("ldr q8, [x0]"); | |
110 | __asm __volatile ("ldr q9, [x0]"); | |
111 | __asm __volatile ("ldr q10, [x0]"); | |
112 | __asm __volatile ("ldr q11, [x0]"); | |
113 | __asm __volatile ("ldr q12, [x0]"); | |
114 | __asm __volatile ("ldr q13, [x0]"); | |
115 | __asm __volatile ("ldr q14, [x0]"); | |
116 | __asm __volatile ("ldr q15, [x0]"); | |
117 | __asm __volatile ("ldr q16, [x0]"); | |
118 | __asm __volatile ("ldr q17, [x0]"); | |
119 | __asm __volatile ("ldr q18, [x0]"); | |
120 | __asm __volatile ("ldr q19, [x0]"); | |
121 | __asm __volatile ("ldr q20, [x0]"); | |
122 | __asm __volatile ("ldr q21, [x0]"); | |
123 | __asm __volatile ("ldr q22, [x0]"); | |
124 | __asm __volatile ("ldr q23, [x0]"); | |
125 | __asm __volatile ("ldr q24, [x0]"); | |
126 | __asm __volatile ("ldr q25, [x0]"); | |
127 | __asm __volatile ("ldr q26, [x0]"); | |
128 | __asm __volatile ("ldr q27, [x0]"); | |
129 | __asm __volatile ("ldr q28, [x0]"); | |
130 | __asm __volatile ("ldr q29, [x0]"); | |
131 | __asm __volatile ("ldr q30, [x0]"); | |
132 | __asm __volatile ("ldr q31, [x0]"); | |
133 | } | |
134 | ||
135 | static void | |
136 | initialize_za_state () | |
137 | { | |
138 | /* zero za */ | |
139 | __asm __volatile (".word 0xC00800FF"); | |
140 | ||
141 | char buffer[256]; | |
142 | ||
143 | for (int i = 0; i < 256; i++) | |
144 | buffer[i] = 0xaa; | |
145 | ||
146 | __asm __volatile ("mov x0, %0\n\t" \ | |
147 | : : "r" (buffer)); | |
148 | ||
149 | /* Initialize loop boundaries. */ | |
150 | __asm __volatile ("mov w12, 0"); | |
151 | __asm __volatile ("mov w17, 256"); | |
152 | ||
153 | /* loop: ldr za[w12, 0], [x0] */ | |
154 | __asm __volatile ("loop: .word 0xe1000000"); | |
155 | __asm __volatile ("add w12, w12, 1"); | |
156 | __asm __volatile ("cmp w12, w17"); | |
157 | __asm __volatile ("bne loop"); | |
158 | } | |
159 | ||
c6727038 LM |
160 | static void |
161 | initialize_zt_state () | |
162 | { | |
163 | unsigned long hwcap2 = getauxval (AT_HWCAP2); | |
164 | ||
165 | if (!(hwcap2 & HWCAP2_SME2) && !(hwcap2 & HWCAP2_SME2P1)) | |
166 | return; | |
167 | ||
168 | char buffer[64]; | |
169 | ||
170 | for (int i = 0; i < 64; i++) | |
171 | buffer[i] = 0xff; | |
172 | ||
173 | __asm __volatile ("mov x0, %0\n\t" \ | |
174 | : : "r" (buffer)); | |
175 | ||
176 | /* Initialize ZT0. */ | |
177 | /* ldr zt0, x0 */ | |
178 | __asm __volatile (".word 0xe11f8000"); | |
179 | } | |
180 | ||
16582a51 LM |
181 | static void |
182 | initialize_sve_state () | |
183 | { | |
184 | __asm __volatile ("dup z0.b, -1"); | |
185 | __asm __volatile ("dup z1.b, -1"); | |
186 | __asm __volatile ("dup z2.b, -1"); | |
187 | __asm __volatile ("dup z3.b, -1"); | |
188 | __asm __volatile ("dup z4.b, -1"); | |
189 | __asm __volatile ("dup z5.b, -1"); | |
190 | __asm __volatile ("dup z6.b, -1"); | |
191 | __asm __volatile ("dup z7.b, -1"); | |
192 | __asm __volatile ("dup z8.b, -1"); | |
193 | __asm __volatile ("dup z9.b, -1"); | |
194 | __asm __volatile ("dup z10.b, -1"); | |
195 | __asm __volatile ("dup z11.b, -1"); | |
196 | __asm __volatile ("dup z12.b, -1"); | |
197 | __asm __volatile ("dup z13.b, -1"); | |
198 | __asm __volatile ("dup z14.b, -1"); | |
199 | __asm __volatile ("dup z15.b, -1"); | |
200 | __asm __volatile ("dup z16.b, -1"); | |
201 | __asm __volatile ("dup z17.b, -1"); | |
202 | __asm __volatile ("dup z18.b, -1"); | |
203 | __asm __volatile ("dup z19.b, -1"); | |
204 | __asm __volatile ("dup z20.b, -1"); | |
205 | __asm __volatile ("dup z21.b, -1"); | |
206 | __asm __volatile ("dup z22.b, -1"); | |
207 | __asm __volatile ("dup z23.b, -1"); | |
208 | __asm __volatile ("dup z24.b, -1"); | |
209 | __asm __volatile ("dup z25.b, -1"); | |
210 | __asm __volatile ("dup z26.b, -1"); | |
211 | __asm __volatile ("dup z27.b, -1"); | |
212 | __asm __volatile ("dup z28.b, -1"); | |
213 | __asm __volatile ("dup z29.b, -1"); | |
214 | __asm __volatile ("dup z30.b, -1"); | |
215 | __asm __volatile ("dup z31.b, -1"); | |
216 | __asm __volatile ("ptrue p0.b"); | |
217 | __asm __volatile ("ptrue p1.b"); | |
218 | __asm __volatile ("ptrue p2.b"); | |
219 | __asm __volatile ("ptrue p3.b"); | |
220 | __asm __volatile ("ptrue p4.b"); | |
221 | __asm __volatile ("ptrue p5.b"); | |
222 | __asm __volatile ("ptrue p6.b"); | |
223 | __asm __volatile ("ptrue p7.b"); | |
224 | __asm __volatile ("ptrue p8.b"); | |
225 | __asm __volatile ("ptrue p9.b"); | |
226 | __asm __volatile ("ptrue p10.b"); | |
227 | __asm __volatile ("ptrue p11.b"); | |
228 | __asm __volatile ("ptrue p12.b"); | |
229 | __asm __volatile ("ptrue p13.b"); | |
230 | __asm __volatile ("ptrue p14.b"); | |
231 | __asm __volatile ("ptrue p15.b"); | |
232 | __asm __volatile ("setffr"); | |
233 | } | |
234 | ||
235 | static int get_vl_size () | |
236 | { | |
237 | int res = prctl (PR_SVE_GET_VL, 0, 0, 0, 0); | |
238 | if (res < 0) | |
239 | { | |
240 | printf ("FAILED to PR_SVE_GET_VL (%d)\n", res); | |
241 | return -1; | |
242 | } | |
243 | return (res & PR_SVE_VL_LEN_MASK); | |
244 | } | |
245 | ||
246 | static int get_svl_size () | |
247 | { | |
248 | int res = prctl (PR_SME_GET_VL, 0, 0, 0, 0); | |
249 | if (res < 0) | |
250 | { | |
251 | printf ("FAILED to PR_SME_GET_VL (%d)\n", res); | |
252 | return -1; | |
253 | } | |
254 | return (res & PR_SVE_VL_LEN_MASK); | |
255 | } | |
256 | ||
257 | static int set_vl_size (int new_vl) | |
258 | { | |
259 | int res = prctl (PR_SVE_SET_VL, new_vl, 0, 0, 0, 0); | |
260 | if (res < 0) | |
261 | { | |
262 | printf ("FAILED to PR_SVE_SET_VL (%d)\n", res); | |
263 | return -1; | |
264 | } | |
265 | ||
266 | res = get_vl_size (); | |
267 | if (res != new_vl) | |
268 | { | |
269 | printf ("Unexpected VL value (%d)\n", res); | |
270 | return -1; | |
271 | } | |
272 | ||
273 | return res; | |
274 | } | |
275 | ||
276 | static int set_svl_size (int new_svl) | |
277 | { | |
278 | int res = prctl (PR_SME_SET_VL, new_svl, 0, 0, 0, 0); | |
279 | if (res < 0) | |
280 | { | |
281 | printf ("FAILED to PR_SME_SET_VL (%d)\n", res); | |
282 | return -1; | |
283 | } | |
284 | ||
285 | res = get_svl_size (); | |
286 | if (res != new_svl) | |
287 | { | |
288 | printf ("Unexpected SVL value (%d)\n", res); | |
289 | return -1; | |
290 | } | |
291 | ||
292 | return res; | |
293 | } | |
294 | ||
295 | /* Enable register states based on STATE. | |
296 | ||
297 | 0 - FPSIMD | |
298 | 1 - SVE | |
299 | 2 - SSVE | |
c6727038 LM |
300 | 3 - ZA (+ SME2 ZT0) |
301 | 4 - ZA and SSVE (+ SME2 ZT0). */ | |
16582a51 LM |
302 | |
303 | void enable_states (int state) | |
304 | { | |
305 | disable_za (); | |
306 | disable_sm (); | |
307 | initialize_fpsimd_state (); | |
308 | ||
309 | if (state == 1) | |
310 | { | |
311 | initialize_sve_state (); | |
312 | } | |
313 | else if (state == 2) | |
314 | { | |
315 | enable_sm (); | |
316 | initialize_sve_state (); | |
317 | } | |
318 | else if (state == 3) | |
319 | { | |
320 | enable_za (); | |
321 | initialize_za_state (); | |
c6727038 | 322 | initialize_zt_state (); |
16582a51 LM |
323 | } |
324 | else if (state == 4) | |
325 | { | |
326 | enable_za (); | |
327 | enable_sm (); | |
328 | initialize_sve_state (); | |
329 | initialize_za_state (); | |
c6727038 | 330 | initialize_zt_state (); |
16582a51 LM |
331 | } |
332 | ||
333 | return; | |
334 | } | |
335 | ||
336 | static int | |
337 | test_id_to_state (int id) | |
338 | { | |
339 | return (id / 25); | |
340 | } | |
341 | ||
342 | static int | |
343 | test_id_to_vl (int id) | |
344 | { | |
345 | return 16 << ((id / 5) % 5); | |
346 | } | |
347 | ||
348 | static int | |
349 | test_id_to_svl (int id) | |
350 | { | |
351 | return 16 << (id % 5); | |
352 | } | |
353 | ||
354 | static void | |
355 | dummy () | |
356 | { | |
357 | } | |
358 | ||
359 | int | |
360 | main (int argc, char **argv) | |
361 | { | |
362 | if (getauxval (AT_HWCAP) & HWCAP_SVE && getauxval (AT_HWCAP2) & HWCAP2_SME) | |
363 | { | |
364 | int id_start = ID_START; | |
365 | int id_end = ID_END; | |
366 | #ifdef SIGILL | |
367 | signal (SIGILL, handler); | |
368 | #endif | |
369 | ||
370 | int signal_count = 0; | |
371 | for (int id = id_start; id <= id_end; id++) | |
372 | { | |
373 | int state = test_id_to_state (id); | |
374 | int vl = test_id_to_vl (id); | |
375 | int svl = test_id_to_svl (id); | |
376 | ||
377 | if (set_vl_size (vl) == -1 || set_svl_size (svl) == -1) | |
378 | continue; | |
379 | ||
380 | signal_count++; | |
381 | enable_states (state); | |
382 | dummy (); /* stop before SIGILL */ | |
383 | __asm __volatile (".word 0xDEADBEEF"); /* illegal instruction */ | |
384 | while (signal_count != count); | |
385 | } | |
386 | } | |
387 | else | |
388 | { | |
389 | printf ("SKIP: no HWCAP_SVE or HWCAP2_SME on this system\n"); | |
390 | return -1; | |
391 | } | |
392 | ||
393 | return 0; | |
394 | } |