162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2019,2021 Arm Limited 462306a36Sopenharmony_ci * Original author: Dave Martin <Dave.Martin@arm.com> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include "system.h" 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <stdbool.h> 1062306a36Sopenharmony_ci#include <stddef.h> 1162306a36Sopenharmony_ci#include <linux/errno.h> 1262306a36Sopenharmony_ci#include <linux/auxvec.h> 1362306a36Sopenharmony_ci#include <linux/signal.h> 1462306a36Sopenharmony_ci#include <asm/sigcontext.h> 1562306a36Sopenharmony_ci#include <asm/ucontext.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_citypedef struct ucontext ucontext_t; 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include "btitest.h" 2062306a36Sopenharmony_ci#include "signal.h" 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#define EXPECTED_TESTS 18 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistatic volatile unsigned int test_num = 1; 2562306a36Sopenharmony_cistatic unsigned int test_passed; 2662306a36Sopenharmony_cistatic unsigned int test_failed; 2762306a36Sopenharmony_cistatic unsigned int test_skipped; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistatic void fdputs(int fd, const char *str) 3062306a36Sopenharmony_ci{ 3162306a36Sopenharmony_ci size_t len = 0; 3262306a36Sopenharmony_ci const char *p = str; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci while (*p++) 3562306a36Sopenharmony_ci ++len; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci write(fd, str, len); 3862306a36Sopenharmony_ci} 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic void putstr(const char *str) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci fdputs(1, str); 4362306a36Sopenharmony_ci} 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic void putnum(unsigned int num) 4662306a36Sopenharmony_ci{ 4762306a36Sopenharmony_ci char c; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci if (num / 10) 5062306a36Sopenharmony_ci putnum(num / 10); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci c = '0' + (num % 10); 5362306a36Sopenharmony_ci write(1, &c, 1); 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci#define puttestname(test_name, trampoline_name) do { \ 5762306a36Sopenharmony_ci putstr(test_name); \ 5862306a36Sopenharmony_ci putstr("/"); \ 5962306a36Sopenharmony_ci putstr(trampoline_name); \ 6062306a36Sopenharmony_ci} while (0) 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_civoid print_summary(void) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci putstr("# Totals: pass:"); 6562306a36Sopenharmony_ci putnum(test_passed); 6662306a36Sopenharmony_ci putstr(" fail:"); 6762306a36Sopenharmony_ci putnum(test_failed); 6862306a36Sopenharmony_ci putstr(" xfail:0 xpass:0 skip:"); 6962306a36Sopenharmony_ci putnum(test_skipped); 7062306a36Sopenharmony_ci putstr(" error:0\n"); 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistatic const char *volatile current_test_name; 7462306a36Sopenharmony_cistatic const char *volatile current_trampoline_name; 7562306a36Sopenharmony_cistatic volatile int sigill_expected, sigill_received; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic void handler(int n, siginfo_t *si __always_unused, 7862306a36Sopenharmony_ci void *uc_ __always_unused) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci ucontext_t *uc = uc_; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci putstr("# \t[SIGILL in "); 8362306a36Sopenharmony_ci puttestname(current_test_name, current_trampoline_name); 8462306a36Sopenharmony_ci putstr(", BTYPE="); 8562306a36Sopenharmony_ci write(1, &"00011011"[((uc->uc_mcontext.pstate & PSR_BTYPE_MASK) 8662306a36Sopenharmony_ci >> PSR_BTYPE_SHIFT) * 2], 2); 8762306a36Sopenharmony_ci if (!sigill_expected) { 8862306a36Sopenharmony_ci putstr("]\n"); 8962306a36Sopenharmony_ci putstr("not ok "); 9062306a36Sopenharmony_ci putnum(test_num); 9162306a36Sopenharmony_ci putstr(" "); 9262306a36Sopenharmony_ci puttestname(current_test_name, current_trampoline_name); 9362306a36Sopenharmony_ci putstr("(unexpected SIGILL)\n"); 9462306a36Sopenharmony_ci print_summary(); 9562306a36Sopenharmony_ci exit(128 + n); 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci putstr(" (expected)]\n"); 9962306a36Sopenharmony_ci sigill_received = 1; 10062306a36Sopenharmony_ci /* zap BTYPE so that resuming the faulting code will work */ 10162306a36Sopenharmony_ci uc->uc_mcontext.pstate &= ~PSR_BTYPE_MASK; 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci/* Does the system have BTI? */ 10562306a36Sopenharmony_cistatic bool have_bti; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_cistatic void __do_test(void (*trampoline)(void (*)(void)), 10862306a36Sopenharmony_ci void (*fn)(void), 10962306a36Sopenharmony_ci const char *trampoline_name, 11062306a36Sopenharmony_ci const char *name, 11162306a36Sopenharmony_ci int expect_sigill) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci /* 11462306a36Sopenharmony_ci * Branch Target exceptions should only happen for BTI 11562306a36Sopenharmony_ci * binaries running on a system with BTI: 11662306a36Sopenharmony_ci */ 11762306a36Sopenharmony_ci if (!BTI || !have_bti) 11862306a36Sopenharmony_ci expect_sigill = 0; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci sigill_expected = expect_sigill; 12162306a36Sopenharmony_ci sigill_received = 0; 12262306a36Sopenharmony_ci current_test_name = name; 12362306a36Sopenharmony_ci current_trampoline_name = trampoline_name; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci trampoline(fn); 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci if (expect_sigill && !sigill_received) { 12862306a36Sopenharmony_ci putstr("not ok "); 12962306a36Sopenharmony_ci test_failed++; 13062306a36Sopenharmony_ci } else { 13162306a36Sopenharmony_ci putstr("ok "); 13262306a36Sopenharmony_ci test_passed++; 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci putnum(test_num++); 13562306a36Sopenharmony_ci putstr(" "); 13662306a36Sopenharmony_ci puttestname(name, trampoline_name); 13762306a36Sopenharmony_ci putstr("\n"); 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci#define do_test(expect_sigill_br_x0, \ 14162306a36Sopenharmony_ci expect_sigill_br_x16, \ 14262306a36Sopenharmony_ci expect_sigill_blr, \ 14362306a36Sopenharmony_ci name) \ 14462306a36Sopenharmony_cido { \ 14562306a36Sopenharmony_ci __do_test(call_using_br_x0, name, "call_using_br_x0", #name, \ 14662306a36Sopenharmony_ci expect_sigill_br_x0); \ 14762306a36Sopenharmony_ci __do_test(call_using_br_x16, name, "call_using_br_x16", #name, \ 14862306a36Sopenharmony_ci expect_sigill_br_x16); \ 14962306a36Sopenharmony_ci __do_test(call_using_blr, name, "call_using_blr", #name, \ 15062306a36Sopenharmony_ci expect_sigill_blr); \ 15162306a36Sopenharmony_ci} while (0) 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_civoid start(int *argcp) 15462306a36Sopenharmony_ci{ 15562306a36Sopenharmony_ci struct sigaction sa; 15662306a36Sopenharmony_ci void *const *p; 15762306a36Sopenharmony_ci const struct auxv_entry { 15862306a36Sopenharmony_ci unsigned long type; 15962306a36Sopenharmony_ci unsigned long val; 16062306a36Sopenharmony_ci } *auxv; 16162306a36Sopenharmony_ci unsigned long hwcap = 0, hwcap2 = 0; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci putstr("TAP version 13\n"); 16462306a36Sopenharmony_ci putstr("1.."); 16562306a36Sopenharmony_ci putnum(EXPECTED_TESTS); 16662306a36Sopenharmony_ci putstr("\n"); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci /* Gross hack for finding AT_HWCAP2 from the initial process stack: */ 16962306a36Sopenharmony_ci p = (void *const *)argcp + 1 + *argcp + 1; /* start of environment */ 17062306a36Sopenharmony_ci /* step over environment */ 17162306a36Sopenharmony_ci while (*p++) 17262306a36Sopenharmony_ci ; 17362306a36Sopenharmony_ci for (auxv = (const struct auxv_entry *)p; auxv->type != AT_NULL; ++auxv) { 17462306a36Sopenharmony_ci switch (auxv->type) { 17562306a36Sopenharmony_ci case AT_HWCAP: 17662306a36Sopenharmony_ci hwcap = auxv->val; 17762306a36Sopenharmony_ci break; 17862306a36Sopenharmony_ci case AT_HWCAP2: 17962306a36Sopenharmony_ci hwcap2 = auxv->val; 18062306a36Sopenharmony_ci break; 18162306a36Sopenharmony_ci default: 18262306a36Sopenharmony_ci break; 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci } 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci if (hwcap & HWCAP_PACA) 18762306a36Sopenharmony_ci putstr("# HWCAP_PACA present\n"); 18862306a36Sopenharmony_ci else 18962306a36Sopenharmony_ci putstr("# HWCAP_PACA not present\n"); 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci if (hwcap2 & HWCAP2_BTI) { 19262306a36Sopenharmony_ci putstr("# HWCAP2_BTI present\n"); 19362306a36Sopenharmony_ci if (!(hwcap & HWCAP_PACA)) 19462306a36Sopenharmony_ci putstr("# Bad hardware? Expect problems.\n"); 19562306a36Sopenharmony_ci have_bti = true; 19662306a36Sopenharmony_ci } else { 19762306a36Sopenharmony_ci putstr("# HWCAP2_BTI not present\n"); 19862306a36Sopenharmony_ci have_bti = false; 19962306a36Sopenharmony_ci } 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci putstr("# Test binary"); 20262306a36Sopenharmony_ci if (!BTI) 20362306a36Sopenharmony_ci putstr(" not"); 20462306a36Sopenharmony_ci putstr(" built for BTI\n"); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci sa.sa_handler = (sighandler_t)(void *)handler; 20762306a36Sopenharmony_ci sa.sa_flags = SA_SIGINFO; 20862306a36Sopenharmony_ci sigemptyset(&sa.sa_mask); 20962306a36Sopenharmony_ci sigaction(SIGILL, &sa, NULL); 21062306a36Sopenharmony_ci sigaddset(&sa.sa_mask, SIGILL); 21162306a36Sopenharmony_ci sigprocmask(SIG_UNBLOCK, &sa.sa_mask, NULL); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci do_test(1, 1, 1, nohint_func); 21462306a36Sopenharmony_ci do_test(1, 1, 1, bti_none_func); 21562306a36Sopenharmony_ci do_test(1, 0, 0, bti_c_func); 21662306a36Sopenharmony_ci do_test(0, 0, 1, bti_j_func); 21762306a36Sopenharmony_ci do_test(0, 0, 0, bti_jc_func); 21862306a36Sopenharmony_ci do_test(1, 0, 0, paciasp_func); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci print_summary(); 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci if (test_num - 1 != EXPECTED_TESTS) 22362306a36Sopenharmony_ci putstr("# WARNING - EXPECTED TEST COUNT WRONG\n"); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci if (test_failed) 22662306a36Sopenharmony_ci exit(1); 22762306a36Sopenharmony_ci else 22862306a36Sopenharmony_ci exit(0); 22962306a36Sopenharmony_ci} 230