1/*-
2 * Copyright (c) 2021 M. Warner Losh <imp@FreeBSD.org>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include <atf-c.h>
8#include <errno.h>
9#include <signal.h>
10#include <stdbool.h>
11#include <stdlib.h>
12
13#if defined(__aarch64__)
14#include <machine/armreg.h>
15#define	SET_TRACE_FLAG(ucp)	(ucp)->uc_mcontext.mc_gpregs.gp_spsr |= PSR_SS
16#define	CLR_TRACE_FLAG(ucp)	(ucp)->uc_mcontext.mc_gpregs.gp_spsr &= ~PSR_SS
17#elif defined(__amd64__)
18#include <machine/psl.h>
19#define	SET_TRACE_FLAG(ucp)	(ucp)->uc_mcontext.mc_rflags |= PSL_T
20#define	CLR_TRACE_FLAG(ucp)	(ucp)->uc_mcontext.mc_rflags &= ~PSL_T
21#elif defined(__i386__)
22#include <machine/psl.h>
23#define	SET_TRACE_FLAG(ucp)	(ucp)->uc_mcontext.mc_eflags |= PSL_T
24#define	CLR_TRACE_FLAG(ucp)	(ucp)->uc_mcontext.mc_eflags &= ~PSL_T
25#endif
26
27static volatile sig_atomic_t signal_fired = 0;
28
29static void
30sig_handler(int signo, siginfo_t *info __unused, void *ucp __unused)
31{
32	signal_fired++;
33}
34
35ATF_TC(signal_test);
36
37ATF_TC_HEAD(signal_test, tc)
38{
39
40	atf_tc_set_md_var(tc, "descr", "Testing delivery of a signal");
41}
42
43ATF_TC_BODY(signal_test, tc)
44{
45	/*
46	 * Setup the signal handlers
47	 */
48	struct sigaction sa = {
49		.sa_sigaction = sig_handler,
50		.sa_flags = SA_SIGINFO,
51	};
52	ATF_REQUIRE(sigemptyset(&sa.sa_mask) == 0);
53	ATF_REQUIRE(sigaction(SIGUSR1, &sa, NULL) == 0);
54	ATF_REQUIRE(sigaction(SIGUSR2, &sa, NULL) == 0);
55	ATF_REQUIRE(sigaction(SIGALRM, &sa, NULL) == 0);
56
57	/*
58	 * Fire SIGUSR1
59	 */
60	ATF_CHECK(signal_fired == 0);
61	ATF_REQUIRE(raise(SIGUSR1) == 0);
62	ATF_CHECK(signal_fired == 1);
63
64	/*
65	 * Fire SIGUSR2
66	 */
67	ATF_REQUIRE(raise(SIGUSR2) == 0);
68	ATF_CHECK(signal_fired == 2);
69
70	/*
71	 * Fire SIGALRM after a timeout
72	 */
73	ATF_REQUIRE(alarm(1) == 0);
74	ATF_REQUIRE(pause() == -1);
75	ATF_REQUIRE(errno == EINTR);
76	ATF_CHECK(signal_fired == 3);
77}
78
79/*
80 * Check setting the machine dependent single step flag works when supported.
81 */
82#ifdef SET_TRACE_FLAG
83static volatile sig_atomic_t trap_signal_fired = 0;
84
85static void
86trap_sig_handler(int signo, siginfo_t *info __unused, void *_ucp)
87{
88	ucontext_t *ucp = _ucp;
89
90	if (trap_signal_fired < 9) {
91		SET_TRACE_FLAG(ucp);
92	} else {
93		CLR_TRACE_FLAG(ucp);
94	}
95	trap_signal_fired++;
96}
97
98ATF_TC(trap_signal_test);
99
100ATF_TC_HEAD(trap_signal_test, tc)
101{
102
103	atf_tc_set_md_var(tc, "descr",
104	    "Testing signal handler setting the MD single step flag");
105}
106
107ATF_TC_BODY(trap_signal_test, tc)
108{
109	/*
110	 * Setup the signal handlers
111	 */
112	struct sigaction sa = {
113		.sa_sigaction = trap_sig_handler,
114		.sa_flags = SA_SIGINFO,
115	};
116	ATF_REQUIRE(sigemptyset(&sa.sa_mask) == 0);
117	ATF_REQUIRE(sigaction(SIGTRAP, &sa, NULL) == 0);
118
119	/*
120	 * Fire SIGTRAP
121	 */
122	ATF_CHECK(trap_signal_fired == 0);
123	ATF_REQUIRE(raise(SIGTRAP) == 0);
124	ATF_CHECK(trap_signal_fired == 10);
125}
126#endif
127
128/*
129 * Special tests for 32-bit arm. We can call thumb code (really just t32) from
130 * normal (a32) mode and vice versa. Likewise, signals can interrupt a T32
131 * context with A32 code and vice versa. Make sure these all work with a simple
132 * test that raises the signal and ensures that it executed. No other platform
133 * has these requirements. Also note: we only support thumb2, so there's no T16
134 * vs T32 issues we have to test for.
135 */
136#ifdef __arm__
137
138#define a32_isa __attribute__((target("arm")))
139#define t32_isa __attribute__((target("thumb")))
140
141static volatile sig_atomic_t t32_fired = 0;
142static volatile sig_atomic_t a32_fired = 0;
143
144a32_isa static void
145sig_a32(int signo, siginfo_t *info __unused, void *ucp __unused)
146{
147	a32_fired++;
148}
149
150t32_isa static void
151sig_t32(int signo, siginfo_t *info __unused, void *ucp __unused)
152{
153	t32_fired++;
154}
155
156
157ATF_TC(signal_test_T32_to_A32);
158
159ATF_TC_HEAD(signal_test_T32_to_A32, tc)
160{
161
162	atf_tc_set_md_var(tc, "descr", "Testing delivery of a signal from T32 to A32");
163}
164
165t32_isa ATF_TC_BODY(signal_test_T32_to_A32, tc)
166{
167	/*
168	 * Setup the signal handlers
169	 */
170	struct sigaction sa = {
171		.sa_sigaction = sig_a32,
172		.sa_flags = SA_SIGINFO,
173	};
174	ATF_REQUIRE(sigemptyset(&sa.sa_mask) == 0);
175	ATF_REQUIRE(sigaction(SIGUSR1, &sa, NULL) == 0);
176
177	ATF_REQUIRE((((uintptr_t)sig_a32) & 1) == 0); /* Make sure compiled as not thumb */
178
179	ATF_CHECK(a32_fired == 0);
180	ATF_REQUIRE(raise(SIGUSR1) == 0);
181	ATF_CHECK(a32_fired == 1);
182}
183
184ATF_TC(signal_test_A32_to_T32);
185
186ATF_TC_HEAD(signal_test_A32_to_T32, tc)
187{
188
189	atf_tc_set_md_var(tc, "descr", "Testing delivery of a signal from A32 to T32");
190}
191
192a32_isa ATF_TC_BODY(signal_test_A32_to_T32, tc)
193{
194	/*
195	 * Setup the signal handlers
196	 */
197	struct sigaction sa = {
198		.sa_sigaction = sig_t32,
199		.sa_flags = SA_SIGINFO,
200	};
201	ATF_REQUIRE(sigemptyset(&sa.sa_mask) == 0);
202	ATF_REQUIRE(sigaction(SIGUSR1, &sa, NULL) == 0);
203
204	ATF_REQUIRE((((uintptr_t)sig_t32) & 1) == 1);	/* Make sure compiled as thumb */
205
206	ATF_CHECK(t32_fired == 0);
207	ATF_REQUIRE(raise(SIGUSR1) == 0);
208	ATF_CHECK(t32_fired == 1);
209}
210#endif
211
212ATF_TP_ADD_TCS(tp)
213{
214
215	ATF_TP_ADD_TC(tp, signal_test);
216#ifdef SET_TRACE_FLAG
217	ATF_TP_ADD_TC(tp, trap_signal_test);
218#endif
219#ifdef __arm__
220	ATF_TP_ADD_TC(tp, signal_test_T32_to_A32);
221	ATF_TP_ADD_TC(tp, signal_test_A32_to_T32);
222#endif
223
224	return (atf_no_error());
225}
226