linux/arch/x86/kernel/xsave.c
<<
>>
Prefs
   1/*
   2 * xsave/xrstor support.
   3 *
   4 * Author: Suresh Siddha <suresh.b.siddha@intel.com>
   5 */
   6#include <linux/bootmem.h>
   7#include <linux/compat.h>
   8#include <asm/i387.h>
   9#ifdef CONFIG_IA32_EMULATION
  10#include <asm/sigcontext32.h>
  11#endif
  12#include <asm/xcr.h>
  13
  14/*
  15 * Supported feature mask by the CPU and the kernel.
  16 */
  17u64 pcntxt_mask;
  18
  19struct _fpx_sw_bytes fx_sw_reserved;
  20#ifdef CONFIG_IA32_EMULATION
  21struct _fpx_sw_bytes fx_sw_reserved_ia32;
  22#endif
  23
  24/*
  25 * Check for the presence of extended state information in the
  26 * user fpstate pointer in the sigcontext.
  27 */
  28int check_for_xstate(struct i387_fxsave_struct __user *buf,
  29                     void __user *fpstate,
  30                     struct _fpx_sw_bytes *fx_sw_user)
  31{
  32        int min_xstate_size = sizeof(struct i387_fxsave_struct) +
  33                              sizeof(struct xsave_hdr_struct);
  34        unsigned int magic2;
  35        int err;
  36
  37        err = __copy_from_user(fx_sw_user, &buf->sw_reserved[0],
  38                               sizeof(struct _fpx_sw_bytes));
  39
  40        if (err)
  41                return err;
  42
  43        /*
  44         * First Magic check failed.
  45         */
  46        if (fx_sw_user->magic1 != FP_XSTATE_MAGIC1)
  47                return -1;
  48
  49        /*
  50         * Check for error scenarios.
  51         */
  52        if (fx_sw_user->xstate_size < min_xstate_size ||
  53            fx_sw_user->xstate_size > xstate_size ||
  54            fx_sw_user->xstate_size > fx_sw_user->extended_size)
  55                return -1;
  56
  57        err = __get_user(magic2, (__u32 *) (((void *)fpstate) +
  58                                            fx_sw_user->extended_size -
  59                                            FP_XSTATE_MAGIC2_SIZE));
  60        /*
  61         * Check for the presence of second magic word at the end of memory
  62         * layout. This detects the case where the user just copied the legacy
  63         * fpstate layout with out copying the extended state information
  64         * in the memory layout.
  65         */
  66        if (err || magic2 != FP_XSTATE_MAGIC2)
  67                return -1;
  68
  69        return 0;
  70}
  71
  72#ifdef CONFIG_X86_64
  73/*
  74 * Signal frame handlers.
  75 */
  76
  77int save_i387_xstate(void __user *buf)
  78{
  79        struct task_struct *tsk = current;
  80        int err = 0;
  81
  82        if (!access_ok(VERIFY_WRITE, buf, sig_xstate_size))
  83                return -EACCES;
  84
  85        BUG_ON(sig_xstate_size < xstate_size);
  86
  87        if ((unsigned long)buf % 64)
  88                printk("save_i387_xstate: bad fpstate %p\n", buf);
  89
  90        if (!used_math())
  91                return 0;
  92
  93        if (task_thread_info(tsk)->status & TS_USEDFPU) {
  94                /*
  95                 * Start with clearing the user buffer. This will present a
  96                 * clean context for the bytes not touched by the fxsave/xsave.
  97                 */
  98                err = __clear_user(buf, sig_xstate_size);
  99                if (err)
 100                        return err;
 101
 102                if (task_thread_info(tsk)->status & TS_XSAVE)
 103                        err = xsave_user(buf);
 104                else
 105                        err = fxsave_user(buf);
 106
 107                if (err)
 108                        return err;
 109                task_thread_info(tsk)->status &= ~TS_USEDFPU;
 110                stts();
 111        } else {
 112                if (__copy_to_user(buf, &tsk->thread.xstate->fxsave,
 113                                   xstate_size))
 114                        return -1;
 115        }
 116
 117        clear_used_math(); /* trigger finit */
 118
 119        if (task_thread_info(tsk)->status & TS_XSAVE) {
 120                struct _fpstate __user *fx = buf;
 121                struct _xstate __user *x = buf;
 122                u64 xstate_bv;
 123
 124                err = __copy_to_user(&fx->sw_reserved, &fx_sw_reserved,
 125                                     sizeof(struct _fpx_sw_bytes));
 126
 127                err |= __put_user(FP_XSTATE_MAGIC2,
 128                                  (__u32 __user *) (buf + sig_xstate_size
 129                                                    - FP_XSTATE_MAGIC2_SIZE));
 130
 131                /*
 132                 * Read the xstate_bv which we copied (directly from the cpu or
 133                 * from the state in task struct) to the user buffers and
 134                 * set the FP/SSE bits.
 135                 */
 136                err |= __get_user(xstate_bv, &x->xstate_hdr.xstate_bv);
 137
 138                /*
 139                 * For legacy compatible, we always set FP/SSE bits in the bit
 140                 * vector while saving the state to the user context. This will
 141                 * enable us capturing any changes(during sigreturn) to
 142                 * the FP/SSE bits by the legacy applications which don't touch
 143                 * xstate_bv in the xsave header.
 144                 *
 145                 * xsave aware apps can change the xstate_bv in the xsave
 146                 * header as well as change any contents in the memory layout.
 147                 * xrestore as part of sigreturn will capture all the changes.
 148                 */
 149                xstate_bv |= XSTATE_FPSSE;
 150
 151                err |= __put_user(xstate_bv, &x->xstate_hdr.xstate_bv);
 152
 153                if (err)
 154                        return err;
 155        }
 156
 157        return 1;
 158}
 159
 160/*
 161 * Restore the extended state if present. Otherwise, restore the FP/SSE
 162 * state.
 163 */
 164static int restore_user_xstate(void __user *buf)
 165{
 166        struct _fpx_sw_bytes fx_sw_user;
 167        u64 mask;
 168        int err;
 169
 170        if (((unsigned long)buf % 64) ||
 171             check_for_xstate(buf, buf, &fx_sw_user))
 172                goto fx_only;
 173
 174        mask = fx_sw_user.xstate_bv;
 175
 176        /*
 177         * restore the state passed by the user.
 178         */
 179        err = xrestore_user(buf, mask);
 180        if (err)
 181                return err;
 182
 183        /*
 184         * init the state skipped by the user.
 185         */
 186        mask = pcntxt_mask & ~mask;
 187
 188        xrstor_state(init_xstate_buf, mask);
 189
 190        return 0;
 191
 192fx_only:
 193        /*
 194         * couldn't find the extended state information in the
 195         * memory layout. Restore just the FP/SSE and init all
 196         * the other extended state.
 197         */
 198        xrstor_state(init_xstate_buf, pcntxt_mask & ~XSTATE_FPSSE);
 199        return fxrstor_checking((__force struct i387_fxsave_struct *)buf);
 200}
 201
 202/*
 203 * This restores directly out of user space. Exceptions are handled.
 204 */
 205int restore_i387_xstate(void __user *buf)
 206{
 207        struct task_struct *tsk = current;
 208        int err = 0;
 209
 210        if (!buf) {
 211                if (used_math())
 212                        goto clear;
 213                return 0;
 214        } else
 215                if (!access_ok(VERIFY_READ, buf, sig_xstate_size))
 216                        return -EACCES;
 217
 218        if (!used_math()) {
 219                err = init_fpu(tsk);
 220                if (err)
 221                        return err;
 222        }
 223
 224        if (!(task_thread_info(current)->status & TS_USEDFPU)) {
 225                clts();
 226                task_thread_info(current)->status |= TS_USEDFPU;
 227        }
 228        if (task_thread_info(tsk)->status & TS_XSAVE)
 229                err = restore_user_xstate(buf);
 230        else
 231                err = fxrstor_checking((__force struct i387_fxsave_struct *)
 232                                       buf);
 233        if (unlikely(err)) {
 234                /*
 235                 * Encountered an error while doing the restore from the
 236                 * user buffer, clear the fpu state.
 237                 */
 238clear:
 239                clear_fpu(tsk);
 240                clear_used_math();
 241        }
 242        return err;
 243}
 244#endif
 245
 246/*
 247 * Prepare the SW reserved portion of the fxsave memory layout, indicating
 248 * the presence of the extended state information in the memory layout
 249 * pointed by the fpstate pointer in the sigcontext.
 250 * This will be saved when ever the FP and extended state context is
 251 * saved on the user stack during the signal handler delivery to the user.
 252 */
 253static void prepare_fx_sw_frame(void)
 254{
 255        int size_extended = (xstate_size - sizeof(struct i387_fxsave_struct)) +
 256                             FP_XSTATE_MAGIC2_SIZE;
 257
 258        sig_xstate_size = sizeof(struct _fpstate) + size_extended;
 259
 260#ifdef CONFIG_IA32_EMULATION
 261        sig_xstate_ia32_size = sizeof(struct _fpstate_ia32) + size_extended;
 262#endif
 263
 264        memset(&fx_sw_reserved, 0, sizeof(fx_sw_reserved));
 265
 266        fx_sw_reserved.magic1 = FP_XSTATE_MAGIC1;
 267        fx_sw_reserved.extended_size = sig_xstate_size;
 268        fx_sw_reserved.xstate_bv = pcntxt_mask;
 269        fx_sw_reserved.xstate_size = xstate_size;
 270#ifdef CONFIG_IA32_EMULATION
 271        memcpy(&fx_sw_reserved_ia32, &fx_sw_reserved,
 272               sizeof(struct _fpx_sw_bytes));
 273        fx_sw_reserved_ia32.extended_size = sig_xstate_ia32_size;
 274#endif
 275}
 276
 277/*
 278 * Represents init state for the supported extended state.
 279 */
 280struct xsave_struct *init_xstate_buf;
 281
 282#ifdef CONFIG_X86_64
 283unsigned int sig_xstate_size = sizeof(struct _fpstate);
 284#endif
 285
 286/*
 287 * Enable the extended processor state save/restore feature
 288 */
 289void __cpuinit xsave_init(void)
 290{
 291        if (!cpu_has_xsave)
 292                return;
 293
 294        set_in_cr4(X86_CR4_OSXSAVE);
 295
 296        /*
 297         * Enable all the features that the HW is capable of
 298         * and the Linux kernel is aware of.
 299         */
 300        xsetbv(XCR_XFEATURE_ENABLED_MASK, pcntxt_mask);
 301}
 302
 303/*
 304 * setup the xstate image representing the init state
 305 */
 306static void __init setup_xstate_init(void)
 307{
 308        init_xstate_buf = alloc_bootmem(xstate_size);
 309        init_xstate_buf->i387.mxcsr = MXCSR_DEFAULT;
 310}
 311
 312/*
 313 * Enable and initialize the xsave feature.
 314 */
 315void __ref xsave_cntxt_init(void)
 316{
 317        unsigned int eax, ebx, ecx, edx;
 318
 319        cpuid_count(0xd, 0, &eax, &ebx, &ecx, &edx);
 320        pcntxt_mask = eax + ((u64)edx << 32);
 321
 322        if ((pcntxt_mask & XSTATE_FPSSE) != XSTATE_FPSSE) {
 323                printk(KERN_ERR "FP/SSE not shown under xsave features 0x%llx\n",
 324                       pcntxt_mask);
 325                BUG();
 326        }
 327
 328        /*
 329         * Support only the state known to OS.
 330         */
 331        pcntxt_mask = pcntxt_mask & XCNTXT_MASK;
 332        xsave_init();
 333
 334        /*
 335         * Recompute the context size for enabled features
 336         */
 337        cpuid_count(0xd, 0, &eax, &ebx, &ecx, &edx);
 338        xstate_size = ebx;
 339
 340        prepare_fx_sw_frame();
 341
 342        setup_xstate_init();
 343
 344        printk(KERN_INFO "xsave/xrstor: enabled xstate_bv 0x%llx, "
 345               "cntxt size 0x%x\n",
 346               pcntxt_mask, xstate_size);
 347}
 348