| // 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; | |
| } |