Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/testing/selftests/arm64/fp/kernel-test.c
26288 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* Copyright (C) 2024 ARM Limited.
4
*/
5
6
#define _GNU_SOURCE
7
8
#include <stdio.h>
9
#include <stdlib.h>
10
#include <stdbool.h>
11
#include <errno.h>
12
#include <fcntl.h>
13
#include <signal.h>
14
#include <string.h>
15
#include <unistd.h>
16
17
#include <sys/socket.h>
18
19
#include <linux/kernel.h>
20
#include <linux/if_alg.h>
21
22
#define DATA_SIZE (16 * 4096)
23
24
static int base, sock;
25
26
static int digest_len;
27
static char *ref;
28
static char *digest;
29
static char *alg_name;
30
31
static struct iovec data_iov;
32
static int zerocopy[2];
33
static int sigs;
34
static int iter;
35
36
static void handle_exit_signal(int sig, siginfo_t *info, void *context)
37
{
38
printf("Terminated by signal %d, iterations=%d, signals=%d\n",
39
sig, iter, sigs);
40
exit(0);
41
}
42
43
static void handle_kick_signal(int sig, siginfo_t *info, void *context)
44
{
45
sigs++;
46
}
47
48
static char *drivers[] = {
49
"sha1-ce",
50
"sha224-arm64",
51
"sha224-arm64-neon",
52
"sha224-ce",
53
"sha256-arm64",
54
"sha256-arm64-neon",
55
"sha256-ce",
56
"sha384-ce",
57
"sha512-ce",
58
"sha3-224-ce",
59
"sha3-256-ce",
60
"sha3-384-ce",
61
"sha3-512-ce",
62
"sm3-ce",
63
"sm3-neon",
64
};
65
66
static bool create_socket(void)
67
{
68
FILE *proc;
69
struct sockaddr_alg addr;
70
char buf[1024];
71
char *c, *driver_name;
72
bool is_shash, match;
73
int ret, i;
74
75
ret = socket(AF_ALG, SOCK_SEQPACKET, 0);
76
if (ret < 0) {
77
if (errno == EAFNOSUPPORT) {
78
printf("AF_ALG not supported\n");
79
return false;
80
}
81
82
printf("Failed to create AF_ALG socket: %s (%d)\n",
83
strerror(errno), errno);
84
return false;
85
}
86
base = ret;
87
88
memset(&addr, 0, sizeof(addr));
89
addr.salg_family = AF_ALG;
90
strncpy((char *)addr.salg_type, "hash", sizeof(addr.salg_type));
91
92
proc = fopen("/proc/crypto", "r");
93
if (!proc) {
94
printf("Unable to open /proc/crypto\n");
95
return false;
96
}
97
98
driver_name = NULL;
99
is_shash = false;
100
match = false;
101
102
/* Look through /proc/crypto for a driver with kernel mode FP usage */
103
while (!match) {
104
c = fgets(buf, sizeof(buf), proc);
105
if (!c) {
106
if (feof(proc)) {
107
printf("Nothing found in /proc/crypto\n");
108
return false;
109
}
110
continue;
111
}
112
113
/* Algorithm descriptions are separated by a blank line */
114
if (*c == '\n') {
115
if (is_shash && driver_name) {
116
for (i = 0; i < ARRAY_SIZE(drivers); i++) {
117
if (strcmp(drivers[i],
118
driver_name) == 0) {
119
match = true;
120
}
121
}
122
}
123
124
if (!match) {
125
digest_len = 0;
126
127
free(driver_name);
128
driver_name = NULL;
129
130
free(alg_name);
131
alg_name = NULL;
132
133
is_shash = false;
134
}
135
continue;
136
}
137
138
/* Remove trailing newline */
139
c = strchr(buf, '\n');
140
if (c)
141
*c = '\0';
142
143
/* Find the field/value separator and start of the value */
144
c = strchr(buf, ':');
145
if (!c)
146
continue;
147
c += 2;
148
149
if (strncmp(buf, "digestsize", strlen("digestsize")) == 0)
150
sscanf(c, "%d", &digest_len);
151
152
if (strncmp(buf, "name", strlen("name")) == 0)
153
alg_name = strdup(c);
154
155
if (strncmp(buf, "driver", strlen("driver")) == 0)
156
driver_name = strdup(c);
157
158
if (strncmp(buf, "type", strlen("type")) == 0)
159
if (strncmp(c, "shash", strlen("shash")) == 0)
160
is_shash = true;
161
}
162
163
strncpy((char *)addr.salg_name, alg_name,
164
sizeof(addr.salg_name) - 1);
165
166
ret = bind(base, (struct sockaddr *)&addr, sizeof(addr));
167
if (ret < 0) {
168
printf("Failed to bind %s: %s (%d)\n",
169
addr.salg_name, strerror(errno), errno);
170
return false;
171
}
172
173
ret = accept(base, NULL, 0);
174
if (ret < 0) {
175
printf("Failed to accept %s: %s (%d)\n",
176
addr.salg_name, strerror(errno), errno);
177
return false;
178
}
179
180
sock = ret;
181
182
ret = pipe(zerocopy);
183
if (ret != 0) {
184
printf("Failed to create zerocopy pipe: %s (%d)\n",
185
strerror(errno), errno);
186
return false;
187
}
188
189
ref = malloc(digest_len);
190
if (!ref) {
191
printf("Failed to allocated %d byte reference\n", digest_len);
192
return false;
193
}
194
195
digest = malloc(digest_len);
196
if (!digest) {
197
printf("Failed to allocated %d byte digest\n", digest_len);
198
return false;
199
}
200
201
return true;
202
}
203
204
static bool compute_digest(void *buf)
205
{
206
struct iovec iov;
207
int ret, wrote;
208
209
iov = data_iov;
210
while (iov.iov_len) {
211
ret = vmsplice(zerocopy[1], &iov, 1, SPLICE_F_GIFT);
212
if (ret < 0) {
213
printf("Failed to send buffer: %s (%d)\n",
214
strerror(errno), errno);
215
return false;
216
}
217
218
wrote = ret;
219
ret = splice(zerocopy[0], NULL, sock, NULL, wrote, 0);
220
if (ret < 0) {
221
printf("Failed to splice buffer: %s (%d)\n",
222
strerror(errno), errno);
223
} else if (ret != wrote) {
224
printf("Short splice: %d < %d\n", ret, wrote);
225
}
226
227
iov.iov_len -= wrote;
228
iov.iov_base += wrote;
229
}
230
231
reread:
232
ret = recv(sock, buf, digest_len, 0);
233
if (ret == 0) {
234
printf("No digest returned\n");
235
return false;
236
}
237
if (ret != digest_len) {
238
if (errno == -EAGAIN)
239
goto reread;
240
printf("Failed to get digest: %s (%d)\n",
241
strerror(errno), errno);
242
return false;
243
}
244
245
return true;
246
}
247
248
int main(void)
249
{
250
char *data;
251
struct sigaction sa;
252
int ret;
253
254
/* Ensure we have unbuffered output */
255
setvbuf(stdout, NULL, _IOLBF, 0);
256
257
/* The parent will communicate with us via signals */
258
memset(&sa, 0, sizeof(sa));
259
sa.sa_sigaction = handle_exit_signal;
260
sa.sa_flags = SA_RESTART | SA_SIGINFO;
261
sigemptyset(&sa.sa_mask);
262
ret = sigaction(SIGTERM, &sa, NULL);
263
if (ret < 0)
264
printf("Failed to install SIGTERM handler: %s (%d)\n",
265
strerror(errno), errno);
266
267
sa.sa_sigaction = handle_kick_signal;
268
ret = sigaction(SIGUSR1, &sa, NULL);
269
if (ret < 0)
270
printf("Failed to install SIGUSR1 handler: %s (%d)\n",
271
strerror(errno), errno);
272
ret = sigaction(SIGUSR2, &sa, NULL);
273
if (ret < 0)
274
printf("Failed to install SIGUSR2 handler: %s (%d)\n",
275
strerror(errno), errno);
276
277
data = malloc(DATA_SIZE);
278
if (!data) {
279
printf("Failed to allocate data buffer\n");
280
return EXIT_FAILURE;
281
}
282
memset(data, 0, DATA_SIZE);
283
284
data_iov.iov_base = data;
285
data_iov.iov_len = DATA_SIZE;
286
287
/*
288
* If we can't create a socket assume it's a lack of system
289
* support and fall back to a basic FPSIMD test for the
290
* benefit of fp-stress.
291
*/
292
if (!create_socket()) {
293
execl("./fpsimd-test", "./fpsimd-test", NULL);
294
printf("Failed to fall back to fspimd-test: %d (%s)\n",
295
errno, strerror(errno));
296
return EXIT_FAILURE;
297
}
298
299
/*
300
* Compute a reference digest we hope is repeatable, we do
301
* this at runtime partly to make it easier to play with
302
* parameters.
303
*/
304
if (!compute_digest(ref)) {
305
printf("Failed to compute reference digest\n");
306
return EXIT_FAILURE;
307
}
308
309
printf("AF_ALG using %s\n", alg_name);
310
311
while (true) {
312
if (!compute_digest(digest)) {
313
printf("Failed to compute digest, iter=%d\n", iter);
314
return EXIT_FAILURE;
315
}
316
317
if (memcmp(ref, digest, digest_len) != 0) {
318
printf("Digest mismatch, iter=%d\n", iter);
319
return EXIT_FAILURE;
320
}
321
322
iter++;
323
}
324
325
return EXIT_FAILURE;
326
}
327
328