diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-08-13 20:20:04 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-08-13 20:20:04 -0400 |
| commit | 7453f33b2e07fc2835e24cda0893de83c78d8d76 (patch) | |
| tree | 02d82193515fcc94cf39e284fd325c4491913331 | |
| parent | fd1cf90580289f83f9c972bb367a74d846d281c4 (diff) | |
| parent | d0f2dd186133a0241a2ccefb188a0e49e8187859 (diff) | |
Merge branch 'x86-xsave-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86/xsave changes from Peter Anvin:
"This is a patchset to support the XSAVES instruction required to
support context switch of supervisor-only features in upcoming
silicon.
This patchset missed the 3.16 merge window, which is why it is based
on 3.15-rc7"
* 'x86-xsave-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
x86, xsave: Add forgotten inline annotation
x86/xsaves: Clean up code in xstate offsets computation in xsave area
x86/xsave: Make it clear that the XSAVE macros use (%edi)/(%rdi)
Define kernel API to get address of each state in xsave area
x86/xsaves: Enable xsaves/xrstors
x86/xsaves: Call booting time xsaves and xrstors in setup_init_fpu_buf
x86/xsaves: Save xstate to task's xsave area in __save_fpu during booting time
x86/xsaves: Add xsaves and xrstors support for booting time
x86/xsaves: Clear reserved bits in xsave header
x86/xsaves: Use xsave/xrstor for saving and restoring user space context
x86/xsaves: Use xsaves/xrstors for context switch
x86/xsaves: Use xsaves/xrstors to save and restore xsave area
x86/xsaves: Define a macro for handling xsave/xrstor instruction fault
x86/xsaves: Define macros for xsave instructions
x86/xsaves: Change compacted format xsave area header
x86/alternative: Add alternative_input_2 to support alternative with two features and input
x86/xsaves: Add a kernel parameter noxsaves to disable xsaves/xrstors
| -rw-r--r-- | Documentation/kernel-parameters.txt | 15 | ||||
| -rw-r--r-- | arch/x86/include/asm/alternative.h | 14 | ||||
| -rw-r--r-- | arch/x86/include/asm/fpu-internal.h | 9 | ||||
| -rw-r--r-- | arch/x86/include/asm/processor.h | 4 | ||||
| -rw-r--r-- | arch/x86/include/asm/xsave.h | 223 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/common.c | 8 | ||||
| -rw-r--r-- | arch/x86/kernel/i387.c | 2 | ||||
| -rw-r--r-- | arch/x86/kernel/process.c | 1 | ||||
| -rw-r--r-- | arch/x86/kernel/xsave.c | 118 |
9 files changed, 324 insertions, 70 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index a8eb6afce6a4..5ae8608ca9f5 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt | |||
| @@ -2200,6 +2200,21 @@ bytes respectively. Such letter suffixes can also be entirely omitted. | |||
| 2200 | and restore using xsave. The kernel will fallback to | 2200 | and restore using xsave. The kernel will fallback to |
| 2201 | enabling legacy floating-point and sse state. | 2201 | enabling legacy floating-point and sse state. |
| 2202 | 2202 | ||
| 2203 | noxsaveopt [X86] Disables xsaveopt used in saving x86 extended | ||
| 2204 | register states. The kernel will fall back to use | ||
| 2205 | xsave to save the states. By using this parameter, | ||
| 2206 | performance of saving the states is degraded because | ||
| 2207 | xsave doesn't support modified optimization while | ||
| 2208 | xsaveopt supports it on xsaveopt enabled systems. | ||
| 2209 | |||
| 2210 | noxsaves [X86] Disables xsaves and xrstors used in saving and | ||
| 2211 | restoring x86 extended register state in compacted | ||
| 2212 | form of xsave area. The kernel will fall back to use | ||
| 2213 | xsaveopt and xrstor to save and restore the states | ||
| 2214 | in standard form of xsave area. By using this | ||
| 2215 | parameter, xsave area per process might occupy more | ||
| 2216 | memory on xsaves enabled systems. | ||
| 2217 | |||
| 2203 | eagerfpu= [X86] | 2218 | eagerfpu= [X86] |
| 2204 | on enable eager fpu restore | 2219 | on enable eager fpu restore |
| 2205 | off disable eager fpu restore | 2220 | off disable eager fpu restore |
diff --git a/arch/x86/include/asm/alternative.h b/arch/x86/include/asm/alternative.h index 0a3f9c9f98d5..473bdbee378a 100644 --- a/arch/x86/include/asm/alternative.h +++ b/arch/x86/include/asm/alternative.h | |||
| @@ -161,6 +161,20 @@ static inline int alternatives_text_reserved(void *start, void *end) | |||
| 161 | asm volatile (ALTERNATIVE(oldinstr, newinstr, feature) \ | 161 | asm volatile (ALTERNATIVE(oldinstr, newinstr, feature) \ |
| 162 | : : "i" (0), ## input) | 162 | : : "i" (0), ## input) |
| 163 | 163 | ||
| 164 | /* | ||
| 165 | * This is similar to alternative_input. But it has two features and | ||
| 166 | * respective instructions. | ||
| 167 | * | ||
| 168 | * If CPU has feature2, newinstr2 is used. | ||
| 169 | * Otherwise, if CPU has feature1, newinstr1 is used. | ||
| 170 | * Otherwise, oldinstr is used. | ||
| 171 | */ | ||
| 172 | #define alternative_input_2(oldinstr, newinstr1, feature1, newinstr2, \ | ||
| 173 | feature2, input...) \ | ||
| 174 | asm volatile(ALTERNATIVE_2(oldinstr, newinstr1, feature1, \ | ||
| 175 | newinstr2, feature2) \ | ||
| 176 | : : "i" (0), ## input) | ||
| 177 | |||
| 164 | /* Like alternative_input, but with a single output argument */ | 178 | /* Like alternative_input, but with a single output argument */ |
| 165 | #define alternative_io(oldinstr, newinstr, feature, output, input...) \ | 179 | #define alternative_io(oldinstr, newinstr, feature, output, input...) \ |
| 166 | asm volatile (ALTERNATIVE(oldinstr, newinstr, feature) \ | 180 | asm volatile (ALTERNATIVE(oldinstr, newinstr, feature) \ |
diff --git a/arch/x86/include/asm/fpu-internal.h b/arch/x86/include/asm/fpu-internal.h index e3b85422cf12..412ececa00b9 100644 --- a/arch/x86/include/asm/fpu-internal.h +++ b/arch/x86/include/asm/fpu-internal.h | |||
| @@ -508,9 +508,12 @@ static inline void user_fpu_begin(void) | |||
| 508 | 508 | ||
| 509 | static inline void __save_fpu(struct task_struct *tsk) | 509 | static inline void __save_fpu(struct task_struct *tsk) |
| 510 | { | 510 | { |
| 511 | if (use_xsave()) | 511 | if (use_xsave()) { |
| 512 | xsave_state(&tsk->thread.fpu.state->xsave, -1); | 512 | if (unlikely(system_state == SYSTEM_BOOTING)) |
| 513 | else | 513 | xsave_state_booting(&tsk->thread.fpu.state->xsave, -1); |
| 514 | else | ||
| 515 | xsave_state(&tsk->thread.fpu.state->xsave, -1); | ||
| 516 | } else | ||
| 514 | fpu_fxsave(&tsk->thread.fpu); | 517 | fpu_fxsave(&tsk->thread.fpu); |
| 515 | } | 518 | } |
| 516 | 519 | ||
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index ee30b9f0b91c..eb71ec794732 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h | |||
| @@ -385,8 +385,8 @@ struct bndcsr_struct { | |||
| 385 | 385 | ||
| 386 | struct xsave_hdr_struct { | 386 | struct xsave_hdr_struct { |
| 387 | u64 xstate_bv; | 387 | u64 xstate_bv; |
| 388 | u64 reserved1[2]; | 388 | u64 xcomp_bv; |
| 389 | u64 reserved2[5]; | 389 | u64 reserved[6]; |
| 390 | } __attribute__((packed)); | 390 | } __attribute__((packed)); |
| 391 | 391 | ||
| 392 | struct xsave_struct { | 392 | struct xsave_struct { |
diff --git a/arch/x86/include/asm/xsave.h b/arch/x86/include/asm/xsave.h index d949ef28c48b..7e7a79ada658 100644 --- a/arch/x86/include/asm/xsave.h +++ b/arch/x86/include/asm/xsave.h | |||
| @@ -52,24 +52,170 @@ extern void xsave_init(void); | |||
| 52 | extern void update_regset_xstate_info(unsigned int size, u64 xstate_mask); | 52 | extern void update_regset_xstate_info(unsigned int size, u64 xstate_mask); |
| 53 | extern int init_fpu(struct task_struct *child); | 53 | extern int init_fpu(struct task_struct *child); |
| 54 | 54 | ||
| 55 | static inline int fpu_xrstor_checking(struct xsave_struct *fx) | 55 | /* These macros all use (%edi)/(%rdi) as the single memory argument. */ |
| 56 | #define XSAVE ".byte " REX_PREFIX "0x0f,0xae,0x27" | ||
| 57 | #define XSAVEOPT ".byte " REX_PREFIX "0x0f,0xae,0x37" | ||
| 58 | #define XSAVES ".byte " REX_PREFIX "0x0f,0xc7,0x2f" | ||
| 59 | #define XRSTOR ".byte " REX_PREFIX "0x0f,0xae,0x2f" | ||
| 60 | #define XRSTORS ".byte " REX_PREFIX "0x0f,0xc7,0x1f" | ||
| 61 | |||
| 62 | #define xstate_fault ".section .fixup,\"ax\"\n" \ | ||
| 63 | "3: movl $-1,%[err]\n" \ | ||
| 64 | " jmp 2b\n" \ | ||
| 65 | ".previous\n" \ | ||
| 66 | _ASM_EXTABLE(1b, 3b) \ | ||
| 67 | : [err] "=r" (err) | ||
| 68 | |||
| 69 | /* | ||
| 70 | * This function is called only during boot time when x86 caps are not set | ||
| 71 | * up and alternative can not be used yet. | ||
| 72 | */ | ||
| 73 | static inline int xsave_state_booting(struct xsave_struct *fx, u64 mask) | ||
| 56 | { | 74 | { |
| 57 | int err; | 75 | u32 lmask = mask; |
| 76 | u32 hmask = mask >> 32; | ||
| 77 | int err = 0; | ||
| 78 | |||
| 79 | WARN_ON(system_state != SYSTEM_BOOTING); | ||
| 80 | |||
| 81 | if (boot_cpu_has(X86_FEATURE_XSAVES)) | ||
| 82 | asm volatile("1:"XSAVES"\n\t" | ||
| 83 | "2:\n\t" | ||
| 84 | : : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask) | ||
| 85 | : "memory"); | ||
| 86 | else | ||
| 87 | asm volatile("1:"XSAVE"\n\t" | ||
| 88 | "2:\n\t" | ||
| 89 | : : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask) | ||
| 90 | : "memory"); | ||
| 91 | |||
| 92 | asm volatile(xstate_fault | ||
| 93 | : "0" (0) | ||
| 94 | : "memory"); | ||
| 95 | |||
| 96 | return err; | ||
| 97 | } | ||
| 98 | |||
| 99 | /* | ||
| 100 | * This function is called only during boot time when x86 caps are not set | ||
| 101 | * up and alternative can not be used yet. | ||
| 102 | */ | ||
| 103 | static inline int xrstor_state_booting(struct xsave_struct *fx, u64 mask) | ||
| 104 | { | ||
| 105 | u32 lmask = mask; | ||
| 106 | u32 hmask = mask >> 32; | ||
| 107 | int err = 0; | ||
| 108 | |||
| 109 | WARN_ON(system_state != SYSTEM_BOOTING); | ||
| 58 | 110 | ||
| 59 | asm volatile("1: .byte " REX_PREFIX "0x0f,0xae,0x2f\n\t" | 111 | if (boot_cpu_has(X86_FEATURE_XSAVES)) |
| 60 | "2:\n" | 112 | asm volatile("1:"XRSTORS"\n\t" |
| 61 | ".section .fixup,\"ax\"\n" | 113 | "2:\n\t" |
| 62 | "3: movl $-1,%[err]\n" | 114 | : : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask) |
| 63 | " jmp 2b\n" | 115 | : "memory"); |
| 64 | ".previous\n" | 116 | else |
| 65 | _ASM_EXTABLE(1b, 3b) | 117 | asm volatile("1:"XRSTOR"\n\t" |
| 66 | : [err] "=r" (err) | 118 | "2:\n\t" |
| 67 | : "D" (fx), "m" (*fx), "a" (-1), "d" (-1), "0" (0) | 119 | : : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask) |
| 120 | : "memory"); | ||
| 121 | |||
| 122 | asm volatile(xstate_fault | ||
| 123 | : "0" (0) | ||
| 124 | : "memory"); | ||
| 125 | |||
| 126 | return err; | ||
| 127 | } | ||
| 128 | |||
| 129 | /* | ||
| 130 | * Save processor xstate to xsave area. | ||
| 131 | */ | ||
| 132 | static inline int xsave_state(struct xsave_struct *fx, u64 mask) | ||
| 133 | { | ||
| 134 | u32 lmask = mask; | ||
| 135 | u32 hmask = mask >> 32; | ||
| 136 | int err = 0; | ||
| 137 | |||
| 138 | /* | ||
| 139 | * If xsaves is enabled, xsaves replaces xsaveopt because | ||
| 140 | * it supports compact format and supervisor states in addition to | ||
| 141 | * modified optimization in xsaveopt. | ||
| 142 | * | ||
| 143 | * Otherwise, if xsaveopt is enabled, xsaveopt replaces xsave | ||
| 144 | * because xsaveopt supports modified optimization which is not | ||
| 145 | * supported by xsave. | ||
| 146 | * | ||
| 147 | * If none of xsaves and xsaveopt is enabled, use xsave. | ||
| 148 | */ | ||
| 149 | alternative_input_2( | ||
| 150 | "1:"XSAVE, | ||
| 151 | "1:"XSAVEOPT, | ||
| 152 | X86_FEATURE_XSAVEOPT, | ||
| 153 | "1:"XSAVES, | ||
| 154 | X86_FEATURE_XSAVES, | ||
| 155 | [fx] "D" (fx), "a" (lmask), "d" (hmask) : | ||
| 156 | "memory"); | ||
| 157 | asm volatile("2:\n\t" | ||
| 158 | xstate_fault | ||
| 159 | : "0" (0) | ||
| 68 | : "memory"); | 160 | : "memory"); |
| 69 | 161 | ||
| 70 | return err; | 162 | return err; |
| 71 | } | 163 | } |
| 72 | 164 | ||
| 165 | /* | ||
| 166 | * Restore processor xstate from xsave area. | ||
| 167 | */ | ||
| 168 | static inline int xrstor_state(struct xsave_struct *fx, u64 mask) | ||
| 169 | { | ||
| 170 | int err = 0; | ||
| 171 | u32 lmask = mask; | ||
| 172 | u32 hmask = mask >> 32; | ||
| 173 | |||
| 174 | /* | ||
| 175 | * Use xrstors to restore context if it is enabled. xrstors supports | ||
| 176 | * compacted format of xsave area which is not supported by xrstor. | ||
| 177 | */ | ||
| 178 | alternative_input( | ||
| 179 | "1: " XRSTOR, | ||
| 180 | "1: " XRSTORS, | ||
| 181 | X86_FEATURE_XSAVES, | ||
| 182 | "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask) | ||
| 183 | : "memory"); | ||
| 184 | |||
| 185 | asm volatile("2:\n" | ||
| 186 | xstate_fault | ||
| 187 | : "0" (0) | ||
| 188 | : "memory"); | ||
| 189 | |||
| 190 | return err; | ||
| 191 | } | ||
| 192 | |||
| 193 | /* | ||
| 194 | * Save xstate context for old process during context switch. | ||
| 195 | */ | ||
| 196 | static inline void fpu_xsave(struct fpu *fpu) | ||
| 197 | { | ||
| 198 | xsave_state(&fpu->state->xsave, -1); | ||
| 199 | } | ||
| 200 | |||
| 201 | /* | ||
| 202 | * Restore xstate context for new process during context switch. | ||
| 203 | */ | ||
| 204 | static inline int fpu_xrstor_checking(struct xsave_struct *fx) | ||
| 205 | { | ||
| 206 | return xrstor_state(fx, -1); | ||
| 207 | } | ||
| 208 | |||
| 209 | /* | ||
| 210 | * Save xstate to user space xsave area. | ||
| 211 | * | ||
| 212 | * We don't use modified optimization because xrstor/xrstors might track | ||
| 213 | * a different application. | ||
| 214 | * | ||
| 215 | * We don't use compacted format xsave area for | ||
| 216 | * backward compatibility for old applications which don't understand | ||
| 217 | * compacted format of xsave area. | ||
| 218 | */ | ||
| 73 | static inline int xsave_user(struct xsave_struct __user *buf) | 219 | static inline int xsave_user(struct xsave_struct __user *buf) |
| 74 | { | 220 | { |
| 75 | int err; | 221 | int err; |
| @@ -83,69 +229,34 @@ static inline int xsave_user(struct xsave_struct __user *buf) | |||
| 83 | return -EFAULT; | 229 | return -EFAULT; |
| 84 | 230 | ||
| 85 | __asm__ __volatile__(ASM_STAC "\n" | 231 | __asm__ __volatile__(ASM_STAC "\n" |
| 86 | "1: .byte " REX_PREFIX "0x0f,0xae,0x27\n" | 232 | "1:"XSAVE"\n" |
| 87 | "2: " ASM_CLAC "\n" | 233 | "2: " ASM_CLAC "\n" |
| 88 | ".section .fixup,\"ax\"\n" | 234 | xstate_fault |
| 89 | "3: movl $-1,%[err]\n" | ||
| 90 | " jmp 2b\n" | ||
| 91 | ".previous\n" | ||
| 92 | _ASM_EXTABLE(1b,3b) | ||
| 93 | : [err] "=r" (err) | ||
| 94 | : "D" (buf), "a" (-1), "d" (-1), "0" (0) | 235 | : "D" (buf), "a" (-1), "d" (-1), "0" (0) |
| 95 | : "memory"); | 236 | : "memory"); |
| 96 | return err; | 237 | return err; |
| 97 | } | 238 | } |
| 98 | 239 | ||
| 240 | /* | ||
| 241 | * Restore xstate from user space xsave area. | ||
| 242 | */ | ||
| 99 | static inline int xrestore_user(struct xsave_struct __user *buf, u64 mask) | 243 | static inline int xrestore_user(struct xsave_struct __user *buf, u64 mask) |
| 100 | { | 244 | { |
| 101 | int err; | 245 | int err = 0; |
| 102 | struct xsave_struct *xstate = ((__force struct xsave_struct *)buf); | 246 | struct xsave_struct *xstate = ((__force struct xsave_struct *)buf); |
| 103 | u32 lmask = mask; | 247 | u32 lmask = mask; |
| 104 | u32 hmask = mask >> 32; | 248 | u32 hmask = mask >> 32; |
| 105 | 249 | ||
| 106 | __asm__ __volatile__(ASM_STAC "\n" | 250 | __asm__ __volatile__(ASM_STAC "\n" |
| 107 | "1: .byte " REX_PREFIX "0x0f,0xae,0x2f\n" | 251 | "1:"XRSTOR"\n" |
| 108 | "2: " ASM_CLAC "\n" | 252 | "2: " ASM_CLAC "\n" |
| 109 | ".section .fixup,\"ax\"\n" | 253 | xstate_fault |
| 110 | "3: movl $-1,%[err]\n" | ||
| 111 | " jmp 2b\n" | ||
| 112 | ".previous\n" | ||
| 113 | _ASM_EXTABLE(1b,3b) | ||
| 114 | : [err] "=r" (err) | ||
| 115 | : "D" (xstate), "a" (lmask), "d" (hmask), "0" (0) | 254 | : "D" (xstate), "a" (lmask), "d" (hmask), "0" (0) |
| 116 | : "memory"); /* memory required? */ | 255 | : "memory"); /* memory required? */ |
| 117 | return err; | 256 | return err; |
| 118 | } | 257 | } |
| 119 | 258 | ||
| 120 | static inline void xrstor_state(struct xsave_struct *fx, u64 mask) | 259 | void *get_xsave_addr(struct xsave_struct *xsave, int xstate); |
| 121 | { | 260 | void setup_xstate_comp(void); |
| 122 | u32 lmask = mask; | ||
| 123 | u32 hmask = mask >> 32; | ||
| 124 | |||
| 125 | asm volatile(".byte " REX_PREFIX "0x0f,0xae,0x2f\n\t" | ||
| 126 | : : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask) | ||
| 127 | : "memory"); | ||
| 128 | } | ||
| 129 | |||
| 130 | static inline void xsave_state(struct xsave_struct *fx, u64 mask) | ||
| 131 | { | ||
| 132 | u32 lmask = mask; | ||
| 133 | u32 hmask = mask >> 32; | ||
| 134 | 261 | ||
| 135 | asm volatile(".byte " REX_PREFIX "0x0f,0xae,0x27\n\t" | ||
| 136 | : : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask) | ||
| 137 | : "memory"); | ||
| 138 | } | ||
| 139 | |||
| 140 | static inline void fpu_xsave(struct fpu *fpu) | ||
| 141 | { | ||
| 142 | /* This, however, we can work around by forcing the compiler to select | ||
| 143 | an addressing mode that doesn't require extended registers. */ | ||
| 144 | alternative_input( | ||
| 145 | ".byte " REX_PREFIX "0x0f,0xae,0x27", | ||
| 146 | ".byte " REX_PREFIX "0x0f,0xae,0x37", | ||
| 147 | X86_FEATURE_XSAVEOPT, | ||
| 148 | [fx] "D" (&fpu->state->xsave), "a" (-1), "d" (-1) : | ||
| 149 | "memory"); | ||
| 150 | } | ||
| 151 | #endif | 262 | #endif |
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 333fd5209336..e4ab2b42bd6f 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c | |||
| @@ -148,6 +148,7 @@ static int __init x86_xsave_setup(char *s) | |||
| 148 | { | 148 | { |
| 149 | setup_clear_cpu_cap(X86_FEATURE_XSAVE); | 149 | setup_clear_cpu_cap(X86_FEATURE_XSAVE); |
| 150 | setup_clear_cpu_cap(X86_FEATURE_XSAVEOPT); | 150 | setup_clear_cpu_cap(X86_FEATURE_XSAVEOPT); |
| 151 | setup_clear_cpu_cap(X86_FEATURE_XSAVES); | ||
| 151 | setup_clear_cpu_cap(X86_FEATURE_AVX); | 152 | setup_clear_cpu_cap(X86_FEATURE_AVX); |
| 152 | setup_clear_cpu_cap(X86_FEATURE_AVX2); | 153 | setup_clear_cpu_cap(X86_FEATURE_AVX2); |
| 153 | return 1; | 154 | return 1; |
| @@ -161,6 +162,13 @@ static int __init x86_xsaveopt_setup(char *s) | |||
| 161 | } | 162 | } |
| 162 | __setup("noxsaveopt", x86_xsaveopt_setup); | 163 | __setup("noxsaveopt", x86_xsaveopt_setup); |
| 163 | 164 | ||
| 165 | static int __init x86_xsaves_setup(char *s) | ||
| 166 | { | ||
| 167 | setup_clear_cpu_cap(X86_FEATURE_XSAVES); | ||
| 168 | return 1; | ||
| 169 | } | ||
| 170 | __setup("noxsaves", x86_xsaves_setup); | ||
| 171 | |||
| 164 | #ifdef CONFIG_X86_32 | 172 | #ifdef CONFIG_X86_32 |
| 165 | static int cachesize_override = -1; | 173 | static int cachesize_override = -1; |
| 166 | static int disable_x86_serial_nr = 1; | 174 | static int disable_x86_serial_nr = 1; |
diff --git a/arch/x86/kernel/i387.c b/arch/x86/kernel/i387.c index d5dd80814419..a9a4229f6161 100644 --- a/arch/x86/kernel/i387.c +++ b/arch/x86/kernel/i387.c | |||
| @@ -375,7 +375,7 @@ int xstateregs_set(struct task_struct *target, const struct user_regset *regset, | |||
| 375 | /* | 375 | /* |
| 376 | * These bits must be zero. | 376 | * These bits must be zero. |
| 377 | */ | 377 | */ |
| 378 | xsave_hdr->reserved1[0] = xsave_hdr->reserved1[1] = 0; | 378 | memset(xsave_hdr->reserved, 0, 48); |
| 379 | 379 | ||
| 380 | return ret; | 380 | return ret; |
| 381 | } | 381 | } |
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index 4505e2a950d8..f804dc935d2a 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c | |||
| @@ -93,6 +93,7 @@ void arch_task_cache_init(void) | |||
| 93 | kmem_cache_create("task_xstate", xstate_size, | 93 | kmem_cache_create("task_xstate", xstate_size, |
| 94 | __alignof__(union thread_xstate), | 94 | __alignof__(union thread_xstate), |
| 95 | SLAB_PANIC | SLAB_NOTRACK, NULL); | 95 | SLAB_PANIC | SLAB_NOTRACK, NULL); |
| 96 | setup_xstate_comp(); | ||
| 96 | } | 97 | } |
| 97 | 98 | ||
| 98 | /* | 99 | /* |
diff --git a/arch/x86/kernel/xsave.c b/arch/x86/kernel/xsave.c index a4b451c6addf..940b142cc11f 100644 --- a/arch/x86/kernel/xsave.c +++ b/arch/x86/kernel/xsave.c | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | 8 | ||
| 9 | #include <linux/bootmem.h> | 9 | #include <linux/bootmem.h> |
| 10 | #include <linux/compat.h> | 10 | #include <linux/compat.h> |
| 11 | #include <linux/cpu.h> | ||
| 11 | #include <asm/i387.h> | 12 | #include <asm/i387.h> |
| 12 | #include <asm/fpu-internal.h> | 13 | #include <asm/fpu-internal.h> |
| 13 | #include <asm/sigframe.h> | 14 | #include <asm/sigframe.h> |
| @@ -24,7 +25,9 @@ u64 pcntxt_mask; | |||
| 24 | struct xsave_struct *init_xstate_buf; | 25 | struct xsave_struct *init_xstate_buf; |
| 25 | 26 | ||
| 26 | static struct _fpx_sw_bytes fx_sw_reserved, fx_sw_reserved_ia32; | 27 | static struct _fpx_sw_bytes fx_sw_reserved, fx_sw_reserved_ia32; |
| 27 | static unsigned int *xstate_offsets, *xstate_sizes, xstate_features; | 28 | static unsigned int *xstate_offsets, *xstate_sizes; |
| 29 | static unsigned int xstate_comp_offsets[sizeof(pcntxt_mask)*8]; | ||
| 30 | static unsigned int xstate_features; | ||
| 28 | 31 | ||
| 29 | /* | 32 | /* |
| 30 | * If a processor implementation discern that a processor state component is | 33 | * If a processor implementation discern that a processor state component is |
| @@ -283,7 +286,7 @@ sanitize_restored_xstate(struct task_struct *tsk, | |||
| 283 | 286 | ||
| 284 | if (use_xsave()) { | 287 | if (use_xsave()) { |
| 285 | /* These bits must be zero. */ | 288 | /* These bits must be zero. */ |
| 286 | xsave_hdr->reserved1[0] = xsave_hdr->reserved1[1] = 0; | 289 | memset(xsave_hdr->reserved, 0, 48); |
| 287 | 290 | ||
| 288 | /* | 291 | /* |
| 289 | * Init the state that is not present in the memory | 292 | * Init the state that is not present in the memory |
| @@ -479,6 +482,52 @@ static void __init setup_xstate_features(void) | |||
| 479 | } | 482 | } |
| 480 | 483 | ||
| 481 | /* | 484 | /* |
| 485 | * This function sets up offsets and sizes of all extended states in | ||
| 486 | * xsave area. This supports both standard format and compacted format | ||
| 487 | * of the xsave aread. | ||
| 488 | * | ||
| 489 | * Input: void | ||
| 490 | * Output: void | ||
| 491 | */ | ||
| 492 | void setup_xstate_comp(void) | ||
| 493 | { | ||
| 494 | unsigned int xstate_comp_sizes[sizeof(pcntxt_mask)*8]; | ||
| 495 | int i; | ||
| 496 | |||
| 497 | /* | ||
| 498 | * The FP xstates and SSE xstates are legacy states. They are always | ||
| 499 | * in the fixed offsets in the xsave area in either compacted form | ||
| 500 | * or standard form. | ||
| 501 | */ | ||
| 502 | xstate_comp_offsets[0] = 0; | ||
| 503 | xstate_comp_offsets[1] = offsetof(struct i387_fxsave_struct, xmm_space); | ||
| 504 | |||
| 505 | if (!cpu_has_xsaves) { | ||
| 506 | for (i = 2; i < xstate_features; i++) { | ||
| 507 | if (test_bit(i, (unsigned long *)&pcntxt_mask)) { | ||
| 508 | xstate_comp_offsets[i] = xstate_offsets[i]; | ||
| 509 | xstate_comp_sizes[i] = xstate_sizes[i]; | ||
| 510 | } | ||
| 511 | } | ||
| 512 | return; | ||
| 513 | } | ||
| 514 | |||
| 515 | xstate_comp_offsets[2] = FXSAVE_SIZE + XSAVE_HDR_SIZE; | ||
| 516 | |||
| 517 | for (i = 2; i < xstate_features; i++) { | ||
| 518 | if (test_bit(i, (unsigned long *)&pcntxt_mask)) | ||
| 519 | xstate_comp_sizes[i] = xstate_sizes[i]; | ||
| 520 | else | ||
| 521 | xstate_comp_sizes[i] = 0; | ||
| 522 | |||
| 523 | if (i > 2) | ||
| 524 | xstate_comp_offsets[i] = xstate_comp_offsets[i-1] | ||
| 525 | + xstate_comp_sizes[i-1]; | ||
| 526 | |||
| 527 | } | ||
| 528 | } | ||
| 529 | |||
| 530 | /* | ||
| 482 | * setup the xstate image representing the init state | 531 | * setup the xstate image representing the init state |
| 483 | */ | 532 | */ |
| 484 | static void __init setup_init_fpu_buf(void) | 533 | static void __init setup_init_fpu_buf(void) |
| @@ -496,15 +545,21 @@ static void __init setup_init_fpu_buf(void) | |||
| 496 | 545 | ||
| 497 | setup_xstate_features(); | 546 | setup_xstate_features(); |
| 498 | 547 | ||
| 548 | if (cpu_has_xsaves) { | ||
| 549 | init_xstate_buf->xsave_hdr.xcomp_bv = | ||
| 550 | (u64)1 << 63 | pcntxt_mask; | ||
| 551 | init_xstate_buf->xsave_hdr.xstate_bv = pcntxt_mask; | ||
| 552 | } | ||
| 553 | |||
| 499 | /* | 554 | /* |
| 500 | * Init all the features state with header_bv being 0x0 | 555 | * Init all the features state with header_bv being 0x0 |
| 501 | */ | 556 | */ |
| 502 | xrstor_state(init_xstate_buf, -1); | 557 | xrstor_state_booting(init_xstate_buf, -1); |
| 503 | /* | 558 | /* |
| 504 | * Dump the init state again. This is to identify the init state | 559 | * Dump the init state again. This is to identify the init state |
| 505 | * of any feature which is not represented by all zero's. | 560 | * of any feature which is not represented by all zero's. |
| 506 | */ | 561 | */ |
| 507 | xsave_state(init_xstate_buf, -1); | 562 | xsave_state_booting(init_xstate_buf, -1); |
| 508 | } | 563 | } |
| 509 | 564 | ||
| 510 | static enum { AUTO, ENABLE, DISABLE } eagerfpu = AUTO; | 565 | static enum { AUTO, ENABLE, DISABLE } eagerfpu = AUTO; |
| @@ -520,6 +575,30 @@ static int __init eager_fpu_setup(char *s) | |||
| 520 | } | 575 | } |
| 521 | __setup("eagerfpu=", eager_fpu_setup); | 576 | __setup("eagerfpu=", eager_fpu_setup); |
| 522 | 577 | ||
| 578 | |||
| 579 | /* | ||
| 580 | * Calculate total size of enabled xstates in XCR0/pcntxt_mask. | ||
| 581 | */ | ||
| 582 | static void __init init_xstate_size(void) | ||
| 583 | { | ||
| 584 | unsigned int eax, ebx, ecx, edx; | ||
| 585 | int i; | ||
| 586 | |||
| 587 | if (!cpu_has_xsaves) { | ||
| 588 | cpuid_count(XSTATE_CPUID, 0, &eax, &ebx, &ecx, &edx); | ||
| 589 | xstate_size = ebx; | ||
| 590 | return; | ||
| 591 | } | ||
| 592 | |||
| 593 | xstate_size = FXSAVE_SIZE + XSAVE_HDR_SIZE; | ||
| 594 | for (i = 2; i < 64; i++) { | ||
| 595 | if (test_bit(i, (unsigned long *)&pcntxt_mask)) { | ||
| 596 | cpuid_count(XSTATE_CPUID, i, &eax, &ebx, &ecx, &edx); | ||
| 597 | xstate_size += eax; | ||
| 598 | } | ||
| 599 | } | ||
| 600 | } | ||
| 601 | |||
| 523 | /* | 602 | /* |
| 524 | * Enable and initialize the xsave feature. | 603 | * Enable and initialize the xsave feature. |
| 525 | */ | 604 | */ |
| @@ -551,8 +630,7 @@ static void __init xstate_enable_boot_cpu(void) | |||
| 551 | /* | 630 | /* |
| 552 | * Recompute the context size for enabled features | 631 | * Recompute the context size for enabled features |
| 553 | */ | 632 | */ |
| 554 | cpuid_count(XSTATE_CPUID, 0, &eax, &ebx, &ecx, &edx); | 633 | init_xstate_size(); |
| 555 | xstate_size = ebx; | ||
| 556 | 634 | ||
| 557 | update_regset_xstate_info(xstate_size, pcntxt_mask); | 635 | update_regset_xstate_info(xstate_size, pcntxt_mask); |
| 558 | prepare_fx_sw_frame(); | 636 | prepare_fx_sw_frame(); |
| @@ -572,8 +650,9 @@ static void __init xstate_enable_boot_cpu(void) | |||
| 572 | } | 650 | } |
| 573 | } | 651 | } |
| 574 | 652 | ||
| 575 | pr_info("enabled xstate_bv 0x%llx, cntxt size 0x%x\n", | 653 | pr_info("enabled xstate_bv 0x%llx, cntxt size 0x%x using %s\n", |
| 576 | pcntxt_mask, xstate_size); | 654 | pcntxt_mask, xstate_size, |
| 655 | cpu_has_xsaves ? "compacted form" : "standard form"); | ||
| 577 | } | 656 | } |
| 578 | 657 | ||
| 579 | /* | 658 | /* |
| @@ -635,3 +714,26 @@ void eager_fpu_init(void) | |||
| 635 | else | 714 | else |
| 636 | fxrstor_checking(&init_xstate_buf->i387); | 715 | fxrstor_checking(&init_xstate_buf->i387); |
| 637 | } | 716 | } |
| 717 | |||
| 718 | /* | ||
| 719 | * Given the xsave area and a state inside, this function returns the | ||
| 720 | * address of the state. | ||
| 721 | * | ||
| 722 | * This is the API that is called to get xstate address in either | ||
| 723 | * standard format or compacted format of xsave area. | ||
| 724 | * | ||
| 725 | * Inputs: | ||
| 726 | * xsave: base address of the xsave area; | ||
| 727 | * xstate: state which is defined in xsave.h (e.g. XSTATE_FP, XSTATE_SSE, | ||
| 728 | * etc.) | ||
| 729 | * Output: | ||
| 730 | * address of the state in the xsave area. | ||
| 731 | */ | ||
| 732 | void *get_xsave_addr(struct xsave_struct *xsave, int xstate) | ||
| 733 | { | ||
| 734 | int feature = fls64(xstate) - 1; | ||
| 735 | if (!test_bit(feature, (unsigned long *)&pcntxt_mask)) | ||
| 736 | return NULL; | ||
| 737 | |||
| 738 | return (void *)xsave + xstate_comp_offsets[feature]; | ||
| 739 | } | ||
