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