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