aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386/xen/enlighten.c
diff options
context:
space:
mode:
authorJeremy Fitzhardinge <jeremy@xensource.com>2007-07-17 21:37:06 -0400
committerJeremy Fitzhardinge <jeremy@goop.org>2007-07-18 11:47:44 -0400
commitf87e4cac4f4e940b328d3deb5b53e642e3881f43 (patch)
tree7409f86561e5f97459378abd2ae21e9a5c82bfea /arch/i386/xen/enlighten.c
parentab55028886dd1dd54585f22bf19a00eb23869340 (diff)
xen: SMP guest support
This is a fairly straightforward Xen implementation of smp_ops. Xen has its own IPI mechanisms, and has no dependency on any APIC-based IPI. The smp_ops hooks and the flush_tlb_others pv_op allow a Xen guest to avoid all APIC code in arch/i386 (the only apic operation is a single apic_read for the apic version number). One subtle point which needs to be addressed is unpinning pagetables when another cpu may have a lazy tlb reference to the pagetable. Xen will not allow an in-use pagetable to be unpinned, so we must find any other cpus with a reference to the pagetable and get them to shoot down their references. Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com> Signed-off-by: Chris Wright <chrisw@sous-sol.org> Cc: Benjamin LaHaise <bcrl@kvack.org> Cc: Ingo Molnar <mingo@redhat.com> Cc: Andi Kleen <ak@suse.de>
Diffstat (limited to 'arch/i386/xen/enlighten.c')
-rw-r--r--arch/i386/xen/enlighten.c115
1 files changed, 89 insertions, 26 deletions
diff --git a/arch/i386/xen/enlighten.c b/arch/i386/xen/enlighten.c
index a9ba834295a2..de62d66e0893 100644
--- a/arch/i386/xen/enlighten.c
+++ b/arch/i386/xen/enlighten.c
@@ -24,6 +24,7 @@
24#include <linux/mm.h> 24#include <linux/mm.h>
25#include <linux/page-flags.h> 25#include <linux/page-flags.h>
26#include <linux/highmem.h> 26#include <linux/highmem.h>
27#include <linux/smp.h>
27 28
28#include <xen/interface/xen.h> 29#include <xen/interface/xen.h>
29#include <xen/interface/physdev.h> 30#include <xen/interface/physdev.h>
@@ -40,6 +41,7 @@
40#include <asm/setup.h> 41#include <asm/setup.h>
41#include <asm/desc.h> 42#include <asm/desc.h>
42#include <asm/pgtable.h> 43#include <asm/pgtable.h>
44#include <asm/tlbflush.h>
43 45
44#include "xen-ops.h" 46#include "xen-ops.h"
45#include "mmu.h" 47#include "mmu.h"
@@ -56,7 +58,7 @@ DEFINE_PER_CPU(unsigned long, xen_cr3);
56struct start_info *xen_start_info; 58struct start_info *xen_start_info;
57EXPORT_SYMBOL_GPL(xen_start_info); 59EXPORT_SYMBOL_GPL(xen_start_info);
58 60
59static void xen_vcpu_setup(int cpu) 61void xen_vcpu_setup(int cpu)
60{ 62{
61 per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu]; 63 per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu];
62} 64}
@@ -347,23 +349,14 @@ static void xen_write_idt_entry(struct desc_struct *dt, int entrynum,
347 } 349 }
348} 350}
349 351
350/* Load a new IDT into Xen. In principle this can be per-CPU, so we 352static void xen_convert_trap_info(const struct Xgt_desc_struct *desc,
351 hold a spinlock to protect the static traps[] array (static because 353 struct trap_info *traps)
352 it avoids allocation, and saves stack space). */
353static void xen_load_idt(const struct Xgt_desc_struct *desc)
354{ 354{
355 static DEFINE_SPINLOCK(lock);
356 static struct trap_info traps[257];
357
358 int cpu = smp_processor_id();
359 unsigned in, out, count; 355 unsigned in, out, count;
360 356
361 per_cpu(idt_desc, cpu) = *desc;
362
363 count = (desc->size+1) / 8; 357 count = (desc->size+1) / 8;
364 BUG_ON(count > 256); 358 BUG_ON(count > 256);
365 359
366 spin_lock(&lock);
367 for (in = out = 0; in < count; in++) { 360 for (in = out = 0; in < count; in++) {
368 const u32 *entry = (u32 *)(desc->address + in * 8); 361 const u32 *entry = (u32 *)(desc->address + in * 8);
369 362
@@ -371,6 +364,31 @@ static void xen_load_idt(const struct Xgt_desc_struct *desc)
371 out++; 364 out++;
372 } 365 }
373 traps[out].address = 0; 366 traps[out].address = 0;
367}
368
369void xen_copy_trap_info(struct trap_info *traps)
370{
371 const struct Xgt_desc_struct *desc = &get_cpu_var(idt_desc);
372
373 xen_convert_trap_info(desc, traps);
374
375 put_cpu_var(idt_desc);
376}
377
378/* Load a new IDT into Xen. In principle this can be per-CPU, so we
379 hold a spinlock to protect the static traps[] array (static because
380 it avoids allocation, and saves stack space). */
381static void xen_load_idt(const struct Xgt_desc_struct *desc)
382{
383 static DEFINE_SPINLOCK(lock);
384 static struct trap_info traps[257];
385 int cpu = smp_processor_id();
386
387 per_cpu(idt_desc, cpu) = *desc;
388
389 spin_lock(&lock);
390
391 xen_convert_trap_info(desc, traps);
374 392
375 xen_mc_flush(); 393 xen_mc_flush();
376 if (HYPERVISOR_set_trap_table(traps)) 394 if (HYPERVISOR_set_trap_table(traps))
@@ -428,6 +446,12 @@ static unsigned long xen_apic_read(unsigned long reg)
428{ 446{
429 return 0; 447 return 0;
430} 448}
449
450static void xen_apic_write(unsigned long reg, unsigned long val)
451{
452 /* Warn to see if there's any stray references */
453 WARN_ON(1);
454}
431#endif 455#endif
432 456
433static void xen_flush_tlb(void) 457static void xen_flush_tlb(void)
@@ -449,6 +473,40 @@ static void xen_flush_tlb_single(unsigned long addr)
449 BUG(); 473 BUG();
450} 474}
451 475
476static void xen_flush_tlb_others(const cpumask_t *cpus, struct mm_struct *mm,
477 unsigned long va)
478{
479 struct mmuext_op op;
480 cpumask_t cpumask = *cpus;
481
482 /*
483 * A couple of (to be removed) sanity checks:
484 *
485 * - current CPU must not be in mask
486 * - mask must exist :)
487 */
488 BUG_ON(cpus_empty(cpumask));
489 BUG_ON(cpu_isset(smp_processor_id(), cpumask));
490 BUG_ON(!mm);
491
492 /* If a CPU which we ran on has gone down, OK. */
493 cpus_and(cpumask, cpumask, cpu_online_map);
494 if (cpus_empty(cpumask))
495 return;
496
497 if (va == TLB_FLUSH_ALL) {
498 op.cmd = MMUEXT_TLB_FLUSH_MULTI;
499 op.arg2.vcpumask = (void *)cpus;
500 } else {
501 op.cmd = MMUEXT_INVLPG_MULTI;
502 op.arg1.linear_addr = va;
503 op.arg2.vcpumask = (void *)cpus;
504 }
505
506 if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF))
507 BUG();
508}
509
452static unsigned long xen_read_cr2(void) 510static unsigned long xen_read_cr2(void)
453{ 511{
454 return x86_read_percpu(xen_vcpu)->arch.cr2; 512 return x86_read_percpu(xen_vcpu)->arch.cr2;
@@ -460,18 +518,6 @@ static void xen_write_cr4(unsigned long cr4)
460 native_write_cr4(cr4 & ~X86_CR4_TSD); 518 native_write_cr4(cr4 & ~X86_CR4_TSD);
461} 519}
462 520
463/*
464 * Page-directory addresses above 4GB do not fit into architectural %cr3.
465 * When accessing %cr3, or equivalent field in vcpu_guest_context, guests
466 * must use the following accessor macros to pack/unpack valid MFNs.
467 *
468 * Note that Xen is using the fact that the pagetable base is always
469 * page-aligned, and putting the 12 MSB of the address into the 12 LSB
470 * of cr3.
471 */
472#define xen_pfn_to_cr3(pfn) (((unsigned)(pfn) << 12) | ((unsigned)(pfn) >> 20))
473#define xen_cr3_to_pfn(cr3) (((unsigned)(cr3) >> 12) | ((unsigned)(cr3) << 20))
474
475static unsigned long xen_read_cr3(void) 521static unsigned long xen_read_cr3(void)
476{ 522{
477 return x86_read_percpu(xen_cr3); 523 return x86_read_percpu(xen_cr3);
@@ -740,8 +786,8 @@ static const struct paravirt_ops xen_paravirt_ops __initdata = {
740 .io_delay = xen_io_delay, 786 .io_delay = xen_io_delay,
741 787
742#ifdef CONFIG_X86_LOCAL_APIC 788#ifdef CONFIG_X86_LOCAL_APIC
743 .apic_write = paravirt_nop, 789 .apic_write = xen_apic_write,
744 .apic_write_atomic = paravirt_nop, 790 .apic_write_atomic = xen_apic_write,
745 .apic_read = xen_apic_read, 791 .apic_read = xen_apic_read,
746 .setup_boot_clock = paravirt_nop, 792 .setup_boot_clock = paravirt_nop,
747 .setup_secondary_clock = paravirt_nop, 793 .setup_secondary_clock = paravirt_nop,
@@ -751,6 +797,7 @@ static const struct paravirt_ops xen_paravirt_ops __initdata = {
751 .flush_tlb_user = xen_flush_tlb, 797 .flush_tlb_user = xen_flush_tlb,
752 .flush_tlb_kernel = xen_flush_tlb, 798 .flush_tlb_kernel = xen_flush_tlb,
753 .flush_tlb_single = xen_flush_tlb_single, 799 .flush_tlb_single = xen_flush_tlb_single,
800 .flush_tlb_others = xen_flush_tlb_others,
754 801
755 .pte_update = paravirt_nop, 802 .pte_update = paravirt_nop,
756 .pte_update_defer = paravirt_nop, 803 .pte_update_defer = paravirt_nop,
@@ -796,6 +843,19 @@ static const struct paravirt_ops xen_paravirt_ops __initdata = {
796 .set_lazy_mode = xen_set_lazy_mode, 843 .set_lazy_mode = xen_set_lazy_mode,
797}; 844};
798 845
846#ifdef CONFIG_SMP
847static const struct smp_ops xen_smp_ops __initdata = {
848 .smp_prepare_boot_cpu = xen_smp_prepare_boot_cpu,
849 .smp_prepare_cpus = xen_smp_prepare_cpus,
850 .cpu_up = xen_cpu_up,
851 .smp_cpus_done = xen_smp_cpus_done,
852
853 .smp_send_stop = xen_smp_send_stop,
854 .smp_send_reschedule = xen_smp_send_reschedule,
855 .smp_call_function_mask = xen_smp_call_function_mask,
856};
857#endif /* CONFIG_SMP */
858
799/* First C function to be called on Xen boot */ 859/* First C function to be called on Xen boot */
800asmlinkage void __init xen_start_kernel(void) 860asmlinkage void __init xen_start_kernel(void)
801{ 861{
@@ -808,6 +868,9 @@ asmlinkage void __init xen_start_kernel(void)
808 868
809 /* Install Xen paravirt ops */ 869 /* Install Xen paravirt ops */
810 paravirt_ops = xen_paravirt_ops; 870 paravirt_ops = xen_paravirt_ops;
871#ifdef CONFIG_SMP
872 smp_ops = xen_smp_ops;
873#endif
811 874
812 xen_setup_features(); 875 xen_setup_features();
813 876