1 // SPDX-License-Identifier: GPL-2.0-only
2 #include <sys/ptrace.h>
3 #include <sys/syscall.h>
4 #include <sys/types.h>
5 #include <sys/wait.h>
6 #include <sys/uio.h>
7 #include <unistd.h>
8 #include <errno.h>
9
10 #include <linux/ptrace.h>
11 #include <linux/elf.h>
12
13 #include "kselftest_harness.h"
14 #include "v_helpers.h"
15
16 #define SR_FS_DIRTY 0x00006000UL
17 #define CSR_VXRM_SHIFT 1
18
19 volatile unsigned long chld_lock;
20
TEST(ptrace_v_not_enabled)21 TEST(ptrace_v_not_enabled)
22 {
23 pid_t pid;
24
25 if (!(is_vector_supported() || is_xtheadvector_supported()))
26 SKIP(return, "Vector not supported");
27
28 chld_lock = 1;
29 pid = (pid_t)syscall(SYS_clone, SIGCHLD, 0, NULL, 0, NULL);
30 ASSERT_LE(0, pid)
31 TH_LOG("clone: %m");
32
33 if (pid == 0) {
34 while (chld_lock == 1)
35 asm volatile("" : : "g"(chld_lock) : "memory");
36
37 asm volatile ("ebreak" : : : );
38 } else {
39 struct __riscv_v_regset_state *regset_data;
40 unsigned long vlenb = get_vr_len();
41 size_t regset_size;
42 struct iovec iov;
43 int status;
44 int ret;
45
46 /* attach */
47
48 ASSERT_EQ(0, ptrace(PTRACE_ATTACH, pid, NULL, NULL));
49 ASSERT_EQ(pid, waitpid(pid, &status, 0));
50 ASSERT_TRUE(WIFSTOPPED(status));
51
52 /* unlock */
53
54 ASSERT_EQ(0, ptrace(PTRACE_POKEDATA, pid, &chld_lock, 0));
55
56 /* resume and wait for ebreak */
57
58 ASSERT_EQ(0, ptrace(PTRACE_CONT, pid, NULL, NULL));
59 ASSERT_EQ(pid, waitpid(pid, &status, 0));
60 ASSERT_TRUE(WIFSTOPPED(status));
61
62 /* try to read vector registers from the tracee */
63
64 regset_size = sizeof(*regset_data) + vlenb * 32;
65 regset_data = calloc(1, regset_size);
66
67 iov.iov_base = regset_data;
68 iov.iov_len = regset_size;
69
70 /* V extension is available, but not yet enabled for the tracee */
71
72 errno = 0;
73 ret = ptrace(PTRACE_GETREGSET, pid, NT_RISCV_VECTOR, &iov);
74 ASSERT_EQ(ENODATA, errno);
75 ASSERT_EQ(-1, ret);
76
77 /* cleanup */
78 free(regset_data);
79 ASSERT_EQ(0, kill(pid, SIGKILL));
80 }
81 }
82
TEST(ptrace_v_early_debug)83 TEST(ptrace_v_early_debug)
84 {
85 static volatile unsigned long vstart;
86 static volatile unsigned long vtype;
87 static volatile unsigned long vlenb;
88 static volatile unsigned long vcsr;
89 static volatile unsigned long vl;
90 bool xtheadvector;
91 pid_t pid;
92
93 if (!(is_vector_supported() || is_xtheadvector_supported()))
94 SKIP(return, "Vector not supported");
95
96 xtheadvector = is_xtheadvector_supported();
97
98 chld_lock = 1;
99 pid = fork();
100 ASSERT_LE(0, pid)
101 TH_LOG("fork: %m");
102
103 if (pid == 0) {
104 unsigned long vxsat, vxrm;
105
106 vlenb = get_vr_len();
107
108 while (chld_lock == 1)
109 asm volatile ("" : : "g"(chld_lock) : "memory");
110
111 asm volatile (
112 "csrr %[vstart], vstart\n"
113 "csrr %[vtype], vtype\n"
114 "csrr %[vl], vl\n"
115 : [vtype] "=r"(vtype), [vstart] "=r"(vstart), [vl] "=r"(vl)
116 :
117 : "memory");
118
119 /* no 'is_xtheadvector_supported()' here to avoid clobbering v-state by syscall */
120 if (xtheadvector) {
121 asm volatile (
122 "csrs sstatus, %[bit]\n"
123 "csrr %[vxsat], vxsat\n"
124 "csrr %[vxrm], vxrm\n"
125 : [vxsat] "=r"(vxsat), [vxrm] "=r"(vxrm)
126 : [bit] "r" (SR_FS_DIRTY)
127 : "memory");
128 vcsr = vxsat | vxrm << CSR_VXRM_SHIFT;
129 } else {
130 asm volatile (
131 "csrr %[vcsr], vcsr\n"
132 : [vcsr] "=r"(vcsr)
133 :
134 : "memory");
135 }
136
137 asm volatile (
138 ".option push\n"
139 ".option norvc\n"
140 "ebreak\n"
141 ".option pop\n");
142 } else {
143 struct __riscv_v_regset_state *regset_data;
144 unsigned long vstart_csr;
145 unsigned long vlenb_csr;
146 unsigned long vtype_csr;
147 unsigned long vcsr_csr;
148 unsigned long vl_csr;
149 size_t regset_size;
150 struct iovec iov;
151 int status;
152
153 /* attach */
154
155 ASSERT_EQ(0, ptrace(PTRACE_ATTACH, pid, NULL, NULL));
156 ASSERT_EQ(pid, waitpid(pid, &status, 0));
157 ASSERT_TRUE(WIFSTOPPED(status));
158
159 /* unlock */
160
161 ASSERT_EQ(0, ptrace(PTRACE_POKEDATA, pid, &chld_lock, 0));
162
163 /* resume and wait for ebreak */
164
165 ASSERT_EQ(0, ptrace(PTRACE_CONT, pid, NULL, NULL));
166 ASSERT_EQ(pid, waitpid(pid, &status, 0));
167 ASSERT_TRUE(WIFSTOPPED(status));
168
169 /* read tracee vector csr regs using ptrace PEEKDATA */
170
171 errno = 0;
172 vstart_csr = ptrace(PTRACE_PEEKDATA, pid, &vstart, NULL);
173 ASSERT_FALSE((errno != 0) && (vstart_csr == -1));
174
175 errno = 0;
176 vl_csr = ptrace(PTRACE_PEEKDATA, pid, &vl, NULL);
177 ASSERT_FALSE((errno != 0) && (vl_csr == -1));
178
179 errno = 0;
180 vtype_csr = ptrace(PTRACE_PEEKDATA, pid, &vtype, NULL);
181 ASSERT_FALSE((errno != 0) && (vtype_csr == -1));
182
183 errno = 0;
184 vcsr_csr = ptrace(PTRACE_PEEKDATA, pid, &vcsr, NULL);
185 ASSERT_FALSE((errno != 0) && (vcsr_csr == -1));
186
187 errno = 0;
188 vlenb_csr = ptrace(PTRACE_PEEKDATA, pid, &vlenb, NULL);
189 ASSERT_FALSE((errno != 0) && (vlenb_csr == -1));
190
191 /* read tracee csr regs using ptrace GETREGSET */
192
193 regset_size = sizeof(*regset_data) + vlenb_csr * 32;
194 regset_data = calloc(1, regset_size);
195
196 iov.iov_base = regset_data;
197 iov.iov_len = regset_size;
198
199 ASSERT_EQ(0, ptrace(PTRACE_GETREGSET, pid, NT_RISCV_VECTOR, &iov));
200
201 /* compare */
202
203 EXPECT_EQ(vstart_csr, regset_data->vstart);
204 EXPECT_EQ(vtype_csr, regset_data->vtype);
205 EXPECT_EQ(vlenb_csr, regset_data->vlenb);
206 EXPECT_EQ(vcsr_csr, regset_data->vcsr);
207 EXPECT_EQ(vl_csr, regset_data->vl);
208
209 /* cleanup */
210 free(regset_data);
211 ASSERT_EQ(0, kill(pid, SIGKILL));
212 }
213 }
214
TEST(ptrace_v_syscall_clobbering)215 TEST(ptrace_v_syscall_clobbering)
216 {
217 pid_t pid;
218
219 if (!is_vector_supported() && !is_xtheadvector_supported())
220 SKIP(return, "Vector not supported");
221
222 chld_lock = 1;
223 pid = fork();
224 ASSERT_LE(0, pid)
225 TH_LOG("fork: %m");
226
227 if (pid == 0) {
228 unsigned long vl;
229
230 while (chld_lock == 1)
231 asm volatile("" : : "g"(chld_lock) : "memory");
232
233 if (is_xtheadvector_supported()) {
234 asm volatile (
235 // 0 | zimm[10:0] | rs1 | 1 1 1 | rd |1010111| vsetvli
236 // vsetvli t4, x0, e16, m2, d1
237 ".4byte 0b00000000010100000111111011010111\n"
238 "mv %[new_vl], t4\n"
239 : [new_vl] "=r" (vl) : : "t4");
240 } else {
241 asm volatile (
242 ".option push\n"
243 ".option arch, +zve32x\n"
244 "vsetvli %[new_vl], x0, e16, m2, tu, mu\n"
245 ".option pop\n"
246 : [new_vl] "=r"(vl) : : );
247 }
248
249 while (1) {
250 asm volatile (
251 ".option push\n"
252 ".option norvc\n"
253 "ebreak\n"
254 ".option pop\n");
255
256 sleep(0);
257 }
258 } else {
259 struct __riscv_v_regset_state *regset_data;
260 unsigned long vlenb = get_vr_len();
261 struct user_regs_struct regs;
262 size_t regset_size;
263 struct iovec iov;
264 int status;
265
266 /* attach */
267
268 ASSERT_EQ(0, ptrace(PTRACE_ATTACH, pid, NULL, NULL));
269 ASSERT_EQ(pid, waitpid(pid, &status, 0));
270 ASSERT_TRUE(WIFSTOPPED(status));
271
272 /* unlock */
273
274 ASSERT_EQ(0, ptrace(PTRACE_POKEDATA, pid, &chld_lock, 0));
275
276 /* resume and wait for the 1st ebreak */
277
278 ASSERT_EQ(0, ptrace(PTRACE_CONT, pid, NULL, NULL));
279 ASSERT_EQ(pid, waitpid(pid, &status, 0));
280 ASSERT_TRUE(WIFSTOPPED(status));
281
282 /* read tracee vector csr regs using ptrace GETREGSET */
283
284 regset_size = sizeof(*regset_data) + vlenb * 32;
285 regset_data = calloc(1, regset_size);
286
287 iov.iov_base = regset_data;
288 iov.iov_len = regset_size;
289
290 ASSERT_EQ(0, ptrace(PTRACE_GETREGSET, pid, NT_RISCV_VECTOR, &iov));
291
292 /* verify initial vsetvli settings */
293
294 if (is_xtheadvector_supported()) {
295 EXPECT_EQ(5UL, regset_data->vtype);
296 } else {
297 EXPECT_EQ(9UL, regset_data->vtype);
298 }
299
300 EXPECT_EQ(regset_data->vlenb, regset_data->vl);
301 EXPECT_EQ(vlenb, regset_data->vlenb);
302 EXPECT_EQ(0UL, regset_data->vstart);
303 EXPECT_EQ(0UL, regset_data->vcsr);
304
305 /* skip 1st ebreak, then resume and wait for the 2nd ebreak */
306
307 iov.iov_base = ®s;
308 iov.iov_len = sizeof(regs);
309
310 ASSERT_EQ(0, ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &iov));
311 regs.pc += 4;
312 ASSERT_EQ(0, ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, &iov));
313
314 ASSERT_EQ(0, ptrace(PTRACE_CONT, pid, NULL, NULL));
315 ASSERT_EQ(pid, waitpid(pid, &status, 0));
316 ASSERT_TRUE(WIFSTOPPED(status));
317
318 /* read tracee vtype using ptrace GETREGSET */
319
320 iov.iov_base = regset_data;
321 iov.iov_len = regset_size;
322
323 ASSERT_EQ(0, ptrace(PTRACE_GETREGSET, pid, NT_RISCV_VECTOR, &iov));
324
325 /* verify that V state is illegal after syscall */
326
327 EXPECT_EQ((1UL << (__riscv_xlen - 1)), regset_data->vtype);
328 EXPECT_EQ(vlenb, regset_data->vlenb);
329 EXPECT_EQ(0UL, regset_data->vstart);
330 EXPECT_EQ(0UL, regset_data->vcsr);
331 EXPECT_EQ(0UL, regset_data->vl);
332
333 /* cleanup */
334 free(regset_data);
335 ASSERT_EQ(0, kill(pid, SIGKILL));
336 }
337 }
338
FIXTURE(v_csr_invalid)339 FIXTURE(v_csr_invalid)
340 {
341 };
342
FIXTURE_SETUP(v_csr_invalid)343 FIXTURE_SETUP(v_csr_invalid)
344 {
345 }
346
FIXTURE_TEARDOWN(v_csr_invalid)347 FIXTURE_TEARDOWN(v_csr_invalid)
348 {
349 }
350
351 #define VECTOR_1_0 _BITUL(0)
352 #define XTHEAD_VECTOR_0_7 _BITUL(1)
353
354 #define vector_test(x) ((x) & VECTOR_1_0)
355 #define xthead_test(x) ((x) & XTHEAD_VECTOR_0_7)
356
357 /* modifications of the initial vsetvli settings */
FIXTURE_VARIANT(v_csr_invalid)358 FIXTURE_VARIANT(v_csr_invalid)
359 {
360 unsigned long vstart;
361 unsigned long vl;
362 unsigned long vtype;
363 unsigned long vcsr;
364 unsigned long vlenb_mul;
365 unsigned long vlenb_min;
366 unsigned long vlenb_max;
367 unsigned long spec;
368 };
369
370 /* unexpected vlenb value */
FIXTURE_VARIANT_ADD(v_csr_invalid,new_vlenb)371 FIXTURE_VARIANT_ADD(v_csr_invalid, new_vlenb)
372 {
373 .vstart = 0x0,
374 .vl = 0x0,
375 .vtype = 0x3,
376 .vcsr = 0x0,
377 .vlenb_mul = 0x2,
378 .vlenb_min = 0x0,
379 .vlenb_max = 0x0,
380 .spec = VECTOR_1_0 | XTHEAD_VECTOR_0_7,
381 };
382
383 /* invalid reserved bits in vcsr */
FIXTURE_VARIANT_ADD(v_csr_invalid,vcsr_invalid_reserved_bits)384 FIXTURE_VARIANT_ADD(v_csr_invalid, vcsr_invalid_reserved_bits)
385 {
386 .vstart = 0x0,
387 .vl = 0x0,
388 .vtype = 0x3,
389 .vcsr = 0x1UL << 8,
390 .vlenb_mul = 0x1,
391 .vlenb_min = 0x0,
392 .vlenb_max = 0x0,
393 .spec = VECTOR_1_0 | XTHEAD_VECTOR_0_7,
394 };
395
396 /* invalid reserved bits in vtype */
FIXTURE_VARIANT_ADD(v_csr_invalid,vtype_invalid_reserved_bits)397 FIXTURE_VARIANT_ADD(v_csr_invalid, vtype_invalid_reserved_bits)
398 {
399 .vstart = 0x0,
400 .vl = 0x0,
401 .vtype = (0x1UL << 8) | 0x3,
402 .vcsr = 0x0,
403 .vlenb_mul = 0x1,
404 .vlenb_min = 0x0,
405 .vlenb_max = 0x0,
406 .spec = VECTOR_1_0 | XTHEAD_VECTOR_0_7,
407 };
408
409 /* set vill bit */
FIXTURE_VARIANT_ADD(v_csr_invalid,invalid_vill_bit)410 FIXTURE_VARIANT_ADD(v_csr_invalid, invalid_vill_bit)
411 {
412 .vstart = 0x0,
413 .vl = 0x0,
414 .vtype = (0x1UL << (__riscv_xlen - 1)) | 0x3,
415 .vcsr = 0x0,
416 .vlenb_mul = 0x1,
417 .vlenb_min = 0x0,
418 .vlenb_max = 0x0,
419 .spec = VECTOR_1_0 | XTHEAD_VECTOR_0_7,
420 };
421
422 /* reserved vsew value: vsew > 3 */
FIXTURE_VARIANT_ADD(v_csr_invalid,reserved_vsew)423 FIXTURE_VARIANT_ADD(v_csr_invalid, reserved_vsew)
424 {
425 .vstart = 0x0,
426 .vl = 0x0,
427 .vtype = 0x4UL << 3,
428 .vcsr = 0x0,
429 .vlenb_mul = 0x1,
430 .vlenb_min = 0x0,
431 .vlenb_max = 0x0,
432 .spec = VECTOR_1_0,
433 };
434
435 /* XTheadVector: unsupported non-zero VEDIV value */
FIXTURE_VARIANT_ADD(v_csr_invalid,reserved_vediv)436 FIXTURE_VARIANT_ADD(v_csr_invalid, reserved_vediv)
437 {
438 .vstart = 0x0,
439 .vl = 0x0,
440 .vtype = 0x3UL << 5,
441 .vcsr = 0x0,
442 .vlenb_mul = 0x1,
443 .vlenb_min = 0x0,
444 .vlenb_max = 0x0,
445 .spec = XTHEAD_VECTOR_0_7,
446 };
447
448 /* reserved vlmul value: vlmul == 4 */
FIXTURE_VARIANT_ADD(v_csr_invalid,reserved_vlmul)449 FIXTURE_VARIANT_ADD(v_csr_invalid, reserved_vlmul)
450 {
451 .vstart = 0x0,
452 .vl = 0x0,
453 .vtype = 0x4,
454 .vcsr = 0x0,
455 .vlenb_mul = 0x1,
456 .vlenb_min = 0x0,
457 .vlenb_max = 0x0,
458 .spec = VECTOR_1_0,
459 };
460
461 /* invalid fractional LMUL for VLEN <= 256: LMUL= 1/8, SEW = 64 */
FIXTURE_VARIANT_ADD(v_csr_invalid,frac_lmul1)462 FIXTURE_VARIANT_ADD(v_csr_invalid, frac_lmul1)
463 {
464 .vstart = 0x0,
465 .vl = 0x0,
466 .vtype = 0x1d,
467 .vcsr = 0x0,
468 .vlenb_mul = 0x1,
469 .vlenb_min = 0x0,
470 .vlenb_max = 0x20,
471 .spec = VECTOR_1_0,
472 };
473
474 /* invalid integral LMUL for VLEN <= 16: LMUL= 2, SEW = 64 */
FIXTURE_VARIANT_ADD(v_csr_invalid,int_lmul1)475 FIXTURE_VARIANT_ADD(v_csr_invalid, int_lmul1)
476 {
477 .vstart = 0x0,
478 .vl = 0x0,
479 .vtype = 0x19,
480 .vcsr = 0x0,
481 .vlenb_mul = 0x1,
482 .vlenb_min = 0x0,
483 .vlenb_max = 0x2,
484 .spec = VECTOR_1_0,
485 };
486
487 /* XTheadVector: invalid integral LMUL for VLEN <= 16: LMUL= 2, SEW = 64 */
FIXTURE_VARIANT_ADD(v_csr_invalid,int_lmul2)488 FIXTURE_VARIANT_ADD(v_csr_invalid, int_lmul2)
489 {
490 .vstart = 0x0,
491 .vl = 0x0,
492 .vtype = 0xd,
493 .vcsr = 0x0,
494 .vlenb_mul = 0x1,
495 .vlenb_min = 0x0,
496 .vlenb_max = 0x2,
497 .spec = XTHEAD_VECTOR_0_7,
498 };
499
500 /* invalid VL for VLEN <= 128: LMUL= 2, SEW = 64, VL = 8 */
FIXTURE_VARIANT_ADD(v_csr_invalid,vl1)501 FIXTURE_VARIANT_ADD(v_csr_invalid, vl1)
502 {
503 .vstart = 0x0,
504 .vl = 0x8,
505 .vtype = 0x19,
506 .vcsr = 0x0,
507 .vlenb_mul = 0x1,
508 .vlenb_min = 0x0,
509 .vlenb_max = 0x10,
510 .spec = VECTOR_1_0,
511 };
512
513 /* XTheadVector: invalid VL for VLEN <= 128: LMUL= 2, SEW = 64, VL = 8 */
FIXTURE_VARIANT_ADD(v_csr_invalid,vl2)514 FIXTURE_VARIANT_ADD(v_csr_invalid, vl2)
515 {
516 .vstart = 0x0,
517 .vl = 0x8,
518 .vtype = 0xd,
519 .vcsr = 0x0,
520 .vlenb_mul = 0x1,
521 .vlenb_min = 0x0,
522 .vlenb_max = 0x10,
523 .spec = XTHEAD_VECTOR_0_7,
524 };
525
TEST_F(v_csr_invalid,ptrace_v_invalid_values)526 TEST_F(v_csr_invalid, ptrace_v_invalid_values)
527 {
528 unsigned long vlenb;
529 pid_t pid;
530
531 if (!is_vector_supported() && !is_xtheadvector_supported())
532 SKIP(return, "Vectors not supported");
533
534 if (is_vector_supported() && !vector_test(variant->spec))
535 SKIP(return, "Test not supported for Vector");
536
537 if (is_xtheadvector_supported() && !xthead_test(variant->spec))
538 SKIP(return, "Test not supported for XTheadVector");
539
540 vlenb = get_vr_len();
541
542 if (variant->vlenb_min) {
543 if (vlenb < variant->vlenb_min)
544 SKIP(return, "This test does not support VLEN < %lu\n",
545 variant->vlenb_min * 8);
546 }
547
548 if (variant->vlenb_max) {
549 if (vlenb > variant->vlenb_max)
550 SKIP(return, "This test does not support VLEN > %lu\n",
551 variant->vlenb_max * 8);
552 }
553
554 chld_lock = 1;
555 pid = fork();
556 ASSERT_LE(0, pid)
557 TH_LOG("fork: %m");
558
559 if (pid == 0) {
560 unsigned long vl;
561
562 while (chld_lock == 1)
563 asm volatile("" : : "g"(chld_lock) : "memory");
564
565 if (is_xtheadvector_supported()) {
566 asm volatile (
567 // 0 | zimm[10:0] | rs1 | 1 1 1 | rd |1010111| vsetvli
568 // vsetvli t4, x0, e16, m2, d1
569 ".4byte 0b00000000010100000111111011010111\n"
570 "mv %[new_vl], t4\n"
571 : [new_vl] "=r" (vl) : : "t4");
572 } else {
573 asm volatile (
574 ".option push\n"
575 ".option arch, +zve32x\n"
576 "vsetvli %[new_vl], x0, e16, m2, tu, mu\n"
577 ".option pop\n"
578 : [new_vl] "=r"(vl) : : );
579 }
580
581 while (1) {
582 asm volatile (
583 ".option push\n"
584 ".option norvc\n"
585 "ebreak\n"
586 "nop\n"
587 ".option pop\n");
588 }
589 } else {
590 struct __riscv_v_regset_state *regset_data;
591 size_t regset_size;
592 struct iovec iov;
593 int status;
594 int ret;
595
596 /* attach */
597
598 ASSERT_EQ(0, ptrace(PTRACE_ATTACH, pid, NULL, NULL));
599 ASSERT_EQ(pid, waitpid(pid, &status, 0));
600 ASSERT_TRUE(WIFSTOPPED(status));
601
602 /* unlock */
603
604 ASSERT_EQ(0, ptrace(PTRACE_POKEDATA, pid, &chld_lock, 0));
605
606 /* resume and wait for the 1st ebreak */
607
608 ASSERT_EQ(0, ptrace(PTRACE_CONT, pid, NULL, NULL));
609 ASSERT_EQ(pid, waitpid(pid, &status, 0));
610 ASSERT_TRUE(WIFSTOPPED(status));
611
612 /* read tracee vector csr regs using ptrace GETREGSET */
613
614 regset_size = sizeof(*regset_data) + vlenb * 32;
615 regset_data = calloc(1, regset_size);
616
617 iov.iov_base = regset_data;
618 iov.iov_len = regset_size;
619
620 ASSERT_EQ(0, ptrace(PTRACE_GETREGSET, pid, NT_RISCV_VECTOR, &iov));
621
622 /* verify initial vsetvli settings */
623
624 if (is_xtheadvector_supported()) {
625 EXPECT_EQ(5UL, regset_data->vtype);
626 } else {
627 EXPECT_EQ(9UL, regset_data->vtype);
628 }
629
630 EXPECT_EQ(regset_data->vlenb, regset_data->vl);
631 EXPECT_EQ(vlenb, regset_data->vlenb);
632 EXPECT_EQ(0UL, regset_data->vstart);
633 EXPECT_EQ(0UL, regset_data->vcsr);
634
635 /* apply invalid settings from fixture variants */
636
637 regset_data->vlenb *= variant->vlenb_mul;
638 regset_data->vstart = variant->vstart;
639 regset_data->vtype = variant->vtype;
640 regset_data->vcsr = variant->vcsr;
641 regset_data->vl = variant->vl;
642
643 iov.iov_base = regset_data;
644 iov.iov_len = regset_size;
645
646 errno = 0;
647 ret = ptrace(PTRACE_SETREGSET, pid, NT_RISCV_VECTOR, &iov);
648 ASSERT_EQ(errno, EINVAL);
649 ASSERT_EQ(ret, -1);
650
651 /* cleanup */
652 free(regset_data);
653 ASSERT_EQ(0, kill(pid, SIGKILL));
654 }
655 }
656
FIXTURE(v_csr_valid)657 FIXTURE(v_csr_valid)
658 {
659 };
660
FIXTURE_SETUP(v_csr_valid)661 FIXTURE_SETUP(v_csr_valid)
662 {
663 }
664
FIXTURE_TEARDOWN(v_csr_valid)665 FIXTURE_TEARDOWN(v_csr_valid)
666 {
667 }
668
669 /* modifications of the initial vsetvli settings */
FIXTURE_VARIANT(v_csr_valid)670 FIXTURE_VARIANT(v_csr_valid)
671 {
672 unsigned long vstart;
673 unsigned long vl;
674 unsigned long vtype;
675 unsigned long vcsr;
676 unsigned long vlenb_mul;
677 unsigned long vlenb_min;
678 unsigned long vlenb_max;
679 unsigned long spec;
680 };
681
682 /* valid for VLEN >= 128: LMUL= 1/4, SEW = 32 */
FIXTURE_VARIANT_ADD(v_csr_valid,frac_lmul1)683 FIXTURE_VARIANT_ADD(v_csr_valid, frac_lmul1)
684 {
685 .vstart = 0x0,
686 .vl = 0x0,
687 .vtype = 0x16,
688 .vcsr = 0x0,
689 .vlenb_mul = 0x1,
690 .vlenb_min = 0x10,
691 .vlenb_max = 0x0,
692 .spec = VECTOR_1_0,
693 };
694
695 /* valid for VLEN >= 16: LMUL= 2, SEW = 32 */
FIXTURE_VARIANT_ADD(v_csr_valid,int_lmul1)696 FIXTURE_VARIANT_ADD(v_csr_valid, int_lmul1)
697 {
698 .vstart = 0x0,
699 .vl = 0x0,
700 .vtype = 0x11,
701 .vcsr = 0x0,
702 .vlenb_mul = 0x1,
703 .vlenb_min = 0x2,
704 .vlenb_max = 0x0,
705 .spec = VECTOR_1_0,
706 };
707
708 /* valid for XTheadVector VLEN >= 16: LMUL= 2, SEW = 32 */
FIXTURE_VARIANT_ADD(v_csr_valid,int_lmul2)709 FIXTURE_VARIANT_ADD(v_csr_valid, int_lmul2)
710 {
711 .vstart = 0x0,
712 .vl = 0x0,
713 .vtype = 0x9,
714 .vcsr = 0x0,
715 .vlenb_mul = 0x1,
716 .vlenb_min = 0x2,
717 .vlenb_max = 0x0,
718 .spec = XTHEAD_VECTOR_0_7,
719 };
720
721 /* valid for VLEN >= 32: LMUL= 2, SEW = 32, VL = 2 */
FIXTURE_VARIANT_ADD(v_csr_valid,int_lmul3)722 FIXTURE_VARIANT_ADD(v_csr_valid, int_lmul3)
723 {
724 .vstart = 0x0,
725 .vl = 0x2,
726 .vtype = 0x11,
727 .vcsr = 0x0,
728 .vlenb_mul = 0x1,
729 .vlenb_min = 0x4,
730 .vlenb_max = 0x0,
731 .spec = VECTOR_1_0,
732 };
733
TEST_F(v_csr_valid,ptrace_v_valid_values)734 TEST_F(v_csr_valid, ptrace_v_valid_values)
735 {
736 unsigned long vlenb;
737 pid_t pid;
738
739 if (!is_vector_supported() && !is_xtheadvector_supported())
740 SKIP(return, "Vectors not supported");
741
742 if (is_vector_supported() && !vector_test(variant->spec))
743 SKIP(return, "Test not supported for Vector");
744
745 if (is_xtheadvector_supported() && !xthead_test(variant->spec))
746 SKIP(return, "Test not supported for XTheadVector");
747
748 vlenb = get_vr_len();
749
750 if (variant->vlenb_min) {
751 if (vlenb < variant->vlenb_min)
752 SKIP(return, "This test does not support VLEN < %lu\n",
753 variant->vlenb_min * 8);
754 }
755 if (variant->vlenb_max) {
756 if (vlenb > variant->vlenb_max)
757 SKIP(return, "This test does not support VLEN > %lu\n",
758 variant->vlenb_max * 8);
759 }
760
761 chld_lock = 1;
762 pid = fork();
763 ASSERT_LE(0, pid)
764 TH_LOG("fork: %m");
765
766 if (pid == 0) {
767 unsigned long vl;
768
769 while (chld_lock == 1)
770 asm volatile("" : : "g"(chld_lock) : "memory");
771
772 if (is_xtheadvector_supported()) {
773 asm volatile (
774 // 0 | zimm[10:0] | rs1 | 1 1 1 | rd |1010111| vsetvli
775 // vsetvli t4, x0, e16, m2, d1
776 ".4byte 0b00000000010100000111111011010111\n"
777 "mv %[new_vl], t4\n"
778 : [new_vl] "=r" (vl) : : "t4");
779 } else {
780 asm volatile (
781 ".option push\n"
782 ".option arch, +zve32x\n"
783 "vsetvli %[new_vl], x0, e16, m2, tu, mu\n"
784 ".option pop\n"
785 : [new_vl] "=r"(vl) : : );
786 }
787
788 asm volatile (
789 ".option push\n"
790 ".option norvc\n"
791 ".option arch, +zve32x\n"
792 "ebreak\n" /* breakpoint 1: apply new V state using ptrace */
793 "nop\n"
794 "ebreak\n" /* breakpoint 2: V state clean - context will not be saved */
795 "vmv.v.i v0, -1\n"
796 "ebreak\n" /* breakpoint 3: V state dirty - context will be saved */
797 ".option pop\n");
798 } else {
799 struct __riscv_v_regset_state *regset_data;
800 struct user_regs_struct regs;
801 size_t regset_size;
802 struct iovec iov;
803 int status;
804
805 /* attach */
806
807 ASSERT_EQ(0, ptrace(PTRACE_ATTACH, pid, NULL, NULL));
808 ASSERT_EQ(pid, waitpid(pid, &status, 0));
809 ASSERT_TRUE(WIFSTOPPED(status));
810
811 /* unlock */
812
813 ASSERT_EQ(0, ptrace(PTRACE_POKEDATA, pid, &chld_lock, 0));
814
815 /* resume and wait for the 1st ebreak */
816
817 ASSERT_EQ(0, ptrace(PTRACE_CONT, pid, NULL, NULL));
818 ASSERT_EQ(pid, waitpid(pid, &status, 0));
819 ASSERT_TRUE(WIFSTOPPED(status));
820
821 /* read tracee vector csr regs using ptrace GETREGSET */
822
823 regset_size = sizeof(*regset_data) + vlenb * 32;
824 regset_data = calloc(1, regset_size);
825
826 iov.iov_base = regset_data;
827 iov.iov_len = regset_size;
828
829 ASSERT_EQ(0, ptrace(PTRACE_GETREGSET, pid, NT_RISCV_VECTOR, &iov));
830
831 /* verify initial vsetvli settings */
832
833 if (is_xtheadvector_supported()) {
834 EXPECT_EQ(5UL, regset_data->vtype);
835 } else {
836 EXPECT_EQ(9UL, regset_data->vtype);
837 }
838
839 EXPECT_EQ(regset_data->vlenb, regset_data->vl);
840 EXPECT_EQ(vlenb, regset_data->vlenb);
841 EXPECT_EQ(0UL, regset_data->vstart);
842 EXPECT_EQ(0UL, regset_data->vcsr);
843
844 /* apply valid settings from fixture variants */
845
846 regset_data->vlenb *= variant->vlenb_mul;
847 regset_data->vstart = variant->vstart;
848 regset_data->vtype = variant->vtype;
849 regset_data->vcsr = variant->vcsr;
850 regset_data->vl = variant->vl;
851
852 iov.iov_base = regset_data;
853 iov.iov_len = regset_size;
854
855 ASSERT_EQ(0, ptrace(PTRACE_SETREGSET, pid, NT_RISCV_VECTOR, &iov));
856
857 /* skip 1st ebreak, then resume and wait for the 2nd ebreak */
858
859 iov.iov_base = ®s;
860 iov.iov_len = sizeof(regs);
861
862 ASSERT_EQ(0, ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &iov));
863 regs.pc += 4;
864 ASSERT_EQ(0, ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, &iov));
865
866 ASSERT_EQ(0, ptrace(PTRACE_CONT, pid, NULL, NULL));
867 ASSERT_EQ(pid, waitpid(pid, &status, 0));
868 ASSERT_TRUE(WIFSTOPPED(status));
869
870 /* read tracee vector csr regs using ptrace GETREGSET */
871
872 iov.iov_base = regset_data;
873 iov.iov_len = regset_size;
874
875 ASSERT_EQ(0, ptrace(PTRACE_GETREGSET, pid, NT_RISCV_VECTOR, &iov));
876
877 /* verify vector csr regs from tracee context */
878
879 EXPECT_EQ(regset_data->vstart, variant->vstart);
880 EXPECT_EQ(regset_data->vtype, variant->vtype);
881 EXPECT_EQ(regset_data->vcsr, variant->vcsr);
882 EXPECT_EQ(regset_data->vl, variant->vl);
883 EXPECT_EQ(regset_data->vlenb, vlenb);
884
885 /* skip 2nd ebreak, then resume and wait for the 3rd ebreak */
886
887 iov.iov_base = ®s;
888 iov.iov_len = sizeof(regs);
889
890 ASSERT_EQ(0, ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &iov));
891 regs.pc += 4;
892 ASSERT_EQ(0, ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, &iov));
893
894 ASSERT_EQ(0, ptrace(PTRACE_CONT, pid, NULL, NULL));
895 ASSERT_EQ(pid, waitpid(pid, &status, 0));
896 ASSERT_TRUE(WIFSTOPPED(status));
897
898 /* read tracee vector csr regs using ptrace GETREGSET */
899
900 iov.iov_base = regset_data;
901 iov.iov_len = regset_size;
902
903 ASSERT_EQ(0, ptrace(PTRACE_GETREGSET, pid, NT_RISCV_VECTOR, &iov));
904
905 /* verify vector csr regs from tracee context */
906
907 EXPECT_EQ(regset_data->vstart, variant->vstart);
908 EXPECT_EQ(regset_data->vtype, variant->vtype);
909 EXPECT_EQ(regset_data->vcsr, variant->vcsr);
910 EXPECT_EQ(regset_data->vl, variant->vl);
911 EXPECT_EQ(regset_data->vlenb, vlenb);
912
913 /* cleanup */
914 free(regset_data);
915 ASSERT_EQ(0, kill(pid, SIGKILL));
916 }
917 }
918
919 TEST_HARNESS_MAIN
920