Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/testing/selftests/arm64/signal/test_signals_utils.c
26292 views
1
// SPDX-License-Identifier: GPL-2.0
2
/* Copyright (C) 2019 ARM Limited */
3
4
#include <stdio.h>
5
#include <stdlib.h>
6
#include <signal.h>
7
#include <string.h>
8
#include <unistd.h>
9
#include <assert.h>
10
#include <sys/auxv.h>
11
#include <linux/auxvec.h>
12
#include <ucontext.h>
13
14
#include <asm/unistd.h>
15
16
#include <kselftest.h>
17
18
#include "test_signals.h"
19
#include "test_signals_utils.h"
20
#include "testcases/testcases.h"
21
22
23
extern struct tdescr *current;
24
25
static int sig_copyctx = SIGTRAP;
26
27
static char const *const feats_names[FMAX_END] = {
28
" SSBS ",
29
" SVE ",
30
" SME ",
31
" FA64 ",
32
" SME2 ",
33
" GCS ",
34
};
35
36
#define MAX_FEATS_SZ 128
37
static char feats_string[MAX_FEATS_SZ];
38
39
static inline char *feats_to_string(unsigned long feats)
40
{
41
size_t flen = MAX_FEATS_SZ - 1;
42
43
feats_string[0] = '\0';
44
45
for (int i = 0; i < FMAX_END; i++) {
46
if (feats & (1UL << i)) {
47
size_t tlen = strlen(feats_names[i]);
48
49
assert(flen > tlen);
50
flen -= tlen;
51
strncat(feats_string, feats_names[i], flen);
52
}
53
}
54
55
return feats_string;
56
}
57
58
static void unblock_signal(int signum)
59
{
60
sigset_t sset;
61
62
sigemptyset(&sset);
63
sigaddset(&sset, signum);
64
sigprocmask(SIG_UNBLOCK, &sset, NULL);
65
}
66
67
static void default_result(struct tdescr *td, bool force_exit)
68
{
69
if (td->result == KSFT_SKIP) {
70
fprintf(stderr, "==>> completed. SKIP.\n");
71
} else if (td->pass) {
72
fprintf(stderr, "==>> completed. PASS(1)\n");
73
td->result = KSFT_PASS;
74
} else {
75
fprintf(stdout, "==>> completed. FAIL(0)\n");
76
td->result = KSFT_FAIL;
77
}
78
79
if (force_exit)
80
exit(td->result);
81
}
82
83
/*
84
* The following handle_signal_* helpers are used by main default_handler
85
* and are meant to return true when signal is handled successfully:
86
* when false is returned instead, it means that the signal was somehow
87
* unexpected in that context and it was NOT handled; default_handler will
88
* take care of such unexpected situations.
89
*/
90
91
static bool handle_signal_unsupported(struct tdescr *td,
92
siginfo_t *si, void *uc)
93
{
94
if (feats_ok(td))
95
return false;
96
97
/* Mangling PC to avoid loops on original SIGILL */
98
((ucontext_t *)uc)->uc_mcontext.pc += 4;
99
100
if (!td->initialized) {
101
fprintf(stderr,
102
"Got SIG_UNSUPP @test_init. Ignore.\n");
103
} else {
104
fprintf(stderr,
105
"-- RX SIG_UNSUPP on unsupported feat...OK\n");
106
td->pass = 1;
107
default_result(current, 1);
108
}
109
110
return true;
111
}
112
113
static bool handle_signal_trigger(struct tdescr *td,
114
siginfo_t *si, void *uc)
115
{
116
td->triggered = 1;
117
/* ->run was asserted NON-NULL in test_setup() already */
118
td->run(td, si, uc);
119
120
return true;
121
}
122
123
static bool handle_signal_ok(struct tdescr *td,
124
siginfo_t *si, void *uc)
125
{
126
/*
127
* it's a bug in the test code when this assert fail:
128
* if sig_trig was defined, it must have been used before getting here.
129
*/
130
assert(!td->sig_trig || td->triggered);
131
fprintf(stderr,
132
"SIG_OK -- SP:0x%llX si_addr@:%p si_code:%d token@:%p offset:%ld\n",
133
((ucontext_t *)uc)->uc_mcontext.sp,
134
si->si_addr, si->si_code, td->token, td->token - si->si_addr);
135
/*
136
* fake_sigreturn tests, which have sanity_enabled=1, set, at the very
137
* last time, the token field to the SP address used to place the fake
138
* sigframe: so token==0 means we never made it to the end,
139
* segfaulting well-before, and the test is possibly broken.
140
*/
141
if (!td->sanity_disabled && !td->token) {
142
fprintf(stdout,
143
"current->token ZEROED...test is probably broken!\n");
144
abort();
145
}
146
if (td->sig_ok_code) {
147
if (si->si_code != td->sig_ok_code) {
148
fprintf(stdout, "si_code is %d not %d\n",
149
si->si_code, td->sig_ok_code);
150
abort();
151
}
152
} else {
153
/*
154
* Trying to narrow down the SEGV to the ones
155
* generated by Kernel itself via
156
* arm64_notify_segfault(). This is a best-effort
157
* check anyway, and the si_code check may need to
158
* change if this aspect of the kernel ABI changes.
159
*/
160
if (td->sig_ok == SIGSEGV && si->si_code != SEGV_ACCERR) {
161
fprintf(stdout,
162
"si_code != SEGV_ACCERR...test is probably broken!\n");
163
abort();
164
}
165
}
166
td->pass = 1;
167
/*
168
* Some tests can lead to SEGV loops: in such a case we want to
169
* terminate immediately exiting straight away; some others are not
170
* supposed to outlive the signal handler code, due to the content of
171
* the fake sigframe which caused the signal itself.
172
*/
173
default_result(current, 1);
174
175
return true;
176
}
177
178
static bool handle_signal_copyctx(struct tdescr *td,
179
siginfo_t *si, void *uc_in)
180
{
181
ucontext_t *uc = uc_in;
182
struct _aarch64_ctx *head;
183
struct extra_context *extra, *copied_extra;
184
size_t offset = 0;
185
size_t to_copy;
186
187
ASSERT_GOOD_CONTEXT(uc);
188
189
/* Mangling PC to avoid loops on original BRK instr */
190
uc->uc_mcontext.pc += 4;
191
192
/*
193
* Check for an preserve any extra data too with fixups.
194
*/
195
head = (struct _aarch64_ctx *)uc->uc_mcontext.__reserved;
196
head = get_header(head, EXTRA_MAGIC, td->live_sz, &offset);
197
if (head) {
198
extra = (struct extra_context *)head;
199
200
/*
201
* The extra buffer must be immediately after the
202
* extra_context and a 16 byte terminator. Include it
203
* in the copy, this was previously validated in
204
* ASSERT_GOOD_CONTEXT().
205
*/
206
to_copy = __builtin_offsetof(ucontext_t,
207
uc_mcontext.__reserved);
208
to_copy += offset + sizeof(struct extra_context) + 16;
209
to_copy += extra->size;
210
copied_extra = (struct extra_context *)&(td->live_uc->uc_mcontext.__reserved[offset]);
211
} else {
212
copied_extra = NULL;
213
to_copy = sizeof(ucontext_t);
214
}
215
216
if (to_copy > td->live_sz) {
217
fprintf(stderr,
218
"Not enough space to grab context, %lu/%lu bytes\n",
219
td->live_sz, to_copy);
220
return false;
221
}
222
223
memcpy(td->live_uc, uc, to_copy);
224
225
/*
226
* If there was any EXTRA_CONTEXT fix up the size to be the
227
* struct extra_context and the following terminator record,
228
* this means that the rest of the code does not need to have
229
* special handling for the record and we don't need to fix up
230
* datap for the new location.
231
*/
232
if (copied_extra)
233
copied_extra->head.size = sizeof(*copied_extra) + 16;
234
235
td->live_uc_valid = 1;
236
fprintf(stderr,
237
"%lu byte GOOD CONTEXT grabbed from sig_copyctx handler\n",
238
to_copy);
239
240
return true;
241
}
242
243
static void default_handler(int signum, siginfo_t *si, void *uc)
244
{
245
if (current->sig_unsupp && signum == current->sig_unsupp &&
246
handle_signal_unsupported(current, si, uc)) {
247
fprintf(stderr, "Handled SIG_UNSUPP\n");
248
} else if (current->sig_trig && signum == current->sig_trig &&
249
handle_signal_trigger(current, si, uc)) {
250
fprintf(stderr, "Handled SIG_TRIG\n");
251
} else if (current->sig_ok && signum == current->sig_ok &&
252
handle_signal_ok(current, si, uc)) {
253
fprintf(stderr, "Handled SIG_OK\n");
254
} else if (signum == sig_copyctx && current->live_uc &&
255
handle_signal_copyctx(current, si, uc)) {
256
fprintf(stderr, "Handled SIG_COPYCTX\n");
257
} else {
258
if (signum == SIGALRM && current->timeout) {
259
fprintf(stderr, "-- Timeout !\n");
260
} else {
261
fprintf(stderr,
262
"-- RX UNEXPECTED SIGNAL: %d code %d address %p\n",
263
signum, si->si_code, si->si_addr);
264
}
265
default_result(current, 1);
266
}
267
}
268
269
static int default_setup(struct tdescr *td)
270
{
271
struct sigaction sa;
272
273
sa.sa_sigaction = default_handler;
274
sa.sa_flags = SA_SIGINFO | SA_RESTART;
275
sa.sa_flags |= td->sa_flags;
276
sigemptyset(&sa.sa_mask);
277
/* uncatchable signals naturally skipped ... */
278
for (int sig = 1; sig < 32; sig++)
279
sigaction(sig, &sa, NULL);
280
/*
281
* RT Signals default disposition is Term but they cannot be
282
* generated by the Kernel in response to our tests; so just catch
283
* them all and report them as UNEXPECTED signals.
284
*/
285
for (int sig = SIGRTMIN; sig <= SIGRTMAX; sig++)
286
sigaction(sig, &sa, NULL);
287
288
/* just in case...unblock explicitly all we need */
289
if (td->sig_trig)
290
unblock_signal(td->sig_trig);
291
if (td->sig_ok)
292
unblock_signal(td->sig_ok);
293
if (td->sig_unsupp)
294
unblock_signal(td->sig_unsupp);
295
296
if (td->timeout) {
297
unblock_signal(SIGALRM);
298
alarm(td->timeout);
299
}
300
fprintf(stderr, "Registered handlers for all signals.\n");
301
302
return 1;
303
}
304
305
static inline int default_trigger(struct tdescr *td)
306
{
307
return !raise(td->sig_trig);
308
}
309
310
int test_init(struct tdescr *td)
311
{
312
if (td->sig_trig == sig_copyctx) {
313
fprintf(stdout,
314
"Signal %d is RESERVED, cannot be used as a trigger. Aborting\n",
315
sig_copyctx);
316
return 0;
317
}
318
/* just in case */
319
unblock_signal(sig_copyctx);
320
321
td->minsigstksz = getauxval(AT_MINSIGSTKSZ);
322
if (!td->minsigstksz)
323
td->minsigstksz = MINSIGSTKSZ;
324
fprintf(stderr, "Detected MINSTKSIGSZ:%d\n", td->minsigstksz);
325
326
if (td->feats_required || td->feats_incompatible) {
327
td->feats_supported = 0;
328
/*
329
* Checking for CPU required features using both the
330
* auxval and the arm64 MRS Emulation to read sysregs.
331
*/
332
if (getauxval(AT_HWCAP) & HWCAP_SSBS)
333
td->feats_supported |= FEAT_SSBS;
334
if (getauxval(AT_HWCAP) & HWCAP_SVE)
335
td->feats_supported |= FEAT_SVE;
336
if (getauxval(AT_HWCAP2) & HWCAP2_SME)
337
td->feats_supported |= FEAT_SME;
338
if (getauxval(AT_HWCAP2) & HWCAP2_SME_FA64)
339
td->feats_supported |= FEAT_SME_FA64;
340
if (getauxval(AT_HWCAP2) & HWCAP2_SME2)
341
td->feats_supported |= FEAT_SME2;
342
if (getauxval(AT_HWCAP) & HWCAP_GCS)
343
td->feats_supported |= FEAT_GCS;
344
if (feats_ok(td)) {
345
if (td->feats_required & td->feats_supported)
346
fprintf(stderr,
347
"Required Features: [%s] supported\n",
348
feats_to_string(td->feats_required &
349
td->feats_supported));
350
if (!(td->feats_incompatible & td->feats_supported))
351
fprintf(stderr,
352
"Incompatible Features: [%s] absent\n",
353
feats_to_string(td->feats_incompatible));
354
} else {
355
if ((td->feats_required & td->feats_supported) !=
356
td->feats_supported)
357
fprintf(stderr,
358
"Required Features: [%s] NOT supported\n",
359
feats_to_string(td->feats_required &
360
~td->feats_supported));
361
if (td->feats_incompatible & td->feats_supported)
362
fprintf(stderr,
363
"Incompatible Features: [%s] supported\n",
364
feats_to_string(td->feats_incompatible &
365
~td->feats_supported));
366
367
368
td->result = KSFT_SKIP;
369
return 0;
370
}
371
}
372
373
/* Perform test specific additional initialization */
374
if (td->init && !td->init(td)) {
375
fprintf(stderr, "FAILED Testcase initialization.\n");
376
return 0;
377
}
378
td->initialized = 1;
379
fprintf(stderr, "Testcase initialized.\n");
380
381
return 1;
382
}
383
384
int test_setup(struct tdescr *td)
385
{
386
/* assert core invariants symptom of a rotten testcase */
387
assert(current);
388
assert(td);
389
assert(td->name);
390
assert(td->run);
391
392
/* Default result is FAIL if test setup fails */
393
td->result = KSFT_FAIL;
394
if (td->setup)
395
return td->setup(td);
396
else
397
return default_setup(td);
398
}
399
400
int test_run(struct tdescr *td)
401
{
402
if (td->trigger)
403
return td->trigger(td);
404
else if (td->sig_trig)
405
return default_trigger(td);
406
else
407
return td->run(td, NULL, NULL);
408
}
409
410
void test_result(struct tdescr *td)
411
{
412
if (td->initialized && td->result != KSFT_SKIP && td->check_result)
413
td->check_result(td);
414
default_result(td, 0);
415
}
416
417
void test_cleanup(struct tdescr *td)
418
{
419
if (td->cleanup)
420
td->cleanup(td);
421
}
422
423