linux/tools/testing/selftests/arm64/signal/test_signals_utils.c
<<
>>
Prefs
   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
  23extern struct tdescr *current;
  24
  25static int sig_copyctx = SIGTRAP;
  26
  27static char const *const feats_names[FMAX_END] = {
  28        " SSBS ",
  29        " SVE ",
  30};
  31
  32#define MAX_FEATS_SZ    128
  33static char feats_string[MAX_FEATS_SZ];
  34
  35static inline char *feats_to_string(unsigned long feats)
  36{
  37        size_t flen = MAX_FEATS_SZ - 1;
  38
  39        for (int i = 0; i < FMAX_END; i++) {
  40                if (feats & (1UL << i)) {
  41                        size_t tlen = strlen(feats_names[i]);
  42
  43                        assert(flen > tlen);
  44                        flen -= tlen;
  45                        strncat(feats_string, feats_names[i], flen);
  46                }
  47        }
  48
  49        return feats_string;
  50}
  51
  52static void unblock_signal(int signum)
  53{
  54        sigset_t sset;
  55
  56        sigemptyset(&sset);
  57        sigaddset(&sset, signum);
  58        sigprocmask(SIG_UNBLOCK, &sset, NULL);
  59}
  60
  61static void default_result(struct tdescr *td, bool force_exit)
  62{
  63        if (td->result == KSFT_SKIP) {
  64                fprintf(stderr, "==>> completed. SKIP.\n");
  65        } else if (td->pass) {
  66                fprintf(stderr, "==>> completed. PASS(1)\n");
  67                td->result = KSFT_PASS;
  68        } else {
  69                fprintf(stdout, "==>> completed. FAIL(0)\n");
  70                td->result = KSFT_FAIL;
  71        }
  72
  73        if (force_exit)
  74                exit(td->result);
  75}
  76
  77/*
  78 * The following handle_signal_* helpers are used by main default_handler
  79 * and are meant to return true when signal is handled successfully:
  80 * when false is returned instead, it means that the signal was somehow
  81 * unexpected in that context and it was NOT handled; default_handler will
  82 * take care of such unexpected situations.
  83 */
  84
  85static bool handle_signal_unsupported(struct tdescr *td,
  86                                      siginfo_t *si, void *uc)
  87{
  88        if (feats_ok(td))
  89                return false;
  90
  91        /* Mangling PC to avoid loops on original SIGILL */
  92        ((ucontext_t *)uc)->uc_mcontext.pc += 4;
  93
  94        if (!td->initialized) {
  95                fprintf(stderr,
  96                        "Got SIG_UNSUPP @test_init. Ignore.\n");
  97        } else {
  98                fprintf(stderr,
  99                        "-- RX SIG_UNSUPP on unsupported feat...OK\n");
 100                td->pass = 1;
 101                default_result(current, 1);
 102        }
 103
 104        return true;
 105}
 106
 107static bool handle_signal_trigger(struct tdescr *td,
 108                                  siginfo_t *si, void *uc)
 109{
 110        td->triggered = 1;
 111        /* ->run was asserted NON-NULL in test_setup() already */
 112        td->run(td, si, uc);
 113
 114        return true;
 115}
 116
 117static bool handle_signal_ok(struct tdescr *td,
 118                             siginfo_t *si, void *uc)
 119{
 120        /*
 121         * it's a bug in the test code when this assert fail:
 122         * if sig_trig was defined, it must have been used before getting here.
 123         */
 124        assert(!td->sig_trig || td->triggered);
 125        fprintf(stderr,
 126                "SIG_OK -- SP:0x%llX  si_addr@:%p  si_code:%d  token@:%p  offset:%ld\n",
 127                ((ucontext_t *)uc)->uc_mcontext.sp,
 128                si->si_addr, si->si_code, td->token, td->token - si->si_addr);
 129        /*
 130         * fake_sigreturn tests, which have sanity_enabled=1, set, at the very
 131         * last time, the token field to the SP address used to place the fake
 132         * sigframe: so token==0 means we never made it to the end,
 133         * segfaulting well-before, and the test is possibly broken.
 134         */
 135        if (!td->sanity_disabled && !td->token) {
 136                fprintf(stdout,
 137                        "current->token ZEROED...test is probably broken!\n");
 138                abort();
 139        }
 140        /*
 141         * Trying to narrow down the SEGV to the ones generated by Kernel itself
 142         * via arm64_notify_segfault(). This is a best-effort check anyway, and
 143         * the si_code check may need to change if this aspect of the kernel
 144         * ABI changes.
 145         */
 146        if (td->sig_ok == SIGSEGV && si->si_code != SEGV_ACCERR) {
 147                fprintf(stdout,
 148                        "si_code != SEGV_ACCERR...test is probably broken!\n");
 149                abort();
 150        }
 151        td->pass = 1;
 152        /*
 153         * Some tests can lead to SEGV loops: in such a case we want to
 154         * terminate immediately exiting straight away; some others are not
 155         * supposed to outlive the signal handler code, due to the content of
 156         * the fake sigframe which caused the signal itself.
 157         */
 158        default_result(current, 1);
 159
 160        return true;
 161}
 162
 163static bool handle_signal_copyctx(struct tdescr *td,
 164                                  siginfo_t *si, void *uc)
 165{
 166        /* Mangling PC to avoid loops on original BRK instr */
 167        ((ucontext_t *)uc)->uc_mcontext.pc += 4;
 168        memcpy(td->live_uc, uc, td->live_sz);
 169        ASSERT_GOOD_CONTEXT(td->live_uc);
 170        td->live_uc_valid = 1;
 171        fprintf(stderr,
 172                "GOOD CONTEXT grabbed from sig_copyctx handler\n");
 173
 174        return true;
 175}
 176
 177static void default_handler(int signum, siginfo_t *si, void *uc)
 178{
 179        if (current->sig_unsupp && signum == current->sig_unsupp &&
 180            handle_signal_unsupported(current, si, uc)) {
 181                fprintf(stderr, "Handled SIG_UNSUPP\n");
 182        } else if (current->sig_trig && signum == current->sig_trig &&
 183                   handle_signal_trigger(current, si, uc)) {
 184                fprintf(stderr, "Handled SIG_TRIG\n");
 185        } else if (current->sig_ok && signum == current->sig_ok &&
 186                   handle_signal_ok(current, si, uc)) {
 187                fprintf(stderr, "Handled SIG_OK\n");
 188        } else if (signum == sig_copyctx && current->live_uc &&
 189                   handle_signal_copyctx(current, si, uc)) {
 190                fprintf(stderr, "Handled SIG_COPYCTX\n");
 191        } else {
 192                if (signum == SIGALRM && current->timeout) {
 193                        fprintf(stderr, "-- Timeout !\n");
 194                } else {
 195                        fprintf(stderr,
 196                                "-- RX UNEXPECTED SIGNAL: %d\n", signum);
 197                }
 198                default_result(current, 1);
 199        }
 200}
 201
 202static int default_setup(struct tdescr *td)
 203{
 204        struct sigaction sa;
 205
 206        sa.sa_sigaction = default_handler;
 207        sa.sa_flags = SA_SIGINFO | SA_RESTART;
 208        sa.sa_flags |= td->sa_flags;
 209        sigemptyset(&sa.sa_mask);
 210        /* uncatchable signals naturally skipped ... */
 211        for (int sig = 1; sig < 32; sig++)
 212                sigaction(sig, &sa, NULL);
 213        /*
 214         * RT Signals default disposition is Term but they cannot be
 215         * generated by the Kernel in response to our tests; so just catch
 216         * them all and report them as UNEXPECTED signals.
 217         */
 218        for (int sig = SIGRTMIN; sig <= SIGRTMAX; sig++)
 219                sigaction(sig, &sa, NULL);
 220
 221        /* just in case...unblock explicitly all we need */
 222        if (td->sig_trig)
 223                unblock_signal(td->sig_trig);
 224        if (td->sig_ok)
 225                unblock_signal(td->sig_ok);
 226        if (td->sig_unsupp)
 227                unblock_signal(td->sig_unsupp);
 228
 229        if (td->timeout) {
 230                unblock_signal(SIGALRM);
 231                alarm(td->timeout);
 232        }
 233        fprintf(stderr, "Registered handlers for all signals.\n");
 234
 235        return 1;
 236}
 237
 238static inline int default_trigger(struct tdescr *td)
 239{
 240        return !raise(td->sig_trig);
 241}
 242
 243int test_init(struct tdescr *td)
 244{
 245        if (td->sig_trig == sig_copyctx) {
 246                fprintf(stdout,
 247                        "Signal %d is RESERVED, cannot be used as a trigger. Aborting\n",
 248                        sig_copyctx);
 249                return 0;
 250        }
 251        /* just in case */
 252        unblock_signal(sig_copyctx);
 253
 254        td->minsigstksz = getauxval(AT_MINSIGSTKSZ);
 255        if (!td->minsigstksz)
 256                td->minsigstksz = MINSIGSTKSZ;
 257        fprintf(stderr, "Detected MINSTKSIGSZ:%d\n", td->minsigstksz);
 258
 259        if (td->feats_required) {
 260                td->feats_supported = 0;
 261                /*
 262                 * Checking for CPU required features using both the
 263                 * auxval and the arm64 MRS Emulation to read sysregs.
 264                 */
 265                if (getauxval(AT_HWCAP) & HWCAP_SSBS)
 266                        td->feats_supported |= FEAT_SSBS;
 267                if (getauxval(AT_HWCAP) & HWCAP_SVE)
 268                        td->feats_supported |= FEAT_SVE;
 269                if (feats_ok(td)) {
 270                        fprintf(stderr,
 271                                "Required Features: [%s] supported\n",
 272                                feats_to_string(td->feats_required &
 273                                                td->feats_supported));
 274                } else {
 275                        fprintf(stderr,
 276                                "Required Features: [%s] NOT supported\n",
 277                                feats_to_string(td->feats_required &
 278                                                ~td->feats_supported));
 279                        td->result = KSFT_SKIP;
 280                        return 0;
 281                }
 282        }
 283
 284        /* Perform test specific additional initialization */
 285        if (td->init && !td->init(td)) {
 286                fprintf(stderr, "FAILED Testcase initialization.\n");
 287                return 0;
 288        }
 289        td->initialized = 1;
 290        fprintf(stderr, "Testcase initialized.\n");
 291
 292        return 1;
 293}
 294
 295int test_setup(struct tdescr *td)
 296{
 297        /* assert core invariants symptom of a rotten testcase */
 298        assert(current);
 299        assert(td);
 300        assert(td->name);
 301        assert(td->run);
 302
 303        /* Default result is FAIL if test setup fails */
 304        td->result = KSFT_FAIL;
 305        if (td->setup)
 306                return td->setup(td);
 307        else
 308                return default_setup(td);
 309}
 310
 311int test_run(struct tdescr *td)
 312{
 313        if (td->sig_trig) {
 314                if (td->trigger)
 315                        return td->trigger(td);
 316                else
 317                        return default_trigger(td);
 318        } else {
 319                return td->run(td, NULL, NULL);
 320        }
 321}
 322
 323void test_result(struct tdescr *td)
 324{
 325        if (td->initialized && td->result != KSFT_SKIP && td->check_result)
 326                td->check_result(td);
 327        default_result(td, 0);
 328}
 329
 330void test_cleanup(struct tdescr *td)
 331{
 332        if (td->cleanup)
 333                td->cleanup(td);
 334}
 335