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 | |