View | Details | Raw Unified | Return to bug 207979 | Differences between
and this patch

Collapse All | Expand All

(-)a/arch/x86/Makefile (+16 lines)
Lines 149-154 ifdef CONFIG_X86_X32 Link Here
149
endif
149
endif
150
export CONFIG_X86_X32_ABI
150
export CONFIG_X86_X32_ABI
151
151
152
#
153
# CFLAGS for compiling floating point code inside the kernel
154
#
155
FPU_CFLAGS += -mhard-float -msse
156
ifdef CONFIG_CC_IS_GCC
157
  ifeq ($(call cc-ifversion, -lt, 0701, y), y)
158
    # Stack alignment mismatch, proceed with caution.
159
    # GCC < 7.1 cannot compile code using `double` and -mpreferred-stack-boundary=3
160
    # (8B stack alignment).
161
    FPU_CFLAGS += -mpreferred-stack-boundary=4
162
  else
163
    FPU_CFLAGS += -msse2
164
  endif
165
endif
166
export FPU_CFLAGS
167
152
#
168
#
153
# If the function graph tracer is used with mcount instead of fentry,
169
# If the function graph tracer is used with mcount instead of fentry,
154
# '-maccumulate-outgoing-args' is needed to prevent a GCC bug
170
# '-maccumulate-outgoing-args' is needed to prevent a GCC bug
(-)a/arch/x86/include/asm/fpu/internal.h (+5 lines)
Lines 619-624 static inline void switch_fpu_finish(struct fpu *new_fpu) Link Here
619
 * MXCSR and XCR definitions:
619
 * MXCSR and XCR definitions:
620
 */
620
 */
621
621
622
static inline void ldmxcsr(u32 mxcsr)
623
{
624
	asm volatile("ldmxcsr %0" :: "m" (mxcsr));
625
}
626
622
extern unsigned int mxcsr_feature_mask;
627
extern unsigned int mxcsr_feature_mask;
623
628
624
#define XCR_XFEATURE_ENABLED_MASK	0x00000000
629
#define XCR_XFEATURE_ENABLED_MASK	0x00000000
(-)a/arch/x86/kernel/fpu/core.c (+1 lines)
Lines 101-106 void kernel_fpu_begin(void) Link Here
101
		copy_fpregs_to_fpstate(&current->thread.fpu);
101
		copy_fpregs_to_fpstate(&current->thread.fpu);
102
	}
102
	}
103
	__cpu_invalidate_fpregs_state();
103
	__cpu_invalidate_fpregs_state();
104
	ldmxcsr(MXCSR_DEFAULT);
104
}
105
}
105
EXPORT_SYMBOL_GPL(kernel_fpu_begin);
106
EXPORT_SYMBOL_GPL(kernel_fpu_begin);
106
107
(-)a/lib/Kconfig.debug (+10 lines)
Lines 2201-2206 config TEST_MEMINIT Link Here
2201
2201
2202
	  If unsure, say N.
2202
	  If unsure, say N.
2203
2203
2204
config TEST_FPU
2205
	tristate "Test floating point operations inside kernel"
2206
	depends on X86
2207
	help
2208
	  Enable this option to add /proc/sys/debug/test_fpu which will trigger
2209
	  a sequence of floating point operations. This is used for self-testing
2210
	  floating point control register setting in kernel_fpu_begin().
2211
2212
	  If unsure, say N.
2213
2204
endif # RUNTIME_TESTING_MENU
2214
endif # RUNTIME_TESTING_MENU
2205
2215
2206
config MEMTEST
2216
config MEMTEST
(-)a/lib/Makefile (+5 lines)
Lines 93-98 obj-$(CONFIG_TEST_BLACKHOLE_DEV) += test_blackhole_dev.o Link Here
93
obj-$(CONFIG_TEST_MEMINIT) += test_meminit.o
93
obj-$(CONFIG_TEST_MEMINIT) += test_meminit.o
94
obj-$(CONFIG_TEST_LOCKUP) += test_lockup.o
94
obj-$(CONFIG_TEST_LOCKUP) += test_lockup.o
95
95
96
ifdef FPU_CFLAGS
97
obj-$(CONFIG_TEST_FPU) += test_fpu.o
98
CFLAGS_test_fpu.o += $(FPU_CFLAGS)
99
endif
100
96
obj-$(CONFIG_TEST_LIVEPATCH) += livepatch/
101
obj-$(CONFIG_TEST_LIVEPATCH) += livepatch/
97
102
98
obj-$(CONFIG_KUNIT) += kunit/
103
obj-$(CONFIG_KUNIT) += kunit/
(-)a/lib/test_fpu.c (+104 lines)
Line 0 Link Here
1
// SPDX-License-Identifier: GPL-2.0+
2
/*
3
 * Test cases for using floating point operations inside a kernel module.
4
 * This tests kernel_fpu_begin() and kernel_fpu_end() functions, especially
5
 * when userland has modified the floating point control registers.
6
 *
7
 * To facilitate the test, this module registers file /proc/sys/debug/test_fpu,
8
 * which when read causes a sequence of floating point operations. If the
9
 * operations fail, either the read returns error status or the kernel crashes.
10
 * If the operations succeed, the read returns 0 bytes.
11
 */
12
13
#include <linux/module.h>
14
#include <linux/kernel.h>
15
#include <asm/fpu/api.h>
16
17
static int test_fpu(void)
18
{
19
	/* This sequence of operations tests that rounding mode is
20
	 * to nearest and that denormal numbers are supported.
21
	 * Volatile variables are used to avoid compiler optimizing
22
	 * the calculations away.
23
	 */
24
	volatile double a, b, c, d, e, f, g;
25
26
	a = 4.0;
27
	b = 1e-15;
28
	c = 1e-310;
29
	d = a + b;     /* Sets precision flag */
30
	e = a + b / 2; /* Result depends on rounding mode */
31
	f = b / c;     /* Denormal and very large values */
32
	g = a + c * f; /* Depends on denormal support */
33
34
	if (d > a && e > a && g > a)
35
		return 0;
36
	else
37
		return -EINVAL;
38
}
39
40
static int test_fpu_sysctl(struct ctl_table *ctl, int write,
41
                           void __user *buffer, size_t *lenp, loff_t *ppos)
42
{
43
	int status = -EINVAL;
44
45
	kernel_fpu_begin();
46
	status = test_fpu();
47
	kernel_fpu_end();
48
49
	*lenp = 0;
50
	return status;
51
}
52
53
static struct ctl_table test_fpu_table[] = {
54
	{
55
		.procname       = "test_fpu",
56
		.data           = NULL,
57
		.maxlen         = 0,
58
		.mode           = 0444,
59
		.proc_handler   = test_fpu_sysctl,
60
	},
61
	{ }
62
};
63
64
static struct ctl_table test_fpu_root_table[] = {
65
	{
66
		.procname       = "debug",
67
		.maxlen         = 0,
68
		.mode           = 0555,
69
		.child          = test_fpu_table,
70
	},
71
	{ }
72
};
73
74
static struct ctl_table_header *test_fpu_header;
75
76
static int __init test_fpu_init(void)
77
{
78
	int status = -EINVAL;
79
80
	test_fpu_header = register_sysctl_table(test_fpu_root_table);
81
	if (!test_fpu_header)
82
		return -ENOMEM;
83
84
	/* FPU operations are tested both during the module loader and
85
	 * later from syscalls.
86
     */
87
	kernel_fpu_begin();
88
	status = test_fpu();
89
	kernel_fpu_end();
90
91
	return status;
92
}
93
94
95
static void __exit test_fpu_exit(void)
96
{
97
	if (test_fpu_header)
98
		unregister_sysctl_table(test_fpu_header);
99
}
100
101
module_init(test_fpu_init);
102
module_exit(test_fpu_exit);
103
104
MODULE_LICENSE("GPL");
(-)a/tools/testing/selftests/x86/Makefile (-1 / +3 lines)
Lines 12-18 CAN_BUILD_WITH_NOPIE := $(shell ./check_cc.sh $(CC) trivial_program.c -no-pie) Link Here
12
12
13
TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt test_mremap_vdso \
13
TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt test_mremap_vdso \
14
			check_initial_reg_state sigreturn iopl ioperm \
14
			check_initial_reg_state sigreturn iopl ioperm \
15
			protection_keys test_vdso test_vsyscall mov_ss_trap \
15
			protection_keys test_fpu test_vdso test_vsyscall mov_ss_trap \
16
			syscall_arg_fault
16
			syscall_arg_fault
17
TARGETS_C_32BIT_ONLY := entry_from_vm86 test_syscall_vdso unwind_vdso \
17
TARGETS_C_32BIT_ONLY := entry_from_vm86 test_syscall_vdso unwind_vdso \
18
			test_FCMOV test_FCOMI test_FISTTP \
18
			test_FCMOV test_FCOMI test_FISTTP \
Lines 98-103 endif Link Here
98
$(OUTPUT)/sysret_ss_attrs_64: thunks.S
98
$(OUTPUT)/sysret_ss_attrs_64: thunks.S
99
$(OUTPUT)/ptrace_syscall_32: raw_syscall_helper_32.S
99
$(OUTPUT)/ptrace_syscall_32: raw_syscall_helper_32.S
100
$(OUTPUT)/test_syscall_vdso_32: thunks_32.S
100
$(OUTPUT)/test_syscall_vdso_32: thunks_32.S
101
$(OUTPUT)/test_fpu_64: -lm
102
$(OUTPUT)/test_fpu_32: -lm
101
103
102
# check_initial_reg_state is special: it needs a custom entry, and it
104
# check_initial_reg_state is special: it needs a custom entry, and it
103
# needs to be static so that its interpreter doesn't destroy its initial
105
# needs to be static so that its interpreter doesn't destroy its initial
(-)a/tools/testing/selftests/x86/test_fpu.c (-1 / +56 lines)
Line 0 Link Here
0
- 
1
// SPDX-License-Identifier: GPL-2.0+
2
/* This testcase operates with the test_fpu kernel driver.
3
 * It modifies the FPU control register in user mode and calls the kernel
4
 * module to perform floating point operations in the kernel. The control
5
 * register value should be independent between kernel and user mode.
6
 */
7
8
#define _GNU_SOURCE
9
#include <stdio.h>
10
#include <fenv.h>
11
#include <unistd.h>
12
#include <fcntl.h>
13
14
int main(void)
15
{
16
	char dummy[1];
17
	int fd = open("/proc/sys/debug/test_fpu", O_RDONLY);
18
19
	if (fd < 0)	{
20
		printf("[SKIP]\ttest_fpu kernel module missing\n");
21
		return 0;
22
	}
23
24
	if (read(fd, dummy, 1) != 0) {
25
		printf("[FAIL]\taccess with default rounding mode failed\n");
26
		return 1;
27
	}
28
29
	fesetround(FE_DOWNWARD);
30
	if (read(fd, dummy, 1) != 0) {
31
		printf("[FAIL]\taccess with downward rounding mode failed\n");
32
		return 2;
33
	}
34
	if (fegetround() != FE_DOWNWARD) {
35
		printf("[FAIL]\tusermode rounding mode clobbered\n");
36
		return 3;
37
	}
38
39
	/* Note: the tests up to this point are quite safe and will only return
40
	 * an error. But the exception mask setting can cause misbehaving kernel
41
	 * to crash.
42
	 */
43
	feclearexcept(FE_ALL_EXCEPT);
44
	feenableexcept(FE_ALL_EXCEPT);
45
	if (read(fd, dummy, 1) != 0) {
46
		printf("[FAIL]\taccess with fpu exceptions unmasked failed\n");
47
		return 4;
48
	}
49
	if (fegetexcept() != FE_ALL_EXCEPT) {
50
		printf("[FAIL]\tusermode fpu exception mask clobbered\n");
51
		return 5;
52
	}
53
54
	printf("[OK]\ttest_fpu\n");
55
	return 0;
56
}

Return to bug 207979