debuggers.hg

view linux-2.6-xen-sparse/arch/xen/kernel/reboot.c @ 6662:3ba3e5fc2530

Fix typo.
Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
author cl349@firebug.cl.cam.ac.uk
date Mon Sep 05 15:46:12 2005 +0000 (2005-09-05)
parents ff14bb5600c9
children d0a4f770a5f4 8db9c5873b9b
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 <asm-xen/evtchn.h>
13 #include <asm-xen/hypervisor.h>
14 #include <asm-xen/xen-public/dom0_ops.h>
15 #include <asm-xen/queues.h>
16 #include <asm-xen/xenbus.h>
17 #include <asm-xen/ctrl_if.h>
18 #include <linux/cpu.h>
19 #include <linux/kthread.h>
21 #define SHUTDOWN_INVALID -1
22 #define SHUTDOWN_POWEROFF 0
23 #define SHUTDOWN_REBOOT 1
24 #define SHUTDOWN_SUSPEND 2
26 void machine_restart(char * __unused)
27 {
28 /* We really want to get pending console data out before we die. */
29 extern void xencons_force_flush(void);
30 xencons_force_flush();
31 HYPERVISOR_reboot();
32 }
34 void machine_halt(void)
35 {
36 machine_power_off();
37 }
39 void machine_power_off(void)
40 {
41 /* We really want to get pending console data out before we die. */
42 extern void xencons_force_flush(void);
43 xencons_force_flush();
44 HYPERVISOR_shutdown();
45 }
47 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
48 int reboot_thru_bios = 0; /* for dmi_scan.c */
49 EXPORT_SYMBOL(machine_restart);
50 EXPORT_SYMBOL(machine_halt);
51 EXPORT_SYMBOL(machine_power_off);
52 #endif
55 /******************************************************************************
56 * Stop/pickle callback handling.
57 */
59 /* Ignore multiple shutdown requests. */
60 static int shutting_down = SHUTDOWN_INVALID;
62 #ifndef CONFIG_HOTPLUG_CPU
63 #define cpu_down(x) (-EOPNOTSUPP)
64 #define cpu_up(x) (-EOPNOTSUPP)
65 #endif
68 static int __do_suspend(void *ignore)
69 {
70 int i, j;
72 #ifdef CONFIG_XEN_USB_FRONTEND
73 extern void usbif_resume();
74 #else
75 #define usbif_resume() do{}while(0)
76 #endif
78 extern int gnttab_suspend(void);
79 extern int gnttab_resume(void);
81 extern void time_suspend(void);
82 extern void time_resume(void);
83 extern unsigned long max_pfn;
84 extern unsigned int *pfn_to_mfn_frame_list;
86 #ifdef CONFIG_SMP
87 extern void smp_suspend(void);
88 extern void smp_resume(void);
90 static vcpu_guest_context_t suspended_cpu_records[NR_CPUS];
91 cpumask_t prev_online_cpus, prev_present_cpus;
93 void save_vcpu_context(int vcpu, vcpu_guest_context_t *ctxt);
94 int restore_vcpu_context(int vcpu, vcpu_guest_context_t *ctxt);
95 #endif
97 extern void xencons_suspend(void);
98 extern void xencons_resume(void);
100 int err = 0;
102 BUG_ON(smp_processor_id() != 0);
103 BUG_ON(in_interrupt());
105 #if defined(CONFIG_SMP) && !defined(CONFIG_HOTPLUG_CPU)
106 if (num_online_cpus() > 1) {
107 printk(KERN_WARNING
108 "Can't suspend SMP guests without CONFIG_HOTPLUG_CPU\n");
109 return -EOPNOTSUPP;
110 }
111 #endif
113 preempt_disable();
114 #ifdef CONFIG_SMP
115 /* Take all of the other cpus offline. We need to be careful not
116 to get preempted between the final test for num_online_cpus()
117 == 1 and disabling interrupts, since otherwise userspace could
118 bring another cpu online, and then we'd be stuffed. At the
119 same time, cpu_down can reschedule, so we need to enable
120 preemption while doing that. This kind of sucks, but should be
121 correct. */
122 /* (We don't need to worry about other cpus bringing stuff up,
123 since by the time num_online_cpus() == 1, there aren't any
124 other cpus) */
125 cpus_clear(prev_online_cpus);
126 while (num_online_cpus() > 1) {
127 preempt_enable();
128 for_each_online_cpu(i) {
129 if (i == 0)
130 continue;
131 err = cpu_down(i);
132 if (err != 0) {
133 printk(KERN_CRIT "Failed to take all CPUs down: %d.\n", err);
134 goto out_reenable_cpus;
135 }
136 cpu_set(i, prev_online_cpus);
137 }
138 preempt_disable();
139 }
140 #endif
142 __cli();
144 preempt_enable();
146 #ifdef CONFIG_SMP
147 cpus_clear(prev_present_cpus);
148 for_each_present_cpu(i) {
149 if (i == 0)
150 continue;
151 save_vcpu_context(i, &suspended_cpu_records[i]);
152 cpu_set(i, prev_present_cpus);
153 }
154 #endif
156 #ifdef __i386__
157 mm_pin_all();
158 kmem_cache_shrink(pgd_cache);
159 #endif
161 time_suspend();
163 #ifdef CONFIG_SMP
164 smp_suspend();
165 #endif
167 xenbus_suspend();
169 xencons_suspend();
171 ctrl_if_suspend();
173 irq_suspend();
175 gnttab_suspend();
177 HYPERVISOR_shared_info = (shared_info_t *)empty_zero_page;
178 clear_fixmap(FIX_SHARED_INFO);
180 xen_start_info->store_mfn = mfn_to_pfn(xen_start_info->store_mfn);
181 xen_start_info->console_mfn = mfn_to_pfn(xen_start_info->console_mfn);
183 /* We'll stop somewhere inside this hypercall. When it returns,
184 we'll start resuming after the restore. */
185 HYPERVISOR_suspend(virt_to_mfn(xen_start_info));
187 shutting_down = SHUTDOWN_INVALID;
189 set_fixmap(FIX_SHARED_INFO, xen_start_info->shared_info);
191 HYPERVISOR_shared_info = (shared_info_t *)fix_to_virt(FIX_SHARED_INFO);
193 memset(empty_zero_page, 0, PAGE_SIZE);
195 for ( i=0, j=0; i < max_pfn; i+=(PAGE_SIZE/sizeof(unsigned long)), j++ )
196 {
197 pfn_to_mfn_frame_list[j] =
198 virt_to_mfn(&phys_to_machine_mapping[i]);
199 }
200 HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list =
201 virt_to_mfn(pfn_to_mfn_frame_list);
203 gnttab_resume();
205 irq_resume();
207 ctrl_if_resume();
209 xencons_resume();
211 xenbus_resume();
213 #ifdef CONFIG_SMP
214 smp_resume();
215 #endif
217 time_resume();
219 usbif_resume();
221 #ifdef CONFIG_SMP
222 for_each_cpu_mask(i, prev_present_cpus)
223 restore_vcpu_context(i, &suspended_cpu_records[i]);
224 #endif
226 __sti();
228 #ifdef CONFIG_SMP
229 out_reenable_cpus:
230 for_each_cpu_mask(i, prev_online_cpus) {
231 j = cpu_up(i);
232 if (j != 0) {
233 printk(KERN_CRIT "Failed to bring cpu %d back up (%d).\n",
234 i, j);
235 err = j;
236 }
237 }
238 #endif
240 return err;
241 }
243 static int shutdown_process(void *__unused)
244 {
245 static char *envp[] = { "HOME=/", "TERM=linux",
246 "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
247 static char *restart_argv[] = { "/sbin/reboot", NULL };
248 static char *poweroff_argv[] = { "/sbin/poweroff", NULL };
250 extern asmlinkage long sys_reboot(int magic1, int magic2,
251 unsigned int cmd, void *arg);
253 daemonize(
254 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
255 "shutdown"
256 #endif
257 );
259 switch ( shutting_down )
260 {
261 case SHUTDOWN_POWEROFF:
262 if ( execve("/sbin/poweroff", poweroff_argv, envp) < 0 )
263 {
264 sys_reboot(LINUX_REBOOT_MAGIC1,
265 LINUX_REBOOT_MAGIC2,
266 LINUX_REBOOT_CMD_POWER_OFF,
267 NULL);
268 }
269 break;
271 case SHUTDOWN_REBOOT:
272 if ( execve("/sbin/reboot", restart_argv, envp) < 0 )
273 {
274 sys_reboot(LINUX_REBOOT_MAGIC1,
275 LINUX_REBOOT_MAGIC2,
276 LINUX_REBOOT_CMD_RESTART,
277 NULL);
278 }
279 break;
280 }
282 shutting_down = SHUTDOWN_INVALID; /* could try again */
284 return 0;
285 }
287 static struct task_struct *kthread_create_on_cpu(int (*f)(void *arg),
288 void *arg,
289 const char *name,
290 int cpu)
291 {
292 struct task_struct *p;
293 p = kthread_create(f, arg, name);
294 kthread_bind(p, cpu);
295 wake_up_process(p);
296 return p;
297 }
299 static void __shutdown_handler(void *unused)
300 {
301 int err;
303 if ( shutting_down != SHUTDOWN_SUSPEND )
304 {
305 err = kernel_thread(shutdown_process, NULL, CLONE_FS | CLONE_FILES);
306 if ( err < 0 )
307 printk(KERN_ALERT "Error creating shutdown process!\n");
308 }
309 else
310 {
311 kthread_create_on_cpu(__do_suspend, NULL, "suspender", 0);
312 }
313 }
315 static void shutdown_handler(struct xenbus_watch *watch, const char *node)
316 {
317 static DECLARE_WORK(shutdown_work, __shutdown_handler, NULL);
319 char *str;
321 str = (char *)xenbus_read("control", "shutdown", NULL);
322 /* Ignore read errors. */
323 if (IS_ERR(str))
324 return;
325 if (strlen(str) == 0) {
326 kfree(str);
327 return;
328 }
330 xenbus_write("control", "shutdown", "", O_CREAT);
332 if (strcmp(str, "poweroff") == 0)
333 shutting_down = SHUTDOWN_POWEROFF;
334 else if (strcmp(str, "reboot") == 0)
335 shutting_down = SHUTDOWN_REBOOT;
336 else if (strcmp(str, "suspend") == 0)
337 shutting_down = SHUTDOWN_SUSPEND;
338 else {
339 printk("Ignoring shutdown request: %s\n", str);
340 shutting_down = SHUTDOWN_INVALID;
341 }
343 kfree(str);
345 if (shutting_down != SHUTDOWN_INVALID)
346 schedule_work(&shutdown_work);
347 }
349 #ifdef CONFIG_MAGIC_SYSRQ
350 static void sysrq_handler(struct xenbus_watch *watch, const char *node)
351 {
352 char sysrq_key = '\0';
354 if (!xenbus_scanf("control", "sysrq", "%c", &sysrq_key)) {
355 printk(KERN_ERR "Unable to read sysrq code in control/sysrq\n");
356 return;
357 }
359 xenbus_printf("control", "sysrq", "%c", '\0');
361 if (sysrq_key != '\0') {
363 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
364 handle_sysrq(sysrq_key, NULL, NULL);
365 #else
366 handle_sysrq(sysrq_key, NULL, NULL, NULL);
367 #endif
368 }
369 }
370 #endif
372 static struct xenbus_watch shutdown_watch = {
373 .node = "control/shutdown",
374 .callback = shutdown_handler
375 };
377 #ifdef CONFIG_MAGIC_SYSRQ
378 static struct xenbus_watch sysrq_watch = {
379 .node ="control/sysrq",
380 .callback = sysrq_handler
381 };
382 #endif
384 static struct notifier_block xenstore_notifier;
386 /* Setup our watcher
387 NB: Assumes xenbus_lock is held!
388 */
389 static int setup_shutdown_watcher(struct notifier_block *notifier,
390 unsigned long event,
391 void *data)
392 {
393 int err1 = 0;
394 #ifdef CONFIG_MAGIC_SYSRQ
395 int err2 = 0;
396 #endif
398 BUG_ON(down_trylock(&xenbus_lock) == 0);
400 err1 = register_xenbus_watch(&shutdown_watch);
401 #ifdef CONFIG_MAGIC_SYSRQ
402 err2 = register_xenbus_watch(&sysrq_watch);
403 #endif
405 if (err1) {
406 printk(KERN_ERR "Failed to set shutdown watcher\n");
407 }
409 #ifdef CONFIG_MAGIC_SYSRQ
410 if (err2) {
411 printk(KERN_ERR "Failed to set sysrq watcher\n");
412 }
413 #endif
415 return NOTIFY_DONE;
416 }
418 static int __init setup_shutdown_event(void)
419 {
421 xenstore_notifier.notifier_call = setup_shutdown_watcher;
423 register_xenstore_notifier(&xenstore_notifier);
425 return 0;
426 }
428 subsys_initcall(setup_shutdown_event);