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