162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* This testcase operates with the test_fpu kernel driver. 362306a36Sopenharmony_ci * It modifies the FPU control register in user mode and calls the kernel 462306a36Sopenharmony_ci * module to perform floating point operations in the kernel. The control 562306a36Sopenharmony_ci * register value should be independent between kernel and user mode. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#define _GNU_SOURCE 962306a36Sopenharmony_ci#include <stdio.h> 1062306a36Sopenharmony_ci#include <errno.h> 1162306a36Sopenharmony_ci#include <string.h> 1262306a36Sopenharmony_ci#include <fenv.h> 1362306a36Sopenharmony_ci#include <unistd.h> 1462306a36Sopenharmony_ci#include <fcntl.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ciconst char *test_fpu_path = "/sys/kernel/debug/selftest_helpers/test_fpu"; 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ciint main(void) 1962306a36Sopenharmony_ci{ 2062306a36Sopenharmony_ci char dummy[1]; 2162306a36Sopenharmony_ci int fd = open(test_fpu_path, O_RDONLY); 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci if (fd < 0) { 2462306a36Sopenharmony_ci printf("[SKIP]\tcan't access %s: %s\n", 2562306a36Sopenharmony_ci test_fpu_path, strerror(errno)); 2662306a36Sopenharmony_ci return 0; 2762306a36Sopenharmony_ci } 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci if (read(fd, dummy, 1) < 0) { 3062306a36Sopenharmony_ci printf("[FAIL]\taccess with default rounding mode failed\n"); 3162306a36Sopenharmony_ci return 1; 3262306a36Sopenharmony_ci } 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci fesetround(FE_DOWNWARD); 3562306a36Sopenharmony_ci if (read(fd, dummy, 1) < 0) { 3662306a36Sopenharmony_ci printf("[FAIL]\taccess with downward rounding mode failed\n"); 3762306a36Sopenharmony_ci return 2; 3862306a36Sopenharmony_ci } 3962306a36Sopenharmony_ci if (fegetround() != FE_DOWNWARD) { 4062306a36Sopenharmony_ci printf("[FAIL]\tusermode rounding mode clobbered\n"); 4162306a36Sopenharmony_ci return 3; 4262306a36Sopenharmony_ci } 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci /* Note: the tests up to this point are quite safe and will only return 4562306a36Sopenharmony_ci * an error. But the exception mask setting can cause misbehaving kernel 4662306a36Sopenharmony_ci * to crash. 4762306a36Sopenharmony_ci */ 4862306a36Sopenharmony_ci feclearexcept(FE_ALL_EXCEPT); 4962306a36Sopenharmony_ci feenableexcept(FE_ALL_EXCEPT); 5062306a36Sopenharmony_ci if (read(fd, dummy, 1) < 0) { 5162306a36Sopenharmony_ci printf("[FAIL]\taccess with fpu exceptions unmasked failed\n"); 5262306a36Sopenharmony_ci return 4; 5362306a36Sopenharmony_ci } 5462306a36Sopenharmony_ci if (fegetexcept() != FE_ALL_EXCEPT) { 5562306a36Sopenharmony_ci printf("[FAIL]\tusermode fpu exception mask clobbered\n"); 5662306a36Sopenharmony_ci return 5; 5762306a36Sopenharmony_ci } 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci printf("[OK]\ttest_fpu\n"); 6062306a36Sopenharmony_ci return 0; 6162306a36Sopenharmony_ci} 62