Linux Audio

Check our new training course

Linux kernel drivers training

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