aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/xen
diff options
context:
space:
mode:
authorJeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>2009-03-07 20:09:27 -0500
committerJeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>2009-04-08 14:51:46 -0400
commit191216b9289ed02256086e6bab4f668112109399 (patch)
tree1f9db4f838ab11d04b34f04f3ebd61ccb1180409 /arch/x86/xen
parent1207cf8eb99d8c699919e352292bdf1f519fbba5 (diff)
xen: mask XSAVE from cpuid
Xen leaves XSAVE set in cpuid, but doesn't allow cr4.OSXSAVE to be set. This confuses the kernel and it ends up crashing on an xsetbv instruction. At boot time, try to set cr4.OSXSAVE, and mask XSAVE out of cpuid it we can't. This will produce a spurious error from Xen, but allows us to support XSAVE if/when Xen does. This also factors out the cpuid mask decisions to boot time. Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
Diffstat (limited to 'arch/x86/xen')
-rw-r--r--arch/x86/xen/enlighten.c50
1 files changed, 44 insertions, 6 deletions
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index 5d9a1c37c51..69de19168a7 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -168,21 +168,23 @@ static void __init xen_banner(void)
168 xen_feature(XENFEAT_mmu_pt_update_preserve_ad) ? " (preserve-AD)" : ""); 168 xen_feature(XENFEAT_mmu_pt_update_preserve_ad) ? " (preserve-AD)" : "");
169} 169}
170 170
171static __read_mostly unsigned int cpuid_leaf1_edx_mask = ~0;
172static __read_mostly unsigned int cpuid_leaf1_ecx_mask = ~0;
173
171static void xen_cpuid(unsigned int *ax, unsigned int *bx, 174static void xen_cpuid(unsigned int *ax, unsigned int *bx,
172 unsigned int *cx, unsigned int *dx) 175 unsigned int *cx, unsigned int *dx)
173{ 176{
177 unsigned maskecx = ~0;
174 unsigned maskedx = ~0; 178 unsigned maskedx = ~0;
175 179
176 /* 180 /*
177 * Mask out inconvenient features, to try and disable as many 181 * Mask out inconvenient features, to try and disable as many
178 * unsupported kernel subsystems as possible. 182 * unsupported kernel subsystems as possible.
179 */ 183 */
180 if (*ax == 1) 184 if (*ax == 1) {
181 maskedx = ~((1 << X86_FEATURE_APIC) | /* disable APIC */ 185 maskecx = cpuid_leaf1_ecx_mask;
182 (1 << X86_FEATURE_ACPI) | /* disable ACPI */ 186 maskedx = cpuid_leaf1_edx_mask;
183 (1 << X86_FEATURE_MCE) | /* disable MCE */ 187 }
184 (1 << X86_FEATURE_MCA) | /* disable MCA */
185 (1 << X86_FEATURE_ACC)); /* thermal monitoring */
186 188
187 asm(XEN_EMULATE_PREFIX "cpuid" 189 asm(XEN_EMULATE_PREFIX "cpuid"
188 : "=a" (*ax), 190 : "=a" (*ax),
@@ -190,9 +192,43 @@ static void xen_cpuid(unsigned int *ax, unsigned int *bx,
190 "=c" (*cx), 192 "=c" (*cx),
191 "=d" (*dx) 193 "=d" (*dx)
192 : "0" (*ax), "2" (*cx)); 194 : "0" (*ax), "2" (*cx));
195
196 *cx &= maskecx;
193 *dx &= maskedx; 197 *dx &= maskedx;
194} 198}
195 199
200static __init void xen_init_cpuid_mask(void)
201{
202 unsigned int ax, bx, cx, dx;
203
204 cpuid_leaf1_edx_mask =
205 ~((1 << X86_FEATURE_MCE) | /* disable MCE */
206 (1 << X86_FEATURE_MCA) | /* disable MCA */
207 (1 << X86_FEATURE_ACC)); /* thermal monitoring */
208
209 if (!xen_initial_domain())
210 cpuid_leaf1_edx_mask &=
211 ~((1 << X86_FEATURE_APIC) | /* disable local APIC */
212 (1 << X86_FEATURE_ACPI)); /* disable ACPI */
213
214 ax = 1;
215 xen_cpuid(&ax, &bx, &cx, &dx);
216
217 /* cpuid claims we support xsave; try enabling it to see what happens */
218 if (cx & (1 << (X86_FEATURE_XSAVE % 32))) {
219 unsigned long cr4;
220
221 set_in_cr4(X86_CR4_OSXSAVE);
222
223 cr4 = read_cr4();
224
225 if ((cr4 & X86_CR4_OSXSAVE) == 0)
226 cpuid_leaf1_ecx_mask &= ~(1 << (X86_FEATURE_XSAVE % 32));
227
228 clear_in_cr4(X86_CR4_OSXSAVE);
229 }
230}
231
196static void xen_set_debugreg(int reg, unsigned long val) 232static void xen_set_debugreg(int reg, unsigned long val)
197{ 233{
198 HYPERVISOR_set_debugreg(reg, val); 234 HYPERVISOR_set_debugreg(reg, val);
@@ -903,6 +939,8 @@ asmlinkage void __init xen_start_kernel(void)
903 939
904 xen_init_irq_ops(); 940 xen_init_irq_ops();
905 941
942 xen_init_cpuid_mask();
943
906#ifdef CONFIG_X86_LOCAL_APIC 944#ifdef CONFIG_X86_LOCAL_APIC
907 /* 945 /*
908 * set up the basic apic ops. 946 * set up the basic apic ops.