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 "compiler.h"
21 #include "signal.h"
22
23 #define EXPECTED_TESTS 18
24
25 static volatile unsigned int test_num = 1;
26 static unsigned int test_passed;
27 static unsigned int test_failed;
28 static unsigned int test_skipped;
29
fdputs(int fd,const char * str)30 static void fdputs(int fd, const char *str)
31 {
32 size_t len = 0;
33 const char *p = str;
34
35 while (*p++)
36 ++len;
37
38 write(fd, str, len);
39 }
40
putstr(const char * str)41 static void putstr(const char *str)
42 {
43 fdputs(1, str);
44 }
45
putnum(unsigned int num)46 static void putnum(unsigned int num)
47 {
48 char c;
49
50 if (num / 10)
51 putnum(num / 10);
52
53 c = '0' + (num % 10);
54 write(1, &c, 1);
55 }
56
57 #define puttestname(test_name, trampoline_name) do { \
58 putstr(test_name); \
59 putstr("/"); \
60 putstr(trampoline_name); \
61 } while (0)
62
print_summary(void)63 void print_summary(void)
64 {
65 putstr("# Totals: pass:");
66 putnum(test_passed);
67 putstr(" fail:");
68 putnum(test_failed);
69 putstr(" xfail:0 xpass:0 skip:");
70 putnum(test_skipped);
71 putstr(" error:0\n");
72 }
73
74 static const char *volatile current_test_name;
75 static const char *volatile current_trampoline_name;
76 static volatile int sigill_expected, sigill_received;
77
handler(int n,siginfo_t * si __always_unused,void * uc_ __always_unused)78 static void handler(int n, siginfo_t *si __always_unused,
79 void *uc_ __always_unused)
80 {
81 ucontext_t *uc = uc_;
82
83 putstr("# \t[SIGILL in ");
84 puttestname(current_test_name, current_trampoline_name);
85 putstr(", BTYPE=");
86 write(1, &"00011011"[((uc->uc_mcontext.pstate & PSR_BTYPE_MASK)
87 >> PSR_BTYPE_SHIFT) * 2], 2);
88 if (!sigill_expected) {
89 putstr("]\n");
90 putstr("not ok ");
91 putnum(test_num);
92 putstr(" ");
93 puttestname(current_test_name, current_trampoline_name);
94 putstr("(unexpected SIGILL)\n");
95 print_summary();
96 exit(128 + n);
97 }
98
99 putstr(" (expected)]\n");
100 sigill_received = 1;
101 /* zap BTYPE so that resuming the faulting code will work */
102 uc->uc_mcontext.pstate &= ~PSR_BTYPE_MASK;
103 }
104
105 /* Does the system have BTI? */
106 static bool have_bti;
107
__do_test(void (* trampoline)(void (*)(void)),void (* fn)(void),const char * trampoline_name,const char * name,int expect_sigill)108 static void __do_test(void (*trampoline)(void (*)(void)),
109 void (*fn)(void),
110 const char *trampoline_name,
111 const char *name,
112 int expect_sigill)
113 {
114 /*
115 * Branch Target exceptions should only happen for BTI
116 * binaries running on a system with BTI:
117 */
118 if (!BTI || !have_bti)
119 expect_sigill = 0;
120
121 sigill_expected = expect_sigill;
122 sigill_received = 0;
123 current_test_name = name;
124 current_trampoline_name = trampoline_name;
125
126 trampoline(fn);
127
128 if (expect_sigill && !sigill_received) {
129 putstr("not ok ");
130 test_failed++;
131 } else {
132 putstr("ok ");
133 test_passed++;
134 }
135 putnum(test_num++);
136 putstr(" ");
137 puttestname(name, trampoline_name);
138 putstr("\n");
139 }
140
141 #define do_test(expect_sigill_br_x0, \
142 expect_sigill_br_x16, \
143 expect_sigill_blr, \
144 name) \
145 do { \
146 __do_test(call_using_br_x0, name, "call_using_br_x0", #name, \
147 expect_sigill_br_x0); \
148 __do_test(call_using_br_x16, name, "call_using_br_x16", #name, \
149 expect_sigill_br_x16); \
150 __do_test(call_using_blr, name, "call_using_blr", #name, \
151 expect_sigill_blr); \
152 } while (0)
153
start(int * argcp)154 void start(int *argcp)
155 {
156 struct sigaction sa;
157 void *const *p;
158 const struct auxv_entry {
159 unsigned long type;
160 unsigned long val;
161 } *auxv;
162 unsigned long hwcap = 0, hwcap2 = 0;
163
164 putstr("TAP version 13\n");
165 putstr("1..");
166 putnum(EXPECTED_TESTS);
167 putstr("\n");
168
169 /* Gross hack for finding AT_HWCAP2 from the initial process stack: */
170 p = (void *const *)argcp + 1 + *argcp + 1; /* start of environment */
171 /* step over environment */
172 while (*p++)
173 ;
174 for (auxv = (const struct auxv_entry *)p; auxv->type != AT_NULL; ++auxv) {
175 switch (auxv->type) {
176 case AT_HWCAP:
177 hwcap = auxv->val;
178 break;
179 case AT_HWCAP2:
180 hwcap2 = auxv->val;
181 break;
182 default:
183 break;
184 }
185 }
186
187 if (hwcap & HWCAP_PACA)
188 putstr("# HWCAP_PACA present\n");
189 else
190 putstr("# HWCAP_PACA not present\n");
191
192 if (hwcap2 & HWCAP2_BTI) {
193 putstr("# HWCAP2_BTI present\n");
194 if (!(hwcap & HWCAP_PACA))
195 putstr("# Bad hardware? Expect problems.\n");
196 have_bti = true;
197 } else {
198 putstr("# HWCAP2_BTI not present\n");
199 have_bti = false;
200 }
201
202 putstr("# Test binary");
203 if (!BTI)
204 putstr(" not");
205 putstr(" built for BTI\n");
206
207 sa.sa_handler = (sighandler_t)(void *)handler;
208 sa.sa_flags = SA_SIGINFO;
209 sigemptyset(&sa.sa_mask);
210 sigaction(SIGILL, &sa, NULL);
211 sigaddset(&sa.sa_mask, SIGILL);
212 sigprocmask(SIG_UNBLOCK, &sa.sa_mask, NULL);
213
214 do_test(1, 1, 1, nohint_func);
215 do_test(1, 1, 1, bti_none_func);
216 do_test(1, 0, 0, bti_c_func);
217 do_test(0, 0, 1, bti_j_func);
218 do_test(0, 0, 0, bti_jc_func);
219 do_test(1, 0, 0, paciasp_func);
220
221 print_summary();
222
223 if (test_num - 1 != EXPECTED_TESTS)
224 putstr("# WARNING - EXPECTED TEST COUNT WRONG\n");
225
226 if (test_failed)
227 exit(1);
228 else
229 exit(0);
230 }
231