1 #include <linux/version.h>
2 #include <linux/kernel.h>
4 #include <linux/unistd.h>
5 #include <linux/module.h>
6 #include <linux/reboot.h>
7 #include <linux/sysrq.h>
8 #include <linux/stringify.h>
9 #include <linux/stop_machine.h>
11 #include <asm/mmu_context.h>
12 #include <xen/evtchn.h>
13 #include <asm/hypervisor.h>
14 #include <xen/xenbus.h>
15 #include <linux/cpu.h>
16 #include <linux/kthread.h>
17 #include <xen/gnttab.h>
18 #include <xen/xencons.h>
19 #include <xen/cpu_hotplug.h>
20 #include <xen/interface/vcpu.h>
22 #if defined(__i386__) || defined(__x86_64__)
25 * Power off function, if any
27 void (*pm_power_off)(void);
28 EXPORT_SYMBOL(pm_power_off);
30 void machine_emergency_restart(void)
32 /* We really want to get pending console data out before we die. */
33 xencons_force_flush();
34 HYPERVISOR_shutdown(SHUTDOWN_reboot);
37 void machine_restart(char * __unused)
39 machine_emergency_restart();
42 void machine_halt(void)
47 void machine_power_off(void)
49 /* We really want to get pending console data out before we die. */
50 xencons_force_flush();
53 HYPERVISOR_shutdown(SHUTDOWN_poweroff);
56 int reboot_thru_bios = 0; /* for dmi_scan.c */
57 EXPORT_SYMBOL(machine_restart);
58 EXPORT_SYMBOL(machine_halt);
59 EXPORT_SYMBOL(machine_power_off);
61 static void pre_suspend(void)
63 HYPERVISOR_shared_info = (shared_info_t *)empty_zero_page;
64 HYPERVISOR_update_va_mapping(fix_to_virt(FIX_SHARED_INFO),
67 xen_start_info->store_mfn = mfn_to_pfn(xen_start_info->store_mfn);
68 xen_start_info->console.domU.mfn =
69 mfn_to_pfn(xen_start_info->console.domU.mfn);
72 static void post_suspend(int suspend_cancelled)
75 unsigned long shinfo_mfn;
76 extern unsigned long max_pfn;
77 extern unsigned long *pfn_to_mfn_frame_list_list;
78 extern unsigned long *pfn_to_mfn_frame_list[];
80 if (suspend_cancelled) {
81 xen_start_info->store_mfn =
82 pfn_to_mfn(xen_start_info->store_mfn);
83 xen_start_info->console.domU.mfn =
84 pfn_to_mfn(xen_start_info->console.domU.mfn);
87 cpu_initialized_map = cpu_online_map;
91 shinfo_mfn = xen_start_info->shared_info >> PAGE_SHIFT;
92 HYPERVISOR_update_va_mapping(fix_to_virt(FIX_SHARED_INFO),
93 pfn_pte_ma(shinfo_mfn, PAGE_KERNEL), 0);
94 HYPERVISOR_shared_info = (shared_info_t *)fix_to_virt(FIX_SHARED_INFO);
96 memset(empty_zero_page, 0, PAGE_SIZE);
98 fpp = PAGE_SIZE/sizeof(unsigned long);
99 for (i = 0, j = 0, k = -1; i < max_pfn; i += fpp, j++) {
100 if ((j % fpp) == 0) {
102 pfn_to_mfn_frame_list_list[k] =
103 virt_to_mfn(pfn_to_mfn_frame_list[k]);
106 pfn_to_mfn_frame_list[k][j] =
107 virt_to_mfn(&phys_to_machine_mapping[i]);
109 HYPERVISOR_shared_info->arch.max_pfn = max_pfn;
110 HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list =
111 virt_to_mfn(pfn_to_mfn_frame_list_list);
114 #else /* !(defined(__i386__) || defined(__x86_64__)) */
116 #define switch_idle_mm() ((void)0)
117 #define mm_pin_all() ((void)0)
118 #define pre_suspend() ((void)0)
119 #define post_suspend(x) ((void)0)
123 static int take_machine_down(void *p_fast_suspend)
125 int fast_suspend = *(int *)p_fast_suspend;
126 int suspend_cancelled, err;
127 extern void time_resume(void);
130 BUG_ON(!irqs_disabled());
132 BUG_ON(irqs_disabled());
142 if (num_online_cpus() == 1)
146 xenbus_suspend_cancel();
157 * This hypercall returns 1 if suspend was cancelled or the domain was
158 * merely checkpointed, and 0 if it is resuming in a new domain.
160 suspend_cancelled = HYPERVISOR_suspend(virt_to_mfn(xen_start_info));
162 post_suspend(suspend_cancelled);
164 if (!suspend_cancelled) {
168 * Older versions of Xen do not save/restore the user %cr3.
169 * We do it here just in case, but there's no need if we are
170 * in fast-suspend mode as that implies a new enough Xen.
174 op.cmd = MMUEXT_NEW_USER_BASEPTR;
175 op.arg1.mfn = pfn_to_mfn(__pa(__user_pgd(
176 current->active_mm->pgd)) >> PAGE_SHIFT);
177 if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF))
187 return suspend_cancelled;
190 int __xen_suspend(int fast_suspend)
192 int err, suspend_cancelled;
194 BUG_ON(smp_processor_id() != 0);
195 BUG_ON(in_interrupt());
197 #if defined(__i386__) || defined(__x86_64__)
198 if (xen_feature(XENFEAT_auto_translated_physmap)) {
199 printk(KERN_WARNING "Cannot suspend in "
200 "auto_translated_physmap mode.\n");
205 /* If we are definitely UP then 'slow mode' is actually faster. */
206 if (num_possible_cpus() == 1)
211 err = stop_machine_run(take_machine_down, &fast_suspend, 0);
213 xenbus_suspend_cancel();
215 err = take_machine_down(&fast_suspend);
221 suspend_cancelled = err;
222 if (!suspend_cancelled) {
226 xenbus_suspend_cancel();