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
17 typedef struct ucontext ucontext_t;
18
19 #include "btitest.h"
20 #include "signal.h"
21
22 #define EXPECTED_TESTS 18
23
24 static volatile unsigned int test_num = 1;
25 static unsigned int test_passed;
26 static unsigned int test_failed;
27 static unsigned int test_skipped;
28
fdputs(int fd,const char * str)29 static 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
putstr(const char * str)40 static void putstr(const char *str)
41 {
42 fdputs(1, str);
43 }
44
putnum(unsigned int num)45 static 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
print_summary(void)62 void 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
73 static const char *volatile current_test_name;
74 static const char *volatile current_trampoline_name;
75 static volatile int sigill_expected, sigill_received;
76
handler(int n,siginfo_t * si __always_unused,void * uc_ __always_unused)77 static 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? */
105 static bool have_bti;
106
__do_test(void (* trampoline)(void (*)(void)),void (* fn)(void),const char * trampoline_name,const char * name,int expect_sigill)107 static 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) \
144 do { \
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
start(int * argcp)153 void 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 }
230