1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2021 ARM Limited
4  *
5  * Verify that the streaming SVE register context in signal frames is
6  * set up as expected.
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 * 64];
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 		/* Skip missing VLs */
38 		vq = sve_vq_from_vl(vl);
39 
40 		vls[nvls++] = vl;
41 	}
42 
43 	/* We need at least one VL */
44 	if (nvls < 1) {
45 		fprintf(stderr, "Only %d VL supported\n", nvls);
46 		return false;
47 	}
48 
49 	return true;
50 }
51 
52 static void setup_ssve_regs(void)
53 {
54 	/* smstart sm; real data is TODO */
55 	asm volatile(".inst 0xd503437f" : : : );
56 }
57 
58 static int do_one_sme_vl(struct tdescr *td, siginfo_t *si, ucontext_t *uc,
59 			 unsigned int vl)
60 {
61 	size_t offset;
62 	struct _aarch64_ctx *head = GET_BUF_RESV_HEAD(context);
63 	struct sve_context *ssve;
64 	int ret;
65 
66 	fprintf(stderr, "Testing VL %d\n", vl);
67 
68 	ret = prctl(PR_SME_SET_VL, vl);
69 	if (ret != vl) {
70 		fprintf(stderr, "Failed to set VL, got %d\n", ret);
71 		return 1;
72 	}
73 
74 	/*
75 	 * Get a signal context which should have a SVE frame and registers
76 	 * in it.
77 	 */
78 	setup_ssve_regs();
79 	if (!get_current_context(td, &context.uc, sizeof(context)))
80 		return 1;
81 
82 	head = get_header(head, SVE_MAGIC, GET_BUF_RESV_SIZE(context),
83 			  &offset);
84 	if (!head) {
85 		fprintf(stderr, "No SVE context\n");
86 		return 1;
87 	}
88 
89 	ssve = (struct sve_context *)head;
90 	if (ssve->vl != vl) {
91 		fprintf(stderr, "Got VL %d, expected %d\n", ssve->vl, vl);
92 		return 1;
93 	}
94 
95 	/* The actual size validation is done in get_current_context() */
96 	fprintf(stderr, "Got expected size %u and VL %d\n",
97 		head->size, ssve->vl);
98 
99 	return 0;
100 }
101 
102 static int sme_regs(struct tdescr *td, siginfo_t *si, ucontext_t *uc)
103 {
104 	int i;
105 
106 	for (i = 0; i < nvls; i++) {
107 		if (do_one_sme_vl(td, si, uc, vls[i]))
108 			return 1;
109 	}
110 
111 	td->pass = 1;
112 
113 	return 0;
114 }
115 
116 struct tdescr tde = {
117 	.name = "Streaming SVE registers",
118 	.descr = "Check that we get the right Streaming SVE registers reported",
119 	/*
120 	 * We shouldn't require FA64 but things like memset() used in the
121 	 * helpers might use unsupported instructions so for now disable
122 	 * the test unless we've got the full instruction set.
123 	 */
124 	.feats_required = FEAT_SME | FEAT_SME_FA64,
125 	.timeout = 3,
126 	.init = sme_get_vls,
127 	.run = sme_regs,
128 };
129