diff options
| author | Ingo Molnar <mingo@elte.hu> | 2008-09-05 03:18:39 -0400 |
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2008-09-05 03:18:39 -0400 |
| commit | accf0fa697eeb5ff4c2360edc4da5b10abac0b7b (patch) | |
| tree | a57dc9aa4a6b83be8ac8b4528cf06db5621e62aa /include | |
| parent | ebd60cd64f8ab1170102c3ab072eb73042b7a33d (diff) | |
| parent | fe47784ba5cbb6b713c013e046859946789b45e4 (diff) | |
Merge branch 'x86/xsave' into x86/core
Diffstat (limited to 'include')
| -rw-r--r-- | include/asm-x86/i387.h | 84 | ||||
| -rw-r--r-- | include/asm-x86/processor-flags.h | 1 | ||||
| -rw-r--r-- | include/asm-x86/processor.h | 20 | ||||
| -rw-r--r-- | include/asm-x86/sigcontext.h | 87 | ||||
| -rw-r--r-- | include/asm-x86/sigcontext32.h | 6 | ||||
| -rw-r--r-- | include/asm-x86/thread_info.h | 1 | ||||
| -rw-r--r-- | include/asm-x86/ucontext.h | 6 | ||||
| -rw-r--r-- | include/asm-x86/xcr.h | 49 | ||||
| -rw-r--r-- | include/asm-x86/xsave.h | 118 |
9 files changed, 354 insertions, 18 deletions
diff --git a/include/asm-x86/i387.h b/include/asm-x86/i387.h index 1ecdc3ed96e4..9ba862a4eac0 100644 --- a/include/asm-x86/i387.h +++ b/include/asm-x86/i387.h | |||
| @@ -19,7 +19,9 @@ | |||
| 19 | #include <asm/sigcontext.h> | 19 | #include <asm/sigcontext.h> |
| 20 | #include <asm/user.h> | 20 | #include <asm/user.h> |
| 21 | #include <asm/uaccess.h> | 21 | #include <asm/uaccess.h> |
| 22 | #include <asm/xsave.h> | ||
| 22 | 23 | ||
| 24 | extern unsigned int sig_xstate_size; | ||
| 23 | extern void fpu_init(void); | 25 | extern void fpu_init(void); |
| 24 | extern void mxcsr_feature_mask_init(void); | 26 | extern void mxcsr_feature_mask_init(void); |
| 25 | extern int init_fpu(struct task_struct *child); | 27 | extern int init_fpu(struct task_struct *child); |
| @@ -31,12 +33,18 @@ extern user_regset_active_fn fpregs_active, xfpregs_active; | |||
| 31 | extern user_regset_get_fn fpregs_get, xfpregs_get, fpregs_soft_get; | 33 | extern user_regset_get_fn fpregs_get, xfpregs_get, fpregs_soft_get; |
| 32 | extern user_regset_set_fn fpregs_set, xfpregs_set, fpregs_soft_set; | 34 | extern user_regset_set_fn fpregs_set, xfpregs_set, fpregs_soft_set; |
| 33 | 35 | ||
| 36 | extern struct _fpx_sw_bytes fx_sw_reserved; | ||
| 34 | #ifdef CONFIG_IA32_EMULATION | 37 | #ifdef CONFIG_IA32_EMULATION |
| 38 | extern unsigned int sig_xstate_ia32_size; | ||
| 39 | extern struct _fpx_sw_bytes fx_sw_reserved_ia32; | ||
| 35 | struct _fpstate_ia32; | 40 | struct _fpstate_ia32; |
| 36 | extern int save_i387_ia32(struct _fpstate_ia32 __user *buf); | 41 | struct _xstate_ia32; |
| 37 | extern int restore_i387_ia32(struct _fpstate_ia32 __user *buf); | 42 | extern int save_i387_xstate_ia32(void __user *buf); |
| 43 | extern int restore_i387_xstate_ia32(void __user *buf); | ||
| 38 | #endif | 44 | #endif |
| 39 | 45 | ||
| 46 | #define X87_FSW_ES (1 << 7) /* Exception Summary */ | ||
| 47 | |||
| 40 | #ifdef CONFIG_X86_64 | 48 | #ifdef CONFIG_X86_64 |
| 41 | 49 | ||
| 42 | /* Ignore delayed exceptions from user space */ | 50 | /* Ignore delayed exceptions from user space */ |
| @@ -47,7 +55,7 @@ static inline void tolerant_fwait(void) | |||
| 47 | _ASM_EXTABLE(1b, 2b)); | 55 | _ASM_EXTABLE(1b, 2b)); |
| 48 | } | 56 | } |
| 49 | 57 | ||
| 50 | static inline int restore_fpu_checking(struct i387_fxsave_struct *fx) | 58 | static inline int fxrstor_checking(struct i387_fxsave_struct *fx) |
| 51 | { | 59 | { |
| 52 | int err; | 60 | int err; |
| 53 | 61 | ||
| @@ -67,15 +75,31 @@ static inline int restore_fpu_checking(struct i387_fxsave_struct *fx) | |||
| 67 | return err; | 75 | return err; |
| 68 | } | 76 | } |
| 69 | 77 | ||
| 70 | #define X87_FSW_ES (1 << 7) /* Exception Summary */ | 78 | static inline int restore_fpu_checking(struct task_struct *tsk) |
| 79 | { | ||
| 80 | if (task_thread_info(tsk)->status & TS_XSAVE) | ||
| 81 | return xrstor_checking(&tsk->thread.xstate->xsave); | ||
| 82 | else | ||
| 83 | return fxrstor_checking(&tsk->thread.xstate->fxsave); | ||
| 84 | } | ||
| 71 | 85 | ||
| 72 | /* AMD CPUs don't save/restore FDP/FIP/FOP unless an exception | 86 | /* AMD CPUs don't save/restore FDP/FIP/FOP unless an exception |
| 73 | is pending. Clear the x87 state here by setting it to fixed | 87 | is pending. Clear the x87 state here by setting it to fixed |
| 74 | values. The kernel data segment can be sometimes 0 and sometimes | 88 | values. The kernel data segment can be sometimes 0 and sometimes |
| 75 | new user value. Both should be ok. | 89 | new user value. Both should be ok. |
| 76 | Use the PDA as safe address because it should be already in L1. */ | 90 | Use the PDA as safe address because it should be already in L1. */ |
| 77 | static inline void clear_fpu_state(struct i387_fxsave_struct *fx) | 91 | static inline void clear_fpu_state(struct task_struct *tsk) |
| 78 | { | 92 | { |
| 93 | struct xsave_struct *xstate = &tsk->thread.xstate->xsave; | ||
| 94 | struct i387_fxsave_struct *fx = &tsk->thread.xstate->fxsave; | ||
| 95 | |||
| 96 | /* | ||
| 97 | * xsave header may indicate the init state of the FP. | ||
| 98 | */ | ||
| 99 | if ((task_thread_info(tsk)->status & TS_XSAVE) && | ||
| 100 | !(xstate->xsave_hdr.xstate_bv & XSTATE_FP)) | ||
| 101 | return; | ||
| 102 | |||
| 79 | if (unlikely(fx->swd & X87_FSW_ES)) | 103 | if (unlikely(fx->swd & X87_FSW_ES)) |
| 80 | asm volatile("fnclex"); | 104 | asm volatile("fnclex"); |
| 81 | alternative_input(ASM_NOP8 ASM_NOP2, | 105 | alternative_input(ASM_NOP8 ASM_NOP2, |
| @@ -84,7 +108,7 @@ static inline void clear_fpu_state(struct i387_fxsave_struct *fx) | |||
| 84 | X86_FEATURE_FXSAVE_LEAK); | 108 | X86_FEATURE_FXSAVE_LEAK); |
| 85 | } | 109 | } |
| 86 | 110 | ||
| 87 | static inline int save_i387_checking(struct i387_fxsave_struct __user *fx) | 111 | static inline int fxsave_user(struct i387_fxsave_struct __user *fx) |
| 88 | { | 112 | { |
| 89 | int err; | 113 | int err; |
| 90 | 114 | ||
| @@ -108,7 +132,7 @@ static inline int save_i387_checking(struct i387_fxsave_struct __user *fx) | |||
| 108 | return err; | 132 | return err; |
| 109 | } | 133 | } |
| 110 | 134 | ||
| 111 | static inline void __save_init_fpu(struct task_struct *tsk) | 135 | static inline void fxsave(struct task_struct *tsk) |
| 112 | { | 136 | { |
| 113 | /* Using "rex64; fxsave %0" is broken because, if the memory operand | 137 | /* Using "rex64; fxsave %0" is broken because, if the memory operand |
| 114 | uses any extended registers for addressing, a second REX prefix | 138 | uses any extended registers for addressing, a second REX prefix |
| @@ -133,7 +157,16 @@ static inline void __save_init_fpu(struct task_struct *tsk) | |||
| 133 | : "=m" (tsk->thread.xstate->fxsave) | 157 | : "=m" (tsk->thread.xstate->fxsave) |
| 134 | : "cdaSDb" (&tsk->thread.xstate->fxsave)); | 158 | : "cdaSDb" (&tsk->thread.xstate->fxsave)); |
| 135 | #endif | 159 | #endif |
| 136 | clear_fpu_state(&tsk->thread.xstate->fxsave); | 160 | } |
| 161 | |||
| 162 | static inline void __save_init_fpu(struct task_struct *tsk) | ||
| 163 | { | ||
| 164 | if (task_thread_info(tsk)->status & TS_XSAVE) | ||
| 165 | xsave(tsk); | ||
| 166 | else | ||
| 167 | fxsave(tsk); | ||
| 168 | |||
| 169 | clear_fpu_state(tsk); | ||
| 137 | task_thread_info(tsk)->status &= ~TS_USEDFPU; | 170 | task_thread_info(tsk)->status &= ~TS_USEDFPU; |
| 138 | } | 171 | } |
| 139 | 172 | ||
| @@ -148,6 +181,10 @@ static inline void tolerant_fwait(void) | |||
| 148 | 181 | ||
| 149 | static inline void restore_fpu(struct task_struct *tsk) | 182 | static inline void restore_fpu(struct task_struct *tsk) |
| 150 | { | 183 | { |
| 184 | if (task_thread_info(tsk)->status & TS_XSAVE) { | ||
| 185 | xrstor_checking(&tsk->thread.xstate->xsave); | ||
| 186 | return; | ||
| 187 | } | ||
| 151 | /* | 188 | /* |
| 152 | * The "nop" is needed to make the instructions the same | 189 | * The "nop" is needed to make the instructions the same |
| 153 | * length. | 190 | * length. |
| @@ -173,6 +210,27 @@ static inline void restore_fpu(struct task_struct *tsk) | |||
| 173 | */ | 210 | */ |
| 174 | static inline void __save_init_fpu(struct task_struct *tsk) | 211 | static inline void __save_init_fpu(struct task_struct *tsk) |
| 175 | { | 212 | { |
| 213 | if (task_thread_info(tsk)->status & TS_XSAVE) { | ||
| 214 | struct xsave_struct *xstate = &tsk->thread.xstate->xsave; | ||
| 215 | struct i387_fxsave_struct *fx = &tsk->thread.xstate->fxsave; | ||
| 216 | |||
| 217 | xsave(tsk); | ||
| 218 | |||
| 219 | /* | ||
| 220 | * xsave header may indicate the init state of the FP. | ||
| 221 | */ | ||
| 222 | if (!(xstate->xsave_hdr.xstate_bv & XSTATE_FP)) | ||
| 223 | goto end; | ||
| 224 | |||
| 225 | if (unlikely(fx->swd & X87_FSW_ES)) | ||
| 226 | asm volatile("fnclex"); | ||
| 227 | |||
| 228 | /* | ||
| 229 | * we can do a simple return here or be paranoid :) | ||
| 230 | */ | ||
| 231 | goto clear_state; | ||
| 232 | } | ||
| 233 | |||
| 176 | /* Use more nops than strictly needed in case the compiler | 234 | /* Use more nops than strictly needed in case the compiler |
| 177 | varies code */ | 235 | varies code */ |
| 178 | alternative_input( | 236 | alternative_input( |
| @@ -182,6 +240,7 @@ static inline void __save_init_fpu(struct task_struct *tsk) | |||
| 182 | X86_FEATURE_FXSR, | 240 | X86_FEATURE_FXSR, |
| 183 | [fx] "m" (tsk->thread.xstate->fxsave), | 241 | [fx] "m" (tsk->thread.xstate->fxsave), |
| 184 | [fsw] "m" (tsk->thread.xstate->fxsave.swd) : "memory"); | 242 | [fsw] "m" (tsk->thread.xstate->fxsave.swd) : "memory"); |
| 243 | clear_state: | ||
| 185 | /* AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception | 244 | /* AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception |
| 186 | is pending. Clear the x87 state here by setting it to fixed | 245 | is pending. Clear the x87 state here by setting it to fixed |
| 187 | values. safe_address is a random variable that should be in L1 */ | 246 | values. safe_address is a random variable that should be in L1 */ |
| @@ -191,16 +250,17 @@ static inline void __save_init_fpu(struct task_struct *tsk) | |||
| 191 | "fildl %[addr]", /* set F?P to defined value */ | 250 | "fildl %[addr]", /* set F?P to defined value */ |
| 192 | X86_FEATURE_FXSAVE_LEAK, | 251 | X86_FEATURE_FXSAVE_LEAK, |
| 193 | [addr] "m" (safe_address)); | 252 | [addr] "m" (safe_address)); |
| 253 | end: | ||
| 194 | task_thread_info(tsk)->status &= ~TS_USEDFPU; | 254 | task_thread_info(tsk)->status &= ~TS_USEDFPU; |
| 195 | } | 255 | } |
| 196 | 256 | ||
| 257 | #endif /* CONFIG_X86_64 */ | ||
| 258 | |||
| 197 | /* | 259 | /* |
| 198 | * Signal frame handlers... | 260 | * Signal frame handlers... |
| 199 | */ | 261 | */ |
| 200 | extern int save_i387(struct _fpstate __user *buf); | 262 | extern int save_i387_xstate(void __user *buf); |
| 201 | extern int restore_i387(struct _fpstate __user *buf); | 263 | extern int restore_i387_xstate(void __user *buf); |
| 202 | |||
| 203 | #endif /* CONFIG_X86_64 */ | ||
| 204 | 264 | ||
| 205 | static inline void __unlazy_fpu(struct task_struct *tsk) | 265 | static inline void __unlazy_fpu(struct task_struct *tsk) |
| 206 | { | 266 | { |
diff --git a/include/asm-x86/processor-flags.h b/include/asm-x86/processor-flags.h index 5dd79774f693..dc5f0712f9fa 100644 --- a/include/asm-x86/processor-flags.h +++ b/include/asm-x86/processor-flags.h | |||
| @@ -59,6 +59,7 @@ | |||
| 59 | #define X86_CR4_OSFXSR 0x00000200 /* enable fast FPU save and restore */ | 59 | #define X86_CR4_OSFXSR 0x00000200 /* enable fast FPU save and restore */ |
| 60 | #define X86_CR4_OSXMMEXCPT 0x00000400 /* enable unmasked SSE exceptions */ | 60 | #define X86_CR4_OSXMMEXCPT 0x00000400 /* enable unmasked SSE exceptions */ |
| 61 | #define X86_CR4_VMXE 0x00002000 /* enable VMX virtualization */ | 61 | #define X86_CR4_VMXE 0x00002000 /* enable VMX virtualization */ |
| 62 | #define X86_CR4_OSXSAVE 0x00040000 /* enable xsave and xrestore */ | ||
| 62 | 63 | ||
| 63 | /* | 64 | /* |
| 64 | * x86-64 Task Priority Register, CR8 | 65 | * x86-64 Task Priority Register, CR8 |
diff --git a/include/asm-x86/processor.h b/include/asm-x86/processor.h index 10471cfab145..df03c98e38d4 100644 --- a/include/asm-x86/processor.h +++ b/include/asm-x86/processor.h | |||
| @@ -326,7 +326,12 @@ struct i387_fxsave_struct { | |||
| 326 | /* 16*16 bytes for each XMM-reg = 256 bytes: */ | 326 | /* 16*16 bytes for each XMM-reg = 256 bytes: */ |
| 327 | u32 xmm_space[64]; | 327 | u32 xmm_space[64]; |
| 328 | 328 | ||
| 329 | u32 padding[24]; | 329 | u32 padding[12]; |
| 330 | |||
| 331 | union { | ||
| 332 | u32 padding1[12]; | ||
| 333 | u32 sw_reserved[12]; | ||
| 334 | }; | ||
| 330 | 335 | ||
| 331 | } __attribute__((aligned(16))); | 336 | } __attribute__((aligned(16))); |
| 332 | 337 | ||
| @@ -350,10 +355,23 @@ struct i387_soft_struct { | |||
| 350 | u32 entry_eip; | 355 | u32 entry_eip; |
| 351 | }; | 356 | }; |
| 352 | 357 | ||
| 358 | struct xsave_hdr_struct { | ||
| 359 | u64 xstate_bv; | ||
| 360 | u64 reserved1[2]; | ||
| 361 | u64 reserved2[5]; | ||
| 362 | } __attribute__((packed)); | ||
| 363 | |||
| 364 | struct xsave_struct { | ||
| 365 | struct i387_fxsave_struct i387; | ||
| 366 | struct xsave_hdr_struct xsave_hdr; | ||
| 367 | /* new processor state extensions will go here */ | ||
| 368 | } __attribute__ ((packed, aligned (64))); | ||
| 369 | |||
| 353 | union thread_xstate { | 370 | union thread_xstate { |
| 354 | struct i387_fsave_struct fsave; | 371 | struct i387_fsave_struct fsave; |
| 355 | struct i387_fxsave_struct fxsave; | 372 | struct i387_fxsave_struct fxsave; |
| 356 | struct i387_soft_struct soft; | 373 | struct i387_soft_struct soft; |
| 374 | struct xsave_struct xsave; | ||
| 357 | }; | 375 | }; |
| 358 | 376 | ||
| 359 | #ifdef CONFIG_X86_64 | 377 | #ifdef CONFIG_X86_64 |
diff --git a/include/asm-x86/sigcontext.h b/include/asm-x86/sigcontext.h index 24879c85b291..ee813f4fe5d5 100644 --- a/include/asm-x86/sigcontext.h +++ b/include/asm-x86/sigcontext.h | |||
| @@ -4,6 +4,40 @@ | |||
| 4 | #include <linux/compiler.h> | 4 | #include <linux/compiler.h> |
| 5 | #include <asm/types.h> | 5 | #include <asm/types.h> |
| 6 | 6 | ||
| 7 | #define FP_XSTATE_MAGIC1 0x46505853U | ||
| 8 | #define FP_XSTATE_MAGIC2 0x46505845U | ||
| 9 | #define FP_XSTATE_MAGIC2_SIZE sizeof(FP_XSTATE_MAGIC2) | ||
| 10 | |||
| 11 | /* | ||
| 12 | * bytes 464..511 in the current 512byte layout of fxsave/fxrstor frame | ||
| 13 | * are reserved for SW usage. On cpu's supporting xsave/xrstor, these bytes | ||
| 14 | * are used to extended the fpstate pointer in the sigcontext, which now | ||
| 15 | * includes the extended state information along with fpstate information. | ||
| 16 | * | ||
| 17 | * Presence of FP_XSTATE_MAGIC1 at the beginning of this SW reserved | ||
| 18 | * area and FP_XSTATE_MAGIC2 at the end of memory layout | ||
| 19 | * (extended_size - FP_XSTATE_MAGIC2_SIZE) indicates the presence of the | ||
| 20 | * extended state information in the memory layout pointed by the fpstate | ||
| 21 | * pointer in sigcontext. | ||
| 22 | */ | ||
| 23 | struct _fpx_sw_bytes { | ||
| 24 | __u32 magic1; /* FP_XSTATE_MAGIC1 */ | ||
| 25 | __u32 extended_size; /* total size of the layout referred by | ||
| 26 | * fpstate pointer in the sigcontext. | ||
| 27 | */ | ||
| 28 | __u64 xstate_bv; | ||
| 29 | /* feature bit mask (including fp/sse/extended | ||
| 30 | * state) that is present in the memory | ||
| 31 | * layout. | ||
| 32 | */ | ||
| 33 | __u32 xstate_size; /* actual xsave state size, based on the | ||
| 34 | * features saved in the layout. | ||
| 35 | * 'extended_size' will be greater than | ||
| 36 | * 'xstate_size'. | ||
| 37 | */ | ||
| 38 | __u32 padding[7]; /* for future use. */ | ||
| 39 | }; | ||
| 40 | |||
| 7 | #ifdef __i386__ | 41 | #ifdef __i386__ |
| 8 | /* | 42 | /* |
| 9 | * As documented in the iBCS2 standard.. | 43 | * As documented in the iBCS2 standard.. |
| @@ -53,7 +87,13 @@ struct _fpstate { | |||
| 53 | unsigned long reserved; | 87 | unsigned long reserved; |
| 54 | struct _fpxreg _fxsr_st[8]; /* FXSR FPU reg data is ignored */ | 88 | struct _fpxreg _fxsr_st[8]; /* FXSR FPU reg data is ignored */ |
| 55 | struct _xmmreg _xmm[8]; | 89 | struct _xmmreg _xmm[8]; |
| 56 | unsigned long padding[56]; | 90 | unsigned long padding1[44]; |
| 91 | |||
| 92 | union { | ||
| 93 | unsigned long padding2[12]; | ||
| 94 | struct _fpx_sw_bytes sw_reserved; /* represents the extended | ||
| 95 | * state info */ | ||
| 96 | }; | ||
| 57 | }; | 97 | }; |
| 58 | 98 | ||
| 59 | #define X86_FXSR_MAGIC 0x0000 | 99 | #define X86_FXSR_MAGIC 0x0000 |
| @@ -79,7 +119,15 @@ struct sigcontext { | |||
| 79 | unsigned long flags; | 119 | unsigned long flags; |
| 80 | unsigned long sp_at_signal; | 120 | unsigned long sp_at_signal; |
| 81 | unsigned short ss, __ssh; | 121 | unsigned short ss, __ssh; |
| 82 | struct _fpstate __user *fpstate; | 122 | |
| 123 | /* | ||
| 124 | * fpstate is really (struct _fpstate *) or (struct _xstate *) | ||
| 125 | * depending on the FP_XSTATE_MAGIC1 encoded in the SW reserved | ||
| 126 | * bytes of (struct _fpstate) and FP_XSTATE_MAGIC2 present at the end | ||
| 127 | * of extended memory layout. See comments at the defintion of | ||
| 128 | * (struct _fpx_sw_bytes) | ||
| 129 | */ | ||
| 130 | void __user *fpstate; /* zero when no FPU/extended context */ | ||
| 83 | unsigned long oldmask; | 131 | unsigned long oldmask; |
| 84 | unsigned long cr2; | 132 | unsigned long cr2; |
| 85 | }; | 133 | }; |
| @@ -130,7 +178,12 @@ struct _fpstate { | |||
| 130 | __u32 mxcsr_mask; | 178 | __u32 mxcsr_mask; |
| 131 | __u32 st_space[32]; /* 8*16 bytes for each FP-reg */ | 179 | __u32 st_space[32]; /* 8*16 bytes for each FP-reg */ |
| 132 | __u32 xmm_space[64]; /* 16*16 bytes for each XMM-reg */ | 180 | __u32 xmm_space[64]; /* 16*16 bytes for each XMM-reg */ |
| 133 | __u32 reserved2[24]; | 181 | __u32 reserved2[12]; |
| 182 | union { | ||
| 183 | __u32 reserved3[12]; | ||
| 184 | struct _fpx_sw_bytes sw_reserved; /* represents the extended | ||
| 185 | * state information */ | ||
| 186 | }; | ||
| 134 | }; | 187 | }; |
| 135 | 188 | ||
| 136 | #ifdef __KERNEL__ | 189 | #ifdef __KERNEL__ |
| @@ -161,7 +214,15 @@ struct sigcontext { | |||
| 161 | unsigned long trapno; | 214 | unsigned long trapno; |
| 162 | unsigned long oldmask; | 215 | unsigned long oldmask; |
| 163 | unsigned long cr2; | 216 | unsigned long cr2; |
| 164 | struct _fpstate __user *fpstate; /* zero when no FPU context */ | 217 | |
| 218 | /* | ||
| 219 | * fpstate is really (struct _fpstate *) or (struct _xstate *) | ||
| 220 | * depending on the FP_XSTATE_MAGIC1 encoded in the SW reserved | ||
| 221 | * bytes of (struct _fpstate) and FP_XSTATE_MAGIC2 present at the end | ||
| 222 | * of extended memory layout. See comments at the defintion of | ||
| 223 | * (struct _fpx_sw_bytes) | ||
| 224 | */ | ||
| 225 | void __user *fpstate; /* zero when no FPU/extended context */ | ||
| 165 | unsigned long reserved1[8]; | 226 | unsigned long reserved1[8]; |
| 166 | }; | 227 | }; |
| 167 | #else /* __KERNEL__ */ | 228 | #else /* __KERNEL__ */ |
| @@ -202,4 +263,22 @@ struct sigcontext { | |||
| 202 | 263 | ||
| 203 | #endif /* !__i386__ */ | 264 | #endif /* !__i386__ */ |
| 204 | 265 | ||
| 266 | struct _xsave_hdr { | ||
| 267 | __u64 xstate_bv; | ||
| 268 | __u64 reserved1[2]; | ||
| 269 | __u64 reserved2[5]; | ||
| 270 | }; | ||
| 271 | |||
| 272 | /* | ||
| 273 | * Extended state pointed by the fpstate pointer in the sigcontext. | ||
| 274 | * In addition to the fpstate, information encoded in the xstate_hdr | ||
| 275 | * indicates the presence of other extended state information | ||
| 276 | * supported by the processor and OS. | ||
| 277 | */ | ||
| 278 | struct _xstate { | ||
| 279 | struct _fpstate fpstate; | ||
| 280 | struct _xsave_hdr xstate_hdr; | ||
| 281 | /* new processor state extensions go here */ | ||
| 282 | }; | ||
| 283 | |||
| 205 | #endif /* ASM_X86__SIGCONTEXT_H */ | 284 | #endif /* ASM_X86__SIGCONTEXT_H */ |
diff --git a/include/asm-x86/sigcontext32.h b/include/asm-x86/sigcontext32.h index 4e2ec732dd01..8c347032c2f2 100644 --- a/include/asm-x86/sigcontext32.h +++ b/include/asm-x86/sigcontext32.h | |||
| @@ -40,7 +40,11 @@ struct _fpstate_ia32 { | |||
| 40 | __u32 reserved; | 40 | __u32 reserved; |
| 41 | struct _fpxreg _fxsr_st[8]; | 41 | struct _fpxreg _fxsr_st[8]; |
| 42 | struct _xmmreg _xmm[8]; /* It's actually 16 */ | 42 | struct _xmmreg _xmm[8]; /* It's actually 16 */ |
| 43 | __u32 padding[56]; | 43 | __u32 padding[44]; |
| 44 | union { | ||
| 45 | __u32 padding2[12]; | ||
| 46 | struct _fpx_sw_bytes sw_reserved; | ||
| 47 | }; | ||
| 44 | }; | 48 | }; |
| 45 | 49 | ||
| 46 | struct sigcontext_ia32 { | 50 | struct sigcontext_ia32 { |
diff --git a/include/asm-x86/thread_info.h b/include/asm-x86/thread_info.h index e64be8863b76..30586f2ee558 100644 --- a/include/asm-x86/thread_info.h +++ b/include/asm-x86/thread_info.h | |||
| @@ -239,6 +239,7 @@ static inline struct thread_info *stack_thread_info(void) | |||
| 239 | #define TS_POLLING 0x0004 /* true if in idle loop | 239 | #define TS_POLLING 0x0004 /* true if in idle loop |
| 240 | and not sleeping */ | 240 | and not sleeping */ |
| 241 | #define TS_RESTORE_SIGMASK 0x0008 /* restore signal mask in do_signal() */ | 241 | #define TS_RESTORE_SIGMASK 0x0008 /* restore signal mask in do_signal() */ |
| 242 | #define TS_XSAVE 0x0010 /* Use xsave/xrstor */ | ||
| 242 | 243 | ||
| 243 | #define tsk_is_polling(t) (task_thread_info(t)->status & TS_POLLING) | 244 | #define tsk_is_polling(t) (task_thread_info(t)->status & TS_POLLING) |
| 244 | 245 | ||
diff --git a/include/asm-x86/ucontext.h b/include/asm-x86/ucontext.h index 9948dd328084..89eaa5456a7e 100644 --- a/include/asm-x86/ucontext.h +++ b/include/asm-x86/ucontext.h | |||
| @@ -1,6 +1,12 @@ | |||
| 1 | #ifndef ASM_X86__UCONTEXT_H | 1 | #ifndef ASM_X86__UCONTEXT_H |
| 2 | #define ASM_X86__UCONTEXT_H | 2 | #define ASM_X86__UCONTEXT_H |
| 3 | 3 | ||
| 4 | #define UC_FP_XSTATE 0x1 /* indicates the presence of extended state | ||
| 5 | * information in the memory layout pointed | ||
| 6 | * by the fpstate pointer in the ucontext's | ||
| 7 | * sigcontext struct (uc_mcontext). | ||
| 8 | */ | ||
| 9 | |||
| 4 | struct ucontext { | 10 | struct ucontext { |
| 5 | unsigned long uc_flags; | 11 | unsigned long uc_flags; |
| 6 | struct ucontext *uc_link; | 12 | struct ucontext *uc_link; |
diff --git a/include/asm-x86/xcr.h b/include/asm-x86/xcr.h new file mode 100644 index 000000000000..f2cba4e79a23 --- /dev/null +++ b/include/asm-x86/xcr.h | |||
| @@ -0,0 +1,49 @@ | |||
| 1 | /* -*- linux-c -*- ------------------------------------------------------- * | ||
| 2 | * | ||
| 3 | * Copyright 2008 rPath, Inc. - All Rights Reserved | ||
| 4 | * | ||
| 5 | * This file is part of the Linux kernel, and is made available under | ||
| 6 | * the terms of the GNU General Public License version 2 or (at your | ||
| 7 | * option) any later version; incorporated herein by reference. | ||
| 8 | * | ||
| 9 | * ----------------------------------------------------------------------- */ | ||
| 10 | |||
| 11 | /* | ||
| 12 | * asm-x86/xcr.h | ||
| 13 | * | ||
| 14 | * Definitions for the eXtended Control Register instructions | ||
| 15 | */ | ||
| 16 | |||
| 17 | #ifndef _ASM_X86_XCR_H | ||
| 18 | #define _ASM_X86_XCR_H | ||
| 19 | |||
| 20 | #define XCR_XFEATURE_ENABLED_MASK 0x00000000 | ||
| 21 | |||
| 22 | #ifdef __KERNEL__ | ||
| 23 | # ifndef __ASSEMBLY__ | ||
| 24 | |||
| 25 | #include <linux/types.h> | ||
| 26 | |||
| 27 | static inline u64 xgetbv(u32 index) | ||
| 28 | { | ||
| 29 | u32 eax, edx; | ||
| 30 | |||
| 31 | asm volatile(".byte 0x0f,0x01,0xd0" /* xgetbv */ | ||
| 32 | : "=a" (eax), "=d" (edx) | ||
| 33 | : "c" (index)); | ||
| 34 | return eax + ((u64)edx << 32); | ||
| 35 | } | ||
| 36 | |||
| 37 | static inline void xsetbv(u32 index, u64 value) | ||
| 38 | { | ||
| 39 | u32 eax = value; | ||
| 40 | u32 edx = value >> 32; | ||
| 41 | |||
| 42 | asm volatile(".byte 0x0f,0x01,0xd1" /* xsetbv */ | ||
| 43 | : : "a" (eax), "d" (edx), "c" (index)); | ||
| 44 | } | ||
| 45 | |||
| 46 | # endif /* __ASSEMBLY__ */ | ||
| 47 | #endif /* __KERNEL__ */ | ||
| 48 | |||
| 49 | #endif /* _ASM_X86_XCR_H */ | ||
diff --git a/include/asm-x86/xsave.h b/include/asm-x86/xsave.h new file mode 100644 index 000000000000..08e9a1ac07a9 --- /dev/null +++ b/include/asm-x86/xsave.h | |||
| @@ -0,0 +1,118 @@ | |||
| 1 | #ifndef __ASM_X86_XSAVE_H | ||
| 2 | #define __ASM_X86_XSAVE_H | ||
| 3 | |||
| 4 | #include <linux/types.h> | ||
| 5 | #include <asm/processor.h> | ||
| 6 | #include <asm/i387.h> | ||
| 7 | |||
| 8 | #define XSTATE_FP 0x1 | ||
| 9 | #define XSTATE_SSE 0x2 | ||
| 10 | |||
| 11 | #define XSTATE_FPSSE (XSTATE_FP | XSTATE_SSE) | ||
| 12 | |||
| 13 | #define FXSAVE_SIZE 512 | ||
| 14 | |||
| 15 | /* | ||
| 16 | * These are the features that the OS can handle currently. | ||
| 17 | */ | ||
| 18 | #define XCNTXT_MASK (XSTATE_FP | XSTATE_SSE) | ||
| 19 | |||
| 20 | #ifdef CONFIG_X86_64 | ||
| 21 | #define REX_PREFIX "0x48, " | ||
| 22 | #else | ||
| 23 | #define REX_PREFIX | ||
| 24 | #endif | ||
| 25 | |||
| 26 | extern unsigned int xstate_size; | ||
| 27 | extern u64 pcntxt_mask; | ||
| 28 | extern struct xsave_struct *init_xstate_buf; | ||
| 29 | |||
| 30 | extern void xsave_cntxt_init(void); | ||
| 31 | extern void xsave_init(void); | ||
| 32 | extern int init_fpu(struct task_struct *child); | ||
| 33 | extern int check_for_xstate(struct i387_fxsave_struct __user *buf, | ||
| 34 | void __user *fpstate, | ||
| 35 | struct _fpx_sw_bytes *sw); | ||
| 36 | |||
| 37 | static inline int xrstor_checking(struct xsave_struct *fx) | ||
| 38 | { | ||
| 39 | int err; | ||
| 40 | |||
| 41 | asm volatile("1: .byte " REX_PREFIX "0x0f,0xae,0x2f\n\t" | ||
| 42 | "2:\n" | ||
| 43 | ".section .fixup,\"ax\"\n" | ||
| 44 | "3: movl $-1,%[err]\n" | ||
| 45 | " jmp 2b\n" | ||
| 46 | ".previous\n" | ||
| 47 | _ASM_EXTABLE(1b, 3b) | ||
| 48 | : [err] "=r" (err) | ||
| 49 | : "D" (fx), "m" (*fx), "a" (-1), "d" (-1), "0" (0) | ||
| 50 | : "memory"); | ||
| 51 | |||
| 52 | return err; | ||
| 53 | } | ||
| 54 | |||
| 55 | static inline int xsave_user(struct xsave_struct __user *buf) | ||
| 56 | { | ||
| 57 | int err; | ||
| 58 | __asm__ __volatile__("1: .byte " REX_PREFIX "0x0f,0xae,0x27\n" | ||
| 59 | "2:\n" | ||
| 60 | ".section .fixup,\"ax\"\n" | ||
| 61 | "3: movl $-1,%[err]\n" | ||
| 62 | " jmp 2b\n" | ||
| 63 | ".previous\n" | ||
| 64 | ".section __ex_table,\"a\"\n" | ||
| 65 | _ASM_ALIGN "\n" | ||
| 66 | _ASM_PTR "1b,3b\n" | ||
| 67 | ".previous" | ||
| 68 | : [err] "=r" (err) | ||
| 69 | : "D" (buf), "a" (-1), "d" (-1), "0" (0) | ||
| 70 | : "memory"); | ||
| 71 | if (unlikely(err) && __clear_user(buf, xstate_size)) | ||
| 72 | err = -EFAULT; | ||
| 73 | /* No need to clear here because the caller clears USED_MATH */ | ||
| 74 | return err; | ||
| 75 | } | ||
| 76 | |||
| 77 | static inline int xrestore_user(struct xsave_struct __user *buf, u64 mask) | ||
| 78 | { | ||
| 79 | int err; | ||
| 80 | struct xsave_struct *xstate = ((__force struct xsave_struct *)buf); | ||
| 81 | u32 lmask = mask; | ||
| 82 | u32 hmask = mask >> 32; | ||
| 83 | |||
| 84 | __asm__ __volatile__("1: .byte " REX_PREFIX "0x0f,0xae,0x2f\n" | ||
| 85 | "2:\n" | ||
| 86 | ".section .fixup,\"ax\"\n" | ||
| 87 | "3: movl $-1,%[err]\n" | ||
| 88 | " jmp 2b\n" | ||
| 89 | ".previous\n" | ||
| 90 | ".section __ex_table,\"a\"\n" | ||
| 91 | _ASM_ALIGN "\n" | ||
| 92 | _ASM_PTR "1b,3b\n" | ||
| 93 | ".previous" | ||
| 94 | : [err] "=r" (err) | ||
| 95 | : "D" (xstate), "a" (lmask), "d" (hmask), "0" (0) | ||
| 96 | : "memory"); /* memory required? */ | ||
| 97 | return err; | ||
| 98 | } | ||
| 99 | |||
| 100 | static inline void xrstor_state(struct xsave_struct *fx, u64 mask) | ||
| 101 | { | ||
| 102 | u32 lmask = mask; | ||
| 103 | u32 hmask = mask >> 32; | ||
| 104 | |||
| 105 | asm volatile(".byte " REX_PREFIX "0x0f,0xae,0x2f\n\t" | ||
| 106 | : : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask) | ||
| 107 | : "memory"); | ||
| 108 | } | ||
| 109 | |||
| 110 | static inline void xsave(struct task_struct *tsk) | ||
| 111 | { | ||
| 112 | /* This, however, we can work around by forcing the compiler to select | ||
| 113 | an addressing mode that doesn't require extended registers. */ | ||
| 114 | __asm__ __volatile__(".byte " REX_PREFIX "0x0f,0xae,0x27" | ||
| 115 | : : "D" (&(tsk->thread.xstate->xsave)), | ||
| 116 | "a" (-1), "d"(-1) : "memory"); | ||
| 117 | } | ||
| 118 | #endif | ||
