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