aboutsummaryrefslogtreecommitdiff
path: root/gdb/testsuite/gdb.arch/aarch64-sme-regs-sigframe.c
blob: 4c991e6e4f9d65fbf204a04dd57a459d5b59f1bc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
/* This testcase is part of GDB, the GNU debugger.

   Copyright 2023-2024 Free Software Foundation, Inc.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */

/* Exercise AArch64's Scalable Vector/Matrix Extension signal frame handling
   for GDB.  */

#include <stdio.h>
#include <sys/auxv.h>
#include <sys/prctl.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>

#ifndef HWCAP_SVE
#define HWCAP_SVE (1 << 22)
#endif

#ifndef HWCAP2_SME
#define HWCAP2_SME (1 << 23)
#endif

#ifndef HWCAP2_SME2
#define HWCAP2_SME2 (1UL << 37)
#define HWCAP2_SME2P1 (1UL << 38)
#endif

#ifndef PR_SVE_SET_VL
#define PR_SVE_SET_VL 50
#define PR_SVE_GET_VL 51
#define PR_SVE_VL_LEN_MASK 0xffff
#endif

#ifndef PR_SME_SET_VL
#define PR_SME_SET_VL 63
#define PR_SME_GET_VL 64
#define PR_SME_VL_LEN_MASK 0xffff
#endif

static int count = 0;

static void
handler (int sig)
{
  count++; /* handler */
}

static void
enable_za ()
{
  /* smstart za */
  __asm __volatile (".word 0xD503457F");
}

static void
disable_za ()
{
  /* smstop za */
  __asm __volatile (".word 0xD503447F");
}

static void
enable_sm ()
{
  /* smstart sm */
  __asm __volatile (".word 0xD503437F");
}

static void
disable_sm ()
{
  /* smstop sm */
  __asm __volatile (".word 0xD503427F");
}

static void
initialize_fpsimd_state ()
{
  char buffer[16];

  for (int i = 0; i < 16; i++)
    buffer[i] = 0x55;

  __asm __volatile ("mov x0, %0\n\t" \
		    : : "r" (buffer));

  __asm __volatile ("ldr q0, [x0]");
  __asm __volatile ("ldr q1, [x0]");
  __asm __volatile ("ldr q2, [x0]");
  __asm __volatile ("ldr q3, [x0]");
  __asm __volatile ("ldr q4, [x0]");
  __asm __volatile ("ldr q5, [x0]");
  __asm __volatile ("ldr q6, [x0]");
  __asm __volatile ("ldr q7, [x0]");
  __asm __volatile ("ldr q8, [x0]");
  __asm __volatile ("ldr q9, [x0]");
  __asm __volatile ("ldr q10, [x0]");
  __asm __volatile ("ldr q11, [x0]");
  __asm __volatile ("ldr q12, [x0]");
  __asm __volatile ("ldr q13, [x0]");
  __asm __volatile ("ldr q14, [x0]");
  __asm __volatile ("ldr q15, [x0]");
  __asm __volatile ("ldr q16, [x0]");
  __asm __volatile ("ldr q17, [x0]");
  __asm __volatile ("ldr q18, [x0]");
  __asm __volatile ("ldr q19, [x0]");
  __asm __volatile ("ldr q20, [x0]");
  __asm __volatile ("ldr q21, [x0]");
  __asm __volatile ("ldr q22, [x0]");
  __asm __volatile ("ldr q23, [x0]");
  __asm __volatile ("ldr q24, [x0]");
  __asm __volatile ("ldr q25, [x0]");
  __asm __volatile ("ldr q26, [x0]");
  __asm __volatile ("ldr q27, [x0]");
  __asm __volatile ("ldr q28, [x0]");
  __asm __volatile ("ldr q29, [x0]");
  __asm __volatile ("ldr q30, [x0]");
  __asm __volatile ("ldr q31, [x0]");
}

static void
initialize_za_state ()
{
  /* zero za */
  __asm __volatile (".word 0xC00800FF");

  char buffer[256];

  for (int i = 0; i < 256; i++)
    buffer[i] = 0xaa;

  __asm __volatile ("mov x0, %0\n\t" \
		    : : "r" (buffer));

  /* Initialize loop boundaries.  */
  __asm __volatile ("mov w12, 0");
  __asm __volatile ("mov w17, 256");

  /* loop: ldr za[w12, 0], [x0] */
  __asm __volatile ("loop: .word 0xe1000000");
  __asm __volatile ("add w12, w12, 1");
  __asm __volatile ("cmp w12, w17");
  __asm __volatile ("bne loop");
}

static void
initialize_zt_state ()
{
  unsigned long hwcap2 = getauxval (AT_HWCAP2);

  if (!(hwcap2 & HWCAP2_SME2) && !(hwcap2 & HWCAP2_SME2P1))
    return;

  char buffer[64];

  for (int i = 0; i < 64; i++)
    buffer[i] = 0xff;

  __asm __volatile ("mov x0, %0\n\t" \
		    : : "r" (buffer));

  /* Initialize ZT0.  */
  /* ldr zt0, x0 */
  __asm __volatile (".word 0xe11f8000");
}

static void
initialize_sve_state ()
{
  __asm __volatile ("dup z0.b, -1");
  __asm __volatile ("dup z1.b, -1");
  __asm __volatile ("dup z2.b, -1");
  __asm __volatile ("dup z3.b, -1");
  __asm __volatile ("dup z4.b, -1");
  __asm __volatile ("dup z5.b, -1");
  __asm __volatile ("dup z6.b, -1");
  __asm __volatile ("dup z7.b, -1");
  __asm __volatile ("dup z8.b, -1");
  __asm __volatile ("dup z9.b, -1");
  __asm __volatile ("dup z10.b, -1");
  __asm __volatile ("dup z11.b, -1");
  __asm __volatile ("dup z12.b, -1");
  __asm __volatile ("dup z13.b, -1");
  __asm __volatile ("dup z14.b, -1");
  __asm __volatile ("dup z15.b, -1");
  __asm __volatile ("dup z16.b, -1");
  __asm __volatile ("dup z17.b, -1");
  __asm __volatile ("dup z18.b, -1");
  __asm __volatile ("dup z19.b, -1");
  __asm __volatile ("dup z20.b, -1");
  __asm __volatile ("dup z21.b, -1");
  __asm __volatile ("dup z22.b, -1");
  __asm __volatile ("dup z23.b, -1");
  __asm __volatile ("dup z24.b, -1");
  __asm __volatile ("dup z25.b, -1");
  __asm __volatile ("dup z26.b, -1");
  __asm __volatile ("dup z27.b, -1");
  __asm __volatile ("dup z28.b, -1");
  __asm __volatile ("dup z29.b, -1");
  __asm __volatile ("dup z30.b, -1");
  __asm __volatile ("dup z31.b, -1");
  __asm __volatile ("ptrue p0.b");
  __asm __volatile ("ptrue p1.b");
  __asm __volatile ("ptrue p2.b");
  __asm __volatile ("ptrue p3.b");
  __asm __volatile ("ptrue p4.b");
  __asm __volatile ("ptrue p5.b");
  __asm __volatile ("ptrue p6.b");
  __asm __volatile ("ptrue p7.b");
  __asm __volatile ("ptrue p8.b");
  __asm __volatile ("ptrue p9.b");
  __asm __volatile ("ptrue p10.b");
  __asm __volatile ("ptrue p11.b");
  __asm __volatile ("ptrue p12.b");
  __asm __volatile ("ptrue p13.b");
  __asm __volatile ("ptrue p14.b");
  __asm __volatile ("ptrue p15.b");
  __asm __volatile ("setffr");
}

static int get_vl_size ()
{
  int res = prctl (PR_SVE_GET_VL, 0, 0, 0, 0);
  if (res < 0)
    {
      printf ("FAILED to PR_SVE_GET_VL (%d)\n", res);
      return -1;
    }
  return (res & PR_SVE_VL_LEN_MASK);
}

static int get_svl_size ()
{
  int res = prctl (PR_SME_GET_VL, 0, 0, 0, 0);
  if (res < 0)
    {
      printf ("FAILED to PR_SME_GET_VL (%d)\n", res);
      return -1;
    }
  return (res & PR_SVE_VL_LEN_MASK);
}

static int set_vl_size (int new_vl)
{
  int res = prctl (PR_SVE_SET_VL, new_vl, 0, 0, 0, 0);
  if (res < 0)
    {
      printf ("FAILED to PR_SVE_SET_VL (%d)\n", res);
      return -1;
    }

  res = get_vl_size ();
  if (res != new_vl)
    {
      printf ("Unexpected VL value (%d)\n", res);
      return -1;
    }

  return res;
}

static int set_svl_size (int new_svl)
{
  int res = prctl (PR_SME_SET_VL, new_svl, 0, 0, 0, 0);
  if (res < 0)
    {
      printf ("FAILED to PR_SME_SET_VL (%d)\n", res);
      return -1;
    }

  res = get_svl_size ();
  if (res != new_svl)
    {
      printf ("Unexpected SVL value (%d)\n", res);
      return -1;
    }

  return res;
}

/* Enable register states based on STATE.

   0 - FPSIMD
   1 - SVE
   2 - SSVE
   3 - ZA (+ SME2 ZT0)
   4 - ZA and SSVE (+ SME2 ZT0).  */

void enable_states (int state)
{
  disable_za ();
  disable_sm ();
  initialize_fpsimd_state ();

  if (state == 1)
    {
      initialize_sve_state ();
    }
  else if (state == 2)
    {
      enable_sm ();
      initialize_sve_state ();
    }
  else if (state == 3)
    {
      enable_za ();
      initialize_za_state ();
      initialize_zt_state ();
    }
  else if (state == 4)
    {
      enable_za ();
      enable_sm ();
      initialize_sve_state ();
      initialize_za_state ();
      initialize_zt_state ();
    }

  return;
}

static int
test_id_to_state (int id)
{
  return (id / 25);
}

static int
test_id_to_vl (int id)
{
  return 16 << ((id / 5) % 5);
}

static int
test_id_to_svl (int id)
{
  return 16 << (id % 5);
}

static void
dummy ()
{
}

int
main (int argc, char **argv)
{
  if (getauxval (AT_HWCAP) & HWCAP_SVE && getauxval (AT_HWCAP2) & HWCAP2_SME)
    {
      int id_start = ID_START;
      int id_end = ID_END;
#ifdef SIGILL
      signal (SIGILL, handler);
#endif

      int signal_count = 0;
      for (int id = id_start; id <= id_end; id++)
	{
	  int state = test_id_to_state (id);
	  int vl = test_id_to_vl (id);
	  int svl = test_id_to_svl (id);

	  if (set_vl_size (vl) == -1 || set_svl_size (svl) == -1)
	    continue;

	  signal_count++;
	  enable_states (state);
	  dummy (); /* stop before SIGILL */
	  __asm __volatile (".word 0xDEADBEEF"); /* illegal instruction */
	  while (signal_count != count);
	}
    }
  else
    {
      printf ("SKIP: no HWCAP_SVE or HWCAP2_SME on this system\n");
      return -1;
    }

  return 0;
}