ia64/xen-unstable

view linux-2.6-xen-sparse/drivers/xen/core/reboot.c @ 9523:de30faffd672

Fix save/restore on 64-bit.

Signed-off-by: Steven Hand <steven@xensource.com>
author smh22@firebug.cl.cam.ac.uk
date Wed Mar 29 18:07:36 2006 +0100 (2006-03-29)
parents 5b1a10f9da4c
children 9316fe0c9c4f
line source
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>
21 #if defined(__i386__) || defined(__x86_64__)
22 /*
23 * Power off function, if any
24 */
25 void (*pm_power_off)(void);
26 EXPORT_SYMBOL(pm_power_off);
27 #endif
29 extern void ctrl_alt_del(void);
31 #define SHUTDOWN_INVALID -1
32 #define SHUTDOWN_POWEROFF 0
33 #define SHUTDOWN_SUSPEND 2
34 /* Code 3 is SHUTDOWN_CRASH, which we don't use because the domain can only
35 * report a crash, not be instructed to crash!
36 * HALT is the same as POWEROFF, as far as we're concerned. The tools use
37 * the distinction when we return the reason code to them.
38 */
39 #define SHUTDOWN_HALT 4
41 void machine_emergency_restart(void)
42 {
43 /* We really want to get pending console data out before we die. */
44 xencons_force_flush();
45 HYPERVISOR_sched_op(SCHEDOP_shutdown, SHUTDOWN_reboot);
46 }
48 void machine_restart(char * __unused)
49 {
50 machine_emergency_restart();
51 }
53 void machine_halt(void)
54 {
55 machine_power_off();
56 }
58 void machine_power_off(void)
59 {
60 /* We really want to get pending console data out before we die. */
61 xencons_force_flush();
62 HYPERVISOR_sched_op(SCHEDOP_shutdown, SHUTDOWN_poweroff);
63 }
65 int reboot_thru_bios = 0; /* for dmi_scan.c */
66 EXPORT_SYMBOL(machine_restart);
67 EXPORT_SYMBOL(machine_halt);
68 EXPORT_SYMBOL(machine_power_off);
71 /******************************************************************************
72 * Stop/pickle callback handling.
73 */
75 /* Ignore multiple shutdown requests. */
76 static int shutting_down = SHUTDOWN_INVALID;
77 static void __shutdown_handler(void *unused);
78 static DECLARE_WORK(shutdown_work, __shutdown_handler, NULL);
80 #ifdef CONFIG_SMP
81 int smp_suspend(void);
82 void smp_resume(void);
83 #else
84 #define smp_suspend() (0)
85 #define smp_resume() ((void)0)
86 #endif
88 static int __do_suspend(void *ignore)
89 {
90 int i, j, k, fpp, err;
92 extern unsigned long max_pfn;
93 extern unsigned long *pfn_to_mfn_frame_list_list;
94 extern unsigned long *pfn_to_mfn_frame_list[];
96 extern void time_resume(void);
98 BUG_ON(smp_processor_id() != 0);
99 BUG_ON(in_interrupt());
101 if (xen_feature(XENFEAT_auto_translated_physmap)) {
102 printk(KERN_WARNING "Cannot suspend in "
103 "auto_translated_physmap mode.\n");
104 return -EOPNOTSUPP;
105 }
107 err = smp_suspend();
108 if (err)
109 return err;
111 xenbus_suspend();
113 preempt_disable();
115 #ifdef __i386__
116 kmem_cache_shrink(pgd_cache);
117 #endif
118 mm_pin_all();
120 __cli();
121 preempt_enable();
123 gnttab_suspend();
125 HYPERVISOR_shared_info = (shared_info_t *)empty_zero_page;
126 clear_fixmap(FIX_SHARED_INFO);
128 xen_start_info->store_mfn = mfn_to_pfn(xen_start_info->store_mfn);
129 xen_start_info->console_mfn = mfn_to_pfn(xen_start_info->console_mfn);
131 /*
132 * We'll stop somewhere inside this hypercall. When it returns,
133 * we'll start resuming after the restore.
134 */
135 HYPERVISOR_suspend(virt_to_mfn(xen_start_info));
137 shutting_down = SHUTDOWN_INVALID;
139 set_fixmap(FIX_SHARED_INFO, xen_start_info->shared_info);
141 HYPERVISOR_shared_info = (shared_info_t *)fix_to_virt(FIX_SHARED_INFO);
143 memset(empty_zero_page, 0, PAGE_SIZE);
145 HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list =
146 virt_to_mfn(pfn_to_mfn_frame_list_list);
148 fpp = PAGE_SIZE/sizeof(unsigned long);
149 for (i = 0, j = 0, k = -1; i < max_pfn; i += fpp, j++) {
150 if ((j % fpp) == 0) {
151 k++;
152 pfn_to_mfn_frame_list_list[k] =
153 virt_to_mfn(pfn_to_mfn_frame_list[k]);
154 j = 0;
155 }
156 pfn_to_mfn_frame_list[k][j] =
157 virt_to_mfn(&phys_to_machine_mapping[i]);
158 }
159 HYPERVISOR_shared_info->arch.max_pfn = max_pfn;
161 gnttab_resume();
163 irq_resume();
165 time_resume();
167 __sti();
169 xencons_resume();
171 xenbus_resume();
173 smp_resume();
175 return err;
176 }
178 static int shutdown_process(void *__unused)
179 {
180 static char *envp[] = { "HOME=/", "TERM=linux",
181 "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
182 static char *poweroff_argv[] = { "/sbin/poweroff", NULL };
184 extern asmlinkage long sys_reboot(int magic1, int magic2,
185 unsigned int cmd, void *arg);
187 if ((shutting_down == SHUTDOWN_POWEROFF) ||
188 (shutting_down == SHUTDOWN_HALT)) {
189 if (execve("/sbin/poweroff", poweroff_argv, envp) < 0) {
190 sys_reboot(LINUX_REBOOT_MAGIC1,
191 LINUX_REBOOT_MAGIC2,
192 LINUX_REBOOT_CMD_POWER_OFF,
193 NULL);
194 }
195 }
197 shutting_down = SHUTDOWN_INVALID; /* could try again */
199 return 0;
200 }
202 static int kthread_create_on_cpu(int (*f)(void *arg),
203 void *arg,
204 const char *name,
205 int cpu)
206 {
207 struct task_struct *p;
208 p = kthread_create(f, arg, name);
209 if (IS_ERR(p))
210 return PTR_ERR(p);
211 kthread_bind(p, cpu);
212 wake_up_process(p);
213 return 0;
214 }
216 static void __shutdown_handler(void *unused)
217 {
218 int err;
220 if (shutting_down != SHUTDOWN_SUSPEND)
221 err = kernel_thread(shutdown_process, NULL,
222 CLONE_FS | CLONE_FILES);
223 else
224 err = kthread_create_on_cpu(__do_suspend, NULL, "suspend", 0);
226 if (err < 0) {
227 printk(KERN_WARNING "Error creating shutdown process (%d): "
228 "retrying...\n", -err);
229 schedule_delayed_work(&shutdown_work, HZ/2);
230 }
231 }
233 static void shutdown_handler(struct xenbus_watch *watch,
234 const char **vec, unsigned int len)
235 {
236 char *str;
237 xenbus_transaction_t xbt;
238 int err;
240 if (shutting_down != SHUTDOWN_INVALID)
241 return;
243 again:
244 err = xenbus_transaction_start(&xbt);
245 if (err)
246 return;
247 str = (char *)xenbus_read(xbt, "control", "shutdown", NULL);
248 /* Ignore read errors and empty reads. */
249 if (XENBUS_IS_ERR_READ(str)) {
250 xenbus_transaction_end(xbt, 1);
251 return;
252 }
254 xenbus_write(xbt, "control", "shutdown", "");
256 err = xenbus_transaction_end(xbt, 0);
257 if (err == -EAGAIN) {
258 kfree(str);
259 goto again;
260 }
262 if (strcmp(str, "poweroff") == 0)
263 shutting_down = SHUTDOWN_POWEROFF;
264 else if (strcmp(str, "reboot") == 0)
265 ctrl_alt_del();
266 else if (strcmp(str, "suspend") == 0)
267 shutting_down = SHUTDOWN_SUSPEND;
268 else if (strcmp(str, "halt") == 0)
269 shutting_down = SHUTDOWN_HALT;
270 else {
271 printk("Ignoring shutdown request: %s\n", str);
272 shutting_down = SHUTDOWN_INVALID;
273 }
275 if (shutting_down != SHUTDOWN_INVALID)
276 schedule_work(&shutdown_work);
278 kfree(str);
279 }
281 static void sysrq_handler(struct xenbus_watch *watch, const char **vec,
282 unsigned int len)
283 {
284 char sysrq_key = '\0';
285 xenbus_transaction_t xbt;
286 int err;
288 again:
289 err = xenbus_transaction_start(&xbt);
290 if (err)
291 return;
292 if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) {
293 printk(KERN_ERR "Unable to read sysrq code in "
294 "control/sysrq\n");
295 xenbus_transaction_end(xbt, 1);
296 return;
297 }
299 if (sysrq_key != '\0')
300 xenbus_printf(xbt, "control", "sysrq", "%c", '\0');
302 err = xenbus_transaction_end(xbt, 0);
303 if (err == -EAGAIN)
304 goto again;
306 #ifdef CONFIG_MAGIC_SYSRQ
307 if (sysrq_key != '\0')
308 handle_sysrq(sysrq_key, NULL, NULL);
309 #endif
310 }
312 static struct xenbus_watch shutdown_watch = {
313 .node = "control/shutdown",
314 .callback = shutdown_handler
315 };
317 static struct xenbus_watch sysrq_watch = {
318 .node ="control/sysrq",
319 .callback = sysrq_handler
320 };
322 static int setup_shutdown_watcher(struct notifier_block *notifier,
323 unsigned long event,
324 void *data)
325 {
326 int err;
328 err = register_xenbus_watch(&shutdown_watch);
329 if (err)
330 printk(KERN_ERR "Failed to set shutdown watcher\n");
332 err = register_xenbus_watch(&sysrq_watch);
333 if (err)
334 printk(KERN_ERR "Failed to set sysrq watcher\n");
336 return NOTIFY_DONE;
337 }
339 static int __init setup_shutdown_event(void)
340 {
341 static struct notifier_block xenstore_notifier = {
342 .notifier_call = setup_shutdown_watcher
343 };
344 register_xenstore_notifier(&xenstore_notifier);
345 return 0;
346 }
348 subsys_initcall(setup_shutdown_event);
350 /*
351 * Local variables:
352 * c-file-style: "linux"
353 * indent-tabs-mode: t
354 * c-indent-level: 8
355 * c-basic-offset: 8
356 * tab-width: 8
357 * End:
358 */