forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge tag 'x86-fpu-2020-08-03' of git://git.kernel.org/pub/scm/linux/…
…kernel/git/tip/tip Pull x86 FPU selftest from Ingo Molnar: "Add the /sys/kernel/debug/selftest_helpers/test_fpu FPU self-test" * tag 'x86-fpu-2020-08-03' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: selftests/fpu: Add an FPU selftest
- Loading branch information
Showing
8 changed files
with
243 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
// SPDX-License-Identifier: GPL-2.0+ | ||
/* | ||
* Test cases for using floating point operations inside a kernel module. | ||
* | ||
* This tests kernel_fpu_begin() and kernel_fpu_end() functions, especially | ||
* when userland has modified the floating point control registers. The kernel | ||
* state might depend on the state set by the userland thread that was active | ||
* before a syscall. | ||
* | ||
* To facilitate the test, this module registers file | ||
* /sys/kernel/debug/selftest_helpers/test_fpu, which when read causes a | ||
* sequence of floating point operations. If the operations fail, either the | ||
* read returns error status or the kernel crashes. | ||
* If the operations succeed, the read returns "1\n". | ||
*/ | ||
|
||
#include <linux/module.h> | ||
#include <linux/kernel.h> | ||
#include <linux/debugfs.h> | ||
#include <asm/fpu/api.h> | ||
|
||
static int test_fpu(void) | ||
{ | ||
/* | ||
* This sequence of operations tests that rounding mode is | ||
* to nearest and that denormal numbers are supported. | ||
* Volatile variables are used to avoid compiler optimizing | ||
* the calculations away. | ||
*/ | ||
volatile double a, b, c, d, e, f, g; | ||
|
||
a = 4.0; | ||
b = 1e-15; | ||
c = 1e-310; | ||
|
||
/* Sets precision flag */ | ||
d = a + b; | ||
|
||
/* Result depends on rounding mode */ | ||
e = a + b / 2; | ||
|
||
/* Denormal and very large values */ | ||
f = b / c; | ||
|
||
/* Depends on denormal support */ | ||
g = a + c * f; | ||
|
||
if (d > a && e > a && g > a) | ||
return 0; | ||
else | ||
return -EINVAL; | ||
} | ||
|
||
static int test_fpu_get(void *data, u64 *val) | ||
{ | ||
int status = -EINVAL; | ||
|
||
kernel_fpu_begin(); | ||
status = test_fpu(); | ||
kernel_fpu_end(); | ||
|
||
*val = 1; | ||
return status; | ||
} | ||
|
||
DEFINE_SIMPLE_ATTRIBUTE(test_fpu_fops, test_fpu_get, NULL, "%lld\n"); | ||
static struct dentry *selftest_dir; | ||
|
||
static int __init test_fpu_init(void) | ||
{ | ||
selftest_dir = debugfs_create_dir("selftest_helpers", NULL); | ||
if (!selftest_dir) | ||
return -ENOMEM; | ||
|
||
debugfs_create_file("test_fpu", 0444, selftest_dir, NULL, | ||
&test_fpu_fops); | ||
|
||
return 0; | ||
} | ||
|
||
static void __exit test_fpu_exit(void) | ||
{ | ||
debugfs_remove(selftest_dir); | ||
} | ||
|
||
module_init(test_fpu_init); | ||
module_exit(test_fpu_exit); | ||
|
||
MODULE_LICENSE("GPL"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
# SPDX-License-Identifier: GPL-2.0+ | ||
test_fpu |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
# SPDX-License-Identifier: GPL-2.0+ | ||
|
||
LDLIBS := -lm | ||
|
||
TEST_GEN_PROGS := test_fpu | ||
|
||
TEST_PROGS := run_test_fpu.sh | ||
|
||
include ../lib.mk |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
#!/bin/bash | ||
# SPDX-License-Identifier: GPL-2.0 | ||
# | ||
# Load kernel module for FPU tests | ||
|
||
uid=$(id -u) | ||
if [ $uid -ne 0 ]; then | ||
echo "$0: Must be run as root" | ||
exit 1 | ||
fi | ||
|
||
if ! which modprobe > /dev/null 2>&1; then | ||
echo "$0: You need modprobe installed" | ||
exit 4 | ||
fi | ||
|
||
if ! modinfo test_fpu > /dev/null 2>&1; then | ||
echo "$0: You must have the following enabled in your kernel:" | ||
echo "CONFIG_TEST_FPU=m" | ||
exit 4 | ||
fi | ||
|
||
NR_CPUS=$(getconf _NPROCESSORS_ONLN) | ||
if [ ! $NR_CPUS ]; then | ||
NR_CPUS=1 | ||
fi | ||
|
||
modprobe test_fpu | ||
|
||
if [ ! -e /sys/kernel/debug/selftest_helpers/test_fpu ]; then | ||
mount -t debugfs none /sys/kernel/debug | ||
|
||
if [ ! -e /sys/kernel/debug/selftest_helpers/test_fpu ]; then | ||
echo "$0: Error mounting debugfs" | ||
exit 4 | ||
fi | ||
fi | ||
|
||
echo "Running 1000 iterations on all CPUs... " | ||
for i in $(seq 1 1000); do | ||
for c in $(seq 1 $NR_CPUS); do | ||
./test_fpu & | ||
done | ||
done | ||
|
||
rmmod test_fpu |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
// 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; | ||
} |