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