| // SPDX-License-Identifier: GPL-2.0+ |
| /* This testcase operates with the test_fpu kernel driver. |
| * It modifies the FPU control register in user mode and calls the kernel |
| * module to perform floating point operations in the kernel. The control |
| * register value should be independent between kernel and user mode. |
| */ |
| |
| #define _GNU_SOURCE |
| #include <stdio.h> |
| #include <errno.h> |
| #include <string.h> |
| #include <fenv.h> |
| #include <unistd.h> |
| #include <fcntl.h> |
| |
| const char *test_fpu_path = "/sys/kernel/debug/selftest_helpers/test_fpu"; |
| |
| int main(void) |
| { |
| char dummy[1]; |
| int fd = open(test_fpu_path, O_RDONLY); |
| |
| if (fd < 0) { |
| printf("[SKIP]\tcan't access %s: %s\n", |
| test_fpu_path, strerror(errno)); |
| return 0; |
| } |
| |
| if (read(fd, dummy, 1) < 0) { |
| printf("[FAIL]\taccess with default rounding mode failed\n"); |
| return 1; |
| } |
| |
| fesetround(FE_DOWNWARD); |
| if (read(fd, dummy, 1) < 0) { |
| printf("[FAIL]\taccess with downward rounding mode failed\n"); |
| return 2; |
| } |
| if (fegetround() != FE_DOWNWARD) { |
| printf("[FAIL]\tusermode rounding mode clobbered\n"); |
| return 3; |
| } |
| |
| /* Note: the tests up to this point are quite safe and will only return |
| * an error. But the exception mask setting can cause misbehaving kernel |
| * to crash. |
| */ |
| feclearexcept(FE_ALL_EXCEPT); |
| feenableexcept(FE_ALL_EXCEPT); |
| if (read(fd, dummy, 1) < 0) { |
| printf("[FAIL]\taccess with fpu exceptions unmasked failed\n"); |
| return 4; |
| } |
| if (fegetexcept() != FE_ALL_EXCEPT) { |
| printf("[FAIL]\tusermode fpu exception mask clobbered\n"); |
| return 5; |
| } |
| |
| printf("[OK]\ttest_fpu\n"); |
| return 0; |
| } |