This commit was manufactured by cvs2svn to create branch 'vserver'.
[linux-2.6.git] / drivers / xen / core / reboot.c
1 #define __KERNEL_SYSCALLS__
2 #include <linux/version.h>
3 #include <linux/kernel.h>
4 #include <linux/mm.h>
5 #include <linux/unistd.h>
6 #include <linux/module.h>
7 #include <linux/reboot.h>
8 #include <linux/sysrq.h>
9 #include <linux/stringify.h>
10 #include <asm/irq.h>
11 #include <asm/mmu_context.h>
12 #include <xen/evtchn.h>
13 #include <asm/hypervisor.h>
14 #include <xen/interface/dom0_ops.h>
15 #include <xen/xenbus.h>
16 #include <linux/cpu.h>
17 #include <linux/kthread.h>
18 #include <xen/gnttab.h>
19 #include <xen/xencons.h>
20 #include <xen/cpu_hotplug.h>
21
22 extern void ctrl_alt_del(void);
23
24 #define SHUTDOWN_INVALID  -1
25 #define SHUTDOWN_POWEROFF  0
26 #define SHUTDOWN_SUSPEND   2
27 /* Code 3 is SHUTDOWN_CRASH, which we don't use because the domain can only
28  * report a crash, not be instructed to crash!
29  * HALT is the same as POWEROFF, as far as we're concerned.  The tools use
30  * the distinction when we return the reason code to them.
31  */
32 #define SHUTDOWN_HALT      4
33
34 #if defined(__i386__) || defined(__x86_64__)
35
36 /*
37  * Power off function, if any
38  */
39 void (*pm_power_off)(void);
40 EXPORT_SYMBOL(pm_power_off);
41
42 void machine_emergency_restart(void)
43 {
44         /* We really want to get pending console data out before we die. */
45         xencons_force_flush();
46         HYPERVISOR_shutdown(SHUTDOWN_reboot);
47 }
48
49 void machine_restart(char * __unused)
50 {
51         machine_emergency_restart();
52 }
53
54 void machine_halt(void)
55 {
56         machine_power_off();
57 }
58
59 void machine_power_off(void)
60 {
61         /* We really want to get pending console data out before we die. */
62         xencons_force_flush();
63         if (pm_power_off)
64                 pm_power_off();
65         HYPERVISOR_shutdown(SHUTDOWN_poweroff);
66 }
67
68 int reboot_thru_bios = 0;       /* for dmi_scan.c */
69 EXPORT_SYMBOL(machine_restart);
70 EXPORT_SYMBOL(machine_halt);
71 EXPORT_SYMBOL(machine_power_off);
72
73 #endif /* defined(__i386__) || defined(__x86_64__) */
74
75 /******************************************************************************
76  * Stop/pickle callback handling.
77  */
78
79 /* Ignore multiple shutdown requests. */
80 static int shutting_down = SHUTDOWN_INVALID;
81 static void __shutdown_handler(void *unused);
82 static DECLARE_WORK(shutdown_work, __shutdown_handler, NULL);
83
84 #if defined(__i386__) || defined(__x86_64__)
85
86 /* Ensure we run on the idle task page tables so that we will
87    switch page tables before running user space. This is needed
88    on architectures with separate kernel and user page tables
89    because the user page table pointer is not saved/restored. */
90 static void switch_idle_mm(void)
91 {
92         struct mm_struct *mm = current->active_mm;
93
94         if (mm == &init_mm)
95                 return;
96
97         atomic_inc(&init_mm.mm_count);
98         switch_mm(mm, &init_mm, current);
99         current->active_mm = &init_mm;
100         mmdrop(mm);
101 }
102
103 static void pre_suspend(void)
104 {
105         HYPERVISOR_shared_info = (shared_info_t *)empty_zero_page;
106         clear_fixmap(FIX_SHARED_INFO);
107
108         xen_start_info->store_mfn = mfn_to_pfn(xen_start_info->store_mfn);
109         xen_start_info->console_mfn = mfn_to_pfn(xen_start_info->console_mfn);
110 }
111
112 static void post_suspend(void)
113 {
114         int i, j, k, fpp;
115         extern unsigned long max_pfn;
116         extern unsigned long *pfn_to_mfn_frame_list_list;
117         extern unsigned long *pfn_to_mfn_frame_list[];
118
119         set_fixmap(FIX_SHARED_INFO, xen_start_info->shared_info);
120
121         HYPERVISOR_shared_info = (shared_info_t *)fix_to_virt(FIX_SHARED_INFO);
122
123         memset(empty_zero_page, 0, PAGE_SIZE);
124
125         HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list =
126                 virt_to_mfn(pfn_to_mfn_frame_list_list);
127
128         fpp = PAGE_SIZE/sizeof(unsigned long);
129         for (i = 0, j = 0, k = -1; i < max_pfn; i += fpp, j++) {
130                 if ((j % fpp) == 0) {
131                         k++;
132                         pfn_to_mfn_frame_list_list[k] =
133                                 virt_to_mfn(pfn_to_mfn_frame_list[k]);
134                         j = 0;
135                 }
136                 pfn_to_mfn_frame_list[k][j] =
137                         virt_to_mfn(&phys_to_machine_mapping[i]);
138         }
139         HYPERVISOR_shared_info->arch.max_pfn = max_pfn;
140 }
141
142 #else /* !(defined(__i386__) || defined(__x86_64__)) */
143
144 #define switch_idle_mm()        ((void)0)
145 #define mm_pin_all()            ((void)0)
146 #define pre_suspend()           ((void)0)
147 #define post_suspend()          ((void)0)
148
149 #endif
150
151 static int __do_suspend(void *ignore)
152 {
153         int err;
154
155         extern void time_resume(void);
156
157         BUG_ON(smp_processor_id() != 0);
158         BUG_ON(in_interrupt());
159
160 #if defined(__i386__) || defined(__x86_64__)
161         if (xen_feature(XENFEAT_auto_translated_physmap)) {
162                 printk(KERN_WARNING "Cannot suspend in "
163                        "auto_translated_physmap mode.\n");
164                 return -EOPNOTSUPP;
165         }
166 #endif
167
168         err = smp_suspend();
169         if (err)
170                 return err;
171
172         xenbus_suspend();
173
174         preempt_disable();
175
176         mm_pin_all();
177         local_irq_disable();
178         preempt_enable();
179
180         gnttab_suspend();
181
182         pre_suspend();
183
184         /*
185          * We'll stop somewhere inside this hypercall. When it returns,
186          * we'll start resuming after the restore.
187          */
188         HYPERVISOR_suspend(virt_to_mfn(xen_start_info));
189
190         shutting_down = SHUTDOWN_INVALID;
191
192         post_suspend();
193
194         gnttab_resume();
195
196         irq_resume();
197
198         time_resume();
199
200         switch_idle_mm();
201
202         local_irq_enable();
203
204         xencons_resume();
205
206         xenbus_resume();
207
208         smp_resume();
209
210         return err;
211 }
212
213 static int shutdown_process(void *__unused)
214 {
215         static char *envp[] = { "HOME=/", "TERM=linux",
216                                 "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
217         static char *poweroff_argv[] = { "/sbin/poweroff", NULL };
218
219         extern asmlinkage long sys_reboot(int magic1, int magic2,
220                                           unsigned int cmd, void *arg);
221
222         if ((shutting_down == SHUTDOWN_POWEROFF) ||
223             (shutting_down == SHUTDOWN_HALT)) {
224                 if (execve("/sbin/poweroff", poweroff_argv, envp) < 0) {
225                         sys_reboot(LINUX_REBOOT_MAGIC1,
226                                    LINUX_REBOOT_MAGIC2,
227                                    LINUX_REBOOT_CMD_POWER_OFF,
228                                    NULL);
229                 }
230         }
231
232         shutting_down = SHUTDOWN_INVALID; /* could try again */
233
234         return 0;
235 }
236
237 static int kthread_create_on_cpu(int (*f)(void *arg),
238                                  void *arg,
239                                  const char *name,
240                                  int cpu)
241 {
242         struct task_struct *p;
243         p = kthread_create(f, arg, name);
244         if (IS_ERR(p))
245                 return PTR_ERR(p);
246         kthread_bind(p, cpu);
247         wake_up_process(p);
248         return 0;
249 }
250
251 static void __shutdown_handler(void *unused)
252 {
253         int err;
254
255         if (shutting_down != SHUTDOWN_SUSPEND)
256                 err = kernel_thread(shutdown_process, NULL,
257                                     CLONE_FS | CLONE_FILES);
258         else
259                 err = kthread_create_on_cpu(__do_suspend, NULL, "suspend", 0);
260
261         if (err < 0) {
262                 printk(KERN_WARNING "Error creating shutdown process (%d): "
263                        "retrying...\n", -err);
264                 schedule_delayed_work(&shutdown_work, HZ/2);
265         }
266 }
267
268 static void shutdown_handler(struct xenbus_watch *watch,
269                              const char **vec, unsigned int len)
270 {
271         char *str;
272         struct xenbus_transaction xbt;
273         int err;
274
275         if (shutting_down != SHUTDOWN_INVALID)
276                 return;
277
278  again:
279         err = xenbus_transaction_start(&xbt);
280         if (err)
281                 return;
282         str = (char *)xenbus_read(xbt, "control", "shutdown", NULL);
283         /* Ignore read errors and empty reads. */
284         if (XENBUS_IS_ERR_READ(str)) {
285                 xenbus_transaction_end(xbt, 1);
286                 return;
287         }
288
289         xenbus_write(xbt, "control", "shutdown", "");
290
291         err = xenbus_transaction_end(xbt, 0);
292         if (err == -EAGAIN) {
293                 kfree(str);
294                 goto again;
295         }
296
297         if (strcmp(str, "poweroff") == 0)
298                 shutting_down = SHUTDOWN_POWEROFF;
299         else if (strcmp(str, "reboot") == 0)
300                 ctrl_alt_del();
301         else if (strcmp(str, "suspend") == 0)
302                 shutting_down = SHUTDOWN_SUSPEND;
303         else if (strcmp(str, "halt") == 0)
304                 shutting_down = SHUTDOWN_HALT;
305         else {
306                 printk("Ignoring shutdown request: %s\n", str);
307                 shutting_down = SHUTDOWN_INVALID;
308         }
309
310         if (shutting_down != SHUTDOWN_INVALID)
311                 schedule_work(&shutdown_work);
312
313         kfree(str);
314 }
315
316 static void sysrq_handler(struct xenbus_watch *watch, const char **vec,
317                           unsigned int len)
318 {
319         char sysrq_key = '\0';
320         struct xenbus_transaction xbt;
321         int err;
322
323  again:
324         err = xenbus_transaction_start(&xbt);
325         if (err)
326                 return;
327         if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) {
328                 printk(KERN_ERR "Unable to read sysrq code in "
329                        "control/sysrq\n");
330                 xenbus_transaction_end(xbt, 1);
331                 return;
332         }
333
334         if (sysrq_key != '\0')
335                 xenbus_printf(xbt, "control", "sysrq", "%c", '\0');
336
337         err = xenbus_transaction_end(xbt, 0);
338         if (err == -EAGAIN)
339                 goto again;
340
341 #ifdef CONFIG_MAGIC_SYSRQ
342         if (sysrq_key != '\0')
343                 handle_sysrq(sysrq_key, NULL, NULL);
344 #endif
345 }
346
347 static struct xenbus_watch shutdown_watch = {
348         .node = "control/shutdown",
349         .callback = shutdown_handler
350 };
351
352 static struct xenbus_watch sysrq_watch = {
353         .node ="control/sysrq",
354         .callback = sysrq_handler
355 };
356
357 static int setup_shutdown_watcher(struct notifier_block *notifier,
358                                   unsigned long event,
359                                   void *data)
360 {
361         int err;
362
363         err = register_xenbus_watch(&shutdown_watch);
364         if (err)
365                 printk(KERN_ERR "Failed to set shutdown watcher\n");
366
367         err = register_xenbus_watch(&sysrq_watch);
368         if (err)
369                 printk(KERN_ERR "Failed to set sysrq watcher\n");
370
371         return NOTIFY_DONE;
372 }
373
374 static int __init setup_shutdown_event(void)
375 {
376         static struct notifier_block xenstore_notifier = {
377                 .notifier_call = setup_shutdown_watcher
378         };
379         register_xenstore_notifier(&xenstore_notifier);
380         return 0;
381 }
382
383 subsys_initcall(setup_shutdown_event);