1457c8996SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
215d94b82SRobin Holt /*
315d94b82SRobin Holt * linux/kernel/reboot.c
415d94b82SRobin Holt *
515d94b82SRobin Holt * Copyright (C) 2013 Linus Torvalds
615d94b82SRobin Holt */
715d94b82SRobin Holt
8972ee83dSRobin Holt #define pr_fmt(fmt) "reboot: " fmt
9972ee83dSRobin Holt
10dfa19b11SMatti Vaittinen #include <linux/atomic.h>
111b3a5d02SRobin Holt #include <linux/ctype.h>
1215d94b82SRobin Holt #include <linux/export.h>
1315d94b82SRobin Holt #include <linux/kexec.h>
1415d94b82SRobin Holt #include <linux/kmod.h>
1515d94b82SRobin Holt #include <linux/kmsg_dump.h>
1615d94b82SRobin Holt #include <linux/reboot.h>
1715d94b82SRobin Holt #include <linux/suspend.h>
1815d94b82SRobin Holt #include <linux/syscalls.h>
1915d94b82SRobin Holt #include <linux/syscore_ops.h>
2015d94b82SRobin Holt #include <linux/uaccess.h>
2115d94b82SRobin Holt
2215d94b82SRobin Holt /*
2315d94b82SRobin Holt * this indicates whether you can reboot with ctrl-alt-del: the default is yes
2415d94b82SRobin Holt */
2515d94b82SRobin Holt
2606d17766Stangmeng static int C_A_D = 1;
2715d94b82SRobin Holt struct pid *cad_pid;
2815d94b82SRobin Holt EXPORT_SYMBOL(cad_pid);
2915d94b82SRobin Holt
30fb37409aSMike Rapoport #if defined(CONFIG_ARM)
311b3a5d02SRobin Holt #define DEFAULT_REBOOT_MODE = REBOOT_HARD
321b3a5d02SRobin Holt #else
331b3a5d02SRobin Holt #define DEFAULT_REBOOT_MODE
341b3a5d02SRobin Holt #endif
351b3a5d02SRobin Holt enum reboot_mode reboot_mode DEFAULT_REBOOT_MODE;
36d46b3f5bSShawn Guo EXPORT_SYMBOL_GPL(reboot_mode);
37b287a25aSAaro Koskinen enum reboot_mode panic_reboot_mode = REBOOT_UNDEFINED;
381b3a5d02SRobin Holt
39*e016173fSAhmad Fatoum static enum hw_protection_action hw_protection_action = HWPROT_ACT_SHUTDOWN;
40*e016173fSAhmad Fatoum
41e2f0b88eSChuansheng Liu /*
42e2f0b88eSChuansheng Liu * This variable is used privately to keep track of whether or not
43e2f0b88eSChuansheng Liu * reboot_type is still set to its default value (i.e., reboot= hasn't
44e2f0b88eSChuansheng Liu * been set on the command line). This is needed so that we can
45e2f0b88eSChuansheng Liu * suppress DMI scanning for reboot quirks. Without it, it's
46e2f0b88eSChuansheng Liu * impossible to override a faulty reboot quirk without recompiling.
47e2f0b88eSChuansheng Liu */
48e2f0b88eSChuansheng Liu int reboot_default = 1;
491b3a5d02SRobin Holt int reboot_cpu;
501b3a5d02SRobin Holt enum reboot_type reboot_type = BOOT_ACPI;
511b3a5d02SRobin Holt int reboot_force;
521b3a5d02SRobin Holt
53232edc2fSDmitry Osipenko struct sys_off_handler {
54232edc2fSDmitry Osipenko struct notifier_block nb;
55232edc2fSDmitry Osipenko int (*sys_off_cb)(struct sys_off_data *data);
56232edc2fSDmitry Osipenko void *cb_data;
57232edc2fSDmitry Osipenko enum sys_off_mode mode;
58232edc2fSDmitry Osipenko bool blocking;
59232edc2fSDmitry Osipenko void *list;
60db2d6038SBenjamin Bara struct device *dev;
61232edc2fSDmitry Osipenko };
6215d94b82SRobin Holt
6315d94b82SRobin Holt /*
64a9a1d6adSDongmin Lee * This variable is used to indicate if a halt was initiated instead of a
65a9a1d6adSDongmin Lee * reboot when the reboot call was invoked with LINUX_REBOOT_CMD_POWER_OFF, but
66a9a1d6adSDongmin Lee * the system cannot be powered off. This allowes kernel_halt() to notify users
67a9a1d6adSDongmin Lee * of that.
68a9a1d6adSDongmin Lee */
69a9a1d6adSDongmin Lee static bool poweroff_fallback_to_halt;
70a9a1d6adSDongmin Lee
71a9a1d6adSDongmin Lee /*
725d34b41aSDmitry Osipenko * Temporary stub that prevents linkage failure while we're in process
735d34b41aSDmitry Osipenko * of removing all uses of legacy pm_power_off() around the kernel.
745d34b41aSDmitry Osipenko */
755d34b41aSDmitry Osipenko void __weak (*pm_power_off)(void);
7615d94b82SRobin Holt
77f2fa0fd4SThomas Weißschuh /*
78f2fa0fd4SThomas Weißschuh * Notifier list for kernel code which wants to be called
79f2fa0fd4SThomas Weißschuh * at shutdown. This is used to stop any idling DMA operations
80f2fa0fd4SThomas Weißschuh * and the like.
81f2fa0fd4SThomas Weißschuh */
82f2fa0fd4SThomas Weißschuh static BLOCKING_NOTIFIER_HEAD(reboot_notifier_list);
83f2fa0fd4SThomas Weißschuh
8415d94b82SRobin Holt /**
8515d94b82SRobin Holt * emergency_restart - reboot the system
8615d94b82SRobin Holt *
8715d94b82SRobin Holt * Without shutting down any hardware or taking any locks
8815d94b82SRobin Holt * reboot the system. This is called when we know we are in
8915d94b82SRobin Holt * trouble so this is our best effort to reboot. This is
9015d94b82SRobin Holt * safe to call in interrupt context.
9115d94b82SRobin Holt */
emergency_restart(void)9215d94b82SRobin Holt void emergency_restart(void)
9315d94b82SRobin Holt {
9415d94b82SRobin Holt kmsg_dump(KMSG_DUMP_EMERG);
9560466c06SBenjamin Bara system_state = SYSTEM_RESTART;
9615d94b82SRobin Holt machine_emergency_restart();
9715d94b82SRobin Holt }
9815d94b82SRobin Holt EXPORT_SYMBOL_GPL(emergency_restart);
9915d94b82SRobin Holt
kernel_restart_prepare(char * cmd)10015d94b82SRobin Holt void kernel_restart_prepare(char *cmd)
10115d94b82SRobin Holt {
10215d94b82SRobin Holt blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd);
10315d94b82SRobin Holt system_state = SYSTEM_RESTART;
10415d94b82SRobin Holt usermodehelper_disable();
10515d94b82SRobin Holt device_shutdown();
10615d94b82SRobin Holt }
10715d94b82SRobin Holt
10815d94b82SRobin Holt /**
10915d94b82SRobin Holt * register_reboot_notifier - Register function to be called at reboot time
11015d94b82SRobin Holt * @nb: Info about notifier function to be called
11115d94b82SRobin Holt *
11215d94b82SRobin Holt * Registers a function with the list of functions
11315d94b82SRobin Holt * to be called at reboot time.
11415d94b82SRobin Holt *
11515d94b82SRobin Holt * Currently always returns zero, as blocking_notifier_chain_register()
11615d94b82SRobin Holt * always returns zero.
11715d94b82SRobin Holt */
register_reboot_notifier(struct notifier_block * nb)11815d94b82SRobin Holt int register_reboot_notifier(struct notifier_block *nb)
11915d94b82SRobin Holt {
12015d94b82SRobin Holt return blocking_notifier_chain_register(&reboot_notifier_list, nb);
12115d94b82SRobin Holt }
12215d94b82SRobin Holt EXPORT_SYMBOL(register_reboot_notifier);
12315d94b82SRobin Holt
12415d94b82SRobin Holt /**
12515d94b82SRobin Holt * unregister_reboot_notifier - Unregister previously registered reboot notifier
12615d94b82SRobin Holt * @nb: Hook to be unregistered
12715d94b82SRobin Holt *
12815d94b82SRobin Holt * Unregisters a previously registered reboot
12915d94b82SRobin Holt * notifier function.
13015d94b82SRobin Holt *
13115d94b82SRobin Holt * Returns zero on success, or %-ENOENT on failure.
13215d94b82SRobin Holt */
unregister_reboot_notifier(struct notifier_block * nb)13315d94b82SRobin Holt int unregister_reboot_notifier(struct notifier_block *nb)
13415d94b82SRobin Holt {
13515d94b82SRobin Holt return blocking_notifier_chain_unregister(&reboot_notifier_list, nb);
13615d94b82SRobin Holt }
13715d94b82SRobin Holt EXPORT_SYMBOL(unregister_reboot_notifier);
13815d94b82SRobin Holt
devm_unregister_reboot_notifier(struct device * dev,void * res)1392d8364baSAndrey Smirnov static void devm_unregister_reboot_notifier(struct device *dev, void *res)
1402d8364baSAndrey Smirnov {
1412d8364baSAndrey Smirnov WARN_ON(unregister_reboot_notifier(*(struct notifier_block **)res));
1422d8364baSAndrey Smirnov }
1432d8364baSAndrey Smirnov
devm_register_reboot_notifier(struct device * dev,struct notifier_block * nb)1442d8364baSAndrey Smirnov int devm_register_reboot_notifier(struct device *dev, struct notifier_block *nb)
1452d8364baSAndrey Smirnov {
1462d8364baSAndrey Smirnov struct notifier_block **rcnb;
1472d8364baSAndrey Smirnov int ret;
1482d8364baSAndrey Smirnov
1492d8364baSAndrey Smirnov rcnb = devres_alloc(devm_unregister_reboot_notifier,
1502d8364baSAndrey Smirnov sizeof(*rcnb), GFP_KERNEL);
1512d8364baSAndrey Smirnov if (!rcnb)
1522d8364baSAndrey Smirnov return -ENOMEM;
1532d8364baSAndrey Smirnov
1542d8364baSAndrey Smirnov ret = register_reboot_notifier(nb);
1552d8364baSAndrey Smirnov if (!ret) {
1562d8364baSAndrey Smirnov *rcnb = nb;
1572d8364baSAndrey Smirnov devres_add(dev, rcnb);
1582d8364baSAndrey Smirnov } else {
1592d8364baSAndrey Smirnov devres_free(rcnb);
1602d8364baSAndrey Smirnov }
1612d8364baSAndrey Smirnov
1622d8364baSAndrey Smirnov return ret;
1632d8364baSAndrey Smirnov }
1642d8364baSAndrey Smirnov EXPORT_SYMBOL(devm_register_reboot_notifier);
1652d8364baSAndrey Smirnov
166b63adb97SGuenter Roeck /*
167b63adb97SGuenter Roeck * Notifier list for kernel code which wants to be called
168b63adb97SGuenter Roeck * to restart the system.
169b63adb97SGuenter Roeck */
170b63adb97SGuenter Roeck static ATOMIC_NOTIFIER_HEAD(restart_handler_list);
171b63adb97SGuenter Roeck
172b63adb97SGuenter Roeck /**
173b63adb97SGuenter Roeck * register_restart_handler - Register function to be called to reset
174b63adb97SGuenter Roeck * the system
175b63adb97SGuenter Roeck * @nb: Info about handler function to be called
176b63adb97SGuenter Roeck * @nb->priority: Handler priority. Handlers should follow the
177b63adb97SGuenter Roeck * following guidelines for setting priorities.
178b63adb97SGuenter Roeck * 0: Restart handler of last resort,
179b63adb97SGuenter Roeck * with limited restart capabilities
180b63adb97SGuenter Roeck * 128: Default restart handler; use if no other
181b63adb97SGuenter Roeck * restart handler is expected to be available,
182b63adb97SGuenter Roeck * and/or if restart functionality is
183b63adb97SGuenter Roeck * sufficient to restart the entire system
184b63adb97SGuenter Roeck * 255: Highest priority restart handler, will
185b63adb97SGuenter Roeck * preempt all other restart handlers
186b63adb97SGuenter Roeck *
187b63adb97SGuenter Roeck * Registers a function with code to be called to restart the
188b63adb97SGuenter Roeck * system.
189b63adb97SGuenter Roeck *
190b63adb97SGuenter Roeck * Registered functions will be called from machine_restart as last
191b63adb97SGuenter Roeck * step of the restart sequence (if the architecture specific
192b63adb97SGuenter Roeck * machine_restart function calls do_kernel_restart - see below
193b63adb97SGuenter Roeck * for details).
194b63adb97SGuenter Roeck * Registered functions are expected to restart the system immediately.
195b63adb97SGuenter Roeck * If more than one function is registered, the restart handler priority
196b63adb97SGuenter Roeck * selects which function will be called first.
197b63adb97SGuenter Roeck *
198b63adb97SGuenter Roeck * Restart handlers are expected to be registered from non-architecture
199b63adb97SGuenter Roeck * code, typically from drivers. A typical use case would be a system
200b63adb97SGuenter Roeck * where restart functionality is provided through a watchdog. Multiple
201b63adb97SGuenter Roeck * restart handlers may exist; for example, one restart handler might
202b63adb97SGuenter Roeck * restart the entire system, while another only restarts the CPU.
203b63adb97SGuenter Roeck * In such cases, the restart handler which only restarts part of the
204b63adb97SGuenter Roeck * hardware is expected to register with low priority to ensure that
205b63adb97SGuenter Roeck * it only runs if no other means to restart the system is available.
206b63adb97SGuenter Roeck *
207b63adb97SGuenter Roeck * Currently always returns zero, as atomic_notifier_chain_register()
208b63adb97SGuenter Roeck * always returns zero.
209b63adb97SGuenter Roeck */
register_restart_handler(struct notifier_block * nb)210b63adb97SGuenter Roeck int register_restart_handler(struct notifier_block *nb)
211b63adb97SGuenter Roeck {
212b63adb97SGuenter Roeck return atomic_notifier_chain_register(&restart_handler_list, nb);
213b63adb97SGuenter Roeck }
214b63adb97SGuenter Roeck EXPORT_SYMBOL(register_restart_handler);
215b63adb97SGuenter Roeck
216b63adb97SGuenter Roeck /**
217b63adb97SGuenter Roeck * unregister_restart_handler - Unregister previously registered
218b63adb97SGuenter Roeck * restart handler
219b63adb97SGuenter Roeck * @nb: Hook to be unregistered
220b63adb97SGuenter Roeck *
221b63adb97SGuenter Roeck * Unregisters a previously registered restart handler function.
222b63adb97SGuenter Roeck *
223b63adb97SGuenter Roeck * Returns zero on success, or %-ENOENT on failure.
224b63adb97SGuenter Roeck */
unregister_restart_handler(struct notifier_block * nb)225b63adb97SGuenter Roeck int unregister_restart_handler(struct notifier_block *nb)
226b63adb97SGuenter Roeck {
227b63adb97SGuenter Roeck return atomic_notifier_chain_unregister(&restart_handler_list, nb);
228b63adb97SGuenter Roeck }
229b63adb97SGuenter Roeck EXPORT_SYMBOL(unregister_restart_handler);
230b63adb97SGuenter Roeck
231b63adb97SGuenter Roeck /**
232b63adb97SGuenter Roeck * do_kernel_restart - Execute kernel restart handler call chain
233b63adb97SGuenter Roeck *
234aafb1245SAhmad Fatoum * @cmd: pointer to buffer containing command to execute for restart
235aafb1245SAhmad Fatoum * or %NULL
236aafb1245SAhmad Fatoum *
237b63adb97SGuenter Roeck * Calls functions registered with register_restart_handler.
238b63adb97SGuenter Roeck *
239b63adb97SGuenter Roeck * Expected to be called from machine_restart as last step of the restart
240b63adb97SGuenter Roeck * sequence.
241b63adb97SGuenter Roeck *
242b63adb97SGuenter Roeck * Restarts the system immediately if a restart handler function has been
243b63adb97SGuenter Roeck * registered. Otherwise does nothing.
244b63adb97SGuenter Roeck */
do_kernel_restart(char * cmd)245b63adb97SGuenter Roeck void do_kernel_restart(char *cmd)
246b63adb97SGuenter Roeck {
247b63adb97SGuenter Roeck atomic_notifier_call_chain(&restart_handler_list, reboot_mode, cmd);
248b63adb97SGuenter Roeck }
249b63adb97SGuenter Roeck
migrate_to_reboot_cpu(void)250c97102baSVivek Goyal void migrate_to_reboot_cpu(void)
25115d94b82SRobin Holt {
25215d94b82SRobin Holt /* The boot cpu is always logical cpu 0 */
2531b3a5d02SRobin Holt int cpu = reboot_cpu;
25415d94b82SRobin Holt
25515d94b82SRobin Holt cpu_hotplug_disable();
25615d94b82SRobin Holt
25715d94b82SRobin Holt /* Make certain the cpu I'm about to reboot on is online */
25815d94b82SRobin Holt if (!cpu_online(cpu))
25915d94b82SRobin Holt cpu = cpumask_first(cpu_online_mask);
26015d94b82SRobin Holt
26115d94b82SRobin Holt /* Prevent races with other tasks migrating this task */
26215d94b82SRobin Holt current->flags |= PF_NO_SETAFFINITY;
26315d94b82SRobin Holt
26415d94b82SRobin Holt /* Make certain I only run on the appropriate processor */
26515d94b82SRobin Holt set_cpus_allowed_ptr(current, cpumask_of(cpu));
26615d94b82SRobin Holt }
26715d94b82SRobin Holt
268e7fd8b68SKai-Heng Feng /*
269e7fd8b68SKai-Heng Feng * Notifier list for kernel code which wants to be called
270e7fd8b68SKai-Heng Feng * to prepare system for restart.
271e7fd8b68SKai-Heng Feng */
272e7fd8b68SKai-Heng Feng static BLOCKING_NOTIFIER_HEAD(restart_prep_handler_list);
273e7fd8b68SKai-Heng Feng
do_kernel_restart_prepare(void)274e7fd8b68SKai-Heng Feng static void do_kernel_restart_prepare(void)
275e7fd8b68SKai-Heng Feng {
276e7fd8b68SKai-Heng Feng blocking_notifier_call_chain(&restart_prep_handler_list, 0, NULL);
277e7fd8b68SKai-Heng Feng }
278e7fd8b68SKai-Heng Feng
27915d94b82SRobin Holt /**
28015d94b82SRobin Holt * kernel_restart - reboot the system
28115d94b82SRobin Holt * @cmd: pointer to buffer containing command to execute for restart
28215d94b82SRobin Holt * or %NULL
28315d94b82SRobin Holt *
28415d94b82SRobin Holt * Shutdown everything and perform a clean reboot.
28515d94b82SRobin Holt * This is not safe to call in interrupt context.
28615d94b82SRobin Holt */
kernel_restart(char * cmd)28715d94b82SRobin Holt void kernel_restart(char *cmd)
28815d94b82SRobin Holt {
28915d94b82SRobin Holt kernel_restart_prepare(cmd);
290e7fd8b68SKai-Heng Feng do_kernel_restart_prepare();
29115d94b82SRobin Holt migrate_to_reboot_cpu();
29215d94b82SRobin Holt syscore_shutdown();
29315d94b82SRobin Holt if (!cmd)
294972ee83dSRobin Holt pr_emerg("Restarting system\n");
29515d94b82SRobin Holt else
296972ee83dSRobin Holt pr_emerg("Restarting system with command '%s'\n", cmd);
2976d3cf962SKees Cook kmsg_dump(KMSG_DUMP_SHUTDOWN);
29815d94b82SRobin Holt machine_restart(cmd);
29915d94b82SRobin Holt }
30015d94b82SRobin Holt EXPORT_SYMBOL_GPL(kernel_restart);
30115d94b82SRobin Holt
kernel_shutdown_prepare(enum system_states state)30215d94b82SRobin Holt static void kernel_shutdown_prepare(enum system_states state)
30315d94b82SRobin Holt {
30415d94b82SRobin Holt blocking_notifier_call_chain(&reboot_notifier_list,
30515d94b82SRobin Holt (state == SYSTEM_HALT) ? SYS_HALT : SYS_POWER_OFF, NULL);
30615d94b82SRobin Holt system_state = state;
30715d94b82SRobin Holt usermodehelper_disable();
30815d94b82SRobin Holt device_shutdown();
30915d94b82SRobin Holt }
31015d94b82SRobin Holt /**
31115d94b82SRobin Holt * kernel_halt - halt the system
31215d94b82SRobin Holt *
31315d94b82SRobin Holt * Shutdown everything and perform a clean system halt.
31415d94b82SRobin Holt */
kernel_halt(void)31515d94b82SRobin Holt void kernel_halt(void)
31615d94b82SRobin Holt {
31715d94b82SRobin Holt kernel_shutdown_prepare(SYSTEM_HALT);
31815d94b82SRobin Holt migrate_to_reboot_cpu();
31915d94b82SRobin Holt syscore_shutdown();
320a9a1d6adSDongmin Lee if (poweroff_fallback_to_halt)
321a9a1d6adSDongmin Lee pr_emerg("Power off not available: System halted instead\n");
322a9a1d6adSDongmin Lee else
323972ee83dSRobin Holt pr_emerg("System halted\n");
3246d3cf962SKees Cook kmsg_dump(KMSG_DUMP_SHUTDOWN);
32515d94b82SRobin Holt machine_halt();
32615d94b82SRobin Holt }
32715d94b82SRobin Holt EXPORT_SYMBOL_GPL(kernel_halt);
32815d94b82SRobin Holt
329232edc2fSDmitry Osipenko /*
330232edc2fSDmitry Osipenko * Notifier list for kernel code which wants to be called
331232edc2fSDmitry Osipenko * to prepare system for power off.
332232edc2fSDmitry Osipenko */
333232edc2fSDmitry Osipenko static BLOCKING_NOTIFIER_HEAD(power_off_prep_handler_list);
334232edc2fSDmitry Osipenko
335232edc2fSDmitry Osipenko /*
336232edc2fSDmitry Osipenko * Notifier list for kernel code which wants to be called
337232edc2fSDmitry Osipenko * to power off system.
338232edc2fSDmitry Osipenko */
339232edc2fSDmitry Osipenko static ATOMIC_NOTIFIER_HEAD(power_off_handler_list);
340232edc2fSDmitry Osipenko
sys_off_notify(struct notifier_block * nb,unsigned long mode,void * cmd)341232edc2fSDmitry Osipenko static int sys_off_notify(struct notifier_block *nb,
342232edc2fSDmitry Osipenko unsigned long mode, void *cmd)
343232edc2fSDmitry Osipenko {
344232edc2fSDmitry Osipenko struct sys_off_handler *handler;
345232edc2fSDmitry Osipenko struct sys_off_data data = {};
346232edc2fSDmitry Osipenko
347232edc2fSDmitry Osipenko handler = container_of(nb, struct sys_off_handler, nb);
348232edc2fSDmitry Osipenko data.cb_data = handler->cb_data;
349232edc2fSDmitry Osipenko data.mode = mode;
350232edc2fSDmitry Osipenko data.cmd = cmd;
351db2d6038SBenjamin Bara data.dev = handler->dev;
352232edc2fSDmitry Osipenko
353232edc2fSDmitry Osipenko return handler->sys_off_cb(&data);
354232edc2fSDmitry Osipenko }
355232edc2fSDmitry Osipenko
356587b9bfeSDmitry Osipenko static struct sys_off_handler platform_sys_off_handler;
357587b9bfeSDmitry Osipenko
alloc_sys_off_handler(int priority)358587b9bfeSDmitry Osipenko static struct sys_off_handler *alloc_sys_off_handler(int priority)
359587b9bfeSDmitry Osipenko {
360587b9bfeSDmitry Osipenko struct sys_off_handler *handler;
3612b8c612cSDmitry Osipenko gfp_t flags;
362587b9bfeSDmitry Osipenko
363587b9bfeSDmitry Osipenko /*
364587b9bfeSDmitry Osipenko * Platforms like m68k can't allocate sys_off handler dynamically
365587b9bfeSDmitry Osipenko * at the early boot time because memory allocator isn't available yet.
366587b9bfeSDmitry Osipenko */
367587b9bfeSDmitry Osipenko if (priority == SYS_OFF_PRIO_PLATFORM) {
368587b9bfeSDmitry Osipenko handler = &platform_sys_off_handler;
369587b9bfeSDmitry Osipenko if (handler->cb_data)
370587b9bfeSDmitry Osipenko return ERR_PTR(-EBUSY);
371587b9bfeSDmitry Osipenko } else {
3722b8c612cSDmitry Osipenko if (system_state > SYSTEM_RUNNING)
3732b8c612cSDmitry Osipenko flags = GFP_ATOMIC;
3742b8c612cSDmitry Osipenko else
3752b8c612cSDmitry Osipenko flags = GFP_KERNEL;
3762b8c612cSDmitry Osipenko
3772b8c612cSDmitry Osipenko handler = kzalloc(sizeof(*handler), flags);
378587b9bfeSDmitry Osipenko if (!handler)
379587b9bfeSDmitry Osipenko return ERR_PTR(-ENOMEM);
380587b9bfeSDmitry Osipenko }
381587b9bfeSDmitry Osipenko
382587b9bfeSDmitry Osipenko return handler;
383587b9bfeSDmitry Osipenko }
384587b9bfeSDmitry Osipenko
free_sys_off_handler(struct sys_off_handler * handler)385587b9bfeSDmitry Osipenko static void free_sys_off_handler(struct sys_off_handler *handler)
386587b9bfeSDmitry Osipenko {
387587b9bfeSDmitry Osipenko if (handler == &platform_sys_off_handler)
388587b9bfeSDmitry Osipenko memset(handler, 0, sizeof(*handler));
389587b9bfeSDmitry Osipenko else
390587b9bfeSDmitry Osipenko kfree(handler);
391587b9bfeSDmitry Osipenko }
392587b9bfeSDmitry Osipenko
393232edc2fSDmitry Osipenko /**
394232edc2fSDmitry Osipenko * register_sys_off_handler - Register sys-off handler
395232edc2fSDmitry Osipenko * @mode: Sys-off mode
396232edc2fSDmitry Osipenko * @priority: Handler priority
397232edc2fSDmitry Osipenko * @callback: Callback function
398232edc2fSDmitry Osipenko * @cb_data: Callback argument
399232edc2fSDmitry Osipenko *
400232edc2fSDmitry Osipenko * Registers system power-off or restart handler that will be invoked
401232edc2fSDmitry Osipenko * at the step corresponding to the given sys-off mode. Handler's callback
402232edc2fSDmitry Osipenko * should return NOTIFY_DONE to permit execution of the next handler in
403232edc2fSDmitry Osipenko * the call chain or NOTIFY_STOP to break the chain (in error case for
404232edc2fSDmitry Osipenko * example).
405232edc2fSDmitry Osipenko *
406232edc2fSDmitry Osipenko * Multiple handlers can be registered at the default priority level.
407232edc2fSDmitry Osipenko *
408232edc2fSDmitry Osipenko * Only one handler can be registered at the non-default priority level,
409232edc2fSDmitry Osipenko * otherwise ERR_PTR(-EBUSY) is returned.
410232edc2fSDmitry Osipenko *
411232edc2fSDmitry Osipenko * Returns a new instance of struct sys_off_handler on success, or
412232edc2fSDmitry Osipenko * an ERR_PTR()-encoded error code otherwise.
413232edc2fSDmitry Osipenko */
414232edc2fSDmitry Osipenko struct sys_off_handler *
register_sys_off_handler(enum sys_off_mode mode,int priority,int (* callback)(struct sys_off_data * data),void * cb_data)415232edc2fSDmitry Osipenko register_sys_off_handler(enum sys_off_mode mode,
416232edc2fSDmitry Osipenko int priority,
417232edc2fSDmitry Osipenko int (*callback)(struct sys_off_data *data),
418232edc2fSDmitry Osipenko void *cb_data)
419232edc2fSDmitry Osipenko {
420232edc2fSDmitry Osipenko struct sys_off_handler *handler;
421232edc2fSDmitry Osipenko int err;
422232edc2fSDmitry Osipenko
423587b9bfeSDmitry Osipenko handler = alloc_sys_off_handler(priority);
424587b9bfeSDmitry Osipenko if (IS_ERR(handler))
425587b9bfeSDmitry Osipenko return handler;
426232edc2fSDmitry Osipenko
427232edc2fSDmitry Osipenko switch (mode) {
428232edc2fSDmitry Osipenko case SYS_OFF_MODE_POWER_OFF_PREPARE:
429232edc2fSDmitry Osipenko handler->list = &power_off_prep_handler_list;
430232edc2fSDmitry Osipenko handler->blocking = true;
431232edc2fSDmitry Osipenko break;
432232edc2fSDmitry Osipenko
433232edc2fSDmitry Osipenko case SYS_OFF_MODE_POWER_OFF:
434232edc2fSDmitry Osipenko handler->list = &power_off_handler_list;
435232edc2fSDmitry Osipenko break;
436232edc2fSDmitry Osipenko
437e7fd8b68SKai-Heng Feng case SYS_OFF_MODE_RESTART_PREPARE:
438e7fd8b68SKai-Heng Feng handler->list = &restart_prep_handler_list;
439e7fd8b68SKai-Heng Feng handler->blocking = true;
440e7fd8b68SKai-Heng Feng break;
441e7fd8b68SKai-Heng Feng
442232edc2fSDmitry Osipenko case SYS_OFF_MODE_RESTART:
443232edc2fSDmitry Osipenko handler->list = &restart_handler_list;
444232edc2fSDmitry Osipenko break;
445232edc2fSDmitry Osipenko
446232edc2fSDmitry Osipenko default:
447587b9bfeSDmitry Osipenko free_sys_off_handler(handler);
448232edc2fSDmitry Osipenko return ERR_PTR(-EINVAL);
449232edc2fSDmitry Osipenko }
450232edc2fSDmitry Osipenko
451232edc2fSDmitry Osipenko handler->nb.notifier_call = sys_off_notify;
452232edc2fSDmitry Osipenko handler->nb.priority = priority;
453232edc2fSDmitry Osipenko handler->sys_off_cb = callback;
454232edc2fSDmitry Osipenko handler->cb_data = cb_data;
455232edc2fSDmitry Osipenko handler->mode = mode;
456232edc2fSDmitry Osipenko
457232edc2fSDmitry Osipenko if (handler->blocking) {
458232edc2fSDmitry Osipenko if (priority == SYS_OFF_PRIO_DEFAULT)
459232edc2fSDmitry Osipenko err = blocking_notifier_chain_register(handler->list,
460232edc2fSDmitry Osipenko &handler->nb);
461232edc2fSDmitry Osipenko else
462232edc2fSDmitry Osipenko err = blocking_notifier_chain_register_unique_prio(handler->list,
463232edc2fSDmitry Osipenko &handler->nb);
464232edc2fSDmitry Osipenko } else {
465232edc2fSDmitry Osipenko if (priority == SYS_OFF_PRIO_DEFAULT)
466232edc2fSDmitry Osipenko err = atomic_notifier_chain_register(handler->list,
467232edc2fSDmitry Osipenko &handler->nb);
468232edc2fSDmitry Osipenko else
469232edc2fSDmitry Osipenko err = atomic_notifier_chain_register_unique_prio(handler->list,
470232edc2fSDmitry Osipenko &handler->nb);
471232edc2fSDmitry Osipenko }
472232edc2fSDmitry Osipenko
473232edc2fSDmitry Osipenko if (err) {
474587b9bfeSDmitry Osipenko free_sys_off_handler(handler);
475232edc2fSDmitry Osipenko return ERR_PTR(err);
476232edc2fSDmitry Osipenko }
477232edc2fSDmitry Osipenko
478232edc2fSDmitry Osipenko return handler;
479232edc2fSDmitry Osipenko }
480232edc2fSDmitry Osipenko EXPORT_SYMBOL_GPL(register_sys_off_handler);
481232edc2fSDmitry Osipenko
482232edc2fSDmitry Osipenko /**
483232edc2fSDmitry Osipenko * unregister_sys_off_handler - Unregister sys-off handler
484232edc2fSDmitry Osipenko * @handler: Sys-off handler
485232edc2fSDmitry Osipenko *
486232edc2fSDmitry Osipenko * Unregisters given sys-off handler.
487232edc2fSDmitry Osipenko */
unregister_sys_off_handler(struct sys_off_handler * handler)488232edc2fSDmitry Osipenko void unregister_sys_off_handler(struct sys_off_handler *handler)
489232edc2fSDmitry Osipenko {
490232edc2fSDmitry Osipenko int err;
491232edc2fSDmitry Osipenko
4922b8c612cSDmitry Osipenko if (IS_ERR_OR_NULL(handler))
493232edc2fSDmitry Osipenko return;
494232edc2fSDmitry Osipenko
495232edc2fSDmitry Osipenko if (handler->blocking)
496232edc2fSDmitry Osipenko err = blocking_notifier_chain_unregister(handler->list,
497232edc2fSDmitry Osipenko &handler->nb);
498232edc2fSDmitry Osipenko else
499232edc2fSDmitry Osipenko err = atomic_notifier_chain_unregister(handler->list,
500232edc2fSDmitry Osipenko &handler->nb);
501232edc2fSDmitry Osipenko
502232edc2fSDmitry Osipenko /* sanity check, shall never happen */
503232edc2fSDmitry Osipenko WARN_ON(err);
504232edc2fSDmitry Osipenko
505587b9bfeSDmitry Osipenko free_sys_off_handler(handler);
506232edc2fSDmitry Osipenko }
507232edc2fSDmitry Osipenko EXPORT_SYMBOL_GPL(unregister_sys_off_handler);
508232edc2fSDmitry Osipenko
devm_unregister_sys_off_handler(void * data)509232edc2fSDmitry Osipenko static void devm_unregister_sys_off_handler(void *data)
510232edc2fSDmitry Osipenko {
511232edc2fSDmitry Osipenko struct sys_off_handler *handler = data;
512232edc2fSDmitry Osipenko
513232edc2fSDmitry Osipenko unregister_sys_off_handler(handler);
514232edc2fSDmitry Osipenko }
515232edc2fSDmitry Osipenko
516232edc2fSDmitry Osipenko /**
517232edc2fSDmitry Osipenko * devm_register_sys_off_handler - Register sys-off handler
518232edc2fSDmitry Osipenko * @dev: Device that registers handler
519232edc2fSDmitry Osipenko * @mode: Sys-off mode
520232edc2fSDmitry Osipenko * @priority: Handler priority
521232edc2fSDmitry Osipenko * @callback: Callback function
522232edc2fSDmitry Osipenko * @cb_data: Callback argument
523232edc2fSDmitry Osipenko *
524232edc2fSDmitry Osipenko * Registers resource-managed sys-off handler.
525232edc2fSDmitry Osipenko *
526232edc2fSDmitry Osipenko * Returns zero on success, or error code on failure.
527232edc2fSDmitry Osipenko */
devm_register_sys_off_handler(struct device * dev,enum sys_off_mode mode,int priority,int (* callback)(struct sys_off_data * data),void * cb_data)528232edc2fSDmitry Osipenko int devm_register_sys_off_handler(struct device *dev,
529232edc2fSDmitry Osipenko enum sys_off_mode mode,
530232edc2fSDmitry Osipenko int priority,
531232edc2fSDmitry Osipenko int (*callback)(struct sys_off_data *data),
532232edc2fSDmitry Osipenko void *cb_data)
533232edc2fSDmitry Osipenko {
534232edc2fSDmitry Osipenko struct sys_off_handler *handler;
535232edc2fSDmitry Osipenko
536232edc2fSDmitry Osipenko handler = register_sys_off_handler(mode, priority, callback, cb_data);
537232edc2fSDmitry Osipenko if (IS_ERR(handler))
538232edc2fSDmitry Osipenko return PTR_ERR(handler);
539db2d6038SBenjamin Bara handler->dev = dev;
540232edc2fSDmitry Osipenko
541232edc2fSDmitry Osipenko return devm_add_action_or_reset(dev, devm_unregister_sys_off_handler,
542232edc2fSDmitry Osipenko handler);
543232edc2fSDmitry Osipenko }
544232edc2fSDmitry Osipenko EXPORT_SYMBOL_GPL(devm_register_sys_off_handler);
545232edc2fSDmitry Osipenko
546d2c54153SDmitry Osipenko /**
547d2c54153SDmitry Osipenko * devm_register_power_off_handler - Register power-off handler
548d2c54153SDmitry Osipenko * @dev: Device that registers callback
549d2c54153SDmitry Osipenko * @callback: Callback function
550d2c54153SDmitry Osipenko * @cb_data: Callback's argument
551d2c54153SDmitry Osipenko *
552d2c54153SDmitry Osipenko * Registers resource-managed sys-off handler with a default priority
553d2c54153SDmitry Osipenko * and using power-off mode.
554d2c54153SDmitry Osipenko *
555d2c54153SDmitry Osipenko * Returns zero on success, or error code on failure.
556d2c54153SDmitry Osipenko */
devm_register_power_off_handler(struct device * dev,int (* callback)(struct sys_off_data * data),void * cb_data)557d2c54153SDmitry Osipenko int devm_register_power_off_handler(struct device *dev,
558d2c54153SDmitry Osipenko int (*callback)(struct sys_off_data *data),
559d2c54153SDmitry Osipenko void *cb_data)
560d2c54153SDmitry Osipenko {
561d2c54153SDmitry Osipenko return devm_register_sys_off_handler(dev,
562d2c54153SDmitry Osipenko SYS_OFF_MODE_POWER_OFF,
563d2c54153SDmitry Osipenko SYS_OFF_PRIO_DEFAULT,
564d2c54153SDmitry Osipenko callback, cb_data);
565d2c54153SDmitry Osipenko }
566d2c54153SDmitry Osipenko EXPORT_SYMBOL_GPL(devm_register_power_off_handler);
567d2c54153SDmitry Osipenko
5686779db97SDmitry Osipenko /**
5696779db97SDmitry Osipenko * devm_register_restart_handler - Register restart handler
5706779db97SDmitry Osipenko * @dev: Device that registers callback
5716779db97SDmitry Osipenko * @callback: Callback function
5726779db97SDmitry Osipenko * @cb_data: Callback's argument
5736779db97SDmitry Osipenko *
5746779db97SDmitry Osipenko * Registers resource-managed sys-off handler with a default priority
5756779db97SDmitry Osipenko * and using restart mode.
5766779db97SDmitry Osipenko *
5776779db97SDmitry Osipenko * Returns zero on success, or error code on failure.
5786779db97SDmitry Osipenko */
devm_register_restart_handler(struct device * dev,int (* callback)(struct sys_off_data * data),void * cb_data)5796779db97SDmitry Osipenko int devm_register_restart_handler(struct device *dev,
5806779db97SDmitry Osipenko int (*callback)(struct sys_off_data *data),
5816779db97SDmitry Osipenko void *cb_data)
5826779db97SDmitry Osipenko {
5836779db97SDmitry Osipenko return devm_register_sys_off_handler(dev,
5846779db97SDmitry Osipenko SYS_OFF_MODE_RESTART,
5856779db97SDmitry Osipenko SYS_OFF_PRIO_DEFAULT,
5866779db97SDmitry Osipenko callback, cb_data);
5876779db97SDmitry Osipenko }
5886779db97SDmitry Osipenko EXPORT_SYMBOL_GPL(devm_register_restart_handler);
5896779db97SDmitry Osipenko
590fb61375eSDmitry Osipenko static struct sys_off_handler *platform_power_off_handler;
591fb61375eSDmitry Osipenko
platform_power_off_notify(struct sys_off_data * data)592fb61375eSDmitry Osipenko static int platform_power_off_notify(struct sys_off_data *data)
593fb61375eSDmitry Osipenko {
594fb61375eSDmitry Osipenko void (*platform_power_power_off_cb)(void) = data->cb_data;
595fb61375eSDmitry Osipenko
596fb61375eSDmitry Osipenko platform_power_power_off_cb();
597fb61375eSDmitry Osipenko
598fb61375eSDmitry Osipenko return NOTIFY_DONE;
599fb61375eSDmitry Osipenko }
600fb61375eSDmitry Osipenko
601fb61375eSDmitry Osipenko /**
602fb61375eSDmitry Osipenko * register_platform_power_off - Register platform-level power-off callback
603fb61375eSDmitry Osipenko * @power_off: Power-off callback
604fb61375eSDmitry Osipenko *
605fb61375eSDmitry Osipenko * Registers power-off callback that will be called as last step
606fb61375eSDmitry Osipenko * of the power-off sequence. This callback is expected to be invoked
607fb61375eSDmitry Osipenko * for the last resort. Only one platform power-off callback is allowed
608fb61375eSDmitry Osipenko * to be registered at a time.
609fb61375eSDmitry Osipenko *
610fb61375eSDmitry Osipenko * Returns zero on success, or error code on failure.
611fb61375eSDmitry Osipenko */
register_platform_power_off(void (* power_off)(void))612fb61375eSDmitry Osipenko int register_platform_power_off(void (*power_off)(void))
613fb61375eSDmitry Osipenko {
614fb61375eSDmitry Osipenko struct sys_off_handler *handler;
615fb61375eSDmitry Osipenko
616fb61375eSDmitry Osipenko handler = register_sys_off_handler(SYS_OFF_MODE_POWER_OFF,
617fb61375eSDmitry Osipenko SYS_OFF_PRIO_PLATFORM,
618fb61375eSDmitry Osipenko platform_power_off_notify,
619fb61375eSDmitry Osipenko power_off);
620fb61375eSDmitry Osipenko if (IS_ERR(handler))
621fb61375eSDmitry Osipenko return PTR_ERR(handler);
622fb61375eSDmitry Osipenko
623fb61375eSDmitry Osipenko platform_power_off_handler = handler;
624fb61375eSDmitry Osipenko
625fb61375eSDmitry Osipenko return 0;
626fb61375eSDmitry Osipenko }
627fb61375eSDmitry Osipenko EXPORT_SYMBOL_GPL(register_platform_power_off);
628fb61375eSDmitry Osipenko
629fb61375eSDmitry Osipenko /**
630fb61375eSDmitry Osipenko * unregister_platform_power_off - Unregister platform-level power-off callback
631fb61375eSDmitry Osipenko * @power_off: Power-off callback
632fb61375eSDmitry Osipenko *
633fb61375eSDmitry Osipenko * Unregisters previously registered platform power-off callback.
634fb61375eSDmitry Osipenko */
unregister_platform_power_off(void (* power_off)(void))635fb61375eSDmitry Osipenko void unregister_platform_power_off(void (*power_off)(void))
636fb61375eSDmitry Osipenko {
637fb61375eSDmitry Osipenko if (platform_power_off_handler &&
638fb61375eSDmitry Osipenko platform_power_off_handler->cb_data == power_off) {
639fb61375eSDmitry Osipenko unregister_sys_off_handler(platform_power_off_handler);
640fb61375eSDmitry Osipenko platform_power_off_handler = NULL;
641fb61375eSDmitry Osipenko }
642fb61375eSDmitry Osipenko }
643fb61375eSDmitry Osipenko EXPORT_SYMBOL_GPL(unregister_platform_power_off);
644fb61375eSDmitry Osipenko
legacy_pm_power_off(struct sys_off_data * data)6457b9a3de9SDmitry Osipenko static int legacy_pm_power_off(struct sys_off_data *data)
6467b9a3de9SDmitry Osipenko {
6477b9a3de9SDmitry Osipenko if (pm_power_off)
6487b9a3de9SDmitry Osipenko pm_power_off();
6497b9a3de9SDmitry Osipenko
6507b9a3de9SDmitry Osipenko return NOTIFY_DONE;
6517b9a3de9SDmitry Osipenko }
6527b9a3de9SDmitry Osipenko
do_kernel_power_off_prepare(void)6537b9a3de9SDmitry Osipenko static void do_kernel_power_off_prepare(void)
6547b9a3de9SDmitry Osipenko {
6557b9a3de9SDmitry Osipenko blocking_notifier_call_chain(&power_off_prep_handler_list, 0, NULL);
6567b9a3de9SDmitry Osipenko }
6577b9a3de9SDmitry Osipenko
65815d94b82SRobin Holt /**
6592b6aa733SDmitry Osipenko * do_kernel_power_off - Execute kernel power-off handler call chain
6602b6aa733SDmitry Osipenko *
6612b6aa733SDmitry Osipenko * Expected to be called as last step of the power-off sequence.
6622b6aa733SDmitry Osipenko *
6632b6aa733SDmitry Osipenko * Powers off the system immediately if a power-off handler function has
6642b6aa733SDmitry Osipenko * been registered. Otherwise does nothing.
6652b6aa733SDmitry Osipenko */
do_kernel_power_off(void)6662b6aa733SDmitry Osipenko void do_kernel_power_off(void)
6672b6aa733SDmitry Osipenko {
6682b8c612cSDmitry Osipenko struct sys_off_handler *sys_off = NULL;
6692b8c612cSDmitry Osipenko
6702b8c612cSDmitry Osipenko /*
6712b8c612cSDmitry Osipenko * Register sys-off handlers for legacy PM callback. This allows
6722b8c612cSDmitry Osipenko * legacy PM callbacks temporary co-exist with the new sys-off API.
6732b8c612cSDmitry Osipenko *
6742b8c612cSDmitry Osipenko * TODO: Remove legacy handlers once all legacy PM users will be
6752b8c612cSDmitry Osipenko * switched to the sys-off based APIs.
6762b8c612cSDmitry Osipenko */
6772b8c612cSDmitry Osipenko if (pm_power_off)
6782b8c612cSDmitry Osipenko sys_off = register_sys_off_handler(SYS_OFF_MODE_POWER_OFF,
6792b8c612cSDmitry Osipenko SYS_OFF_PRIO_DEFAULT,
6802b8c612cSDmitry Osipenko legacy_pm_power_off, NULL);
6812b8c612cSDmitry Osipenko
6822b6aa733SDmitry Osipenko atomic_notifier_call_chain(&power_off_handler_list, 0, NULL);
6832b8c612cSDmitry Osipenko
6842b8c612cSDmitry Osipenko unregister_sys_off_handler(sys_off);
6852b6aa733SDmitry Osipenko }
6862b6aa733SDmitry Osipenko
6872b6aa733SDmitry Osipenko /**
6880e2110d2SDmitry Osipenko * kernel_can_power_off - check whether system can be powered off
6890e2110d2SDmitry Osipenko *
6900e2110d2SDmitry Osipenko * Returns true if power-off handler is registered and system can be
6910e2110d2SDmitry Osipenko * powered off, false otherwise.
6920e2110d2SDmitry Osipenko */
kernel_can_power_off(void)6930e2110d2SDmitry Osipenko bool kernel_can_power_off(void)
6940e2110d2SDmitry Osipenko {
6952b8c612cSDmitry Osipenko return !atomic_notifier_call_chain_is_empty(&power_off_handler_list) ||
6962b8c612cSDmitry Osipenko pm_power_off;
6970e2110d2SDmitry Osipenko }
6980e2110d2SDmitry Osipenko EXPORT_SYMBOL_GPL(kernel_can_power_off);
6990e2110d2SDmitry Osipenko
70015d94b82SRobin Holt /**
70115d94b82SRobin Holt * kernel_power_off - power_off the system
70215d94b82SRobin Holt *
70315d94b82SRobin Holt * Shutdown everything and perform a clean system power_off.
70415d94b82SRobin Holt */
kernel_power_off(void)70515d94b82SRobin Holt void kernel_power_off(void)
70615d94b82SRobin Holt {
70715d94b82SRobin Holt kernel_shutdown_prepare(SYSTEM_POWER_OFF);
7087b9a3de9SDmitry Osipenko do_kernel_power_off_prepare();
70915d94b82SRobin Holt migrate_to_reboot_cpu();
71015d94b82SRobin Holt syscore_shutdown();
711972ee83dSRobin Holt pr_emerg("Power down\n");
7126d3cf962SKees Cook pr_flush(1000, true);
71315d94b82SRobin Holt kmsg_dump(KMSG_DUMP_SHUTDOWN);
71415d94b82SRobin Holt machine_power_off();
71515d94b82SRobin Holt }
71615d94b82SRobin Holt EXPORT_SYMBOL_GPL(kernel_power_off);
71755f2503cSPingfan Liu
71815d94b82SRobin Holt DEFINE_MUTEX(system_transition_mutex);
71915d94b82SRobin Holt
72015d94b82SRobin Holt /*
72115d94b82SRobin Holt * Reboot system call: for obvious reasons only root may call it,
72215d94b82SRobin Holt * and even root needs to set up some magic numbers in the registers
72315d94b82SRobin Holt * so that some mistake won't make this reboot the whole machine.
72415d94b82SRobin Holt * You can also set the meaning of the ctrl-alt-del-key here.
72515d94b82SRobin Holt *
72615d94b82SRobin Holt * reboot doesn't sync: do that yourself before calling this.
72715d94b82SRobin Holt */
SYSCALL_DEFINE4(reboot,int,magic1,int,magic2,unsigned int,cmd,void __user *,arg)72815d94b82SRobin Holt SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
72915d94b82SRobin Holt void __user *, arg)
73015d94b82SRobin Holt {
73115d94b82SRobin Holt struct pid_namespace *pid_ns = task_active_pid_ns(current);
73215d94b82SRobin Holt char buffer[256];
73315d94b82SRobin Holt int ret = 0;
73415d94b82SRobin Holt
73515d94b82SRobin Holt /* We only trust the superuser with rebooting the system. */
73615d94b82SRobin Holt if (!ns_capable(pid_ns->user_ns, CAP_SYS_BOOT))
73715d94b82SRobin Holt return -EPERM;
73815d94b82SRobin Holt
73915d94b82SRobin Holt /* For safety, we require "magic" arguments. */
74015d94b82SRobin Holt if (magic1 != LINUX_REBOOT_MAGIC1 ||
74115d94b82SRobin Holt (magic2 != LINUX_REBOOT_MAGIC2 &&
74215d94b82SRobin Holt magic2 != LINUX_REBOOT_MAGIC2A &&
74315d94b82SRobin Holt magic2 != LINUX_REBOOT_MAGIC2B &&
74415d94b82SRobin Holt magic2 != LINUX_REBOOT_MAGIC2C))
74515d94b82SRobin Holt return -EINVAL;
74615d94b82SRobin Holt
74715d94b82SRobin Holt /*
74815d94b82SRobin Holt * If pid namespaces are enabled and the current task is in a child
74915d94b82SRobin Holt * pid_namespace, the command is handled by reboot_pid_ns() which will
75015d94b82SRobin Holt * call do_exit().
75115d94b82SRobin Holt */
75215d94b82SRobin Holt ret = reboot_pid_ns(pid_ns, cmd);
75315d94b82SRobin Holt if (ret)
75415d94b82SRobin Holt return ret;
75515d94b82SRobin Holt
75615d94b82SRobin Holt /* Instead of trying to make the power_off code look like
75715d94b82SRobin Holt * halt when pm_power_off is not set do it the easy way.
758a9a1d6adSDongmin Lee */
759a9a1d6adSDongmin Lee if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !kernel_can_power_off()) {
76015d94b82SRobin Holt poweroff_fallback_to_halt = true;
761a9a1d6adSDongmin Lee cmd = LINUX_REBOOT_CMD_HALT;
76215d94b82SRobin Holt }
76355f2503cSPingfan Liu
76415d94b82SRobin Holt mutex_lock(&system_transition_mutex);
76515d94b82SRobin Holt switch (cmd) {
76615d94b82SRobin Holt case LINUX_REBOOT_CMD_RESTART:
76715d94b82SRobin Holt kernel_restart(NULL);
76815d94b82SRobin Holt break;
76915d94b82SRobin Holt
77015d94b82SRobin Holt case LINUX_REBOOT_CMD_CAD_ON:
77115d94b82SRobin Holt C_A_D = 1;
77215d94b82SRobin Holt break;
77315d94b82SRobin Holt
77415d94b82SRobin Holt case LINUX_REBOOT_CMD_CAD_OFF:
77515d94b82SRobin Holt C_A_D = 0;
77615d94b82SRobin Holt break;
77715d94b82SRobin Holt
77815d94b82SRobin Holt case LINUX_REBOOT_CMD_HALT:
77915d94b82SRobin Holt kernel_halt();
78015d94b82SRobin Holt do_exit(0);
78115d94b82SRobin Holt
78215d94b82SRobin Holt case LINUX_REBOOT_CMD_POWER_OFF:
78315d94b82SRobin Holt kernel_power_off();
78415d94b82SRobin Holt do_exit(0);
78515d94b82SRobin Holt break;
78615d94b82SRobin Holt
787972ee83dSRobin Holt case LINUX_REBOOT_CMD_RESTART2:
788972ee83dSRobin Holt ret = strncpy_from_user(&buffer[0], arg, sizeof(buffer) - 1);
78915d94b82SRobin Holt if (ret < 0) {
79015d94b82SRobin Holt ret = -EFAULT;
79115d94b82SRobin Holt break;
79215d94b82SRobin Holt }
79315d94b82SRobin Holt buffer[sizeof(buffer) - 1] = '\0';
79415d94b82SRobin Holt
79515d94b82SRobin Holt kernel_restart(buffer);
79615d94b82SRobin Holt break;
7972965faa5SDave Young
79815d94b82SRobin Holt #ifdef CONFIG_KEXEC_CORE
79915d94b82SRobin Holt case LINUX_REBOOT_CMD_KEXEC:
80015d94b82SRobin Holt ret = kernel_kexec();
80115d94b82SRobin Holt break;
80215d94b82SRobin Holt #endif
80315d94b82SRobin Holt
80415d94b82SRobin Holt #ifdef CONFIG_HIBERNATION
80515d94b82SRobin Holt case LINUX_REBOOT_CMD_SW_SUSPEND:
80615d94b82SRobin Holt ret = hibernate();
80715d94b82SRobin Holt break;
80815d94b82SRobin Holt #endif
80915d94b82SRobin Holt
81015d94b82SRobin Holt default:
81115d94b82SRobin Holt ret = -EINVAL;
81215d94b82SRobin Holt break;
81355f2503cSPingfan Liu }
81415d94b82SRobin Holt mutex_unlock(&system_transition_mutex);
81515d94b82SRobin Holt return ret;
81615d94b82SRobin Holt }
81715d94b82SRobin Holt
deferred_cad(struct work_struct * dummy)81815d94b82SRobin Holt static void deferred_cad(struct work_struct *dummy)
81915d94b82SRobin Holt {
82015d94b82SRobin Holt kernel_restart(NULL);
82115d94b82SRobin Holt }
82215d94b82SRobin Holt
82315d94b82SRobin Holt /*
82415d94b82SRobin Holt * This function gets called by ctrl-alt-del - ie the keyboard interrupt.
82515d94b82SRobin Holt * As it's called within an interrupt, it may NOT sync: the only choice
82615d94b82SRobin Holt * is whether to reboot at once, or just ignore the ctrl-alt-del.
82715d94b82SRobin Holt */
ctrl_alt_del(void)82815d94b82SRobin Holt void ctrl_alt_del(void)
82915d94b82SRobin Holt {
83015d94b82SRobin Holt static DECLARE_WORK(cad_work, deferred_cad);
83115d94b82SRobin Holt
83215d94b82SRobin Holt if (C_A_D)
83315d94b82SRobin Holt schedule_work(&cad_work);
83415d94b82SRobin Holt else
83515d94b82SRobin Holt kill_cad_pid(SIGINT, 1);
83615d94b82SRobin Holt }
83706d17766Stangmeng
83806d17766Stangmeng #define POWEROFF_CMD_PATH_LEN 256
8397a54f46bSJoel Stanley static char poweroff_cmd[POWEROFF_CMD_PATH_LEN] = "/sbin/poweroff";
84015d94b82SRobin Holt static const char reboot_cmd[] = "/sbin/reboot";
8417a54f46bSJoel Stanley
run_cmd(const char * cmd)84215d94b82SRobin Holt static int run_cmd(const char *cmd)
84315d94b82SRobin Holt {
84415d94b82SRobin Holt char **argv;
84515d94b82SRobin Holt static char *envp[] = {
84615d94b82SRobin Holt "HOME=/",
84715d94b82SRobin Holt "PATH=/sbin:/bin:/usr/sbin:/usr/bin",
84815d94b82SRobin Holt NULL
84915d94b82SRobin Holt };
8507a54f46bSJoel Stanley int ret;
85115d94b82SRobin Holt argv = argv_split(GFP_KERNEL, cmd, NULL);
85215d94b82SRobin Holt if (argv) {
85315d94b82SRobin Holt ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
85415d94b82SRobin Holt argv_free(argv);
85515d94b82SRobin Holt } else {
85615d94b82SRobin Holt ret = -ENOMEM;
85715d94b82SRobin Holt }
8587a54f46bSJoel Stanley
8597a54f46bSJoel Stanley return ret;
8607a54f46bSJoel Stanley }
8617a54f46bSJoel Stanley
__orderly_reboot(void)8627a54f46bSJoel Stanley static int __orderly_reboot(void)
8637a54f46bSJoel Stanley {
8647a54f46bSJoel Stanley int ret;
8657a54f46bSJoel Stanley
8667a54f46bSJoel Stanley ret = run_cmd(reboot_cmd);
8677a54f46bSJoel Stanley
8687a54f46bSJoel Stanley if (ret) {
8697a54f46bSJoel Stanley pr_warn("Failed to start orderly reboot: forcing the issue\n");
8707a54f46bSJoel Stanley emergency_sync();
8717a54f46bSJoel Stanley kernel_restart(NULL);
8727a54f46bSJoel Stanley }
8737a54f46bSJoel Stanley
8747a54f46bSJoel Stanley return ret;
8757a54f46bSJoel Stanley }
8767a54f46bSJoel Stanley
__orderly_poweroff(bool force)8777a54f46bSJoel Stanley static int __orderly_poweroff(bool force)
8787a54f46bSJoel Stanley {
8797a54f46bSJoel Stanley int ret;
8807a54f46bSJoel Stanley
8817a54f46bSJoel Stanley ret = run_cmd(poweroff_cmd);
88215d94b82SRobin Holt
883972ee83dSRobin Holt if (ret && force) {
8847a54f46bSJoel Stanley pr_warn("Failed to start orderly shutdown: forcing the issue\n");
88515d94b82SRobin Holt
88615d94b82SRobin Holt /*
88715d94b82SRobin Holt * I guess this should try to kick off some daemon to sync and
88815d94b82SRobin Holt * poweroff asap. Or not even bother syncing if we're doing an
88915d94b82SRobin Holt * emergency shutdown?
89015d94b82SRobin Holt */
89115d94b82SRobin Holt emergency_sync();
89215d94b82SRobin Holt kernel_power_off();
89315d94b82SRobin Holt }
89415d94b82SRobin Holt
89515d94b82SRobin Holt return ret;
89615d94b82SRobin Holt }
89715d94b82SRobin Holt
89815d94b82SRobin Holt static bool poweroff_force;
89915d94b82SRobin Holt
poweroff_work_func(struct work_struct * work)90015d94b82SRobin Holt static void poweroff_work_func(struct work_struct *work)
90115d94b82SRobin Holt {
90215d94b82SRobin Holt __orderly_poweroff(poweroff_force);
90315d94b82SRobin Holt }
90415d94b82SRobin Holt
90515d94b82SRobin Holt static DECLARE_WORK(poweroff_work, poweroff_work_func);
90615d94b82SRobin Holt
90715d94b82SRobin Holt /**
90815d94b82SRobin Holt * orderly_poweroff - Trigger an orderly system poweroff
90915d94b82SRobin Holt * @force: force poweroff if command execution fails
91015d94b82SRobin Holt *
91115d94b82SRobin Holt * This may be called from any context to trigger a system shutdown.
91215d94b82SRobin Holt * If the orderly shutdown fails, it will force an immediate shutdown.
9137a54f46bSJoel Stanley */
orderly_poweroff(bool force)91415d94b82SRobin Holt void orderly_poweroff(bool force)
91515d94b82SRobin Holt {
91615d94b82SRobin Holt if (force) /* do not override the pending "true" */
91715d94b82SRobin Holt poweroff_force = true;
91815d94b82SRobin Holt schedule_work(&poweroff_work);
91915d94b82SRobin Holt }
9201b3a5d02SRobin Holt EXPORT_SYMBOL_GPL(orderly_poweroff);
9217a54f46bSJoel Stanley
reboot_work_func(struct work_struct * work)9227a54f46bSJoel Stanley static void reboot_work_func(struct work_struct *work)
9237a54f46bSJoel Stanley {
9247a54f46bSJoel Stanley __orderly_reboot();
9257a54f46bSJoel Stanley }
9267a54f46bSJoel Stanley
9277a54f46bSJoel Stanley static DECLARE_WORK(reboot_work, reboot_work_func);
9287a54f46bSJoel Stanley
9297a54f46bSJoel Stanley /**
9307a54f46bSJoel Stanley * orderly_reboot - Trigger an orderly system reboot
9317a54f46bSJoel Stanley *
9327a54f46bSJoel Stanley * This may be called from any context to trigger a system reboot.
9337a54f46bSJoel Stanley * If the orderly reboot fails, it will force an immediate reboot.
9347a54f46bSJoel Stanley */
orderly_reboot(void)9357a54f46bSJoel Stanley void orderly_reboot(void)
9367a54f46bSJoel Stanley {
9377a54f46bSJoel Stanley schedule_work(&reboot_work);
9387a54f46bSJoel Stanley }
9397a54f46bSJoel Stanley EXPORT_SYMBOL_GPL(orderly_reboot);
940bbf0ec4fSAhmad Fatoum
hw_protection_action_str(enum hw_protection_action action)941bbf0ec4fSAhmad Fatoum static const char *hw_protection_action_str(enum hw_protection_action action)
942bbf0ec4fSAhmad Fatoum {
943bbf0ec4fSAhmad Fatoum switch (action) {
944bbf0ec4fSAhmad Fatoum case HWPROT_ACT_SHUTDOWN:
945bbf0ec4fSAhmad Fatoum return "shutdown";
946bbf0ec4fSAhmad Fatoum case HWPROT_ACT_REBOOT:
947bbf0ec4fSAhmad Fatoum return "reboot";
948bbf0ec4fSAhmad Fatoum default:
949bbf0ec4fSAhmad Fatoum return "undefined";
950bbf0ec4fSAhmad Fatoum }
951bbf0ec4fSAhmad Fatoum }
952bbf0ec4fSAhmad Fatoum
953bbf0ec4fSAhmad Fatoum static enum hw_protection_action hw_failure_emergency_action;
954dfa19b11SMatti Vaittinen
955bbf0ec4fSAhmad Fatoum /**
956bbf0ec4fSAhmad Fatoum * hw_failure_emergency_action_func - emergency action work after a known delay
957dfa19b11SMatti Vaittinen * @work: work_struct associated with the emergency action function
958dfa19b11SMatti Vaittinen *
959bbf0ec4fSAhmad Fatoum * This function is called in very critical situations to force
960dfa19b11SMatti Vaittinen * a kernel poweroff or reboot after a configurable timeout value.
961bbf0ec4fSAhmad Fatoum */
hw_failure_emergency_action_func(struct work_struct * work)962dfa19b11SMatti Vaittinen static void hw_failure_emergency_action_func(struct work_struct *work)
963bbf0ec4fSAhmad Fatoum {
964bbf0ec4fSAhmad Fatoum const char *action_str = hw_protection_action_str(hw_failure_emergency_action);
965bbf0ec4fSAhmad Fatoum
966bbf0ec4fSAhmad Fatoum pr_emerg("Hardware protection timed-out. Trying forced %s\n",
967bbf0ec4fSAhmad Fatoum action_str);
968dfa19b11SMatti Vaittinen
969bbf0ec4fSAhmad Fatoum /*
970bbf0ec4fSAhmad Fatoum * We have reached here after the emergency action waiting period has
971bbf0ec4fSAhmad Fatoum * expired. This means orderly_poweroff/reboot has not been able to
972dfa19b11SMatti Vaittinen * shut off the system for some reason.
973bbf0ec4fSAhmad Fatoum *
974dfa19b11SMatti Vaittinen * Try to shut off the system immediately if possible
975bbf0ec4fSAhmad Fatoum */
976bbf0ec4fSAhmad Fatoum
977bbf0ec4fSAhmad Fatoum if (hw_failure_emergency_action == HWPROT_ACT_REBOOT)
978bbf0ec4fSAhmad Fatoum kernel_restart(NULL);
979dfa19b11SMatti Vaittinen else
980dfa19b11SMatti Vaittinen kernel_power_off();
981dfa19b11SMatti Vaittinen
982dfa19b11SMatti Vaittinen /*
983dfa19b11SMatti Vaittinen * Worst of the worst case trigger emergency restart
984bbf0ec4fSAhmad Fatoum */
985bbf0ec4fSAhmad Fatoum pr_emerg("Hardware protection %s failed. Trying emergency restart\n",
986dfa19b11SMatti Vaittinen action_str);
987dfa19b11SMatti Vaittinen emergency_restart();
988dfa19b11SMatti Vaittinen }
989bbf0ec4fSAhmad Fatoum
990bbf0ec4fSAhmad Fatoum static DECLARE_DELAYED_WORK(hw_failure_emergency_action_work,
991dfa19b11SMatti Vaittinen hw_failure_emergency_action_func);
992dfa19b11SMatti Vaittinen
993bbf0ec4fSAhmad Fatoum /**
994bbf0ec4fSAhmad Fatoum * hw_failure_emergency_schedule - Schedule an emergency system shutdown or reboot
995bbf0ec4fSAhmad Fatoum *
996bbf0ec4fSAhmad Fatoum * @action: The hardware protection action to be taken
997dfa19b11SMatti Vaittinen * @action_delay_ms: Time in milliseconds to elapse before triggering action
998dfa19b11SMatti Vaittinen *
999bbf0ec4fSAhmad Fatoum * This may be called from any critical situation to trigger a system shutdown
1000bbf0ec4fSAhmad Fatoum * or reboot after a given period of time.
1001dfa19b11SMatti Vaittinen * If time is negative this is not scheduled.
1002bbf0ec4fSAhmad Fatoum */
hw_failure_emergency_schedule(enum hw_protection_action action,int action_delay_ms)1003bbf0ec4fSAhmad Fatoum static void hw_failure_emergency_schedule(enum hw_protection_action action,
1004dfa19b11SMatti Vaittinen int action_delay_ms)
1005bbf0ec4fSAhmad Fatoum {
1006dfa19b11SMatti Vaittinen if (action_delay_ms <= 0)
1007bbf0ec4fSAhmad Fatoum return;
1008bbf0ec4fSAhmad Fatoum hw_failure_emergency_action = action;
1009bbf0ec4fSAhmad Fatoum schedule_delayed_work(&hw_failure_emergency_action_work,
1010dfa19b11SMatti Vaittinen msecs_to_jiffies(action_delay_ms));
1011dfa19b11SMatti Vaittinen }
1012dfa19b11SMatti Vaittinen
101381cab0f9SAhmad Fatoum /**
1014dfa19b11SMatti Vaittinen * __hw_protection_trigger - Trigger an emergency system shutdown or reboot
101579fa723bSFabio Estevam *
101679fa723bSFabio Estevam * @reason: Reason of emergency shutdown or reboot to be printed.
101779fa723bSFabio Estevam * @ms_until_forced: Time to wait for orderly shutdown or reboot before
101879fa723bSFabio Estevam * triggering it. Negative value disables the forced
1019318f05a0SAhmad Fatoum * shutdown or reboot.
1020dfa19b11SMatti Vaittinen * @action: The hardware protection action to be taken.
102179fa723bSFabio Estevam *
102279fa723bSFabio Estevam * Initiate an emergency system shutdown or reboot in order to protect
102379fa723bSFabio Estevam * hardware from further damage. Usage examples include a thermal protection.
102479fa723bSFabio Estevam * NOTE: The request is ignored if protection shutdown or reboot is already
102579fa723bSFabio Estevam * pending even if the previous request has given a large timeout for forced
1026dfa19b11SMatti Vaittinen * shutdown/reboot.
102781cab0f9SAhmad Fatoum */
__hw_protection_trigger(const char * reason,int ms_until_forced,enum hw_protection_action action)1028318f05a0SAhmad Fatoum void __hw_protection_trigger(const char *reason, int ms_until_forced,
1029dfa19b11SMatti Vaittinen enum hw_protection_action action)
1030dfa19b11SMatti Vaittinen {
1031dfa19b11SMatti Vaittinen static atomic_t allow_proceed = ATOMIC_INIT(1);
1032*e016173fSAhmad Fatoum
1033*e016173fSAhmad Fatoum if (action == HWPROT_ACT_DEFAULT)
1034*e016173fSAhmad Fatoum action = hw_protection_action;
103596201a8aSAhmad Fatoum
103696201a8aSAhmad Fatoum pr_emerg("HARDWARE PROTECTION %s (%s)\n",
1037dfa19b11SMatti Vaittinen hw_protection_action_str(action), reason);
1038dfa19b11SMatti Vaittinen
1039dfa19b11SMatti Vaittinen /* Shutdown should be initiated only once. */
104007a22b61SPetr Mladek if (!atomic_dec_and_test(&allow_proceed))
1041dfa19b11SMatti Vaittinen return;
1042dfa19b11SMatti Vaittinen
1043dfa19b11SMatti Vaittinen /*
1044dfa19b11SMatti Vaittinen * Queue a backup emergency shutdown in the event of
1045dfa19b11SMatti Vaittinen * orderly_poweroff failure
1046bbf0ec4fSAhmad Fatoum */
1047318f05a0SAhmad Fatoum hw_failure_emergency_schedule(action, ms_until_forced);
104879fa723bSFabio Estevam if (action == HWPROT_ACT_REBOOT)
1049318f05a0SAhmad Fatoum orderly_reboot();
1050318f05a0SAhmad Fatoum else
1051dfa19b11SMatti Vaittinen orderly_poweroff(true);
105281cab0f9SAhmad Fatoum }
1053dfa19b11SMatti Vaittinen EXPORT_SYMBOL_GPL(__hw_protection_trigger);
1054*e016173fSAhmad Fatoum
hw_protection_action_parse(const char * str,enum hw_protection_action * action)1055*e016173fSAhmad Fatoum static bool hw_protection_action_parse(const char *str,
1056*e016173fSAhmad Fatoum enum hw_protection_action *action)
1057*e016173fSAhmad Fatoum {
1058*e016173fSAhmad Fatoum if (sysfs_streq(str, "shutdown"))
1059*e016173fSAhmad Fatoum *action = HWPROT_ACT_SHUTDOWN;
1060*e016173fSAhmad Fatoum else if (sysfs_streq(str, "reboot"))
1061*e016173fSAhmad Fatoum *action = HWPROT_ACT_REBOOT;
1062*e016173fSAhmad Fatoum else
1063*e016173fSAhmad Fatoum return false;
1064*e016173fSAhmad Fatoum
1065*e016173fSAhmad Fatoum return true;
1066*e016173fSAhmad Fatoum }
1067*e016173fSAhmad Fatoum
hw_protection_setup(char * str)1068*e016173fSAhmad Fatoum static int __init hw_protection_setup(char *str)
1069*e016173fSAhmad Fatoum {
1070*e016173fSAhmad Fatoum hw_protection_action_parse(str, &hw_protection_action);
1071*e016173fSAhmad Fatoum return 1;
1072*e016173fSAhmad Fatoum }
1073*e016173fSAhmad Fatoum __setup("hw_protection=", hw_protection_setup);
1074*e016173fSAhmad Fatoum
1075*e016173fSAhmad Fatoum #ifdef CONFIG_SYSFS
hw_protection_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)1076*e016173fSAhmad Fatoum static ssize_t hw_protection_show(struct kobject *kobj,
1077*e016173fSAhmad Fatoum struct kobj_attribute *attr, char *buf)
1078*e016173fSAhmad Fatoum {
1079*e016173fSAhmad Fatoum return sysfs_emit(buf, "%s\n",
1080*e016173fSAhmad Fatoum hw_protection_action_str(hw_protection_action));
1081*e016173fSAhmad Fatoum }
hw_protection_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)1082*e016173fSAhmad Fatoum static ssize_t hw_protection_store(struct kobject *kobj,
1083*e016173fSAhmad Fatoum struct kobj_attribute *attr, const char *buf,
1084*e016173fSAhmad Fatoum size_t count)
1085*e016173fSAhmad Fatoum {
1086*e016173fSAhmad Fatoum if (!capable(CAP_SYS_ADMIN))
1087*e016173fSAhmad Fatoum return -EPERM;
1088*e016173fSAhmad Fatoum
1089*e016173fSAhmad Fatoum if (!hw_protection_action_parse(buf, &hw_protection_action))
1090*e016173fSAhmad Fatoum return -EINVAL;
1091*e016173fSAhmad Fatoum
1092*e016173fSAhmad Fatoum return count;
1093*e016173fSAhmad Fatoum }
1094*e016173fSAhmad Fatoum static struct kobj_attribute hw_protection_attr = __ATTR_RW(hw_protection);
1095*e016173fSAhmad Fatoum #endif
10961b3a5d02SRobin Holt
reboot_setup(char * str)10971b3a5d02SRobin Holt static int __init reboot_setup(char *str)
10981b3a5d02SRobin Holt {
1099b287a25aSAaro Koskinen for (;;) {
1100b287a25aSAaro Koskinen enum reboot_mode *mode;
11011b3a5d02SRobin Holt
11021b3a5d02SRobin Holt /*
11031b3a5d02SRobin Holt * Having anything passed on the command line via
11041b3a5d02SRobin Holt * reboot= will cause us to disable DMI checking
11051b3a5d02SRobin Holt * below.
11061b3a5d02SRobin Holt */
11071b3a5d02SRobin Holt reboot_default = 0;
1108b287a25aSAaro Koskinen
1109b287a25aSAaro Koskinen if (!strncmp(str, "panic_", 6)) {
1110b287a25aSAaro Koskinen mode = &panic_reboot_mode;
1111b287a25aSAaro Koskinen str += 6;
1112b287a25aSAaro Koskinen } else {
1113b287a25aSAaro Koskinen mode = &reboot_mode;
1114b287a25aSAaro Koskinen }
11151b3a5d02SRobin Holt
11161b3a5d02SRobin Holt switch (*str) {
1117b287a25aSAaro Koskinen case 'w':
11181b3a5d02SRobin Holt *mode = REBOOT_WARM;
11191b3a5d02SRobin Holt break;
11201b3a5d02SRobin Holt
1121b287a25aSAaro Koskinen case 'c':
11221b3a5d02SRobin Holt *mode = REBOOT_COLD;
11231b3a5d02SRobin Holt break;
11241b3a5d02SRobin Holt
1125b287a25aSAaro Koskinen case 'h':
11261b3a5d02SRobin Holt *mode = REBOOT_HARD;
11271b3a5d02SRobin Holt break;
11281b3a5d02SRobin Holt
1129f9a90501SMatteo Croce case 's':
1130f9a90501SMatteo Croce /*
1131f9a90501SMatteo Croce * reboot_cpu is s[mp]#### with #### being the processor
1132f9a90501SMatteo Croce * to be used for rebooting. Skip 's' or 'smp' prefix.
1133f9a90501SMatteo Croce */
1134f9a90501SMatteo Croce str += str[1] == 'm' && str[2] == 'p' ? 3 : 1;
1135f9a90501SMatteo Croce
1136f9a90501SMatteo Croce if (isdigit(str[0])) {
1137f9a90501SMatteo Croce int cpu = simple_strtoul(str, NULL, 0);
1138f9a90501SMatteo Croce
1139df5b0ab3SMatteo Croce if (cpu >= num_possible_cpus()) {
1140df5b0ab3SMatteo Croce pr_err("Ignoring the CPU number in reboot= option. "
1141f9a90501SMatteo Croce "CPU %d exceeds possible cpu number %d\n",
1142df5b0ab3SMatteo Croce cpu, num_possible_cpus());
1143df5b0ab3SMatteo Croce break;
1144f9a90501SMatteo Croce }
1145f9a90501SMatteo Croce reboot_cpu = cpu;
1146f9a90501SMatteo Croce } else
11471b3a5d02SRobin Holt *mode = REBOOT_SOFT;
11488b92c4ffSMatteo Croce break;
11491b3a5d02SRobin Holt
1150b287a25aSAaro Koskinen case 'g':
11511b3a5d02SRobin Holt *mode = REBOOT_GPIO;
11521b3a5d02SRobin Holt break;
11531b3a5d02SRobin Holt
11541b3a5d02SRobin Holt case 'b':
11551b3a5d02SRobin Holt case 'a':
11561b3a5d02SRobin Holt case 'k':
11571b3a5d02SRobin Holt case 't':
11581b3a5d02SRobin Holt case 'e':
11591b3a5d02SRobin Holt case 'p':
11601b3a5d02SRobin Holt reboot_type = *str;
11611b3a5d02SRobin Holt break;
11621b3a5d02SRobin Holt
11631b3a5d02SRobin Holt case 'f':
11641b3a5d02SRobin Holt reboot_force = 1;
11651b3a5d02SRobin Holt break;
11661b3a5d02SRobin Holt }
11671b3a5d02SRobin Holt
11681b3a5d02SRobin Holt str = strchr(str, ',');
11691b3a5d02SRobin Holt if (str)
11701b3a5d02SRobin Holt str++;
11711b3a5d02SRobin Holt else
11721b3a5d02SRobin Holt break;
11731b3a5d02SRobin Holt }
11741b3a5d02SRobin Holt return 1;
11751b3a5d02SRobin Holt }
11762c622ed0SMatteo Croce __setup("reboot=", reboot_setup);
11772c622ed0SMatteo Croce
11782c622ed0SMatteo Croce #ifdef CONFIG_SYSFS
11792c622ed0SMatteo Croce
11802c622ed0SMatteo Croce #define REBOOT_COLD_STR "cold"
11812c622ed0SMatteo Croce #define REBOOT_WARM_STR "warm"
11822c622ed0SMatteo Croce #define REBOOT_HARD_STR "hard"
11832c622ed0SMatteo Croce #define REBOOT_SOFT_STR "soft"
11842c622ed0SMatteo Croce #define REBOOT_GPIO_STR "gpio"
11852c622ed0SMatteo Croce #define REBOOT_UNDEFINED_STR "undefined"
11862c622ed0SMatteo Croce
11872c622ed0SMatteo Croce #define BOOT_TRIPLE_STR "triple"
11882c622ed0SMatteo Croce #define BOOT_KBD_STR "kbd"
11892c622ed0SMatteo Croce #define BOOT_BIOS_STR "bios"
11902c622ed0SMatteo Croce #define BOOT_ACPI_STR "acpi"
11910c5c0179SMatteo Croce #define BOOT_EFI_STR "efi"
11922c622ed0SMatteo Croce #define BOOT_PCI_STR "pci"
11932c622ed0SMatteo Croce
mode_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)11942c622ed0SMatteo Croce static ssize_t mode_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
11952c622ed0SMatteo Croce {
11962c622ed0SMatteo Croce const char *val;
11972c622ed0SMatteo Croce
11982c622ed0SMatteo Croce switch (reboot_mode) {
11992c622ed0SMatteo Croce case REBOOT_COLD:
12002c622ed0SMatteo Croce val = REBOOT_COLD_STR;
12012c622ed0SMatteo Croce break;
12022c622ed0SMatteo Croce case REBOOT_WARM:
12032c622ed0SMatteo Croce val = REBOOT_WARM_STR;
12042c622ed0SMatteo Croce break;
12052c622ed0SMatteo Croce case REBOOT_HARD:
12062c622ed0SMatteo Croce val = REBOOT_HARD_STR;
12072c622ed0SMatteo Croce break;
12082c622ed0SMatteo Croce case REBOOT_SOFT:
12092c622ed0SMatteo Croce val = REBOOT_SOFT_STR;
12102c622ed0SMatteo Croce break;
12112c622ed0SMatteo Croce case REBOOT_GPIO:
12122c622ed0SMatteo Croce val = REBOOT_GPIO_STR;
12132c622ed0SMatteo Croce break;
12142c622ed0SMatteo Croce default:
12152c622ed0SMatteo Croce val = REBOOT_UNDEFINED_STR;
12162c622ed0SMatteo Croce }
121745dac195Szhangguopeng
12182c622ed0SMatteo Croce return sysfs_emit(buf, "%s\n", val);
12192c622ed0SMatteo Croce }
mode_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)12202c622ed0SMatteo Croce static ssize_t mode_store(struct kobject *kobj, struct kobj_attribute *attr,
12212c622ed0SMatteo Croce const char *buf, size_t count)
12222c622ed0SMatteo Croce {
12232c622ed0SMatteo Croce if (!capable(CAP_SYS_BOOT))
12242c622ed0SMatteo Croce return -EPERM;
12252c622ed0SMatteo Croce
12262c622ed0SMatteo Croce if (!strncmp(buf, REBOOT_COLD_STR, strlen(REBOOT_COLD_STR)))
12272c622ed0SMatteo Croce reboot_mode = REBOOT_COLD;
12282c622ed0SMatteo Croce else if (!strncmp(buf, REBOOT_WARM_STR, strlen(REBOOT_WARM_STR)))
12292c622ed0SMatteo Croce reboot_mode = REBOOT_WARM;
12302c622ed0SMatteo Croce else if (!strncmp(buf, REBOOT_HARD_STR, strlen(REBOOT_HARD_STR)))
12312c622ed0SMatteo Croce reboot_mode = REBOOT_HARD;
12322c622ed0SMatteo Croce else if (!strncmp(buf, REBOOT_SOFT_STR, strlen(REBOOT_SOFT_STR)))
12332c622ed0SMatteo Croce reboot_mode = REBOOT_SOFT;
12342c622ed0SMatteo Croce else if (!strncmp(buf, REBOOT_GPIO_STR, strlen(REBOOT_GPIO_STR)))
12352c622ed0SMatteo Croce reboot_mode = REBOOT_GPIO;
12362c622ed0SMatteo Croce else
12372c622ed0SMatteo Croce return -EINVAL;
12381a9d079fSMatteo Croce
12391a9d079fSMatteo Croce reboot_default = 0;
12402c622ed0SMatteo Croce
12412c622ed0SMatteo Croce return count;
12422c622ed0SMatteo Croce }
12432c622ed0SMatteo Croce static struct kobj_attribute reboot_mode_attr = __ATTR_RW(mode);
124440247e55SMatteo Croce
124540247e55SMatteo Croce #ifdef CONFIG_X86
force_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)124640247e55SMatteo Croce static ssize_t force_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
124745dac195Szhangguopeng {
124840247e55SMatteo Croce return sysfs_emit(buf, "%d\n", reboot_force);
124940247e55SMatteo Croce }
force_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)125040247e55SMatteo Croce static ssize_t force_store(struct kobject *kobj, struct kobj_attribute *attr,
125140247e55SMatteo Croce const char *buf, size_t count)
125240247e55SMatteo Croce {
125340247e55SMatteo Croce bool res;
125440247e55SMatteo Croce
125540247e55SMatteo Croce if (!capable(CAP_SYS_BOOT))
125640247e55SMatteo Croce return -EPERM;
125740247e55SMatteo Croce
125840247e55SMatteo Croce if (kstrtobool(buf, &res))
125940247e55SMatteo Croce return -EINVAL;
126040247e55SMatteo Croce
126140247e55SMatteo Croce reboot_default = 0;
126240247e55SMatteo Croce reboot_force = res;
126340247e55SMatteo Croce
126440247e55SMatteo Croce return count;
126540247e55SMatteo Croce }
126640247e55SMatteo Croce static struct kobj_attribute reboot_force_attr = __ATTR_RW(force);
12672c622ed0SMatteo Croce
type_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)12682c622ed0SMatteo Croce static ssize_t type_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
12692c622ed0SMatteo Croce {
12702c622ed0SMatteo Croce const char *val;
12712c622ed0SMatteo Croce
12722c622ed0SMatteo Croce switch (reboot_type) {
12732c622ed0SMatteo Croce case BOOT_TRIPLE:
12742c622ed0SMatteo Croce val = BOOT_TRIPLE_STR;
12752c622ed0SMatteo Croce break;
12762c622ed0SMatteo Croce case BOOT_KBD:
12772c622ed0SMatteo Croce val = BOOT_KBD_STR;
12782c622ed0SMatteo Croce break;
12792c622ed0SMatteo Croce case BOOT_BIOS:
12802c622ed0SMatteo Croce val = BOOT_BIOS_STR;
12812c622ed0SMatteo Croce break;
12822c622ed0SMatteo Croce case BOOT_ACPI:
12832c622ed0SMatteo Croce val = BOOT_ACPI_STR;
12842c622ed0SMatteo Croce break;
12852c622ed0SMatteo Croce case BOOT_EFI:
12862c622ed0SMatteo Croce val = BOOT_EFI_STR;
12872c622ed0SMatteo Croce break;
12880c5c0179SMatteo Croce case BOOT_CF9_FORCE:
12892c622ed0SMatteo Croce val = BOOT_PCI_STR;
12902c622ed0SMatteo Croce break;
12912c622ed0SMatteo Croce default:
12922c622ed0SMatteo Croce val = REBOOT_UNDEFINED_STR;
12932c622ed0SMatteo Croce }
129445dac195Szhangguopeng
12952c622ed0SMatteo Croce return sysfs_emit(buf, "%s\n", val);
12962c622ed0SMatteo Croce }
type_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)12972c622ed0SMatteo Croce static ssize_t type_store(struct kobject *kobj, struct kobj_attribute *attr,
12982c622ed0SMatteo Croce const char *buf, size_t count)
12992c622ed0SMatteo Croce {
13002c622ed0SMatteo Croce if (!capable(CAP_SYS_BOOT))
13012c622ed0SMatteo Croce return -EPERM;
13022c622ed0SMatteo Croce
13032c622ed0SMatteo Croce if (!strncmp(buf, BOOT_TRIPLE_STR, strlen(BOOT_TRIPLE_STR)))
13042c622ed0SMatteo Croce reboot_type = BOOT_TRIPLE;
13052c622ed0SMatteo Croce else if (!strncmp(buf, BOOT_KBD_STR, strlen(BOOT_KBD_STR)))
13062c622ed0SMatteo Croce reboot_type = BOOT_KBD;
13072c622ed0SMatteo Croce else if (!strncmp(buf, BOOT_BIOS_STR, strlen(BOOT_BIOS_STR)))
13082c622ed0SMatteo Croce reboot_type = BOOT_BIOS;
13092c622ed0SMatteo Croce else if (!strncmp(buf, BOOT_ACPI_STR, strlen(BOOT_ACPI_STR)))
13102c622ed0SMatteo Croce reboot_type = BOOT_ACPI;
13112c622ed0SMatteo Croce else if (!strncmp(buf, BOOT_EFI_STR, strlen(BOOT_EFI_STR)))
13120c5c0179SMatteo Croce reboot_type = BOOT_EFI;
13132c622ed0SMatteo Croce else if (!strncmp(buf, BOOT_PCI_STR, strlen(BOOT_PCI_STR)))
13142c622ed0SMatteo Croce reboot_type = BOOT_CF9_FORCE;
13152c622ed0SMatteo Croce else
13162c622ed0SMatteo Croce return -EINVAL;
13171a9d079fSMatteo Croce
13181a9d079fSMatteo Croce reboot_default = 0;
13192c622ed0SMatteo Croce
13202c622ed0SMatteo Croce return count;
13212c622ed0SMatteo Croce }
132240247e55SMatteo Croce static struct kobj_attribute reboot_type_attr = __ATTR_RW(type);
13232c622ed0SMatteo Croce #endif
132440247e55SMatteo Croce
13252c622ed0SMatteo Croce #ifdef CONFIG_SMP
cpu_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)13262c622ed0SMatteo Croce static ssize_t cpu_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
132745dac195Szhangguopeng {
13282c622ed0SMatteo Croce return sysfs_emit(buf, "%d\n", reboot_cpu);
13292c622ed0SMatteo Croce }
cpu_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)13302c622ed0SMatteo Croce static ssize_t cpu_store(struct kobject *kobj, struct kobj_attribute *attr,
13312c622ed0SMatteo Croce const char *buf, size_t count)
13322c622ed0SMatteo Croce {
13332c622ed0SMatteo Croce unsigned int cpunum;
13342c622ed0SMatteo Croce int rc;
13352c622ed0SMatteo Croce
13362c622ed0SMatteo Croce if (!capable(CAP_SYS_BOOT))
13372c622ed0SMatteo Croce return -EPERM;
13382c622ed0SMatteo Croce
13392c622ed0SMatteo Croce rc = kstrtouint(buf, 0, &cpunum);
13402c622ed0SMatteo Croce
13412c622ed0SMatteo Croce if (rc)
13422c622ed0SMatteo Croce return rc;
13432c622ed0SMatteo Croce
13442c622ed0SMatteo Croce if (cpunum >= num_possible_cpus())
13452c622ed0SMatteo Croce return -ERANGE;
13461a9d079fSMatteo Croce
13472c622ed0SMatteo Croce reboot_default = 0;
13482c622ed0SMatteo Croce reboot_cpu = cpunum;
13492c622ed0SMatteo Croce
13502c622ed0SMatteo Croce return count;
13512c622ed0SMatteo Croce }
135240247e55SMatteo Croce static struct kobj_attribute reboot_cpu_attr = __ATTR_RW(cpu);
13532c622ed0SMatteo Croce #endif
13542c622ed0SMatteo Croce
1355*e016173fSAhmad Fatoum static struct attribute *reboot_attrs[] = {
13562c622ed0SMatteo Croce &hw_protection_attr.attr,
135740247e55SMatteo Croce &reboot_mode_attr.attr,
13582c622ed0SMatteo Croce #ifdef CONFIG_X86
135940247e55SMatteo Croce &reboot_force_attr.attr,
136040247e55SMatteo Croce &reboot_type_attr.attr,
136140247e55SMatteo Croce #endif
136240247e55SMatteo Croce #ifdef CONFIG_SMP
136340247e55SMatteo Croce &reboot_cpu_attr.attr,
13642c622ed0SMatteo Croce #endif
13652c622ed0SMatteo Croce NULL,
13662c622ed0SMatteo Croce };
1367764aaf44SYueHaibing
13681751f872SJoel Granados #ifdef CONFIG_SYSCTL
1369764aaf44SYueHaibing static const struct ctl_table kern_reboot_table[] = {
1370764aaf44SYueHaibing {
1371764aaf44SYueHaibing .procname = "poweroff_cmd",
1372764aaf44SYueHaibing .data = &poweroff_cmd,
1373764aaf44SYueHaibing .maxlen = POWEROFF_CMD_PATH_LEN,
1374764aaf44SYueHaibing .mode = 0644,
1375764aaf44SYueHaibing .proc_handler = proc_dostring,
1376764aaf44SYueHaibing },
1377764aaf44SYueHaibing {
1378764aaf44SYueHaibing .procname = "ctrl-alt-del",
1379764aaf44SYueHaibing .data = &C_A_D,
1380764aaf44SYueHaibing .maxlen = sizeof(int),
1381764aaf44SYueHaibing .mode = 0644,
1382764aaf44SYueHaibing .proc_handler = proc_dointvec,
1383764aaf44SYueHaibing },
1384764aaf44SYueHaibing };
1385764aaf44SYueHaibing
kernel_reboot_sysctls_init(void)1386764aaf44SYueHaibing static void __init kernel_reboot_sysctls_init(void)
1387764aaf44SYueHaibing {
1388764aaf44SYueHaibing register_sysctl_init("kernel", kern_reboot_table);
1389764aaf44SYueHaibing }
1390764aaf44SYueHaibing #else
1391764aaf44SYueHaibing #define kernel_reboot_sysctls_init() do { } while (0)
1392764aaf44SYueHaibing #endif /* CONFIG_SYSCTL */
13932c622ed0SMatteo Croce
13942c622ed0SMatteo Croce static const struct attribute_group reboot_attr_group = {
13952c622ed0SMatteo Croce .attrs = reboot_attrs,
13962c622ed0SMatteo Croce };
13972c622ed0SMatteo Croce
reboot_ksysfs_init(void)13982c622ed0SMatteo Croce static int __init reboot_ksysfs_init(void)
13992c622ed0SMatteo Croce {
14002c622ed0SMatteo Croce struct kobject *reboot_kobj;
14012c622ed0SMatteo Croce int ret;
14022c622ed0SMatteo Croce
14032c622ed0SMatteo Croce reboot_kobj = kobject_create_and_add("reboot", kernel_kobj);
14042c622ed0SMatteo Croce if (!reboot_kobj)
14052c622ed0SMatteo Croce return -ENOMEM;
14062c622ed0SMatteo Croce
14072c622ed0SMatteo Croce ret = sysfs_create_group(reboot_kobj, &reboot_attr_group);
14082c622ed0SMatteo Croce if (ret) {
14092c622ed0SMatteo Croce kobject_put(reboot_kobj);
14102c622ed0SMatteo Croce return ret;
14112c622ed0SMatteo Croce }
141206d17766Stangmeng
141306d17766Stangmeng kernel_reboot_sysctls_init();
14142c622ed0SMatteo Croce
14152c622ed0SMatteo Croce return 0;
14162c622ed0SMatteo Croce }
14172c622ed0SMatteo Croce late_initcall(reboot_ksysfs_init);
14182c622ed0SMatteo Croce
1419 #endif
1420