File Index
Files and directories
Sign in
FILE

test.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/arm64/bti/test.c C
  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 <stdbool.h>
 10#include <stddef.h>
 11#include <linux/errno.h>
 12#include <linux/auxvec.h>
 13#include <linux/signal.h>
 14#include <asm/sigcontext.h>
 15#include <asm/ucontext.h>
 16
 17typedef struct ucontext ucontext_t;
 18
 19#include "btitest.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
104/* Does the system have BTI? */
105static bool have_bti;
106
107static void __do_test(void (*trampoline)(void (*)(void)),
108		      void (*fn)(void),
109		      const char *trampoline_name,
110		      const char *name,
111		      int expect_sigill)
112{
113	/*
114	 * Branch Target exceptions should only happen for BTI
115	 * binaries running on a system with BTI:
116	 */
117	if (!BTI || !have_bti)
118		expect_sigill = 0;
119
120	sigill_expected = expect_sigill;
121	sigill_received = 0;
122	current_test_name = name;
123	current_trampoline_name = trampoline_name;
124
125	trampoline(fn);
126
127	if (expect_sigill && !sigill_received) {
128		putstr("not ok ");
129		test_failed++;
130	} else {
131		putstr("ok ");
132		test_passed++;
133	}
134	putnum(test_num++);
135	putstr(" ");
136	puttestname(name, trampoline_name);
137	putstr("\n");
138}
139
140#define do_test(expect_sigill_br_x0,					\
141		expect_sigill_br_x16,					\
142		expect_sigill_blr,					\
143		name)							\
144do {									\
145	__do_test(call_using_br_x0, name, "call_using_br_x0", #name,	\
146		  expect_sigill_br_x0);					\
147	__do_test(call_using_br_x16, name, "call_using_br_x16", #name,	\
148		  expect_sigill_br_x16);				\
149	__do_test(call_using_blr, name, "call_using_blr", #name,	\
150		  expect_sigill_blr);					\
151} while (0)
152
153void start(int *argcp)
154{
155	struct sigaction sa;
156	void *const *p;
157	const struct auxv_entry {
158		unsigned long type;
159		unsigned long val;
160	} *auxv;
161	unsigned long hwcap = 0, hwcap2 = 0;
162
163	putstr("TAP version 13\n");
164	putstr("1..");
165	putnum(EXPECTED_TESTS);
166	putstr("\n");
167
168	/* Gross hack for finding AT_HWCAP2 from the initial process stack: */
169	p = (void *const *)argcp + 1 + *argcp + 1; /* start of environment */
170	/* step over environment */
171	while (*p++)
172		;
173	for (auxv = (const struct auxv_entry *)p; auxv->type != AT_NULL; ++auxv) {
174		switch (auxv->type) {
175		case AT_HWCAP:
176			hwcap = auxv->val;
177			break;
178		case AT_HWCAP2:
179			hwcap2 = auxv->val;
180			break;
181		default:
182			break;
183		}
184	}
185
186	if (hwcap & HWCAP_PACA)
187		putstr("# HWCAP_PACA present\n");
188	else
189		putstr("# HWCAP_PACA not present\n");
190
191	if (hwcap2 & HWCAP2_BTI) {
192		putstr("# HWCAP2_BTI present\n");
193		if (!(hwcap & HWCAP_PACA))
194			putstr("# Bad hardware?  Expect problems.\n");
195		have_bti = true;
196	} else {
197		putstr("# HWCAP2_BTI not present\n");
198		have_bti = false;
199	}
200
201	putstr("# Test binary");
202	if (!BTI)
203		putstr(" not");
204	putstr(" built for BTI\n");
205
206	sa.sa_handler = (sighandler_t)(void *)handler;
207	sa.sa_flags = SA_SIGINFO;
208	sigemptyset(&sa.sa_mask);
209	sigaction(SIGILL, &sa, NULL);
210	sigaddset(&sa.sa_mask, SIGILL);
211	sigprocmask(SIG_UNBLOCK, &sa.sa_mask, NULL);
212
213	do_test(1, 1, 1, nohint_func);
214	do_test(1, 1, 1, bti_none_func);
215	do_test(1, 0, 0, bti_c_func);
216	do_test(0, 0, 1, bti_j_func);
217	do_test(0, 0, 0, bti_jc_func);
218	do_test(1, 0, 0, paciasp_func);
219
220	print_summary();
221
222	if (test_num - 1 != EXPECTED_TESTS)
223		putstr("# WARNING - EXPECTED TEST COUNT WRONG\n");
224
225	if (test_failed)
226		exit(1);
227	else
228		exit(0);
229}
~/ Read-only file preview.