diff options
Diffstat (limited to 'arch/x86/xen/enlighten.c')
-rw-r--r-- | arch/x86/xen/enlighten.c | 89 |
1 files changed, 69 insertions, 20 deletions
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 82cd39a6cbd3..f09e8c36ee80 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c | |||
@@ -42,6 +42,7 @@ | |||
42 | #include <asm/xen/hypervisor.h> | 42 | #include <asm/xen/hypervisor.h> |
43 | #include <asm/fixmap.h> | 43 | #include <asm/fixmap.h> |
44 | #include <asm/processor.h> | 44 | #include <asm/processor.h> |
45 | #include <asm/proto.h> | ||
45 | #include <asm/msr-index.h> | 46 | #include <asm/msr-index.h> |
46 | #include <asm/setup.h> | 47 | #include <asm/setup.h> |
47 | #include <asm/desc.h> | 48 | #include <asm/desc.h> |
@@ -168,21 +169,23 @@ static void __init xen_banner(void) | |||
168 | xen_feature(XENFEAT_mmu_pt_update_preserve_ad) ? " (preserve-AD)" : ""); | 169 | xen_feature(XENFEAT_mmu_pt_update_preserve_ad) ? " (preserve-AD)" : ""); |
169 | } | 170 | } |
170 | 171 | ||
172 | static __read_mostly unsigned int cpuid_leaf1_edx_mask = ~0; | ||
173 | static __read_mostly unsigned int cpuid_leaf1_ecx_mask = ~0; | ||
174 | |||
171 | static void xen_cpuid(unsigned int *ax, unsigned int *bx, | 175 | static void xen_cpuid(unsigned int *ax, unsigned int *bx, |
172 | unsigned int *cx, unsigned int *dx) | 176 | unsigned int *cx, unsigned int *dx) |
173 | { | 177 | { |
178 | unsigned maskecx = ~0; | ||
174 | unsigned maskedx = ~0; | 179 | unsigned maskedx = ~0; |
175 | 180 | ||
176 | /* | 181 | /* |
177 | * Mask out inconvenient features, to try and disable as many | 182 | * Mask out inconvenient features, to try and disable as many |
178 | * unsupported kernel subsystems as possible. | 183 | * unsupported kernel subsystems as possible. |
179 | */ | 184 | */ |
180 | if (*ax == 1) | 185 | if (*ax == 1) { |
181 | maskedx = ~((1 << X86_FEATURE_APIC) | /* disable APIC */ | 186 | maskecx = cpuid_leaf1_ecx_mask; |
182 | (1 << X86_FEATURE_ACPI) | /* disable ACPI */ | 187 | maskedx = cpuid_leaf1_edx_mask; |
183 | (1 << X86_FEATURE_MCE) | /* disable MCE */ | 188 | } |
184 | (1 << X86_FEATURE_MCA) | /* disable MCA */ | ||
185 | (1 << X86_FEATURE_ACC)); /* thermal monitoring */ | ||
186 | 189 | ||
187 | asm(XEN_EMULATE_PREFIX "cpuid" | 190 | asm(XEN_EMULATE_PREFIX "cpuid" |
188 | : "=a" (*ax), | 191 | : "=a" (*ax), |
@@ -190,9 +193,43 @@ static void xen_cpuid(unsigned int *ax, unsigned int *bx, | |||
190 | "=c" (*cx), | 193 | "=c" (*cx), |
191 | "=d" (*dx) | 194 | "=d" (*dx) |
192 | : "0" (*ax), "2" (*cx)); | 195 | : "0" (*ax), "2" (*cx)); |
196 | |||
197 | *cx &= maskecx; | ||
193 | *dx &= maskedx; | 198 | *dx &= maskedx; |
194 | } | 199 | } |
195 | 200 | ||
201 | static __init void xen_init_cpuid_mask(void) | ||
202 | { | ||
203 | unsigned int ax, bx, cx, dx; | ||
204 | |||
205 | cpuid_leaf1_edx_mask = | ||
206 | ~((1 << X86_FEATURE_MCE) | /* disable MCE */ | ||
207 | (1 << X86_FEATURE_MCA) | /* disable MCA */ | ||
208 | (1 << X86_FEATURE_ACC)); /* thermal monitoring */ | ||
209 | |||
210 | if (!xen_initial_domain()) | ||
211 | cpuid_leaf1_edx_mask &= | ||
212 | ~((1 << X86_FEATURE_APIC) | /* disable local APIC */ | ||
213 | (1 << X86_FEATURE_ACPI)); /* disable ACPI */ | ||
214 | |||
215 | ax = 1; | ||
216 | xen_cpuid(&ax, &bx, &cx, &dx); | ||
217 | |||
218 | /* cpuid claims we support xsave; try enabling it to see what happens */ | ||
219 | if (cx & (1 << (X86_FEATURE_XSAVE % 32))) { | ||
220 | unsigned long cr4; | ||
221 | |||
222 | set_in_cr4(X86_CR4_OSXSAVE); | ||
223 | |||
224 | cr4 = read_cr4(); | ||
225 | |||
226 | if ((cr4 & X86_CR4_OSXSAVE) == 0) | ||
227 | cpuid_leaf1_ecx_mask &= ~(1 << (X86_FEATURE_XSAVE % 32)); | ||
228 | |||
229 | clear_in_cr4(X86_CR4_OSXSAVE); | ||
230 | } | ||
231 | } | ||
232 | |||
196 | static void xen_set_debugreg(int reg, unsigned long val) | 233 | static void xen_set_debugreg(int reg, unsigned long val) |
197 | { | 234 | { |
198 | HYPERVISOR_set_debugreg(reg, val); | 235 | HYPERVISOR_set_debugreg(reg, val); |
@@ -284,12 +321,11 @@ static void xen_set_ldt(const void *addr, unsigned entries) | |||
284 | 321 | ||
285 | static void xen_load_gdt(const struct desc_ptr *dtr) | 322 | static void xen_load_gdt(const struct desc_ptr *dtr) |
286 | { | 323 | { |
287 | unsigned long *frames; | ||
288 | unsigned long va = dtr->address; | 324 | unsigned long va = dtr->address; |
289 | unsigned int size = dtr->size + 1; | 325 | unsigned int size = dtr->size + 1; |
290 | unsigned pages = (size + PAGE_SIZE - 1) / PAGE_SIZE; | 326 | unsigned pages = (size + PAGE_SIZE - 1) / PAGE_SIZE; |
327 | unsigned long frames[pages]; | ||
291 | int f; | 328 | int f; |
292 | struct multicall_space mcs; | ||
293 | 329 | ||
294 | /* A GDT can be up to 64k in size, which corresponds to 8192 | 330 | /* A GDT can be up to 64k in size, which corresponds to 8192 |
295 | 8-byte entries, or 16 4k pages.. */ | 331 | 8-byte entries, or 16 4k pages.. */ |
@@ -297,19 +333,26 @@ static void xen_load_gdt(const struct desc_ptr *dtr) | |||
297 | BUG_ON(size > 65536); | 333 | BUG_ON(size > 65536); |
298 | BUG_ON(va & ~PAGE_MASK); | 334 | BUG_ON(va & ~PAGE_MASK); |
299 | 335 | ||
300 | mcs = xen_mc_entry(sizeof(*frames) * pages); | ||
301 | frames = mcs.args; | ||
302 | |||
303 | for (f = 0; va < dtr->address + size; va += PAGE_SIZE, f++) { | 336 | for (f = 0; va < dtr->address + size; va += PAGE_SIZE, f++) { |
304 | frames[f] = arbitrary_virt_to_mfn((void *)va); | 337 | int level; |
338 | pte_t *ptep = lookup_address(va, &level); | ||
339 | unsigned long pfn, mfn; | ||
340 | void *virt; | ||
341 | |||
342 | BUG_ON(ptep == NULL); | ||
343 | |||
344 | pfn = pte_pfn(*ptep); | ||
345 | mfn = pfn_to_mfn(pfn); | ||
346 | virt = __va(PFN_PHYS(pfn)); | ||
347 | |||
348 | frames[f] = mfn; | ||
305 | 349 | ||
306 | make_lowmem_page_readonly((void *)va); | 350 | make_lowmem_page_readonly((void *)va); |
307 | make_lowmem_page_readonly(mfn_to_virt(frames[f])); | 351 | make_lowmem_page_readonly(virt); |
308 | } | 352 | } |
309 | 353 | ||
310 | MULTI_set_gdt(mcs.mc, frames, size / sizeof(struct desc_struct)); | 354 | if (HYPERVISOR_set_gdt(frames, size / sizeof(struct desc_struct))) |
311 | 355 | BUG(); | |
312 | xen_mc_issue(PARAVIRT_LAZY_CPU); | ||
313 | } | 356 | } |
314 | 357 | ||
315 | static void load_TLS_descriptor(struct thread_struct *t, | 358 | static void load_TLS_descriptor(struct thread_struct *t, |
@@ -385,7 +428,7 @@ static void xen_write_ldt_entry(struct desc_struct *dt, int entrynum, | |||
385 | static int cvt_gate_to_trap(int vector, const gate_desc *val, | 428 | static int cvt_gate_to_trap(int vector, const gate_desc *val, |
386 | struct trap_info *info) | 429 | struct trap_info *info) |
387 | { | 430 | { |
388 | if (val->type != 0xf && val->type != 0xe) | 431 | if (val->type != GATE_TRAP && val->type != GATE_INTERRUPT) |
389 | return 0; | 432 | return 0; |
390 | 433 | ||
391 | info->vector = vector; | 434 | info->vector = vector; |
@@ -393,8 +436,8 @@ static int cvt_gate_to_trap(int vector, const gate_desc *val, | |||
393 | info->cs = gate_segment(*val); | 436 | info->cs = gate_segment(*val); |
394 | info->flags = val->dpl; | 437 | info->flags = val->dpl; |
395 | /* interrupt gates clear IF */ | 438 | /* interrupt gates clear IF */ |
396 | if (val->type == 0xe) | 439 | if (val->type == GATE_INTERRUPT) |
397 | info->flags |= 4; | 440 | info->flags |= 1 << 2; |
398 | 441 | ||
399 | return 1; | 442 | return 1; |
400 | } | 443 | } |
@@ -872,7 +915,6 @@ static const struct machine_ops __initdata xen_machine_ops = { | |||
872 | .emergency_restart = xen_emergency_restart, | 915 | .emergency_restart = xen_emergency_restart, |
873 | }; | 916 | }; |
874 | 917 | ||
875 | |||
876 | /* First C function to be called on Xen boot */ | 918 | /* First C function to be called on Xen boot */ |
877 | asmlinkage void __init xen_start_kernel(void) | 919 | asmlinkage void __init xen_start_kernel(void) |
878 | { | 920 | { |
@@ -897,6 +939,8 @@ asmlinkage void __init xen_start_kernel(void) | |||
897 | 939 | ||
898 | xen_init_irq_ops(); | 940 | xen_init_irq_ops(); |
899 | 941 | ||
942 | xen_init_cpuid_mask(); | ||
943 | |||
900 | #ifdef CONFIG_X86_LOCAL_APIC | 944 | #ifdef CONFIG_X86_LOCAL_APIC |
901 | /* | 945 | /* |
902 | * set up the basic apic ops. | 946 | * set up the basic apic ops. |
@@ -938,6 +982,11 @@ asmlinkage void __init xen_start_kernel(void) | |||
938 | if (!xen_initial_domain()) | 982 | if (!xen_initial_domain()) |
939 | __supported_pte_mask &= ~(_PAGE_PWT | _PAGE_PCD); | 983 | __supported_pte_mask &= ~(_PAGE_PWT | _PAGE_PCD); |
940 | 984 | ||
985 | #ifdef CONFIG_X86_64 | ||
986 | /* Work out if we support NX */ | ||
987 | check_efer(); | ||
988 | #endif | ||
989 | |||
941 | /* Don't do the full vcpu_info placement stuff until we have a | 990 | /* Don't do the full vcpu_info placement stuff until we have a |
942 | possible map and a non-dummy shared_info. */ | 991 | possible map and a non-dummy shared_info. */ |
943 | per_cpu(xen_vcpu, 0) = &HYPERVISOR_shared_info->vcpu_info[0]; | 992 | per_cpu(xen_vcpu, 0) = &HYPERVISOR_shared_info->vcpu_info[0]; |