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