diff options
Diffstat (limited to 'arch/x86/xen/smp.c')
-rw-r--r-- | arch/x86/xen/smp.c | 29 |
1 files changed, 18 insertions, 11 deletions
diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c index 7005974c3ff3..c670d7518cf4 100644 --- a/arch/x86/xen/smp.c +++ b/arch/x86/xen/smp.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <xen/hvc-console.h> | 37 | #include <xen/hvc-console.h> |
38 | #include "xen-ops.h" | 38 | #include "xen-ops.h" |
39 | #include "mmu.h" | 39 | #include "mmu.h" |
40 | #include "smp.h" | ||
40 | 41 | ||
41 | cpumask_var_t xen_cpu_initialized_map; | 42 | cpumask_var_t xen_cpu_initialized_map; |
42 | 43 | ||
@@ -99,10 +100,14 @@ static void cpu_bringup(void) | |||
99 | wmb(); /* make sure everything is out */ | 100 | wmb(); /* make sure everything is out */ |
100 | } | 101 | } |
101 | 102 | ||
102 | /* Note: cpu parameter is only relevant for PVH */ | 103 | /* |
103 | static void cpu_bringup_and_idle(int cpu) | 104 | * Note: cpu parameter is only relevant for PVH. The reason for passing it |
105 | * is we can't do smp_processor_id until the percpu segments are loaded, for | ||
106 | * which we need the cpu number! So we pass it in rdi as first parameter. | ||
107 | */ | ||
108 | asmlinkage __visible void cpu_bringup_and_idle(int cpu) | ||
104 | { | 109 | { |
105 | #ifdef CONFIG_X86_64 | 110 | #ifdef CONFIG_XEN_PVH |
106 | if (xen_feature(XENFEAT_auto_translated_physmap) && | 111 | if (xen_feature(XENFEAT_auto_translated_physmap) && |
107 | xen_feature(XENFEAT_supervisor_mode_kernel)) | 112 | xen_feature(XENFEAT_supervisor_mode_kernel)) |
108 | xen_pvh_secondary_vcpu_init(cpu); | 113 | xen_pvh_secondary_vcpu_init(cpu); |
@@ -374,11 +379,10 @@ cpu_initialize_context(unsigned int cpu, struct task_struct *idle) | |||
374 | ctxt->user_regs.fs = __KERNEL_PERCPU; | 379 | ctxt->user_regs.fs = __KERNEL_PERCPU; |
375 | ctxt->user_regs.gs = __KERNEL_STACK_CANARY; | 380 | ctxt->user_regs.gs = __KERNEL_STACK_CANARY; |
376 | #endif | 381 | #endif |
377 | ctxt->user_regs.eip = (unsigned long)cpu_bringup_and_idle; | ||
378 | |||
379 | memset(&ctxt->fpu_ctxt, 0, sizeof(ctxt->fpu_ctxt)); | 382 | memset(&ctxt->fpu_ctxt, 0, sizeof(ctxt->fpu_ctxt)); |
380 | 383 | ||
381 | if (!xen_feature(XENFEAT_auto_translated_physmap)) { | 384 | if (!xen_feature(XENFEAT_auto_translated_physmap)) { |
385 | ctxt->user_regs.eip = (unsigned long)cpu_bringup_and_idle; | ||
382 | ctxt->flags = VGCF_IN_KERNEL; | 386 | ctxt->flags = VGCF_IN_KERNEL; |
383 | ctxt->user_regs.eflags = 0x1000; /* IOPL_RING1 */ | 387 | ctxt->user_regs.eflags = 0x1000; /* IOPL_RING1 */ |
384 | ctxt->user_regs.ds = __USER_DS; | 388 | ctxt->user_regs.ds = __USER_DS; |
@@ -413,15 +417,18 @@ cpu_initialize_context(unsigned int cpu, struct task_struct *idle) | |||
413 | (unsigned long)xen_failsafe_callback; | 417 | (unsigned long)xen_failsafe_callback; |
414 | ctxt->user_regs.cs = __KERNEL_CS; | 418 | ctxt->user_regs.cs = __KERNEL_CS; |
415 | per_cpu(xen_cr3, cpu) = __pa(swapper_pg_dir); | 419 | per_cpu(xen_cr3, cpu) = __pa(swapper_pg_dir); |
416 | #ifdef CONFIG_X86_32 | ||
417 | } | 420 | } |
418 | #else | 421 | #ifdef CONFIG_XEN_PVH |
419 | } else | 422 | else { |
420 | /* N.B. The user_regs.eip (cpu_bringup_and_idle) is called with | 423 | /* |
421 | * %rdi having the cpu number - which means are passing in | 424 | * The vcpu comes on kernel page tables which have the NX pte |
422 | * as the first parameter the cpu. Subtle! | 425 | * bit set. This means before DS/SS is touched, NX in |
426 | * EFER must be set. Hence the following assembly glue code. | ||
423 | */ | 427 | */ |
428 | ctxt->user_regs.eip = (unsigned long)xen_pvh_early_cpu_init; | ||
424 | ctxt->user_regs.rdi = cpu; | 429 | ctxt->user_regs.rdi = cpu; |
430 | ctxt->user_regs.rsi = true; /* entry == true */ | ||
431 | } | ||
425 | #endif | 432 | #endif |
426 | ctxt->user_regs.esp = idle->thread.sp0 - sizeof(struct pt_regs); | 433 | ctxt->user_regs.esp = idle->thread.sp0 - sizeof(struct pt_regs); |
427 | ctxt->ctrlreg[3] = xen_pfn_to_cr3(virt_to_mfn(swapper_pg_dir)); | 434 | ctxt->ctrlreg[3] = xen_pfn_to_cr3(virt_to_mfn(swapper_pg_dir)); |