xref: /openbmc/linux/drivers/xen/manage.c (revision baa7eb025ab14f3cba2e35c0a8648f9c9f01d24f)
1 /*
2  * Handle extern requests for shutdown, reboot and sysrq
3  */
4 #include <linux/kernel.h>
5 #include <linux/err.h>
6 #include <linux/slab.h>
7 #include <linux/reboot.h>
8 #include <linux/sysrq.h>
9 #include <linux/stop_machine.h>
10 #include <linux/freezer.h>
11 
12 #include <xen/xen.h>
13 #include <xen/xenbus.h>
14 #include <xen/grant_table.h>
15 #include <xen/events.h>
16 #include <xen/hvc-console.h>
17 #include <xen/xen-ops.h>
18 
19 #include <asm/xen/hypercall.h>
20 #include <asm/xen/page.h>
21 #include <asm/xen/hypervisor.h>
22 
23 enum shutdown_state {
24 	SHUTDOWN_INVALID = -1,
25 	SHUTDOWN_POWEROFF = 0,
26 	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 	 SHUTDOWN_HALT = 4,
32 };
33 
34 /* Ignore multiple shutdown requests. */
35 static enum shutdown_state shutting_down = SHUTDOWN_INVALID;
36 
37 #ifdef CONFIG_PM_SLEEP
38 static int xen_hvm_suspend(void *data)
39 {
40 	struct sched_shutdown r = { .reason = SHUTDOWN_suspend };
41 	int *cancelled = data;
42 
43 	BUG_ON(!irqs_disabled());
44 
45 	*cancelled = HYPERVISOR_sched_op(SCHEDOP_shutdown, &r);
46 
47 	xen_hvm_post_suspend(*cancelled);
48 	gnttab_resume();
49 
50 	if (!*cancelled) {
51 		xen_irq_resume();
52 		xen_console_resume();
53 		xen_timer_resume();
54 	}
55 
56 	return 0;
57 }
58 
59 static int xen_suspend(void *data)
60 {
61 	int err;
62 	int *cancelled = data;
63 
64 	BUG_ON(!irqs_disabled());
65 
66 	err = sysdev_suspend(PMSG_SUSPEND);
67 	if (err) {
68 		printk(KERN_ERR "xen_suspend: sysdev_suspend failed: %d\n",
69 			err);
70 		return err;
71 	}
72 
73 	xen_mm_pin_all();
74 	gnttab_suspend();
75 	xen_pre_suspend();
76 
77 	/*
78 	 * This hypercall returns 1 if suspend was cancelled
79 	 * or the domain was merely checkpointed, and 0 if it
80 	 * is resuming in a new domain.
81 	 */
82 	*cancelled = HYPERVISOR_suspend(virt_to_mfn(xen_start_info));
83 
84 	xen_post_suspend(*cancelled);
85 	gnttab_resume();
86 	xen_mm_unpin_all();
87 
88 	if (!*cancelled) {
89 		xen_irq_resume();
90 		xen_console_resume();
91 		xen_timer_resume();
92 	}
93 
94 	sysdev_resume();
95 
96 	return 0;
97 }
98 
99 static void do_suspend(void)
100 {
101 	int err;
102 	int cancelled = 1;
103 
104 	shutting_down = SHUTDOWN_SUSPEND;
105 
106 #ifdef CONFIG_PREEMPT
107 	/* If the kernel is preemptible, we need to freeze all the processes
108 	   to prevent them from being in the middle of a pagetable update
109 	   during suspend. */
110 	err = freeze_processes();
111 	if (err) {
112 		printk(KERN_ERR "xen suspend: freeze failed %d\n", err);
113 		goto out;
114 	}
115 #endif
116 
117 	err = dpm_suspend_start(PMSG_SUSPEND);
118 	if (err) {
119 		printk(KERN_ERR "xen suspend: dpm_suspend_start %d\n", err);
120 		goto out_thaw;
121 	}
122 
123 	printk(KERN_DEBUG "suspending xenstore...\n");
124 	xs_suspend();
125 
126 	err = dpm_suspend_noirq(PMSG_SUSPEND);
127 	if (err) {
128 		printk(KERN_ERR "dpm_suspend_noirq failed: %d\n", err);
129 		goto out_resume;
130 	}
131 
132 	if (xen_hvm_domain())
133 		err = stop_machine(xen_hvm_suspend, &cancelled, cpumask_of(0));
134 	else
135 		err = stop_machine(xen_suspend, &cancelled, cpumask_of(0));
136 
137 	dpm_resume_noirq(PMSG_RESUME);
138 
139 	if (err) {
140 		printk(KERN_ERR "failed to start xen_suspend: %d\n", err);
141 		cancelled = 1;
142 	}
143 
144 out_resume:
145 	if (!cancelled) {
146 		xen_arch_resume();
147 		xs_resume();
148 	} else
149 		xs_suspend_cancel();
150 
151 	dpm_resume_end(PMSG_RESUME);
152 
153 	/* Make sure timer events get retriggered on all CPUs */
154 	clock_was_set();
155 
156 out_thaw:
157 #ifdef CONFIG_PREEMPT
158 	thaw_processes();
159 out:
160 #endif
161 	shutting_down = SHUTDOWN_INVALID;
162 }
163 #endif	/* CONFIG_PM_SLEEP */
164 
165 static void shutdown_handler(struct xenbus_watch *watch,
166 			     const char **vec, unsigned int len)
167 {
168 	char *str;
169 	struct xenbus_transaction xbt;
170 	int err;
171 
172 	if (shutting_down != SHUTDOWN_INVALID)
173 		return;
174 
175  again:
176 	err = xenbus_transaction_start(&xbt);
177 	if (err)
178 		return;
179 
180 	str = (char *)xenbus_read(xbt, "control", "shutdown", NULL);
181 	/* Ignore read errors and empty reads. */
182 	if (XENBUS_IS_ERR_READ(str)) {
183 		xenbus_transaction_end(xbt, 1);
184 		return;
185 	}
186 
187 	xenbus_write(xbt, "control", "shutdown", "");
188 
189 	err = xenbus_transaction_end(xbt, 0);
190 	if (err == -EAGAIN) {
191 		kfree(str);
192 		goto again;
193 	}
194 
195 	if (strcmp(str, "poweroff") == 0 ||
196 	    strcmp(str, "halt") == 0) {
197 		shutting_down = SHUTDOWN_POWEROFF;
198 		orderly_poweroff(false);
199 	} else if (strcmp(str, "reboot") == 0) {
200 		shutting_down = SHUTDOWN_POWEROFF; /* ? */
201 		ctrl_alt_del();
202 #ifdef CONFIG_PM_SLEEP
203 	} else if (strcmp(str, "suspend") == 0) {
204 		do_suspend();
205 #endif
206 	} else {
207 		printk(KERN_INFO "Ignoring shutdown request: %s\n", str);
208 		shutting_down = SHUTDOWN_INVALID;
209 	}
210 
211 	kfree(str);
212 }
213 
214 #ifdef CONFIG_MAGIC_SYSRQ
215 static void sysrq_handler(struct xenbus_watch *watch, const char **vec,
216 			  unsigned int len)
217 {
218 	char sysrq_key = '\0';
219 	struct xenbus_transaction xbt;
220 	int err;
221 
222  again:
223 	err = xenbus_transaction_start(&xbt);
224 	if (err)
225 		return;
226 	if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) {
227 		printk(KERN_ERR "Unable to read sysrq code in "
228 		       "control/sysrq\n");
229 		xenbus_transaction_end(xbt, 1);
230 		return;
231 	}
232 
233 	if (sysrq_key != '\0')
234 		xenbus_printf(xbt, "control", "sysrq", "%c", '\0');
235 
236 	err = xenbus_transaction_end(xbt, 0);
237 	if (err == -EAGAIN)
238 		goto again;
239 
240 	if (sysrq_key != '\0')
241 		handle_sysrq(sysrq_key);
242 }
243 
244 static struct xenbus_watch sysrq_watch = {
245 	.node = "control/sysrq",
246 	.callback = sysrq_handler
247 };
248 #endif
249 
250 static struct xenbus_watch shutdown_watch = {
251 	.node = "control/shutdown",
252 	.callback = shutdown_handler
253 };
254 
255 static int setup_shutdown_watcher(void)
256 {
257 	int err;
258 
259 	err = register_xenbus_watch(&shutdown_watch);
260 	if (err) {
261 		printk(KERN_ERR "Failed to set shutdown watcher\n");
262 		return err;
263 	}
264 
265 #ifdef CONFIG_MAGIC_SYSRQ
266 	err = register_xenbus_watch(&sysrq_watch);
267 	if (err) {
268 		printk(KERN_ERR "Failed to set sysrq watcher\n");
269 		return err;
270 	}
271 #endif
272 
273 	return 0;
274 }
275 
276 static int shutdown_event(struct notifier_block *notifier,
277 			  unsigned long event,
278 			  void *data)
279 {
280 	setup_shutdown_watcher();
281 	return NOTIFY_DONE;
282 }
283 
284 static int __init __setup_shutdown_event(void)
285 {
286 	/* Delay initialization in the PV on HVM case */
287 	if (xen_hvm_domain())
288 		return 0;
289 
290 	if (!xen_pv_domain())
291 		return -ENODEV;
292 
293 	return xen_setup_shutdown_event();
294 }
295 
296 int xen_setup_shutdown_event(void)
297 {
298 	static struct notifier_block xenstore_notifier = {
299 		.notifier_call = shutdown_event
300 	};
301 	register_xenstore_notifier(&xenstore_notifier);
302 
303 	return 0;
304 }
305 EXPORT_SYMBOL_GPL(xen_setup_shutdown_event);
306 
307 subsys_initcall(__setup_shutdown_event);
308