linux/include/asm-x86/i387.h
<<
>>
Prefs
   1/*
   2 * Copyright (C) 1994 Linus Torvalds
   3 *
   4 * Pentium III FXSR, SSE support
   5 * General FPU state handling cleanups
   6 *      Gareth Hughes <gareth@valinux.com>, May 2000
   7 * x86-64 work by Andi Kleen 2002
   8 */
   9
  10#ifndef _ASM_X86_I387_H
  11#define _ASM_X86_I387_H
  12
  13#include <linux/sched.h>
  14#include <linux/kernel_stat.h>
  15#include <linux/regset.h>
  16#include <asm/asm.h>
  17#include <asm/processor.h>
  18#include <asm/sigcontext.h>
  19#include <asm/user.h>
  20#include <asm/uaccess.h>
  21
  22extern void fpu_init(void);
  23extern void mxcsr_feature_mask_init(void);
  24extern void init_fpu(struct task_struct *child);
  25extern asmlinkage void math_state_restore(void);
  26
  27extern user_regset_active_fn fpregs_active, xfpregs_active;
  28extern user_regset_get_fn fpregs_get, xfpregs_get, fpregs_soft_get;
  29extern user_regset_set_fn fpregs_set, xfpregs_set, fpregs_soft_set;
  30
  31#ifdef CONFIG_IA32_EMULATION
  32struct _fpstate_ia32;
  33extern int save_i387_ia32(struct _fpstate_ia32 __user *buf);
  34extern int restore_i387_ia32(struct _fpstate_ia32 __user *buf);
  35#endif
  36
  37#ifdef CONFIG_X86_64
  38
  39/* Ignore delayed exceptions from user space */
  40static inline void tolerant_fwait(void)
  41{
  42        asm volatile("1: fwait\n"
  43                     "2:\n"
  44                     _ASM_EXTABLE(1b,2b));
  45}
  46
  47static inline int restore_fpu_checking(struct i387_fxsave_struct *fx)
  48{
  49        int err;
  50
  51        asm volatile("1:  rex64/fxrstor (%[fx])\n\t"
  52                     "2:\n"
  53                     ".section .fixup,\"ax\"\n"
  54                     "3:  movl $-1,%[err]\n"
  55                     "    jmp  2b\n"
  56                     ".previous\n"
  57                     _ASM_EXTABLE(1b,3b)
  58                     : [err] "=r" (err)
  59#if 0 /* See comment in __save_init_fpu() below. */
  60                     : [fx] "r" (fx), "m" (*fx), "0" (0));
  61#else
  62                     : [fx] "cdaSDb" (fx), "m" (*fx), "0" (0));
  63#endif
  64        if (unlikely(err))
  65                init_fpu(current);
  66        return err;
  67}
  68
  69#define X87_FSW_ES (1 << 7)     /* Exception Summary */
  70
  71/* AMD CPUs don't save/restore FDP/FIP/FOP unless an exception
  72   is pending. Clear the x87 state here by setting it to fixed
  73   values. The kernel data segment can be sometimes 0 and sometimes
  74   new user value. Both should be ok.
  75   Use the PDA as safe address because it should be already in L1. */
  76static inline void clear_fpu_state(struct i387_fxsave_struct *fx)
  77{
  78        if (unlikely(fx->swd & X87_FSW_ES))
  79                 asm volatile("fnclex");
  80        alternative_input(ASM_NOP8 ASM_NOP2,
  81                     "    emms\n"               /* clear stack tags */
  82                     "    fildl %%gs:0",        /* load to clear state */
  83                     X86_FEATURE_FXSAVE_LEAK);
  84}
  85
  86static inline int save_i387_checking(struct i387_fxsave_struct __user *fx)
  87{
  88        int err;
  89
  90        asm volatile("1:  rex64/fxsave (%[fx])\n\t"
  91                     "2:\n"
  92                     ".section .fixup,\"ax\"\n"
  93                     "3:  movl $-1,%[err]\n"
  94                     "    jmp  2b\n"
  95                     ".previous\n"
  96                     _ASM_EXTABLE(1b,3b)
  97                     : [err] "=r" (err), "=m" (*fx)
  98#if 0 /* See comment in __fxsave_clear() below. */
  99                     : [fx] "r" (fx), "0" (0));
 100#else
 101                     : [fx] "cdaSDb" (fx), "0" (0));
 102#endif
 103        if (unlikely(err) && __clear_user(fx, sizeof(struct i387_fxsave_struct)))
 104                err = -EFAULT;
 105        /* No need to clear here because the caller clears USED_MATH */
 106        return err;
 107}
 108
 109static inline void __save_init_fpu(struct task_struct *tsk)
 110{
 111        /* Using "rex64; fxsave %0" is broken because, if the memory operand
 112           uses any extended registers for addressing, a second REX prefix
 113           will be generated (to the assembler, rex64 followed by semicolon
 114           is a separate instruction), and hence the 64-bitness is lost. */
 115#if 0
 116        /* Using "fxsaveq %0" would be the ideal choice, but is only supported
 117           starting with gas 2.16. */
 118        __asm__ __volatile__("fxsaveq %0"
 119                             : "=m" (tsk->thread.i387.fxsave));
 120#elif 0
 121        /* Using, as a workaround, the properly prefixed form below isn't
 122           accepted by any binutils version so far released, complaining that
 123           the same type of prefix is used twice if an extended register is
 124           needed for addressing (fix submitted to mainline 2005-11-21). */
 125        __asm__ __volatile__("rex64/fxsave %0"
 126                             : "=m" (tsk->thread.i387.fxsave));
 127#else
 128        /* This, however, we can work around by forcing the compiler to select
 129           an addressing mode that doesn't require extended registers. */
 130        __asm__ __volatile__("rex64/fxsave %P2(%1)"
 131                             : "=m" (tsk->thread.i387.fxsave)
 132                             : "cdaSDb" (tsk),
 133                                "i" (offsetof(__typeof__(*tsk),
 134                                              thread.i387.fxsave)));
 135#endif
 136        clear_fpu_state(&tsk->thread.i387.fxsave);
 137        task_thread_info(tsk)->status &= ~TS_USEDFPU;
 138}
 139
 140/*
 141 * Signal frame handlers.
 142 */
 143
 144static inline int save_i387(struct _fpstate __user *buf)
 145{
 146        struct task_struct *tsk = current;
 147        int err = 0;
 148
 149        BUILD_BUG_ON(sizeof(struct user_i387_struct) !=
 150                        sizeof(tsk->thread.i387.fxsave));
 151
 152        if ((unsigned long)buf % 16)
 153                printk("save_i387: bad fpstate %p\n", buf);
 154
 155        if (!used_math())
 156                return 0;
 157        clear_used_math(); /* trigger finit */
 158        if (task_thread_info(tsk)->status & TS_USEDFPU) {
 159                err = save_i387_checking((struct i387_fxsave_struct __user *)buf);
 160                if (err) return err;
 161                task_thread_info(tsk)->status &= ~TS_USEDFPU;
 162                stts();
 163        } else {
 164                if (__copy_to_user(buf, &tsk->thread.i387.fxsave,
 165                                   sizeof(struct i387_fxsave_struct)))
 166                        return -1;
 167        }
 168        return 1;
 169}
 170
 171/*
 172 * This restores directly out of user space. Exceptions are handled.
 173 */
 174static inline int restore_i387(struct _fpstate __user *buf)
 175{
 176        set_used_math();
 177        if (!(task_thread_info(current)->status & TS_USEDFPU)) {
 178                clts();
 179                task_thread_info(current)->status |= TS_USEDFPU;
 180        }
 181        return restore_fpu_checking((__force struct i387_fxsave_struct *)buf);
 182}
 183
 184#else  /* CONFIG_X86_32 */
 185
 186static inline void tolerant_fwait(void)
 187{
 188        asm volatile("fnclex ; fwait");
 189}
 190
 191static inline void restore_fpu(struct task_struct *tsk)
 192{
 193        /*
 194         * The "nop" is needed to make the instructions the same
 195         * length.
 196         */
 197        alternative_input(
 198                "nop ; frstor %1",
 199                "fxrstor %1",
 200                X86_FEATURE_FXSR,
 201                "m" ((tsk)->thread.i387.fxsave));
 202}
 203
 204/* We need a safe address that is cheap to find and that is already
 205   in L1 during context switch. The best choices are unfortunately
 206   different for UP and SMP */
 207#ifdef CONFIG_SMP
 208#define safe_address (__per_cpu_offset[0])
 209#else
 210#define safe_address (kstat_cpu(0).cpustat.user)
 211#endif
 212
 213/*
 214 * These must be called with preempt disabled
 215 */
 216static inline void __save_init_fpu(struct task_struct *tsk)
 217{
 218        /* Use more nops than strictly needed in case the compiler
 219           varies code */
 220        alternative_input(
 221                "fnsave %[fx] ;fwait;" GENERIC_NOP8 GENERIC_NOP4,
 222                "fxsave %[fx]\n"
 223                "bt $7,%[fsw] ; jnc 1f ; fnclex\n1:",
 224                X86_FEATURE_FXSR,
 225                [fx] "m" (tsk->thread.i387.fxsave),
 226                [fsw] "m" (tsk->thread.i387.fxsave.swd) : "memory");
 227        /* AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception
 228           is pending.  Clear the x87 state here by setting it to fixed
 229           values. safe_address is a random variable that should be in L1 */
 230        alternative_input(
 231                GENERIC_NOP8 GENERIC_NOP2,
 232                "emms\n\t"              /* clear stack tags */
 233                "fildl %[addr]",        /* set F?P to defined value */
 234                X86_FEATURE_FXSAVE_LEAK,
 235                [addr] "m" (safe_address));
 236        task_thread_info(tsk)->status &= ~TS_USEDFPU;
 237}
 238
 239/*
 240 * Signal frame handlers...
 241 */
 242extern int save_i387(struct _fpstate __user *buf);
 243extern int restore_i387(struct _fpstate __user *buf);
 244
 245#endif  /* CONFIG_X86_64 */
 246
 247static inline void __unlazy_fpu(struct task_struct *tsk)
 248{
 249        if (task_thread_info(tsk)->status & TS_USEDFPU) {
 250                __save_init_fpu(tsk);
 251                stts();
 252        } else
 253                tsk->fpu_counter = 0;
 254}
 255
 256static inline void __clear_fpu(struct task_struct *tsk)
 257{
 258        if (task_thread_info(tsk)->status & TS_USEDFPU) {
 259                tolerant_fwait();
 260                task_thread_info(tsk)->status &= ~TS_USEDFPU;
 261                stts();
 262        }
 263}
 264
 265static inline void kernel_fpu_begin(void)
 266{
 267        struct thread_info *me = current_thread_info();
 268        preempt_disable();
 269        if (me->status & TS_USEDFPU)
 270                __save_init_fpu(me->task);
 271        else
 272                clts();
 273}
 274
 275static inline void kernel_fpu_end(void)
 276{
 277        stts();
 278        preempt_enable();
 279}
 280
 281#ifdef CONFIG_X86_64
 282
 283static inline void save_init_fpu(struct task_struct *tsk)
 284{
 285        __save_init_fpu(tsk);
 286        stts();
 287}
 288
 289#define unlazy_fpu      __unlazy_fpu
 290#define clear_fpu       __clear_fpu
 291
 292#else  /* CONFIG_X86_32 */
 293
 294/*
 295 * These disable preemption on their own and are safe
 296 */
 297static inline void save_init_fpu(struct task_struct *tsk)
 298{
 299        preempt_disable();
 300        __save_init_fpu(tsk);
 301        stts();
 302        preempt_enable();
 303}
 304
 305static inline void unlazy_fpu(struct task_struct *tsk)
 306{
 307        preempt_disable();
 308        __unlazy_fpu(tsk);
 309        preempt_enable();
 310}
 311
 312static inline void clear_fpu(struct task_struct *tsk)
 313{
 314        preempt_disable();
 315        __clear_fpu(tsk);
 316        preempt_enable();
 317}
 318
 319#endif  /* CONFIG_X86_64 */
 320
 321/*
 322 * i387 state interaction
 323 */
 324static inline unsigned short get_fpu_cwd(struct task_struct *tsk)
 325{
 326        if (cpu_has_fxsr) {
 327                return tsk->thread.i387.fxsave.cwd;
 328        } else {
 329                return (unsigned short)tsk->thread.i387.fsave.cwd;
 330        }
 331}
 332
 333static inline unsigned short get_fpu_swd(struct task_struct *tsk)
 334{
 335        if (cpu_has_fxsr) {
 336                return tsk->thread.i387.fxsave.swd;
 337        } else {
 338                return (unsigned short)tsk->thread.i387.fsave.swd;
 339        }
 340}
 341
 342static inline unsigned short get_fpu_mxcsr(struct task_struct *tsk)
 343{
 344        if (cpu_has_xmm) {
 345                return tsk->thread.i387.fxsave.mxcsr;
 346        } else {
 347                return MXCSR_DEFAULT;
 348        }
 349}
 350
 351#endif  /* _ASM_X86_I387_H */
 352
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.