aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/xen
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/xen')
-rw-r--r--arch/x86/xen/Kconfig5
-rw-r--r--arch/x86/xen/Makefile2
-rw-r--r--arch/x86/xen/enlighten.c197
-rw-r--r--arch/x86/xen/mmu.c35
-rw-r--r--arch/x86/xen/mmu.h1
-rw-r--r--arch/x86/xen/platform-pci-unplug.c137
-rw-r--r--arch/x86/xen/setup.c72
-rw-r--r--arch/x86/xen/smp.c2
-rw-r--r--arch/x86/xen/suspend.c12
-rw-r--r--arch/x86/xen/time.c96
-rw-r--r--arch/x86/xen/xen-ops.h13
11 files changed, 506 insertions, 66 deletions
diff --git a/arch/x86/xen/Kconfig b/arch/x86/xen/Kconfig
index b83e119fbeb0..68128a1b401a 100644
--- a/arch/x86/xen/Kconfig
+++ b/arch/x86/xen/Kconfig
@@ -13,6 +13,11 @@ config XEN
13 kernel to boot in a paravirtualized environment under the 13 kernel to boot in a paravirtualized environment under the
14 Xen hypervisor. 14 Xen hypervisor.
15 15
16config XEN_PVHVM
17 def_bool y
18 depends on XEN
19 depends on X86_LOCAL_APIC
20
16config XEN_MAX_DOMAIN_MEMORY 21config XEN_MAX_DOMAIN_MEMORY
17 int "Maximum allowed size of a domain in gigabytes" 22 int "Maximum allowed size of a domain in gigabytes"
18 default 8 if X86_32 23 default 8 if X86_32
diff --git a/arch/x86/xen/Makefile b/arch/x86/xen/Makefile
index 3bb4fc21f4f2..930954685980 100644
--- a/arch/x86/xen/Makefile
+++ b/arch/x86/xen/Makefile
@@ -12,7 +12,7 @@ CFLAGS_mmu.o := $(nostackp)
12 12
13obj-y := enlighten.o setup.o multicalls.o mmu.o irq.o \ 13obj-y := enlighten.o setup.o multicalls.o mmu.o irq.o \
14 time.o xen-asm.o xen-asm_$(BITS).o \ 14 time.o xen-asm.o xen-asm_$(BITS).o \
15 grant-table.o suspend.o 15 grant-table.o suspend.o platform-pci-unplug.o
16 16
17obj-$(CONFIG_SMP) += smp.o 17obj-$(CONFIG_SMP) += smp.o
18obj-$(CONFIG_PARAVIRT_SPINLOCKS)+= spinlock.o 18obj-$(CONFIG_PARAVIRT_SPINLOCKS)+= spinlock.o
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index 65d8d79b46a8..d4ff5e83621d 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -11,6 +11,7 @@
11 * Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007 11 * Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007
12 */ 12 */
13 13
14#include <linux/cpu.h>
14#include <linux/kernel.h> 15#include <linux/kernel.h>
15#include <linux/init.h> 16#include <linux/init.h>
16#include <linux/smp.h> 17#include <linux/smp.h>
@@ -35,8 +36,10 @@
35#include <xen/interface/version.h> 36#include <xen/interface/version.h>
36#include <xen/interface/physdev.h> 37#include <xen/interface/physdev.h>
37#include <xen/interface/vcpu.h> 38#include <xen/interface/vcpu.h>
39#include <xen/interface/memory.h>
38#include <xen/features.h> 40#include <xen/features.h>
39#include <xen/page.h> 41#include <xen/page.h>
42#include <xen/hvm.h>
40#include <xen/hvc-console.h> 43#include <xen/hvc-console.h>
41 44
42#include <asm/paravirt.h> 45#include <asm/paravirt.h>
@@ -55,7 +58,9 @@
55#include <asm/pgtable.h> 58#include <asm/pgtable.h>
56#include <asm/tlbflush.h> 59#include <asm/tlbflush.h>
57#include <asm/reboot.h> 60#include <asm/reboot.h>
61#include <asm/setup.h>
58#include <asm/stackprotector.h> 62#include <asm/stackprotector.h>
63#include <asm/hypervisor.h>
59 64
60#include "xen-ops.h" 65#include "xen-ops.h"
61#include "mmu.h" 66#include "mmu.h"
@@ -76,6 +81,10 @@ struct shared_info xen_dummy_shared_info;
76 81
77void *xen_initial_gdt; 82void *xen_initial_gdt;
78 83
84RESERVE_BRK(shared_info_page_brk, PAGE_SIZE);
85__read_mostly int xen_have_vector_callback;
86EXPORT_SYMBOL_GPL(xen_have_vector_callback);
87
79/* 88/*
80 * Point at some empty memory to start with. We map the real shared_info 89 * Point at some empty memory to start with. We map the real shared_info
81 * page as soon as fixmap is up and running. 90 * page as soon as fixmap is up and running.
@@ -97,6 +106,14 @@ struct shared_info *HYPERVISOR_shared_info = (void *)&xen_dummy_shared_info;
97 */ 106 */
98static int have_vcpu_info_placement = 1; 107static int have_vcpu_info_placement = 1;
99 108
109static void clamp_max_cpus(void)
110{
111#ifdef CONFIG_SMP
112 if (setup_max_cpus > MAX_VIRT_CPUS)
113 setup_max_cpus = MAX_VIRT_CPUS;
114#endif
115}
116
100static void xen_vcpu_setup(int cpu) 117static void xen_vcpu_setup(int cpu)
101{ 118{
102 struct vcpu_register_vcpu_info info; 119 struct vcpu_register_vcpu_info info;
@@ -104,13 +121,17 @@ static void xen_vcpu_setup(int cpu)
104 struct vcpu_info *vcpup; 121 struct vcpu_info *vcpup;
105 122
106 BUG_ON(HYPERVISOR_shared_info == &xen_dummy_shared_info); 123 BUG_ON(HYPERVISOR_shared_info == &xen_dummy_shared_info);
107 per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu];
108 124
109 if (!have_vcpu_info_placement) 125 if (cpu < MAX_VIRT_CPUS)
110 return; /* already tested, not available */ 126 per_cpu(xen_vcpu,cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu];
111 127
112 vcpup = &per_cpu(xen_vcpu_info, cpu); 128 if (!have_vcpu_info_placement) {
129 if (cpu >= MAX_VIRT_CPUS)
130 clamp_max_cpus();
131 return;
132 }
113 133
134 vcpup = &per_cpu(xen_vcpu_info, cpu);
114 info.mfn = arbitrary_virt_to_mfn(vcpup); 135 info.mfn = arbitrary_virt_to_mfn(vcpup);
115 info.offset = offset_in_page(vcpup); 136 info.offset = offset_in_page(vcpup);
116 137
@@ -125,6 +146,7 @@ static void xen_vcpu_setup(int cpu)
125 if (err) { 146 if (err) {
126 printk(KERN_DEBUG "register_vcpu_info failed: err=%d\n", err); 147 printk(KERN_DEBUG "register_vcpu_info failed: err=%d\n", err);
127 have_vcpu_info_placement = 0; 148 have_vcpu_info_placement = 0;
149 clamp_max_cpus();
128 } else { 150 } else {
129 /* This cpu is using the registered vcpu info, even if 151 /* This cpu is using the registered vcpu info, even if
130 later ones fail to. */ 152 later ones fail to. */
@@ -731,7 +753,6 @@ static void set_xen_basic_apic_ops(void)
731 753
732#endif 754#endif
733 755
734
735static void xen_clts(void) 756static void xen_clts(void)
736{ 757{
737 struct multicall_space mcs; 758 struct multicall_space mcs;
@@ -926,10 +947,6 @@ static const struct pv_init_ops xen_init_ops __initdata = {
926 .patch = xen_patch, 947 .patch = xen_patch,
927}; 948};
928 949
929static const struct pv_time_ops xen_time_ops __initdata = {
930 .sched_clock = xen_sched_clock,
931};
932
933static const struct pv_cpu_ops xen_cpu_ops __initdata = { 950static const struct pv_cpu_ops xen_cpu_ops __initdata = {
934 .cpuid = xen_cpuid, 951 .cpuid = xen_cpuid,
935 952
@@ -1028,6 +1045,23 @@ static void xen_crash_shutdown(struct pt_regs *regs)
1028 xen_reboot(SHUTDOWN_crash); 1045 xen_reboot(SHUTDOWN_crash);
1029} 1046}
1030 1047
1048static int
1049xen_panic_event(struct notifier_block *this, unsigned long event, void *ptr)
1050{
1051 xen_reboot(SHUTDOWN_crash);
1052 return NOTIFY_DONE;
1053}
1054
1055static struct notifier_block xen_panic_block = {
1056 .notifier_call= xen_panic_event,
1057};
1058
1059int xen_panic_handler_init(void)
1060{
1061 atomic_notifier_chain_register(&panic_notifier_list, &xen_panic_block);
1062 return 0;
1063}
1064
1031static const struct machine_ops __initdata xen_machine_ops = { 1065static const struct machine_ops __initdata xen_machine_ops = {
1032 .restart = xen_restart, 1066 .restart = xen_restart,
1033 .halt = xen_machine_halt, 1067 .halt = xen_machine_halt,
@@ -1067,7 +1101,6 @@ asmlinkage void __init xen_start_kernel(void)
1067 /* Install Xen paravirt ops */ 1101 /* Install Xen paravirt ops */
1068 pv_info = xen_info; 1102 pv_info = xen_info;
1069 pv_init_ops = xen_init_ops; 1103 pv_init_ops = xen_init_ops;
1070 pv_time_ops = xen_time_ops;
1071 pv_cpu_ops = xen_cpu_ops; 1104 pv_cpu_ops = xen_cpu_ops;
1072 pv_apic_ops = xen_apic_ops; 1105 pv_apic_ops = xen_apic_ops;
1073 1106
@@ -1075,13 +1108,7 @@ asmlinkage void __init xen_start_kernel(void)
1075 x86_init.oem.arch_setup = xen_arch_setup; 1108 x86_init.oem.arch_setup = xen_arch_setup;
1076 x86_init.oem.banner = xen_banner; 1109 x86_init.oem.banner = xen_banner;
1077 1110
1078 x86_init.timers.timer_init = xen_time_init; 1111 xen_init_time_ops();
1079 x86_init.timers.setup_percpu_clockev = x86_init_noop;
1080 x86_cpuinit.setup_percpu_clockev = x86_init_noop;
1081
1082 x86_platform.calibrate_tsc = xen_tsc_khz;
1083 x86_platform.get_wallclock = xen_get_wallclock;
1084 x86_platform.set_wallclock = xen_set_wallclock;
1085 1112
1086 /* 1113 /*
1087 * Set up some pagetable state before starting to set any ptes. 1114 * Set up some pagetable state before starting to set any ptes.
@@ -1206,3 +1233,139 @@ asmlinkage void __init xen_start_kernel(void)
1206 x86_64_start_reservations((char *)__pa_symbol(&boot_params)); 1233 x86_64_start_reservations((char *)__pa_symbol(&boot_params));
1207#endif 1234#endif
1208} 1235}
1236
1237static uint32_t xen_cpuid_base(void)
1238{
1239 uint32_t base, eax, ebx, ecx, edx;
1240 char signature[13];
1241
1242 for (base = 0x40000000; base < 0x40010000; base += 0x100) {
1243 cpuid(base, &eax, &ebx, &ecx, &edx);
1244 *(uint32_t *)(signature + 0) = ebx;
1245 *(uint32_t *)(signature + 4) = ecx;
1246 *(uint32_t *)(signature + 8) = edx;
1247 signature[12] = 0;
1248
1249 if (!strcmp("XenVMMXenVMM", signature) && ((eax - base) >= 2))
1250 return base;
1251 }
1252
1253 return 0;
1254}
1255
1256static int init_hvm_pv_info(int *major, int *minor)
1257{
1258 uint32_t eax, ebx, ecx, edx, pages, msr, base;
1259 u64 pfn;
1260
1261 base = xen_cpuid_base();
1262 cpuid(base + 1, &eax, &ebx, &ecx, &edx);
1263
1264 *major = eax >> 16;
1265 *minor = eax & 0xffff;
1266 printk(KERN_INFO "Xen version %d.%d.\n", *major, *minor);
1267
1268 cpuid(base + 2, &pages, &msr, &ecx, &edx);
1269
1270 pfn = __pa(hypercall_page);
1271 wrmsr_safe(msr, (u32)pfn, (u32)(pfn >> 32));
1272
1273 xen_setup_features();
1274
1275 pv_info = xen_info;
1276 pv_info.kernel_rpl = 0;
1277
1278 xen_domain_type = XEN_HVM_DOMAIN;
1279
1280 return 0;
1281}
1282
1283void xen_hvm_init_shared_info(void)
1284{
1285 int cpu;
1286 struct xen_add_to_physmap xatp;
1287 static struct shared_info *shared_info_page = 0;
1288
1289 if (!shared_info_page)
1290 shared_info_page = (struct shared_info *)
1291 extend_brk(PAGE_SIZE, PAGE_SIZE);
1292 xatp.domid = DOMID_SELF;
1293 xatp.idx = 0;
1294 xatp.space = XENMAPSPACE_shared_info;
1295 xatp.gpfn = __pa(shared_info_page) >> PAGE_SHIFT;
1296 if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp))
1297 BUG();
1298
1299 HYPERVISOR_shared_info = (struct shared_info *)shared_info_page;
1300
1301 /* xen_vcpu is a pointer to the vcpu_info struct in the shared_info
1302 * page, we use it in the event channel upcall and in some pvclock
1303 * related functions. We don't need the vcpu_info placement
1304 * optimizations because we don't use any pv_mmu or pv_irq op on
1305 * HVM.
1306 * When xen_hvm_init_shared_info is run at boot time only vcpu 0 is
1307 * online but xen_hvm_init_shared_info is run at resume time too and
1308 * in that case multiple vcpus might be online. */
1309 for_each_online_cpu(cpu) {
1310 per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu];
1311 }
1312}
1313
1314#ifdef CONFIG_XEN_PVHVM
1315static int __cpuinit xen_hvm_cpu_notify(struct notifier_block *self,
1316 unsigned long action, void *hcpu)
1317{
1318 int cpu = (long)hcpu;
1319 switch (action) {
1320 case CPU_UP_PREPARE:
1321 per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu];
1322 break;
1323 default:
1324 break;
1325 }
1326 return NOTIFY_OK;
1327}
1328
1329static struct notifier_block __cpuinitdata xen_hvm_cpu_notifier = {
1330 .notifier_call = xen_hvm_cpu_notify,
1331};
1332
1333static void __init xen_hvm_guest_init(void)
1334{
1335 int r;
1336 int major, minor;
1337
1338 r = init_hvm_pv_info(&major, &minor);
1339 if (r < 0)
1340 return;
1341
1342 xen_hvm_init_shared_info();
1343
1344 if (xen_feature(XENFEAT_hvm_callback_vector))
1345 xen_have_vector_callback = 1;
1346 register_cpu_notifier(&xen_hvm_cpu_notifier);
1347 xen_unplug_emulated_devices();
1348 have_vcpu_info_placement = 0;
1349 x86_init.irqs.intr_init = xen_init_IRQ;
1350 xen_hvm_init_time_ops();
1351 xen_hvm_init_mmu_ops();
1352}
1353
1354static bool __init xen_hvm_platform(void)
1355{
1356 if (xen_pv_domain())
1357 return false;
1358
1359 if (!xen_cpuid_base())
1360 return false;
1361
1362 return true;
1363}
1364
1365const __refconst struct hypervisor_x86 x86_hyper_xen_hvm = {
1366 .name = "Xen HVM",
1367 .detect = xen_hvm_platform,
1368 .init_platform = xen_hvm_guest_init,
1369};
1370EXPORT_SYMBOL(x86_hyper_xen_hvm);
1371#endif
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
index 914f04695ce5..413b19b3d0fe 100644
--- a/arch/x86/xen/mmu.c
+++ b/arch/x86/xen/mmu.c
@@ -58,6 +58,7 @@
58 58
59#include <xen/page.h> 59#include <xen/page.h>
60#include <xen/interface/xen.h> 60#include <xen/interface/xen.h>
61#include <xen/interface/hvm/hvm_op.h>
61#include <xen/interface/version.h> 62#include <xen/interface/version.h>
62#include <xen/hvc-console.h> 63#include <xen/hvc-console.h>
63 64
@@ -1941,6 +1942,40 @@ void __init xen_init_mmu_ops(void)
1941 pv_mmu_ops = xen_mmu_ops; 1942 pv_mmu_ops = xen_mmu_ops;
1942} 1943}
1943 1944
1945#ifdef CONFIG_XEN_PVHVM
1946static void xen_hvm_exit_mmap(struct mm_struct *mm)
1947{
1948 struct xen_hvm_pagetable_dying a;
1949 int rc;
1950
1951 a.domid = DOMID_SELF;
1952 a.gpa = __pa(mm->pgd);
1953 rc = HYPERVISOR_hvm_op(HVMOP_pagetable_dying, &a);
1954 WARN_ON_ONCE(rc < 0);
1955}
1956
1957static int is_pagetable_dying_supported(void)
1958{
1959 struct xen_hvm_pagetable_dying a;
1960 int rc = 0;
1961
1962 a.domid = DOMID_SELF;
1963 a.gpa = 0x00;
1964 rc = HYPERVISOR_hvm_op(HVMOP_pagetable_dying, &a);
1965 if (rc < 0) {
1966 printk(KERN_DEBUG "HVMOP_pagetable_dying not supported\n");
1967 return 0;
1968 }
1969 return 1;
1970}
1971
1972void __init xen_hvm_init_mmu_ops(void)
1973{
1974 if (is_pagetable_dying_supported())
1975 pv_mmu_ops.exit_mmap = xen_hvm_exit_mmap;
1976}
1977#endif
1978
1944#ifdef CONFIG_XEN_DEBUG_FS 1979#ifdef CONFIG_XEN_DEBUG_FS
1945 1980
1946static struct dentry *d_mmu_debug; 1981static struct dentry *d_mmu_debug;
diff --git a/arch/x86/xen/mmu.h b/arch/x86/xen/mmu.h
index 5fe6bc7f5ecf..fa938c4aa2f7 100644
--- a/arch/x86/xen/mmu.h
+++ b/arch/x86/xen/mmu.h
@@ -60,4 +60,5 @@ void xen_ptep_modify_prot_commit(struct mm_struct *mm, unsigned long addr,
60unsigned long xen_read_cr2_direct(void); 60unsigned long xen_read_cr2_direct(void);
61 61
62extern void xen_init_mmu_ops(void); 62extern void xen_init_mmu_ops(void);
63extern void xen_hvm_init_mmu_ops(void);
63#endif /* _XEN_MMU_H */ 64#endif /* _XEN_MMU_H */
diff --git a/arch/x86/xen/platform-pci-unplug.c b/arch/x86/xen/platform-pci-unplug.c
new file mode 100644
index 000000000000..554c002a1e1a
--- /dev/null
+++ b/arch/x86/xen/platform-pci-unplug.c
@@ -0,0 +1,137 @@
1/******************************************************************************
2 * platform-pci-unplug.c
3 *
4 * Xen platform PCI device driver
5 * Copyright (c) 2010, Citrix
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms and conditions of the GNU General Public License,
9 * version 2, as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
18 * Place - Suite 330, Boston, MA 02111-1307 USA.
19 *
20 */
21
22#include <linux/init.h>
23#include <linux/io.h>
24#include <linux/module.h>
25
26#include <xen/platform_pci.h>
27
28#define XEN_PLATFORM_ERR_MAGIC -1
29#define XEN_PLATFORM_ERR_PROTOCOL -2
30#define XEN_PLATFORM_ERR_BLACKLIST -3
31
32/* store the value of xen_emul_unplug after the unplug is done */
33int xen_platform_pci_unplug;
34EXPORT_SYMBOL_GPL(xen_platform_pci_unplug);
35#ifdef CONFIG_XEN_PVHVM
36static int xen_emul_unplug;
37
38static int __init check_platform_magic(void)
39{
40 short magic;
41 char protocol;
42
43 magic = inw(XEN_IOPORT_MAGIC);
44 if (magic != XEN_IOPORT_MAGIC_VAL) {
45 printk(KERN_ERR "Xen Platform PCI: unrecognised magic value\n");
46 return XEN_PLATFORM_ERR_MAGIC;
47 }
48
49 protocol = inb(XEN_IOPORT_PROTOVER);
50
51 printk(KERN_DEBUG "Xen Platform PCI: I/O protocol version %d\n",
52 protocol);
53
54 switch (protocol) {
55 case 1:
56 outw(XEN_IOPORT_LINUX_PRODNUM, XEN_IOPORT_PRODNUM);
57 outl(XEN_IOPORT_LINUX_DRVVER, XEN_IOPORT_DRVVER);
58 if (inw(XEN_IOPORT_MAGIC) != XEN_IOPORT_MAGIC_VAL) {
59 printk(KERN_ERR "Xen Platform: blacklisted by host\n");
60 return XEN_PLATFORM_ERR_BLACKLIST;
61 }
62 break;
63 default:
64 printk(KERN_WARNING "Xen Platform PCI: unknown I/O protocol version");
65 return XEN_PLATFORM_ERR_PROTOCOL;
66 }
67
68 return 0;
69}
70
71void __init xen_unplug_emulated_devices(void)
72{
73 int r;
74
75 /* check the version of the xen platform PCI device */
76 r = check_platform_magic();
77 /* If the version matches enable the Xen platform PCI driver.
78 * Also enable the Xen platform PCI driver if the version is really old
79 * and the user told us to ignore it. */
80 if (r && !(r == XEN_PLATFORM_ERR_MAGIC &&
81 (xen_emul_unplug & XEN_UNPLUG_IGNORE)))
82 return;
83 /* Set the default value of xen_emul_unplug depending on whether or
84 * not the Xen PV frontends and the Xen platform PCI driver have
85 * been compiled for this kernel (modules or built-in are both OK). */
86 if (!xen_emul_unplug) {
87 if (xen_must_unplug_nics()) {
88 printk(KERN_INFO "Netfront and the Xen platform PCI driver have "
89 "been compiled for this kernel: unplug emulated NICs.\n");
90 xen_emul_unplug |= XEN_UNPLUG_ALL_NICS;
91 }
92 if (xen_must_unplug_disks()) {
93 printk(KERN_INFO "Blkfront and the Xen platform PCI driver have "
94 "been compiled for this kernel: unplug emulated disks.\n"
95 "You might have to change the root device\n"
96 "from /dev/hd[a-d] to /dev/xvd[a-d]\n"
97 "in your root= kernel command line option\n");
98 xen_emul_unplug |= XEN_UNPLUG_ALL_IDE_DISKS;
99 }
100 }
101 /* Now unplug the emulated devices */
102 if (!(xen_emul_unplug & XEN_UNPLUG_IGNORE))
103 outw(xen_emul_unplug, XEN_IOPORT_UNPLUG);
104 xen_platform_pci_unplug = xen_emul_unplug;
105}
106
107static int __init parse_xen_emul_unplug(char *arg)
108{
109 char *p, *q;
110 int l;
111
112 for (p = arg; p; p = q) {
113 q = strchr(p, ',');
114 if (q) {
115 l = q - p;
116 q++;
117 } else {
118 l = strlen(p);
119 }
120 if (!strncmp(p, "all", l))
121 xen_emul_unplug |= XEN_UNPLUG_ALL;
122 else if (!strncmp(p, "ide-disks", l))
123 xen_emul_unplug |= XEN_UNPLUG_ALL_IDE_DISKS;
124 else if (!strncmp(p, "aux-ide-disks", l))
125 xen_emul_unplug |= XEN_UNPLUG_AUX_IDE_DISKS;
126 else if (!strncmp(p, "nics", l))
127 xen_emul_unplug |= XEN_UNPLUG_ALL_NICS;
128 else if (!strncmp(p, "ignore", l))
129 xen_emul_unplug |= XEN_UNPLUG_IGNORE;
130 else
131 printk(KERN_WARNING "unrecognised option '%s' "
132 "in parameter 'xen_emul_unplug'\n", p);
133 }
134 return 0;
135}
136early_param("xen_emul_unplug", parse_xen_emul_unplug);
137#endif
diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c
index ad0047f47cd4..328b00305426 100644
--- a/arch/x86/xen/setup.c
+++ b/arch/x86/xen/setup.c
@@ -20,6 +20,7 @@
20#include <xen/page.h> 20#include <xen/page.h>
21#include <xen/interface/callback.h> 21#include <xen/interface/callback.h>
22#include <xen/interface/physdev.h> 22#include <xen/interface/physdev.h>
23#include <xen/interface/memory.h>
23#include <xen/features.h> 24#include <xen/features.h>
24 25
25#include "xen-ops.h" 26#include "xen-ops.h"
@@ -32,6 +33,73 @@ extern void xen_sysenter_target(void);
32extern void xen_syscall_target(void); 33extern void xen_syscall_target(void);
33extern void xen_syscall32_target(void); 34extern void xen_syscall32_target(void);
34 35
36static unsigned long __init xen_release_chunk(phys_addr_t start_addr,
37 phys_addr_t end_addr)
38{
39 struct xen_memory_reservation reservation = {
40 .address_bits = 0,
41 .extent_order = 0,
42 .domid = DOMID_SELF
43 };
44 unsigned long start, end;
45 unsigned long len = 0;
46 unsigned long pfn;
47 int ret;
48
49 start = PFN_UP(start_addr);
50 end = PFN_DOWN(end_addr);
51
52 if (end <= start)
53 return 0;
54
55 printk(KERN_INFO "xen_release_chunk: looking at area pfn %lx-%lx: ",
56 start, end);
57 for(pfn = start; pfn < end; pfn++) {
58 unsigned long mfn = pfn_to_mfn(pfn);
59
60 /* Make sure pfn exists to start with */
61 if (mfn == INVALID_P2M_ENTRY || mfn_to_pfn(mfn) != pfn)
62 continue;
63
64 set_xen_guest_handle(reservation.extent_start, &mfn);
65 reservation.nr_extents = 1;
66
67 ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation,
68 &reservation);
69 WARN(ret != 1, "Failed to release memory %lx-%lx err=%d\n",
70 start, end, ret);
71 if (ret == 1) {
72 set_phys_to_machine(pfn, INVALID_P2M_ENTRY);
73 len++;
74 }
75 }
76 printk(KERN_CONT "%ld pages freed\n", len);
77
78 return len;
79}
80
81static unsigned long __init xen_return_unused_memory(unsigned long max_pfn,
82 const struct e820map *e820)
83{
84 phys_addr_t max_addr = PFN_PHYS(max_pfn);
85 phys_addr_t last_end = 0;
86 unsigned long released = 0;
87 int i;
88
89 for (i = 0; i < e820->nr_map && last_end < max_addr; i++) {
90 phys_addr_t end = e820->map[i].addr;
91 end = min(max_addr, end);
92
93 released += xen_release_chunk(last_end, end);
94 last_end = e820->map[i].addr + e820->map[i].size;
95 }
96
97 if (last_end < max_addr)
98 released += xen_release_chunk(last_end, max_addr);
99
100 printk(KERN_INFO "released %ld pages of unused memory\n", released);
101 return released;
102}
35 103
36/** 104/**
37 * machine_specific_memory_setup - Hook for machine specific memory setup. 105 * machine_specific_memory_setup - Hook for machine specific memory setup.
@@ -67,6 +135,8 @@ char * __init xen_memory_setup(void)
67 135
68 sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map); 136 sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
69 137
138 xen_return_unused_memory(xen_start_info->nr_pages, &e820);
139
70 return "Xen"; 140 return "Xen";
71} 141}
72 142
@@ -156,6 +226,8 @@ void __init xen_arch_setup(void)
156 struct physdev_set_iopl set_iopl; 226 struct physdev_set_iopl set_iopl;
157 int rc; 227 int rc;
158 228
229 xen_panic_handler_init();
230
159 HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_4gb_segments); 231 HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_4gb_segments);
160 HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_writable_pagetables); 232 HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_writable_pagetables);
161 233
diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c
index a29693fd3138..25f232b18a82 100644
--- a/arch/x86/xen/smp.c
+++ b/arch/x86/xen/smp.c
@@ -394,6 +394,8 @@ static void stop_self(void *v)
394 load_cr3(swapper_pg_dir); 394 load_cr3(swapper_pg_dir);
395 /* should set up a minimal gdt */ 395 /* should set up a minimal gdt */
396 396
397 set_cpu_online(cpu, false);
398
397 HYPERVISOR_vcpu_op(VCPUOP_down, cpu, NULL); 399 HYPERVISOR_vcpu_op(VCPUOP_down, cpu, NULL);
398 BUG(); 400 BUG();
399} 401}
diff --git a/arch/x86/xen/suspend.c b/arch/x86/xen/suspend.c
index a9c661108034..1d789d56877c 100644
--- a/arch/x86/xen/suspend.c
+++ b/arch/x86/xen/suspend.c
@@ -26,6 +26,18 @@ void xen_pre_suspend(void)
26 BUG(); 26 BUG();
27} 27}
28 28
29void xen_hvm_post_suspend(int suspend_cancelled)
30{
31 int cpu;
32 xen_hvm_init_shared_info();
33 xen_callback_vector();
34 if (xen_feature(XENFEAT_hvm_safe_pvclock)) {
35 for_each_online_cpu(cpu) {
36 xen_setup_runstate_info(cpu);
37 }
38 }
39}
40
29void xen_post_suspend(int suspend_cancelled) 41void xen_post_suspend(int suspend_cancelled)
30{ 42{
31 xen_build_mfn_list_list(); 43 xen_build_mfn_list_list();
diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c
index b3c6c59ed302..1a5353a753fc 100644
--- a/arch/x86/xen/time.c
+++ b/arch/x86/xen/time.c
@@ -20,6 +20,7 @@
20#include <asm/xen/hypercall.h> 20#include <asm/xen/hypercall.h>
21 21
22#include <xen/events.h> 22#include <xen/events.h>
23#include <xen/features.h>
23#include <xen/interface/xen.h> 24#include <xen/interface/xen.h>
24#include <xen/interface/vcpu.h> 25#include <xen/interface/vcpu.h>
25 26
@@ -155,47 +156,8 @@ static void do_stolen_accounting(void)
155 account_idle_ticks(ticks); 156 account_idle_ticks(ticks);
156} 157}
157 158
158/*
159 * Xen sched_clock implementation. Returns the number of unstolen
160 * nanoseconds, which is nanoseconds the VCPU spent in RUNNING+BLOCKED
161 * states.
162 */
163unsigned long long xen_sched_clock(void)
164{
165 struct vcpu_runstate_info state;
166 cycle_t now;
167 u64 ret;
168 s64 offset;
169
170 /*
171 * Ideally sched_clock should be called on a per-cpu basis
172 * anyway, so preempt should already be disabled, but that's
173 * not current practice at the moment.
174 */
175 preempt_disable();
176
177 now = xen_clocksource_read();
178
179 get_runstate_snapshot(&state);
180
181 WARN_ON(state.state != RUNSTATE_running);
182
183 offset = now - state.state_entry_time;
184 if (offset < 0)
185 offset = 0;
186
187 ret = state.time[RUNSTATE_blocked] +
188 state.time[RUNSTATE_running] +
189 offset;
190
191 preempt_enable();
192
193 return ret;
194}
195
196
197/* Get the TSC speed from Xen */ 159/* Get the TSC speed from Xen */
198unsigned long xen_tsc_khz(void) 160static unsigned long xen_tsc_khz(void)
199{ 161{
200 struct pvclock_vcpu_time_info *info = 162 struct pvclock_vcpu_time_info *info =
201 &HYPERVISOR_shared_info->vcpu_info[0].time; 163 &HYPERVISOR_shared_info->vcpu_info[0].time;
@@ -230,7 +192,7 @@ static void xen_read_wallclock(struct timespec *ts)
230 put_cpu_var(xen_vcpu); 192 put_cpu_var(xen_vcpu);
231} 193}
232 194
233unsigned long xen_get_wallclock(void) 195static unsigned long xen_get_wallclock(void)
234{ 196{
235 struct timespec ts; 197 struct timespec ts;
236 198
@@ -238,7 +200,7 @@ unsigned long xen_get_wallclock(void)
238 return ts.tv_sec; 200 return ts.tv_sec;
239} 201}
240 202
241int xen_set_wallclock(unsigned long now) 203static int xen_set_wallclock(unsigned long now)
242{ 204{
243 /* do nothing for domU */ 205 /* do nothing for domU */
244 return -1; 206 return -1;
@@ -473,7 +435,11 @@ void xen_timer_resume(void)
473 } 435 }
474} 436}
475 437
476__init void xen_time_init(void) 438static const struct pv_time_ops xen_time_ops __initdata = {
439 .sched_clock = xen_clocksource_read,
440};
441
442static __init void xen_time_init(void)
477{ 443{
478 int cpu = smp_processor_id(); 444 int cpu = smp_processor_id();
479 struct timespec tp; 445 struct timespec tp;
@@ -497,3 +463,47 @@ __init void xen_time_init(void)
497 xen_setup_timer(cpu); 463 xen_setup_timer(cpu);
498 xen_setup_cpu_clockevents(); 464 xen_setup_cpu_clockevents();
499} 465}
466
467__init void xen_init_time_ops(void)
468{
469 pv_time_ops = xen_time_ops;
470
471 x86_init.timers.timer_init = xen_time_init;
472 x86_init.timers.setup_percpu_clockev = x86_init_noop;
473 x86_cpuinit.setup_percpu_clockev = x86_init_noop;
474
475 x86_platform.calibrate_tsc = xen_tsc_khz;
476 x86_platform.get_wallclock = xen_get_wallclock;
477 x86_platform.set_wallclock = xen_set_wallclock;
478}
479
480#ifdef CONFIG_XEN_PVHVM
481static void xen_hvm_setup_cpu_clockevents(void)
482{
483 int cpu = smp_processor_id();
484 xen_setup_runstate_info(cpu);
485 xen_setup_timer(cpu);
486 xen_setup_cpu_clockevents();
487}
488
489__init void xen_hvm_init_time_ops(void)
490{
491 /* vector callback is needed otherwise we cannot receive interrupts
492 * on cpu > 0 */
493 if (!xen_have_vector_callback && num_present_cpus() > 1)
494 return;
495 if (!xen_feature(XENFEAT_hvm_safe_pvclock)) {
496 printk(KERN_INFO "Xen doesn't support pvclock on HVM,"
497 "disable pv timer\n");
498 return;
499 }
500
501 pv_time_ops = xen_time_ops;
502 x86_init.timers.setup_percpu_clockev = xen_time_init;
503 x86_cpuinit.setup_percpu_clockev = xen_hvm_setup_cpu_clockevents;
504
505 x86_platform.calibrate_tsc = xen_tsc_khz;
506 x86_platform.get_wallclock = xen_get_wallclock;
507 x86_platform.set_wallclock = xen_set_wallclock;
508}
509#endif
diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h
index f9153a300bce..7c8ab86163e9 100644
--- a/arch/x86/xen/xen-ops.h
+++ b/arch/x86/xen/xen-ops.h
@@ -38,6 +38,10 @@ void xen_enable_sysenter(void);
38void xen_enable_syscall(void); 38void xen_enable_syscall(void);
39void xen_vcpu_restore(void); 39void xen_vcpu_restore(void);
40 40
41void xen_callback_vector(void);
42void xen_hvm_init_shared_info(void);
43void __init xen_unplug_emulated_devices(void);
44
41void __init xen_build_dynamic_phys_to_machine(void); 45void __init xen_build_dynamic_phys_to_machine(void);
42 46
43void xen_init_irq_ops(void); 47void xen_init_irq_ops(void);
@@ -46,11 +50,8 @@ void xen_setup_runstate_info(int cpu);
46void xen_teardown_timer(int cpu); 50void xen_teardown_timer(int cpu);
47cycle_t xen_clocksource_read(void); 51cycle_t xen_clocksource_read(void);
48void xen_setup_cpu_clockevents(void); 52void xen_setup_cpu_clockevents(void);
49unsigned long xen_tsc_khz(void); 53void __init xen_init_time_ops(void);
50void __init xen_time_init(void); 54void __init xen_hvm_init_time_ops(void);
51unsigned long xen_get_wallclock(void);
52int xen_set_wallclock(unsigned long time);
53unsigned long long xen_sched_clock(void);
54 55
55irqreturn_t xen_debug_interrupt(int irq, void *dev_id); 56irqreturn_t xen_debug_interrupt(int irq, void *dev_id);
56 57
@@ -101,4 +102,6 @@ void xen_sysret32(void);
101void xen_sysret64(void); 102void xen_sysret64(void);
102void xen_adjust_exception_frame(void); 103void xen_adjust_exception_frame(void);
103 104
105extern int xen_panic_handler_init(void);
106
104#endif /* XEN_OPS_H */ 107#endif /* XEN_OPS_H */