Merge branch 'upstream/pvhvm' into upstream/xen
[pandora-kernel.git] / arch / x86 / xen / enlighten.c
index 3c4da8b..d4ff5e8 100644 (file)
@@ -11,6 +11,7 @@
  * Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007
  */
 
+#include <linux/cpu.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/smp.h>
 #include <xen/interface/version.h>
 #include <xen/interface/physdev.h>
 #include <xen/interface/vcpu.h>
+#include <xen/interface/memory.h>
 #include <xen/features.h>
 #include <xen/page.h>
+#include <xen/hvm.h>
 #include <xen/hvc-console.h>
 
 #include <asm/paravirt.h>
@@ -55,7 +58,9 @@
 #include <asm/pgtable.h>
 #include <asm/tlbflush.h>
 #include <asm/reboot.h>
+#include <asm/setup.h>
 #include <asm/stackprotector.h>
+#include <asm/hypervisor.h>
 
 #include "xen-ops.h"
 #include "mmu.h"
@@ -76,6 +81,10 @@ struct shared_info xen_dummy_shared_info;
 
 void *xen_initial_gdt;
 
+RESERVE_BRK(shared_info_page_brk, PAGE_SIZE);
+__read_mostly int xen_have_vector_callback;
+EXPORT_SYMBOL_GPL(xen_have_vector_callback);
+
 /*
  * Point at some empty memory to start with. We map the real shared_info
  * page as soon as fixmap is up and running.
@@ -938,10 +947,6 @@ static const struct pv_init_ops xen_init_ops __initdata = {
        .patch = xen_patch,
 };
 
-static const struct pv_time_ops xen_time_ops __initdata = {
-       .sched_clock = xen_clocksource_read,
-};
-
 static const struct pv_cpu_ops xen_cpu_ops __initdata = {
        .cpuid = xen_cpuid,
 
@@ -1096,7 +1101,6 @@ asmlinkage void __init xen_start_kernel(void)
        /* Install Xen paravirt ops */
        pv_info = xen_info;
        pv_init_ops = xen_init_ops;
-       pv_time_ops = xen_time_ops;
        pv_cpu_ops = xen_cpu_ops;
        pv_apic_ops = xen_apic_ops;
 
@@ -1104,13 +1108,7 @@ asmlinkage void __init xen_start_kernel(void)
        x86_init.oem.arch_setup = xen_arch_setup;
        x86_init.oem.banner = xen_banner;
 
-       x86_init.timers.timer_init = xen_time_init;
-       x86_init.timers.setup_percpu_clockev = x86_init_noop;
-       x86_cpuinit.setup_percpu_clockev = x86_init_noop;
-
-       x86_platform.calibrate_tsc = xen_tsc_khz;
-       x86_platform.get_wallclock = xen_get_wallclock;
-       x86_platform.set_wallclock = xen_set_wallclock;
+       xen_init_time_ops();
 
        /*
         * Set up some pagetable state before starting to set any ptes.
@@ -1235,3 +1233,139 @@ asmlinkage void __init xen_start_kernel(void)
        x86_64_start_reservations((char *)__pa_symbol(&boot_params));
 #endif
 }
+
+static uint32_t xen_cpuid_base(void)
+{
+       uint32_t base, eax, ebx, ecx, edx;
+       char signature[13];
+
+       for (base = 0x40000000; base < 0x40010000; base += 0x100) {
+               cpuid(base, &eax, &ebx, &ecx, &edx);
+               *(uint32_t *)(signature + 0) = ebx;
+               *(uint32_t *)(signature + 4) = ecx;
+               *(uint32_t *)(signature + 8) = edx;
+               signature[12] = 0;
+
+               if (!strcmp("XenVMMXenVMM", signature) && ((eax - base) >= 2))
+                       return base;
+       }
+
+       return 0;
+}
+
+static int init_hvm_pv_info(int *major, int *minor)
+{
+       uint32_t eax, ebx, ecx, edx, pages, msr, base;
+       u64 pfn;
+
+       base = xen_cpuid_base();
+       cpuid(base + 1, &eax, &ebx, &ecx, &edx);
+
+       *major = eax >> 16;
+       *minor = eax & 0xffff;
+       printk(KERN_INFO "Xen version %d.%d.\n", *major, *minor);
+
+       cpuid(base + 2, &pages, &msr, &ecx, &edx);
+
+       pfn = __pa(hypercall_page);
+       wrmsr_safe(msr, (u32)pfn, (u32)(pfn >> 32));
+
+       xen_setup_features();
+
+       pv_info = xen_info;
+       pv_info.kernel_rpl = 0;
+
+       xen_domain_type = XEN_HVM_DOMAIN;
+
+       return 0;
+}
+
+void xen_hvm_init_shared_info(void)
+{
+       int cpu;
+       struct xen_add_to_physmap xatp;
+       static struct shared_info *shared_info_page = 0;
+
+       if (!shared_info_page)
+               shared_info_page = (struct shared_info *)
+                       extend_brk(PAGE_SIZE, PAGE_SIZE);
+       xatp.domid = DOMID_SELF;
+       xatp.idx = 0;
+       xatp.space = XENMAPSPACE_shared_info;
+       xatp.gpfn = __pa(shared_info_page) >> PAGE_SHIFT;
+       if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp))
+               BUG();
+
+       HYPERVISOR_shared_info = (struct shared_info *)shared_info_page;
+
+       /* xen_vcpu is a pointer to the vcpu_info struct in the shared_info
+        * page, we use it in the event channel upcall and in some pvclock
+        * related functions. We don't need the vcpu_info placement
+        * optimizations because we don't use any pv_mmu or pv_irq op on
+        * HVM.
+        * When xen_hvm_init_shared_info is run at boot time only vcpu 0 is
+        * online but xen_hvm_init_shared_info is run at resume time too and
+        * in that case multiple vcpus might be online. */
+       for_each_online_cpu(cpu) {
+               per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu];
+       }
+}
+
+#ifdef CONFIG_XEN_PVHVM
+static int __cpuinit xen_hvm_cpu_notify(struct notifier_block *self,
+                                   unsigned long action, void *hcpu)
+{
+       int cpu = (long)hcpu;
+       switch (action) {
+       case CPU_UP_PREPARE:
+               per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu];
+               break;
+       default:
+               break;
+       }
+       return NOTIFY_OK;
+}
+
+static struct notifier_block __cpuinitdata xen_hvm_cpu_notifier = {
+       .notifier_call  = xen_hvm_cpu_notify,
+};
+
+static void __init xen_hvm_guest_init(void)
+{
+       int r;
+       int major, minor;
+
+       r = init_hvm_pv_info(&major, &minor);
+       if (r < 0)
+               return;
+
+       xen_hvm_init_shared_info();
+
+       if (xen_feature(XENFEAT_hvm_callback_vector))
+               xen_have_vector_callback = 1;
+       register_cpu_notifier(&xen_hvm_cpu_notifier);
+       xen_unplug_emulated_devices();
+       have_vcpu_info_placement = 0;
+       x86_init.irqs.intr_init = xen_init_IRQ;
+       xen_hvm_init_time_ops();
+       xen_hvm_init_mmu_ops();
+}
+
+static bool __init xen_hvm_platform(void)
+{
+       if (xen_pv_domain())
+               return false;
+
+       if (!xen_cpuid_base())
+               return false;
+
+       return true;
+}
+
+const __refconst struct hypervisor_x86 x86_hyper_xen_hvm = {
+       .name                   = "Xen HVM",
+       .detect                 = xen_hvm_platform,
+       .init_platform          = xen_hvm_guest_init,
+};
+EXPORT_SYMBOL(x86_hyper_xen_hvm);
+#endif