|
@@ -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>
|
|
@@ -35,8 +36,10 @@
|
|
|
#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
|