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