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 | |
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')
-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 |
8 files changed, 309 insertions, 70 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 |
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 | } | ||