123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * Copyright (C) 2019,2021 Arm Limited
- * Original author: Dave Martin <[email protected]>
- */
- #include "system.h"
- #include <stddef.h>
- #include <linux/errno.h>
- #include <linux/auxvec.h>
- #include <linux/signal.h>
- #include <asm/sigcontext.h>
- #include <asm/ucontext.h>
- typedef struct ucontext ucontext_t;
- #include "btitest.h"
- #include "compiler.h"
- #include "signal.h"
- #define EXPECTED_TESTS 18
- static volatile unsigned int test_num = 1;
- static unsigned int test_passed;
- static unsigned int test_failed;
- static unsigned int test_skipped;
- static void fdputs(int fd, const char *str)
- {
- size_t len = 0;
- const char *p = str;
- while (*p++)
- ++len;
- write(fd, str, len);
- }
- static void putstr(const char *str)
- {
- fdputs(1, str);
- }
- static void putnum(unsigned int num)
- {
- char c;
- if (num / 10)
- putnum(num / 10);
- c = '0' + (num % 10);
- write(1, &c, 1);
- }
- #define puttestname(test_name, trampoline_name) do { \
- putstr(test_name); \
- putstr("/"); \
- putstr(trampoline_name); \
- } while (0)
- void print_summary(void)
- {
- putstr("# Totals: pass:");
- putnum(test_passed);
- putstr(" fail:");
- putnum(test_failed);
- putstr(" xfail:0 xpass:0 skip:");
- putnum(test_skipped);
- putstr(" error:0\n");
- }
- static const char *volatile current_test_name;
- static const char *volatile current_trampoline_name;
- static volatile int sigill_expected, sigill_received;
- static void handler(int n, siginfo_t *si __always_unused,
- void *uc_ __always_unused)
- {
- ucontext_t *uc = uc_;
- putstr("# \t[SIGILL in ");
- puttestname(current_test_name, current_trampoline_name);
- putstr(", BTYPE=");
- write(1, &"00011011"[((uc->uc_mcontext.pstate & PSR_BTYPE_MASK)
- >> PSR_BTYPE_SHIFT) * 2], 2);
- if (!sigill_expected) {
- putstr("]\n");
- putstr("not ok ");
- putnum(test_num);
- putstr(" ");
- puttestname(current_test_name, current_trampoline_name);
- putstr("(unexpected SIGILL)\n");
- print_summary();
- exit(128 + n);
- }
- putstr(" (expected)]\n");
- sigill_received = 1;
- /* zap BTYPE so that resuming the faulting code will work */
- uc->uc_mcontext.pstate &= ~PSR_BTYPE_MASK;
- }
- static int skip_all;
- static void __do_test(void (*trampoline)(void (*)(void)),
- void (*fn)(void),
- const char *trampoline_name,
- const char *name,
- int expect_sigill)
- {
- if (skip_all) {
- test_skipped++;
- putstr("ok ");
- putnum(test_num);
- putstr(" ");
- puttestname(name, trampoline_name);
- putstr(" # SKIP\n");
- return;
- }
- /* Branch Target exceptions should only happen in BTI binaries: */
- if (!BTI)
- expect_sigill = 0;
- sigill_expected = expect_sigill;
- sigill_received = 0;
- current_test_name = name;
- current_trampoline_name = trampoline_name;
- trampoline(fn);
- if (expect_sigill && !sigill_received) {
- putstr("not ok ");
- test_failed++;
- } else {
- putstr("ok ");
- test_passed++;
- }
- putnum(test_num++);
- putstr(" ");
- puttestname(name, trampoline_name);
- putstr("\n");
- }
- #define do_test(expect_sigill_br_x0, \
- expect_sigill_br_x16, \
- expect_sigill_blr, \
- name) \
- do { \
- __do_test(call_using_br_x0, name, "call_using_br_x0", #name, \
- expect_sigill_br_x0); \
- __do_test(call_using_br_x16, name, "call_using_br_x16", #name, \
- expect_sigill_br_x16); \
- __do_test(call_using_blr, name, "call_using_blr", #name, \
- expect_sigill_blr); \
- } while (0)
- void start(int *argcp)
- {
- struct sigaction sa;
- void *const *p;
- const struct auxv_entry {
- unsigned long type;
- unsigned long val;
- } *auxv;
- unsigned long hwcap = 0, hwcap2 = 0;
- putstr("TAP version 13\n");
- putstr("1..");
- putnum(EXPECTED_TESTS);
- putstr("\n");
- /* Gross hack for finding AT_HWCAP2 from the initial process stack: */
- p = (void *const *)argcp + 1 + *argcp + 1; /* start of environment */
- /* step over environment */
- while (*p++)
- ;
- for (auxv = (const struct auxv_entry *)p; auxv->type != AT_NULL; ++auxv) {
- switch (auxv->type) {
- case AT_HWCAP:
- hwcap = auxv->val;
- break;
- case AT_HWCAP2:
- hwcap2 = auxv->val;
- break;
- default:
- break;
- }
- }
- if (hwcap & HWCAP_PACA)
- putstr("# HWCAP_PACA present\n");
- else
- putstr("# HWCAP_PACA not present\n");
- if (hwcap2 & HWCAP2_BTI) {
- putstr("# HWCAP2_BTI present\n");
- if (!(hwcap & HWCAP_PACA))
- putstr("# Bad hardware? Expect problems.\n");
- } else {
- putstr("# HWCAP2_BTI not present\n");
- skip_all = 1;
- }
- putstr("# Test binary");
- if (!BTI)
- putstr(" not");
- putstr(" built for BTI\n");
- sa.sa_handler = (sighandler_t)(void *)handler;
- sa.sa_flags = SA_SIGINFO;
- sigemptyset(&sa.sa_mask);
- sigaction(SIGILL, &sa, NULL);
- sigaddset(&sa.sa_mask, SIGILL);
- sigprocmask(SIG_UNBLOCK, &sa.sa_mask, NULL);
- do_test(1, 1, 1, nohint_func);
- do_test(1, 1, 1, bti_none_func);
- do_test(1, 0, 0, bti_c_func);
- do_test(0, 0, 1, bti_j_func);
- do_test(0, 0, 0, bti_jc_func);
- do_test(1, 0, 0, paciasp_func);
- print_summary();
- if (test_num - 1 != EXPECTED_TESTS)
- putstr("# WARNING - EXPECTED TEST COUNT WRONG\n");
- if (test_failed)
- exit(1);
- else
- exit(0);
- }
|