1/* SPDX-License-Identifier: GPL-2.0 */
2#define _GNU_SOURCE
3#include <linux/membarrier.h>
4#include <syscall.h>
5#include <stdio.h>
6#include <errno.h>
7#include <string.h>
8#include <pthread.h>
9
10#include "../kselftest.h"
11
12static int sys_membarrier(int cmd, int flags)
13{
14	return syscall(__NR_membarrier, cmd, flags);
15}
16
17static int test_membarrier_cmd_fail(void)
18{
19	int cmd = -1, flags = 0;
20	const char *test_name = "sys membarrier invalid command";
21
22	if (sys_membarrier(cmd, flags) != -1) {
23		ksft_exit_fail_msg(
24			"%s test: command = %d, flags = %d. Should fail, but passed\n",
25			test_name, cmd, flags);
26	}
27	if (errno != EINVAL) {
28		ksft_exit_fail_msg(
29			"%s test: flags = %d. Should return (%d: \"%s\"), but returned (%d: \"%s\").\n",
30			test_name, flags, EINVAL, strerror(EINVAL),
31			errno, strerror(errno));
32	}
33
34	ksft_test_result_pass(
35		"%s test: command = %d, flags = %d, errno = %d. Failed as expected\n",
36		test_name, cmd, flags, errno);
37	return 0;
38}
39
40static int test_membarrier_flags_fail(void)
41{
42	int cmd = MEMBARRIER_CMD_QUERY, flags = 1;
43	const char *test_name = "sys membarrier MEMBARRIER_CMD_QUERY invalid flags";
44
45	if (sys_membarrier(cmd, flags) != -1) {
46		ksft_exit_fail_msg(
47			"%s test: flags = %d. Should fail, but passed\n",
48			test_name, flags);
49	}
50	if (errno != EINVAL) {
51		ksft_exit_fail_msg(
52			"%s test: flags = %d. Should return (%d: \"%s\"), but returned (%d: \"%s\").\n",
53			test_name, flags, EINVAL, strerror(EINVAL),
54			errno, strerror(errno));
55	}
56
57	ksft_test_result_pass(
58		"%s test: flags = %d, errno = %d. Failed as expected\n",
59		test_name, flags, errno);
60	return 0;
61}
62
63static int test_membarrier_global_success(void)
64{
65	int cmd = MEMBARRIER_CMD_GLOBAL, flags = 0;
66	const char *test_name = "sys membarrier MEMBARRIER_CMD_GLOBAL";
67
68	if (sys_membarrier(cmd, flags) != 0) {
69		ksft_exit_fail_msg(
70			"%s test: flags = %d, errno = %d\n",
71			test_name, flags, errno);
72	}
73
74	ksft_test_result_pass(
75		"%s test: flags = %d\n", test_name, flags);
76	return 0;
77}
78
79static int test_membarrier_private_expedited_fail(void)
80{
81	int cmd = MEMBARRIER_CMD_PRIVATE_EXPEDITED, flags = 0;
82	const char *test_name = "sys membarrier MEMBARRIER_CMD_PRIVATE_EXPEDITED not registered failure";
83
84	if (sys_membarrier(cmd, flags) != -1) {
85		ksft_exit_fail_msg(
86			"%s test: flags = %d. Should fail, but passed\n",
87			test_name, flags);
88	}
89	if (errno != EPERM) {
90		ksft_exit_fail_msg(
91			"%s test: flags = %d. Should return (%d: \"%s\"), but returned (%d: \"%s\").\n",
92			test_name, flags, EPERM, strerror(EPERM),
93			errno, strerror(errno));
94	}
95
96	ksft_test_result_pass(
97		"%s test: flags = %d, errno = %d\n",
98		test_name, flags, errno);
99	return 0;
100}
101
102static int test_membarrier_register_private_expedited_success(void)
103{
104	int cmd = MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED, flags = 0;
105	const char *test_name = "sys membarrier MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED";
106
107	if (sys_membarrier(cmd, flags) != 0) {
108		ksft_exit_fail_msg(
109			"%s test: flags = %d, errno = %d\n",
110			test_name, flags, errno);
111	}
112
113	ksft_test_result_pass(
114		"%s test: flags = %d\n",
115		test_name, flags);
116	return 0;
117}
118
119static int test_membarrier_private_expedited_success(void)
120{
121	int cmd = MEMBARRIER_CMD_PRIVATE_EXPEDITED, flags = 0;
122	const char *test_name = "sys membarrier MEMBARRIER_CMD_PRIVATE_EXPEDITED";
123
124	if (sys_membarrier(cmd, flags) != 0) {
125		ksft_exit_fail_msg(
126			"%s test: flags = %d, errno = %d\n",
127			test_name, flags, errno);
128	}
129
130	ksft_test_result_pass(
131		"%s test: flags = %d\n",
132		test_name, flags);
133	return 0;
134}
135
136static int test_membarrier_private_expedited_sync_core_fail(void)
137{
138	int cmd = MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE, flags = 0;
139	const char *test_name = "sys membarrier MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE not registered failure";
140
141	if (sys_membarrier(cmd, flags) != -1) {
142		ksft_exit_fail_msg(
143			"%s test: flags = %d. Should fail, but passed\n",
144			test_name, flags);
145	}
146	if (errno != EPERM) {
147		ksft_exit_fail_msg(
148			"%s test: flags = %d. Should return (%d: \"%s\"), but returned (%d: \"%s\").\n",
149			test_name, flags, EPERM, strerror(EPERM),
150			errno, strerror(errno));
151	}
152
153	ksft_test_result_pass(
154		"%s test: flags = %d, errno = %d\n",
155		test_name, flags, errno);
156	return 0;
157}
158
159static int test_membarrier_register_private_expedited_sync_core_success(void)
160{
161	int cmd = MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE, flags = 0;
162	const char *test_name = "sys membarrier MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE";
163
164	if (sys_membarrier(cmd, flags) != 0) {
165		ksft_exit_fail_msg(
166			"%s test: flags = %d, errno = %d\n",
167			test_name, flags, errno);
168	}
169
170	ksft_test_result_pass(
171		"%s test: flags = %d\n",
172		test_name, flags);
173	return 0;
174}
175
176static int test_membarrier_private_expedited_sync_core_success(void)
177{
178	int cmd = MEMBARRIER_CMD_PRIVATE_EXPEDITED, flags = 0;
179	const char *test_name = "sys membarrier MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE";
180
181	if (sys_membarrier(cmd, flags) != 0) {
182		ksft_exit_fail_msg(
183			"%s test: flags = %d, errno = %d\n",
184			test_name, flags, errno);
185	}
186
187	ksft_test_result_pass(
188		"%s test: flags = %d\n",
189		test_name, flags);
190	return 0;
191}
192
193static int test_membarrier_register_global_expedited_success(void)
194{
195	int cmd = MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED, flags = 0;
196	const char *test_name = "sys membarrier MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED";
197
198	if (sys_membarrier(cmd, flags) != 0) {
199		ksft_exit_fail_msg(
200			"%s test: flags = %d, errno = %d\n",
201			test_name, flags, errno);
202	}
203
204	ksft_test_result_pass(
205		"%s test: flags = %d\n",
206		test_name, flags);
207	return 0;
208}
209
210static int test_membarrier_global_expedited_success(void)
211{
212	int cmd = MEMBARRIER_CMD_GLOBAL_EXPEDITED, flags = 0;
213	const char *test_name = "sys membarrier MEMBARRIER_CMD_GLOBAL_EXPEDITED";
214
215	if (sys_membarrier(cmd, flags) != 0) {
216		ksft_exit_fail_msg(
217			"%s test: flags = %d, errno = %d\n",
218			test_name, flags, errno);
219	}
220
221	ksft_test_result_pass(
222		"%s test: flags = %d\n",
223		test_name, flags);
224	return 0;
225}
226
227static int test_membarrier_fail(void)
228{
229	int status;
230
231	status = test_membarrier_cmd_fail();
232	if (status)
233		return status;
234	status = test_membarrier_flags_fail();
235	if (status)
236		return status;
237	status = test_membarrier_private_expedited_fail();
238	if (status)
239		return status;
240	status = sys_membarrier(MEMBARRIER_CMD_QUERY, 0);
241	if (status < 0) {
242		ksft_test_result_fail("sys_membarrier() failed\n");
243		return status;
244	}
245	if (status & MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE) {
246		status = test_membarrier_private_expedited_sync_core_fail();
247		if (status)
248			return status;
249	}
250	return 0;
251}
252
253static int test_membarrier_success(void)
254{
255	int status;
256
257	status = test_membarrier_global_success();
258	if (status)
259		return status;
260	status = test_membarrier_register_private_expedited_success();
261	if (status)
262		return status;
263	status = test_membarrier_private_expedited_success();
264	if (status)
265		return status;
266	status = sys_membarrier(MEMBARRIER_CMD_QUERY, 0);
267	if (status < 0) {
268		ksft_test_result_fail("sys_membarrier() failed\n");
269		return status;
270	}
271	if (status & MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE) {
272		status = test_membarrier_register_private_expedited_sync_core_success();
273		if (status)
274			return status;
275		status = test_membarrier_private_expedited_sync_core_success();
276		if (status)
277			return status;
278	}
279	/*
280	 * It is valid to send a global membarrier from a non-registered
281	 * process.
282	 */
283	status = test_membarrier_global_expedited_success();
284	if (status)
285		return status;
286	status = test_membarrier_register_global_expedited_success();
287	if (status)
288		return status;
289	status = test_membarrier_global_expedited_success();
290	if (status)
291		return status;
292	return 0;
293}
294
295static int test_membarrier_query(void)
296{
297	int flags = 0, ret;
298
299	ret = sys_membarrier(MEMBARRIER_CMD_QUERY, flags);
300	if (ret < 0) {
301		if (errno == ENOSYS) {
302			/*
303			 * It is valid to build a kernel with
304			 * CONFIG_MEMBARRIER=n. However, this skips the tests.
305			 */
306			ksft_exit_skip(
307				"sys membarrier (CONFIG_MEMBARRIER) is disabled.\n");
308		}
309		ksft_exit_fail_msg("sys_membarrier() failed\n");
310	}
311	if (!(ret & MEMBARRIER_CMD_GLOBAL))
312		ksft_exit_skip(
313			"sys_membarrier unsupported: CMD_GLOBAL not found.\n");
314
315	ksft_test_result_pass("sys_membarrier available\n");
316	return 0;
317}
318