1 // SPDX-License-Identifier: GPL-2.0+
2 /* This testcase operates with the test_fpu kernel driver.
3  * It modifies the FPU control register in user mode and calls the kernel
4  * module to perform floating point operations in the kernel. The control
5  * register value should be independent between kernel and user mode.
6  */
7 
8 #define _GNU_SOURCE
9 #include <stdio.h>
10 #include <errno.h>
11 #include <string.h>
12 #include <fenv.h>
13 #include <unistd.h>
14 #include <fcntl.h>
15 
16 const char *test_fpu_path = "/sys/kernel/debug/selftest_helpers/test_fpu";
17 
18 int main(void)
19 {
20 	char dummy[1];
21 	int fd = open(test_fpu_path, O_RDONLY);
22 
23 	if (fd < 0) {
24 		printf("[SKIP]\tcan't access %s: %s\n",
25 		       test_fpu_path, strerror(errno));
26 		return 0;
27 	}
28 
29 	if (read(fd, dummy, 1) < 0) {
30 		printf("[FAIL]\taccess with default rounding mode failed\n");
31 		return 1;
32 	}
33 
34 	fesetround(FE_DOWNWARD);
35 	if (read(fd, dummy, 1) < 0) {
36 		printf("[FAIL]\taccess with downward rounding mode failed\n");
37 		return 2;
38 	}
39 	if (fegetround() != FE_DOWNWARD) {
40 		printf("[FAIL]\tusermode rounding mode clobbered\n");
41 		return 3;
42 	}
43 
44 	/* Note: the tests up to this point are quite safe and will only return
45 	 * an error. But the exception mask setting can cause misbehaving kernel
46 	 * to crash.
47 	 */
48 	feclearexcept(FE_ALL_EXCEPT);
49 	feenableexcept(FE_ALL_EXCEPT);
50 	if (read(fd, dummy, 1) < 0) {
51 		printf("[FAIL]\taccess with fpu exceptions unmasked failed\n");
52 		return 4;
53 	}
54 	if (fegetexcept() != FE_ALL_EXCEPT) {
55 		printf("[FAIL]\tusermode fpu exception mask clobbered\n");
56 		return 5;
57 	}
58 
59 	printf("[OK]\ttest_fpu\n");
60 	return 0;
61 }
62