1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Test cases for using floating point operations inside a kernel module. 4 * 5 * This tests kernel_fpu_begin() and kernel_fpu_end() functions, especially 6 * when userland has modified the floating point control registers. The kernel 7 * state might depend on the state set by the userland thread that was active 8 * before a syscall. 9 * 10 * To facilitate the test, this module registers file 11 * /sys/kernel/debug/selftest_helpers/test_fpu, which when read causes a 12 * sequence of floating point operations. If the operations fail, either the 13 * read returns error status or the kernel crashes. 14 * If the operations succeed, the read returns "1\n". 15 */ 16 17 #include <linux/module.h> 18 #include <linux/kernel.h> 19 #include <linux/debugfs.h> 20 #include <linux/fpu.h> 21 22 #include "test_fpu.h" 23 24 static int test_fpu_get(void *data, u64 *val) 25 { 26 int status = -EINVAL; 27 28 kernel_fpu_begin(); 29 status = test_fpu(); 30 kernel_fpu_end(); 31 32 *val = 1; 33 return status; 34 } 35 36 DEFINE_DEBUGFS_ATTRIBUTE(test_fpu_fops, test_fpu_get, NULL, "%lld\n"); 37 static struct dentry *selftest_dir; 38 39 static int __init test_fpu_init(void) 40 { 41 if (!kernel_fpu_available()) 42 return -EINVAL; 43 44 selftest_dir = debugfs_create_dir("selftest_helpers", NULL); 45 if (!selftest_dir) 46 return -ENOMEM; 47 48 debugfs_create_file_unsafe("test_fpu", 0444, selftest_dir, NULL, 49 &test_fpu_fops); 50 51 return 0; 52 } 53 54 static void __exit test_fpu_exit(void) 55 { 56 debugfs_remove(selftest_dir); 57 } 58 59 module_init(test_fpu_init); 60 module_exit(test_fpu_exit); 61 62 MODULE_LICENSE("GPL"); 63