diff options
Diffstat (limited to 'arch/x86/kernel/i387.c')
| -rw-r--r-- | arch/x86/kernel/i387.c | 58 |
1 files changed, 28 insertions, 30 deletions
diff --git a/arch/x86/kernel/i387.c b/arch/x86/kernel/i387.c index a46cb3522c0c..58bb239a2fd7 100644 --- a/arch/x86/kernel/i387.c +++ b/arch/x86/kernel/i387.c | |||
| @@ -68,19 +68,22 @@ static void __cpuinit init_thread_xstate(void) | |||
| 68 | */ | 68 | */ |
| 69 | 69 | ||
| 70 | if (!HAVE_HWFP) { | 70 | if (!HAVE_HWFP) { |
| 71 | /* | ||
| 72 | * Disable xsave as we do not support it if i387 | ||
| 73 | * emulation is enabled. | ||
| 74 | */ | ||
| 75 | setup_clear_cpu_cap(X86_FEATURE_XSAVE); | ||
| 76 | setup_clear_cpu_cap(X86_FEATURE_XSAVEOPT); | ||
| 71 | xstate_size = sizeof(struct i387_soft_struct); | 77 | xstate_size = sizeof(struct i387_soft_struct); |
| 72 | return; | 78 | return; |
| 73 | } | 79 | } |
| 74 | 80 | ||
| 75 | if (cpu_has_fxsr) | 81 | if (cpu_has_fxsr) |
| 76 | xstate_size = sizeof(struct i387_fxsave_struct); | 82 | xstate_size = sizeof(struct i387_fxsave_struct); |
| 77 | #ifdef CONFIG_X86_32 | ||
| 78 | else | 83 | else |
| 79 | xstate_size = sizeof(struct i387_fsave_struct); | 84 | xstate_size = sizeof(struct i387_fsave_struct); |
| 80 | #endif | ||
| 81 | } | 85 | } |
| 82 | 86 | ||
| 83 | #ifdef CONFIG_X86_64 | ||
| 84 | /* | 87 | /* |
| 85 | * Called at bootup to set up the initial FPU state that is later cloned | 88 | * Called at bootup to set up the initial FPU state that is later cloned |
| 86 | * into all processes. | 89 | * into all processes. |
| @@ -88,12 +91,21 @@ static void __cpuinit init_thread_xstate(void) | |||
| 88 | 91 | ||
| 89 | void __cpuinit fpu_init(void) | 92 | void __cpuinit fpu_init(void) |
| 90 | { | 93 | { |
| 91 | unsigned long oldcr0 = read_cr0(); | 94 | unsigned long cr0; |
| 92 | 95 | unsigned long cr4_mask = 0; | |
| 93 | set_in_cr4(X86_CR4_OSFXSR); | ||
| 94 | set_in_cr4(X86_CR4_OSXMMEXCPT); | ||
| 95 | 96 | ||
| 96 | write_cr0(oldcr0 & ~(X86_CR0_TS|X86_CR0_EM)); /* clear TS and EM */ | 97 | if (cpu_has_fxsr) |
| 98 | cr4_mask |= X86_CR4_OSFXSR; | ||
| 99 | if (cpu_has_xmm) | ||
| 100 | cr4_mask |= X86_CR4_OSXMMEXCPT; | ||
| 101 | if (cr4_mask) | ||
| 102 | set_in_cr4(cr4_mask); | ||
| 103 | |||
| 104 | cr0 = read_cr0(); | ||
| 105 | cr0 &= ~(X86_CR0_TS|X86_CR0_EM); /* clear TS and EM */ | ||
| 106 | if (!HAVE_HWFP) | ||
| 107 | cr0 |= X86_CR0_EM; | ||
| 108 | write_cr0(cr0); | ||
| 97 | 109 | ||
| 98 | if (!smp_processor_id()) | 110 | if (!smp_processor_id()) |
| 99 | init_thread_xstate(); | 111 | init_thread_xstate(); |
| @@ -104,24 +116,12 @@ void __cpuinit fpu_init(void) | |||
| 104 | clear_used_math(); | 116 | clear_used_math(); |
| 105 | } | 117 | } |
| 106 | 118 | ||
| 107 | #else /* CONFIG_X86_64 */ | ||
| 108 | |||
| 109 | void __cpuinit fpu_init(void) | ||
| 110 | { | ||
| 111 | if (!smp_processor_id()) | ||
| 112 | init_thread_xstate(); | ||
| 113 | } | ||
| 114 | |||
| 115 | #endif /* CONFIG_X86_32 */ | ||
| 116 | |||
| 117 | void fpu_finit(struct fpu *fpu) | 119 | void fpu_finit(struct fpu *fpu) |
| 118 | { | 120 | { |
| 119 | #ifdef CONFIG_X86_32 | ||
| 120 | if (!HAVE_HWFP) { | 121 | if (!HAVE_HWFP) { |
| 121 | finit_soft_fpu(&fpu->state->soft); | 122 | finit_soft_fpu(&fpu->state->soft); |
| 122 | return; | 123 | return; |
| 123 | } | 124 | } |
| 124 | #endif | ||
| 125 | 125 | ||
| 126 | if (cpu_has_fxsr) { | 126 | if (cpu_has_fxsr) { |
| 127 | struct i387_fxsave_struct *fx = &fpu->state->fxsave; | 127 | struct i387_fxsave_struct *fx = &fpu->state->fxsave; |
| @@ -386,19 +386,17 @@ convert_from_fxsr(struct user_i387_ia32_struct *env, struct task_struct *tsk) | |||
| 386 | #ifdef CONFIG_X86_64 | 386 | #ifdef CONFIG_X86_64 |
| 387 | env->fip = fxsave->rip; | 387 | env->fip = fxsave->rip; |
| 388 | env->foo = fxsave->rdp; | 388 | env->foo = fxsave->rdp; |
| 389 | /* | ||
| 390 | * should be actually ds/cs at fpu exception time, but | ||
| 391 | * that information is not available in 64bit mode. | ||
| 392 | */ | ||
| 393 | env->fcs = task_pt_regs(tsk)->cs; | ||
| 389 | if (tsk == current) { | 394 | if (tsk == current) { |
| 390 | /* | 395 | savesegment(ds, env->fos); |
| 391 | * should be actually ds/cs at fpu exception time, but | ||
| 392 | * that information is not available in 64bit mode. | ||
| 393 | */ | ||
| 394 | asm("mov %%ds, %[fos]" : [fos] "=r" (env->fos)); | ||
| 395 | asm("mov %%cs, %[fcs]" : [fcs] "=r" (env->fcs)); | ||
| 396 | } else { | 396 | } else { |
| 397 | struct pt_regs *regs = task_pt_regs(tsk); | 397 | env->fos = tsk->thread.ds; |
| 398 | |||
| 399 | env->fos = 0xffff0000 | tsk->thread.ds; | ||
| 400 | env->fcs = regs->cs; | ||
| 401 | } | 398 | } |
| 399 | env->fos |= 0xffff0000; | ||
| 402 | #else | 400 | #else |
| 403 | env->fip = fxsave->fip; | 401 | env->fip = fxsave->fip; |
| 404 | env->fcs = (u16) fxsave->fcs | ((u32) fxsave->fop << 16); | 402 | env->fcs = (u16) fxsave->fcs | ((u32) fxsave->fop << 16); |
