init.c 5.9 KB
Newer Older
1 2 3
/*
 * x86 FPU boot time init code
 */
4
#include <asm/fpu/internal.h>
5 6
#include <asm/tlbflush.h>

7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
/*
 * Boot time CPU/FPU FDIV bug detection code:
 */

static double __initdata x = 4195835.0;
static double __initdata y = 3145727.0;

/*
 * This used to check for exceptions..
 * However, it turns out that to support that,
 * the XMM trap handlers basically had to
 * be buggy. So let's have a correct XMM trap
 * handler, and forget about printing out
 * some status at boot.
 *
 * We should really only care about bugs here
 * anyway. Not features.
 */
static void __init check_fpu(void)
{
	s32 fdiv_bug;

	kernel_fpu_begin();

	/*
	 * trap_init() enabled FXSR and company _before_ testing for FP
	 * problems here.
	 *
	 * Test for the divl bug: http://en.wikipedia.org/wiki/Fdiv_bug
	 */
	__asm__("fninit\n\t"
		"fldl %1\n\t"
		"fdivl %2\n\t"
		"fmull %2\n\t"
		"fldl %1\n\t"
		"fsubp %%st,%%st(1)\n\t"
		"fistpl %0\n\t"
		"fwait\n\t"
		"fninit"
		: "=m" (*&fdiv_bug)
		: "m" (*&x), "m" (*&y));

	kernel_fpu_end();

	if (fdiv_bug) {
		set_cpu_bug(&boot_cpu_data, X86_BUG_FDIV);
		pr_warn("Hmm, FPU with FDIV bug\n");
	}
}

void fpu__init_check_bugs(void)
{
	/*
	 * kernel_fpu_begin/end() in check_fpu() relies on the patched
	 * alternative instructions.
	 */
	if (cpu_has_fpu)
		check_fpu();
}

/*
 * Boot time FPU feature detection code:
 */
70
unsigned int mxcsr_feature_mask __read_mostly = 0xffffffffu;
71

72 73 74 75 76
unsigned int xstate_size;
EXPORT_SYMBOL_GPL(xstate_size);

static void mxcsr_feature_mask_init(void)
{
77
	unsigned int mask = 0;
78 79

	if (cpu_has_fxsr) {
80 81 82 83 84 85 86 87 88 89 90
		struct i387_fxsave_struct fx_tmp __aligned(32) = { };

		asm volatile("fxsave %0" : "+m" (fx_tmp));

		mask = fx_tmp.mxcsr_mask;

		/*
		 * If zero then use the default features mask,
		 * which has all features set, except the
		 * denormals-are-zero feature bit:
		 */
91 92 93 94 95 96 97 98
		if (mask == 0)
			mask = 0x0000ffbf;
	}
	mxcsr_feature_mask &= mask;
}

static void fpstate_xstate_init_size(void)
{
99 100 101 102 103 104
	static bool on_boot_cpu = 1;

	if (!on_boot_cpu)
		return;
	on_boot_cpu = 0;

105 106
	/*
	 * Note that xstate_size might be overwriten later during
I
Ingo Molnar 已提交
107
	 * fpu__init_system_xstate().
108 109 110 111 112 113 114 115 116 117
	 */

	if (!cpu_has_fpu) {
		/*
		 * Disable xsave as we do not support it if i387
		 * emulation is enabled.
		 */
		setup_clear_cpu_cap(X86_FEATURE_XSAVE);
		setup_clear_cpu_cap(X86_FEATURE_XSAVEOPT);
		xstate_size = sizeof(struct i387_soft_struct);
118 119 120 121 122
	} else {
		if (cpu_has_fxsr)
			xstate_size = sizeof(struct i387_fxsave_struct);
		else
			xstate_size = sizeof(struct i387_fsave_struct);
123 124 125
	}
}

126 127 128 129 130 131 132 133 134 135 136 137
/*
 * Initialize the TS bit in CR0 according to the style of context-switches
 * we are using:
 */
static void fpu__init_cpu_ctx_switch(void)
{
	if (!cpu_has_eager_fpu)
		stts();
	else
		clts();
}

138
/*
139
 * Enable all supported FPU features. Called when a CPU is brought online.
140
 */
141
void fpu__init_cpu(void)
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
{
	unsigned long cr0;
	unsigned long cr4_mask = 0;

#ifndef CONFIG_MATH_EMULATION
	if (!cpu_has_fpu) {
		pr_emerg("No FPU found and no math emulation present\n");
		pr_emerg("Giving up\n");
		for (;;)
			asm volatile("hlt");
	}
#endif
	if (cpu_has_fxsr)
		cr4_mask |= X86_CR4_OSFXSR;
	if (cpu_has_xmm)
		cr4_mask |= X86_CR4_OSXMMEXCPT;
	if (cr4_mask)
		cr4_set_bits(cr4_mask);

	cr0 = read_cr0();
	cr0 &= ~(X86_CR0_TS|X86_CR0_EM); /* clear TS and EM */
	if (!cpu_has_fpu)
		cr0 |= X86_CR0_EM;
	write_cr0(cr0);

I
Ingo Molnar 已提交
167
	fpu__init_cpu_xstate();
168
	fpu__init_cpu_ctx_switch();
169 170
}

171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
static enum { AUTO, ENABLE, DISABLE } eagerfpu = AUTO;

static int __init eager_fpu_setup(char *s)
{
	if (!strcmp(s, "on"))
		eagerfpu = ENABLE;
	else if (!strcmp(s, "off"))
		eagerfpu = DISABLE;
	else if (!strcmp(s, "auto"))
		eagerfpu = AUTO;
	return 1;
}
__setup("eagerfpu=", eager_fpu_setup);

/*
 * setup_init_fpu_buf() is __init and it is OK to call it here because
 * init_xstate_ctx will be unset only once during boot.
 */
189
static void fpu__init_system_ctx_switch(void)
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
{
	WARN_ON(current->thread.fpu.fpstate_active);
	current_thread_info()->status = 0;

	/* Auto enable eagerfpu for xsaveopt */
	if (cpu_has_xsaveopt && eagerfpu != DISABLE)
		eagerfpu = ENABLE;

	if (xfeatures_mask & XSTATE_EAGER) {
		if (eagerfpu == DISABLE) {
			pr_err("x86/fpu: eagerfpu switching disabled, disabling the following xstate features: 0x%llx.\n",
			       xfeatures_mask & XSTATE_EAGER);
			xfeatures_mask &= ~XSTATE_EAGER;
		} else {
			eagerfpu = ENABLE;
		}
	}

	if (eagerfpu == ENABLE)
		setup_force_cpu_cap(X86_FEATURE_EAGER_FPU);

	printk_once(KERN_INFO "x86/fpu: Using '%s' FPU context switches.\n", eagerfpu == ENABLE ? "eager" : "lazy");
}

214 215 216 217 218 219 220 221
/*
 * Called on the boot CPU once per system bootup, to set up the initial FPU state that
 * is later cloned into all processes.
 */
void fpu__init_system(void)
{
	/* The FPU has to be operational for some of the later FPU init activities: */
	fpu__init_cpu();
222

223 224 225 226 227 228 229
	/*
	 * But don't leave CR0::TS set yet, as some of the FPU setup methods depend
	 * on being able to execute FPU instructions that will fault on a set TS,
	 * such as the FXSAVE in mxcsr_feature_mask_init().
	 */
	clts();

230 231 232 233 234 235
	/*
	 * Set up the legacy init FPU context. (xstate init might overwrite this
	 * with a more modern format, if the CPU supports it.)
	 */
	fx_finit(&init_xstate_ctx.i387);

236
	mxcsr_feature_mask_init();
237 238

	fpstate_xstate_init_size();
I
Ingo Molnar 已提交
239
	fpu__init_system_xstate();
240

241
	fpu__init_system_ctx_switch();
242
}
243

244 245 246 247 248
void fpu__cpu_init(void)
{
	fpu__init_cpu();
}

249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279
static int __init no_387(char *s)
{
	setup_clear_cpu_cap(X86_FEATURE_FPU);
	return 1;
}

__setup("no387", no_387);

/*
 * Set the X86_FEATURE_FPU CPU-capability bit based on
 * trying to execute an actual sequence of FPU instructions:
 */
void fpu__detect(struct cpuinfo_x86 *c)
{
	unsigned long cr0;
	u16 fsw, fcw;

	fsw = fcw = 0xffff;

	cr0 = read_cr0();
	cr0 &= ~(X86_CR0_TS | X86_CR0_EM);
	write_cr0(cr0);

	asm volatile("fninit ; fnstsw %0 ; fnstcw %1"
		     : "+m" (fsw), "+m" (fcw));

	if (fsw == 0 && (fcw & 0x103f) == 0x003f)
		set_cpu_cap(c, X86_FEATURE_FPU);
	else
		clear_cpu_cap(c, X86_FEATURE_FPU);

280
	fpu__init_system();
281
	/* The final cr0 value is set later, in fpu_init() */
282
}