ia64/xen-unstable

view linux-2.6-xen-sparse/arch/xen/kernel/reboot.c @ 6294:1a0723cd37f1

Fix many uses of machine addresses in XenLinux. Primarily
this fixes users of virt_to_machine/machine_to_virt to
use virt_to_mfn/mfn_to_virt where that is more appropriate.

This should be a big step to improved PAE stability.

Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Fri Aug 19 16:06:43 2005 +0000 (2005-08-19)
parents 47d49e8b8042
children 473af43ac65b 531ad4bde8f2 81576d3d1ca8
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/linux-public/suspend.h>
16 #include <asm-xen/queues.h>
17 #include <asm-xen/xenbus.h>
18 #include <asm-xen/ctrl_if.h>
19 #include <linux/cpu.h>
20 #include <linux/kthread.h>
22 #define SHUTDOWN_INVALID -1
23 #define SHUTDOWN_POWEROFF 0
24 #define SHUTDOWN_REBOOT 1
25 #define SHUTDOWN_SUSPEND 2
27 void machine_restart(char * __unused)
28 {
29 /* We really want to get pending console data out before we die. */
30 extern void xencons_force_flush(void);
31 xencons_force_flush();
32 HYPERVISOR_reboot();
33 }
35 void machine_halt(void)
36 {
37 machine_power_off();
38 }
40 void machine_power_off(void)
41 {
42 /* We really want to get pending console data out before we die. */
43 extern void xencons_force_flush(void);
44 xencons_force_flush();
45 HYPERVISOR_shutdown();
46 }
48 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
49 int reboot_thru_bios = 0; /* for dmi_scan.c */
50 EXPORT_SYMBOL(machine_restart);
51 EXPORT_SYMBOL(machine_halt);
52 EXPORT_SYMBOL(machine_power_off);
53 #endif
56 /******************************************************************************
57 * Stop/pickle callback handling.
58 */
60 /* Ignore multiple shutdown requests. */
61 static int shutting_down = SHUTDOWN_INVALID;
63 #ifndef CONFIG_HOTPLUG_CPU
64 #define cpu_down(x) (-EOPNOTSUPP)
65 #define cpu_up(x) (-EOPNOTSUPP)
66 #endif
68 static void save_vcpu_context(int vcpu, vcpu_guest_context_t *ctxt)
69 {
70 int r;
71 int gdt_pages;
72 r = HYPERVISOR_vcpu_pickle(vcpu, ctxt);
73 if (r != 0)
74 panic("pickling vcpu %d -> %d!\n", vcpu, r);
76 /* Translate from machine to physical addresses where necessary,
77 so that they can be translated to our new machine address space
78 after resume. libxc is responsible for doing this to vcpu0,
79 but we do it to the others. */
80 gdt_pages = (ctxt->gdt_ents + 511) / 512;
81 ctxt->ctrlreg[3] = machine_to_phys(ctxt->ctrlreg[3]);
82 for (r = 0; r < gdt_pages; r++)
83 ctxt->gdt_frames[r] = mfn_to_pfn(ctxt->gdt_frames[r]);
84 }
86 void _restore_vcpu(int cpu);
88 atomic_t vcpus_rebooting;
90 static int restore_vcpu_context(int vcpu, vcpu_guest_context_t *ctxt)
91 {
92 int r;
93 int gdt_pages = (ctxt->gdt_ents + 511) / 512;
95 /* This is kind of a hack, and implicitly relies on the fact that
96 the vcpu stops in a place where all of the call clobbered
97 registers are already dead. */
98 ctxt->user_regs.esp -= 4;
99 ((unsigned long *)ctxt->user_regs.esp)[0] = ctxt->user_regs.eip;
100 ctxt->user_regs.eip = (unsigned long)_restore_vcpu;
102 /* De-canonicalise. libxc handles this for vcpu 0, but we need
103 to do it for the other vcpus. */
104 ctxt->ctrlreg[3] = phys_to_machine(ctxt->ctrlreg[3]);
105 for (r = 0; r < gdt_pages; r++)
106 ctxt->gdt_frames[r] = pfn_to_mfn(ctxt->gdt_frames[r]);
108 atomic_set(&vcpus_rebooting, 1);
109 r = HYPERVISOR_boot_vcpu(vcpu, ctxt);
110 if (r != 0) {
111 printk(KERN_EMERG "Failed to reboot vcpu %d (%d)\n", vcpu, r);
112 return -1;
113 }
115 /* Make sure we wait for the new vcpu to come up before trying to do
116 anything with it or starting the next one. */
117 while (atomic_read(&vcpus_rebooting))
118 barrier();
120 return 0;
121 }
123 static int __do_suspend(void *ignore)
124 {
125 int i, j;
126 suspend_record_t *suspend_record;
127 static vcpu_guest_context_t suspended_cpu_records[NR_CPUS];
129 /* Hmmm... a cleaner interface to suspend/resume blkdevs would be nice. */
130 /* XXX SMH: yes it would :-( */
132 #ifdef CONFIG_XEN_NETDEV_FRONTEND
133 extern void netif_suspend(void);
134 extern void netif_resume(void);
135 #else
136 #define netif_suspend() do{}while(0)
137 #define netif_resume() do{}while(0)
138 #endif
140 #ifdef CONFIG_XEN_USB_FRONTEND
141 extern void usbif_resume();
142 #else
143 #define usbif_resume() do{}while(0)
144 #endif
146 #ifdef CONFIG_XEN_BLKDEV_GRANT
147 extern int gnttab_suspend(void);
148 extern int gnttab_resume(void);
149 #else
150 #define gnttab_suspend() do{}while(0)
151 #define gnttab_resume() do{}while(0)
152 #endif
154 #ifdef CONFIG_SMP
155 extern void smp_suspend(void);
156 extern void smp_resume(void);
157 #endif
158 extern void time_suspend(void);
159 extern void time_resume(void);
160 extern unsigned long max_pfn;
161 extern unsigned int *pfn_to_mfn_frame_list;
163 cpumask_t prev_online_cpus, prev_present_cpus;
164 int err = 0;
166 BUG_ON(smp_processor_id() != 0);
167 BUG_ON(in_interrupt());
169 #if defined(CONFIG_SMP) && !defined(CONFIG_HOTPLUG_CPU)
170 if (num_online_cpus() > 1) {
171 printk(KERN_WARNING "Can't suspend SMP guests without CONFIG_HOTPLUG_CPU\n");
172 return -EOPNOTSUPP;
173 }
174 #endif
176 suspend_record = (suspend_record_t *)__get_free_page(GFP_KERNEL);
177 if ( suspend_record == NULL )
178 goto out;
180 /* Take all of the other cpus offline. We need to be careful not
181 to get preempted between the final test for num_online_cpus()
182 == 1 and disabling interrupts, since otherwise userspace could
183 bring another cpu online, and then we'd be stuffed. At the
184 same time, cpu_down can reschedule, so we need to enable
185 preemption while doing that. This kind of sucks, but should be
186 correct. */
187 /* (We don't need to worry about other cpus bringing stuff up,
188 since by the time num_online_cpus() == 1, there aren't any
189 other cpus) */
190 cpus_clear(prev_online_cpus);
191 preempt_disable();
192 while (num_online_cpus() > 1) {
193 preempt_enable();
194 for_each_online_cpu(i) {
195 if (i == 0)
196 continue;
197 err = cpu_down(i);
198 if (err != 0) {
199 printk(KERN_CRIT "Failed to take all CPUs down: %d.\n", err);
200 goto out_reenable_cpus;
201 }
202 cpu_set(i, prev_online_cpus);
203 }
204 preempt_disable();
205 }
207 suspend_record->nr_pfns = max_pfn; /* final number of pfns */
209 __cli();
211 preempt_enable();
213 cpus_clear(prev_present_cpus);
214 for_each_present_cpu(i) {
215 if (i == 0)
216 continue;
217 save_vcpu_context(i, &suspended_cpu_records[i]);
218 cpu_set(i, prev_present_cpus);
219 }
221 #ifdef __i386__
222 mm_pin_all();
223 kmem_cache_shrink(pgd_cache);
224 #endif
226 netif_suspend();
228 time_suspend();
230 #ifdef CONFIG_SMP
231 smp_suspend();
232 #endif
234 xenbus_suspend();
236 ctrl_if_suspend();
238 irq_suspend();
240 gnttab_suspend();
242 HYPERVISOR_shared_info = (shared_info_t *)empty_zero_page;
243 clear_fixmap(FIX_SHARED_INFO);
245 memcpy(&suspend_record->resume_info, &xen_start_info,
246 sizeof(xen_start_info));
248 /* We'll stop somewhere inside this hypercall. When it returns,
249 we'll start resuming after the restore. */
250 HYPERVISOR_suspend(virt_to_mfn(suspend_record));
252 shutting_down = SHUTDOWN_INVALID;
254 memcpy(&xen_start_info, &suspend_record->resume_info,
255 sizeof(xen_start_info));
257 set_fixmap(FIX_SHARED_INFO, xen_start_info.shared_info);
259 HYPERVISOR_shared_info = (shared_info_t *)fix_to_virt(FIX_SHARED_INFO);
261 memset(empty_zero_page, 0, PAGE_SIZE);
263 for ( i=0, j=0; i < max_pfn; i+=(PAGE_SIZE/sizeof(unsigned long)), j++ )
264 {
265 pfn_to_mfn_frame_list[j] =
266 virt_to_mfn(&phys_to_machine_mapping[i]);
267 }
268 HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list =
269 virt_to_mfn(pfn_to_mfn_frame_list);
271 gnttab_resume();
273 irq_resume();
275 ctrl_if_resume();
277 xenbus_resume();
279 #ifdef CONFIG_SMP
280 smp_resume();
281 #endif
283 time_resume();
285 netif_resume();
287 usbif_resume();
289 for_each_cpu_mask(i, prev_present_cpus) {
290 restore_vcpu_context(i, &suspended_cpu_records[i]);
291 }
293 __sti();
295 out_reenable_cpus:
296 for_each_cpu_mask(i, prev_online_cpus) {
297 j = cpu_up(i);
298 if (j != 0) {
299 printk(KERN_CRIT "Failed to bring cpu %d back up (%d).\n",
300 i, j);
301 err = j;
302 }
303 }
305 out:
306 if ( suspend_record != NULL )
307 free_page((unsigned long)suspend_record);
308 return err;
309 }
311 static int shutdown_process(void *__unused)
312 {
313 static char *envp[] = { "HOME=/", "TERM=linux",
314 "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
315 static char *restart_argv[] = { "/sbin/reboot", NULL };
316 static char *poweroff_argv[] = { "/sbin/poweroff", NULL };
318 extern asmlinkage long sys_reboot(int magic1, int magic2,
319 unsigned int cmd, void *arg);
321 daemonize(
322 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
323 "shutdown"
324 #endif
325 );
327 switch ( shutting_down )
328 {
329 case SHUTDOWN_POWEROFF:
330 if ( execve("/sbin/poweroff", poweroff_argv, envp) < 0 )
331 {
332 sys_reboot(LINUX_REBOOT_MAGIC1,
333 LINUX_REBOOT_MAGIC2,
334 LINUX_REBOOT_CMD_POWER_OFF,
335 NULL);
336 }
337 break;
339 case SHUTDOWN_REBOOT:
340 if ( execve("/sbin/reboot", restart_argv, envp) < 0 )
341 {
342 sys_reboot(LINUX_REBOOT_MAGIC1,
343 LINUX_REBOOT_MAGIC2,
344 LINUX_REBOOT_CMD_RESTART,
345 NULL);
346 }
347 break;
348 }
350 shutting_down = SHUTDOWN_INVALID; /* could try again */
352 return 0;
353 }
355 static struct task_struct *kthread_create_on_cpu(int (*f)(void *arg),
356 void *arg,
357 const char *name,
358 int cpu)
359 {
360 struct task_struct *p;
361 p = kthread_create(f, arg, name);
362 kthread_bind(p, cpu);
363 wake_up_process(p);
364 return p;
365 }
367 static void __shutdown_handler(void *unused)
368 {
369 int err;
371 if ( shutting_down != SHUTDOWN_SUSPEND )
372 {
373 err = kernel_thread(shutdown_process, NULL, CLONE_FS | CLONE_FILES);
374 if ( err < 0 )
375 printk(KERN_ALERT "Error creating shutdown process!\n");
376 }
377 else
378 {
379 kthread_create_on_cpu(__do_suspend, NULL, "suspender", 0);
380 }
381 }
383 static void shutdown_handler(struct xenbus_watch *watch, const char *node)
384 {
385 static DECLARE_WORK(shutdown_work, __shutdown_handler, NULL);
387 char *str;
389 str = (char *)xenbus_read("control", "shutdown", NULL);
390 /* Ignore read errors. */
391 if (IS_ERR(str))
392 return;
393 if (strlen(str) == 0) {
394 kfree(str);
395 return;
396 }
398 xenbus_write("control", "shutdown", "", O_CREAT);
400 if (strcmp(str, "poweroff") == 0)
401 shutting_down = SHUTDOWN_POWEROFF;
402 else if (strcmp(str, "reboot") == 0)
403 shutting_down = SHUTDOWN_REBOOT;
404 else if (strcmp(str, "suspend") == 0)
405 shutting_down = SHUTDOWN_SUSPEND;
406 else {
407 printk("Ignoring shutdown request: %s\n", str);
408 shutting_down = SHUTDOWN_INVALID;
409 }
411 kfree(str);
413 if (shutting_down != SHUTDOWN_INVALID)
414 schedule_work(&shutdown_work);
415 }
417 #ifdef CONFIG_MAGIC_SYSRQ
418 static void sysrq_handler(struct xenbus_watch *watch, const char *node)
419 {
420 char sysrq_key = '\0';
422 if (!xenbus_scanf("control", "sysrq", "%c", &sysrq_key)) {
423 printk(KERN_ERR "Unable to read sysrq code in control/sysrq\n");
424 return;
425 }
427 xenbus_printf("control", "sysrq", "%c", '\0');
429 if (sysrq_key != '\0') {
431 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
432 handle_sysrq(sysrq_key, NULL, NULL);
433 #else
434 handle_sysrq(sysrq_key, NULL, NULL, NULL);
435 #endif
436 }
437 }
438 #endif
440 static struct xenbus_watch shutdown_watch = {
441 .node = "control/shutdown",
442 .callback = shutdown_handler
443 };
445 #ifdef CONFIG_MAGIC_SYSRQ
446 static struct xenbus_watch sysrq_watch = {
447 .node ="control/sysrq",
448 .callback = sysrq_handler
449 };
450 #endif
452 static struct notifier_block xenstore_notifier;
454 /* Setup our watcher
455 NB: Assumes xenbus_lock is held!
456 */
457 static int setup_shutdown_watcher(struct notifier_block *notifier,
458 unsigned long event,
459 void *data)
460 {
461 int err1 = 0;
462 #ifdef CONFIG_MAGIC_SYSRQ
463 int err2 = 0;
464 #endif
466 BUG_ON(down_trylock(&xenbus_lock) == 0);
468 err1 = register_xenbus_watch(&shutdown_watch);
469 #ifdef CONFIG_MAGIC_SYSRQ
470 err2 = register_xenbus_watch(&sysrq_watch);
471 #endif
473 if (err1) {
474 printk(KERN_ERR "Failed to set shutdown watcher\n");
475 }
477 #ifdef CONFIG_MAGIC_SYSRQ
478 if (err2) {
479 printk(KERN_ERR "Failed to set sysrq watcher\n");
480 }
481 #endif
483 return NOTIFY_DONE;
484 }
486 static int __init setup_shutdown_event(void)
487 {
489 xenstore_notifier.notifier_call = setup_shutdown_watcher;
491 register_xenstore_notifier(&xenstore_notifier);
493 return 0;
494 }
496 subsys_initcall(setup_shutdown_event);