linux/tools/testing/selftests/arm64/bti/test.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (C) 2019,2021  Arm Limited
   4 * Original author: Dave Martin <Dave.Martin@arm.com>
   5 */
   6
   7#include "system.h"
   8
   9#include <stddef.h>
  10#include <linux/errno.h>
  11#include <linux/auxvec.h>
  12#include <linux/signal.h>
  13#include <asm/sigcontext.h>
  14#include <asm/ucontext.h>
  15
  16typedef struct ucontext ucontext_t;
  17
  18#include "btitest.h"
  19#include "compiler.h"
  20#include "signal.h"
  21
  22#define EXPECTED_TESTS 18
  23
  24static volatile unsigned int test_num = 1;
  25static unsigned int test_passed;
  26static unsigned int test_failed;
  27static unsigned int test_skipped;
  28
  29static void fdputs(int fd, const char *str)
  30{
  31        size_t len = 0;
  32        const char *p = str;
  33
  34        while (*p++)
  35                ++len;
  36
  37        write(fd, str, len);
  38}
  39
  40static void putstr(const char *str)
  41{
  42        fdputs(1, str);
  43}
  44
  45static void putnum(unsigned int num)
  46{
  47        char c;
  48
  49        if (num / 10)
  50                putnum(num / 10);
  51
  52        c = '0' + (num % 10);
  53        write(1, &c, 1);
  54}
  55
  56#define puttestname(test_name, trampoline_name) do {    \
  57        putstr(test_name);                              \
  58        putstr("/");                                    \
  59        putstr(trampoline_name);                        \
  60} while (0)
  61
  62void print_summary(void)
  63{
  64        putstr("# Totals: pass:");
  65        putnum(test_passed);
  66        putstr(" fail:");
  67        putnum(test_failed);
  68        putstr(" xfail:0 xpass:0 skip:");
  69        putnum(test_skipped);
  70        putstr(" error:0\n");
  71}
  72
  73static const char *volatile current_test_name;
  74static const char *volatile current_trampoline_name;
  75static volatile int sigill_expected, sigill_received;
  76
  77static void handler(int n, siginfo_t *si __always_unused,
  78                    void *uc_ __always_unused)
  79{
  80        ucontext_t *uc = uc_;
  81
  82        putstr("# \t[SIGILL in ");
  83        puttestname(current_test_name, current_trampoline_name);
  84        putstr(", BTYPE=");
  85        write(1, &"00011011"[((uc->uc_mcontext.pstate & PSR_BTYPE_MASK)
  86                              >> PSR_BTYPE_SHIFT) * 2], 2);
  87        if (!sigill_expected) {
  88                putstr("]\n");
  89                putstr("not ok ");
  90                putnum(test_num);
  91                putstr(" ");
  92                puttestname(current_test_name, current_trampoline_name);
  93                putstr("(unexpected SIGILL)\n");
  94                print_summary();
  95                exit(128 + n);
  96        }
  97
  98        putstr(" (expected)]\n");
  99        sigill_received = 1;
 100        /* zap BTYPE so that resuming the faulting code will work */
 101        uc->uc_mcontext.pstate &= ~PSR_BTYPE_MASK;
 102}
 103
 104static int skip_all;
 105
 106static void __do_test(void (*trampoline)(void (*)(void)),
 107                      void (*fn)(void),
 108                      const char *trampoline_name,
 109                      const char *name,
 110                      int expect_sigill)
 111{
 112        if (skip_all) {
 113                test_skipped++;
 114                putstr("ok ");
 115                putnum(test_num);
 116                putstr(" ");
 117                puttestname(name, trampoline_name);
 118                putstr(" # SKIP\n");
 119
 120                return;
 121        }
 122
 123        /* Branch Target exceptions should only happen in BTI binaries: */
 124        if (!BTI)
 125                expect_sigill = 0;
 126
 127        sigill_expected = expect_sigill;
 128        sigill_received = 0;
 129        current_test_name = name;
 130        current_trampoline_name = trampoline_name;
 131
 132        trampoline(fn);
 133
 134        if (expect_sigill && !sigill_received) {
 135                putstr("not ok ");
 136                test_failed++;
 137        } else {
 138                putstr("ok ");
 139                test_passed++;
 140        }
 141        putnum(test_num++);
 142        putstr(" ");
 143        puttestname(name, trampoline_name);
 144        putstr("\n");
 145}
 146
 147#define do_test(expect_sigill_br_x0,                                    \
 148                expect_sigill_br_x16,                                   \
 149                expect_sigill_blr,                                      \
 150                name)                                                   \
 151do {                                                                    \
 152        __do_test(call_using_br_x0, name, "call_using_br_x0", #name,    \
 153                  expect_sigill_br_x0);                                 \
 154        __do_test(call_using_br_x16, name, "call_using_br_x16", #name,  \
 155                  expect_sigill_br_x16);                                \
 156        __do_test(call_using_blr, name, "call_using_blr", #name,        \
 157                  expect_sigill_blr);                                   \
 158} while (0)
 159
 160void start(int *argcp)
 161{
 162        struct sigaction sa;
 163        void *const *p;
 164        const struct auxv_entry {
 165                unsigned long type;
 166                unsigned long val;
 167        } *auxv;
 168        unsigned long hwcap = 0, hwcap2 = 0;
 169
 170        putstr("TAP version 13\n");
 171        putstr("1..");
 172        putnum(EXPECTED_TESTS);
 173        putstr("\n");
 174
 175        /* Gross hack for finding AT_HWCAP2 from the initial process stack: */
 176        p = (void *const *)argcp + 1 + *argcp + 1; /* start of environment */
 177        /* step over environment */
 178        while (*p++)
 179                ;
 180        for (auxv = (const struct auxv_entry *)p; auxv->type != AT_NULL; ++auxv) {
 181                switch (auxv->type) {
 182                case AT_HWCAP:
 183                        hwcap = auxv->val;
 184                        break;
 185                case AT_HWCAP2:
 186                        hwcap2 = auxv->val;
 187                        break;
 188                default:
 189                        break;
 190                }
 191        }
 192
 193        if (hwcap & HWCAP_PACA)
 194                putstr("# HWCAP_PACA present\n");
 195        else
 196                putstr("# HWCAP_PACA not present\n");
 197
 198        if (hwcap2 & HWCAP2_BTI) {
 199                putstr("# HWCAP2_BTI present\n");
 200                if (!(hwcap & HWCAP_PACA))
 201                        putstr("# Bad hardware?  Expect problems.\n");
 202        } else {
 203                putstr("# HWCAP2_BTI not present\n");
 204                skip_all = 1;
 205        }
 206
 207        putstr("# Test binary");
 208        if (!BTI)
 209                putstr(" not");
 210        putstr(" built for BTI\n");
 211
 212        sa.sa_handler = (sighandler_t)(void *)handler;
 213        sa.sa_flags = SA_SIGINFO;
 214        sigemptyset(&sa.sa_mask);
 215        sigaction(SIGILL, &sa, NULL);
 216        sigaddset(&sa.sa_mask, SIGILL);
 217        sigprocmask(SIG_UNBLOCK, &sa.sa_mask, NULL);
 218
 219        do_test(1, 1, 1, nohint_func);
 220        do_test(1, 1, 1, bti_none_func);
 221        do_test(1, 0, 0, bti_c_func);
 222        do_test(0, 0, 1, bti_j_func);
 223        do_test(0, 0, 0, bti_jc_func);
 224        do_test(1, 0, 0, paciasp_func);
 225
 226        print_summary();
 227
 228        if (test_num - 1 != EXPECTED_TESTS)
 229                putstr("# WARNING - EXPECTED TEST COUNT WRONG\n");
 230
 231        if (test_failed)
 232                exit(1);
 233        else
 234                exit(0);
 235}
 236