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 /arch/x86/include | |
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
Diffstat (limited to 'arch/x86/include')
-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 |
4 files changed, 189 insertions, 61 deletions
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 |