13d0407baSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 23d0407baSopenharmony_ci/* 33d0407baSopenharmony_ci * linux/kernel/reboot.c 43d0407baSopenharmony_ci * 53d0407baSopenharmony_ci * Copyright (C) 2013 Linus Torvalds 63d0407baSopenharmony_ci */ 73d0407baSopenharmony_ci 83d0407baSopenharmony_ci#define pr_fmt(fmt) "reboot: " fmt 93d0407baSopenharmony_ci 103d0407baSopenharmony_ci#include <linux/ctype.h> 113d0407baSopenharmony_ci#include <linux/export.h> 123d0407baSopenharmony_ci#include <linux/kexec.h> 133d0407baSopenharmony_ci#include <linux/kmod.h> 143d0407baSopenharmony_ci#include <linux/kmsg_dump.h> 153d0407baSopenharmony_ci#include <linux/reboot.h> 163d0407baSopenharmony_ci#include <linux/suspend.h> 173d0407baSopenharmony_ci#include <linux/syscalls.h> 183d0407baSopenharmony_ci#include <linux/syscore_ops.h> 193d0407baSopenharmony_ci#include <linux/uaccess.h> 203d0407baSopenharmony_ci 213d0407baSopenharmony_ci/* 223d0407baSopenharmony_ci * this indicates whether you can reboot with ctrl-alt-del: the default is yes 233d0407baSopenharmony_ci */ 243d0407baSopenharmony_ci 253d0407baSopenharmony_ciint C_A_D = 1; 263d0407baSopenharmony_cistruct pid *cad_pid; 273d0407baSopenharmony_ciEXPORT_SYMBOL(cad_pid); 283d0407baSopenharmony_ci 293d0407baSopenharmony_ci#if defined(CONFIG_ARM) 303d0407baSopenharmony_ci#define DEFAULT_REBOOT_MODE = REBOOT_HARD 313d0407baSopenharmony_ci#else 323d0407baSopenharmony_ci#define DEFAULT_REBOOT_MODE 333d0407baSopenharmony_ci#endif 343d0407baSopenharmony_cienum reboot_mode reboot_mode DEFAULT_REBOOT_MODE; 353d0407baSopenharmony_cienum reboot_mode panic_reboot_mode = REBOOT_UNDEFINED; 363d0407baSopenharmony_ci 373d0407baSopenharmony_ci/* 383d0407baSopenharmony_ci * This variable is used privately to keep track of whether or not 393d0407baSopenharmony_ci * reboot_type is still set to its default value (i.e., reboot= hasn't 403d0407baSopenharmony_ci * been set on the command line). This is needed so that we can 413d0407baSopenharmony_ci * suppress DMI scanning for reboot quirks. Without it, it's 423d0407baSopenharmony_ci * impossible to override a faulty reboot quirk without recompiling. 433d0407baSopenharmony_ci */ 443d0407baSopenharmony_ciint reboot_default = 1; 453d0407baSopenharmony_ciint reboot_cpu; 463d0407baSopenharmony_cienum reboot_type reboot_type = BOOT_ACPI; 473d0407baSopenharmony_ciint reboot_force; 483d0407baSopenharmony_ci 493d0407baSopenharmony_ci/* 503d0407baSopenharmony_ci * If set, this is used for preparing the system to power off. 513d0407baSopenharmony_ci */ 523d0407baSopenharmony_ci 533d0407baSopenharmony_civoid (*pm_power_off_prepare)(void); 543d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(pm_power_off_prepare); 553d0407baSopenharmony_ci 563d0407baSopenharmony_ci/** 573d0407baSopenharmony_ci * emergency_restart - reboot the system 583d0407baSopenharmony_ci * 593d0407baSopenharmony_ci * Without shutting down any hardware or taking any locks 603d0407baSopenharmony_ci * reboot the system. This is called when we know we are in 613d0407baSopenharmony_ci * trouble so this is our best effort to reboot. This is 623d0407baSopenharmony_ci * safe to call in interrupt context. 633d0407baSopenharmony_ci */ 643d0407baSopenharmony_civoid emergency_restart(void) 653d0407baSopenharmony_ci{ 663d0407baSopenharmony_ci kmsg_dump(KMSG_DUMP_EMERG); 673d0407baSopenharmony_ci machine_emergency_restart(); 683d0407baSopenharmony_ci} 693d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(emergency_restart); 703d0407baSopenharmony_ci 713d0407baSopenharmony_civoid kernel_restart_prepare(char *cmd) 723d0407baSopenharmony_ci{ 733d0407baSopenharmony_ci blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd); 743d0407baSopenharmony_ci system_state = SYSTEM_RESTART; 753d0407baSopenharmony_ci usermodehelper_disable(); 763d0407baSopenharmony_ci device_shutdown(); 773d0407baSopenharmony_ci} 783d0407baSopenharmony_ci 793d0407baSopenharmony_ci/** 803d0407baSopenharmony_ci * register_reboot_notifier - Register function to be called at reboot time 813d0407baSopenharmony_ci * @nb: Info about notifier function to be called 823d0407baSopenharmony_ci * 833d0407baSopenharmony_ci * Registers a function with the list of functions 843d0407baSopenharmony_ci * to be called at reboot time. 853d0407baSopenharmony_ci * 863d0407baSopenharmony_ci * Currently always returns zero, as blocking_notifier_chain_register() 873d0407baSopenharmony_ci * always returns zero. 883d0407baSopenharmony_ci */ 893d0407baSopenharmony_ciint register_reboot_notifier(struct notifier_block *nb) 903d0407baSopenharmony_ci{ 913d0407baSopenharmony_ci return blocking_notifier_chain_register(&reboot_notifier_list, nb); 923d0407baSopenharmony_ci} 933d0407baSopenharmony_ciEXPORT_SYMBOL(register_reboot_notifier); 943d0407baSopenharmony_ci 953d0407baSopenharmony_ci/** 963d0407baSopenharmony_ci * unregister_reboot_notifier - Unregister previously registered reboot notifier 973d0407baSopenharmony_ci * @nb: Hook to be unregistered 983d0407baSopenharmony_ci * 993d0407baSopenharmony_ci * Unregisters a previously registered reboot 1003d0407baSopenharmony_ci * notifier function. 1013d0407baSopenharmony_ci * 1023d0407baSopenharmony_ci * Returns zero on success, or %-ENOENT on failure. 1033d0407baSopenharmony_ci */ 1043d0407baSopenharmony_ciint unregister_reboot_notifier(struct notifier_block *nb) 1053d0407baSopenharmony_ci{ 1063d0407baSopenharmony_ci return blocking_notifier_chain_unregister(&reboot_notifier_list, nb); 1073d0407baSopenharmony_ci} 1083d0407baSopenharmony_ciEXPORT_SYMBOL(unregister_reboot_notifier); 1093d0407baSopenharmony_ci 1103d0407baSopenharmony_cistatic void devm_unregister_reboot_notifier(struct device *dev, void *res) 1113d0407baSopenharmony_ci{ 1123d0407baSopenharmony_ci WARN_ON(unregister_reboot_notifier(*(struct notifier_block **)res)); 1133d0407baSopenharmony_ci} 1143d0407baSopenharmony_ci 1153d0407baSopenharmony_ciint devm_register_reboot_notifier(struct device *dev, struct notifier_block *nb) 1163d0407baSopenharmony_ci{ 1173d0407baSopenharmony_ci struct notifier_block **rcnb; 1183d0407baSopenharmony_ci int ret; 1193d0407baSopenharmony_ci 1203d0407baSopenharmony_ci rcnb = devres_alloc(devm_unregister_reboot_notifier, sizeof(*rcnb), GFP_KERNEL); 1213d0407baSopenharmony_ci if (!rcnb) { 1223d0407baSopenharmony_ci return -ENOMEM; 1233d0407baSopenharmony_ci } 1243d0407baSopenharmony_ci 1253d0407baSopenharmony_ci ret = register_reboot_notifier(nb); 1263d0407baSopenharmony_ci if (!ret) { 1273d0407baSopenharmony_ci *rcnb = nb; 1283d0407baSopenharmony_ci devres_add(dev, rcnb); 1293d0407baSopenharmony_ci } else { 1303d0407baSopenharmony_ci devres_free(rcnb); 1313d0407baSopenharmony_ci } 1323d0407baSopenharmony_ci 1333d0407baSopenharmony_ci return ret; 1343d0407baSopenharmony_ci} 1353d0407baSopenharmony_ciEXPORT_SYMBOL(devm_register_reboot_notifier); 1363d0407baSopenharmony_ci 1373d0407baSopenharmony_ci/* 1383d0407baSopenharmony_ci * Notifier list for kernel code which wants to be called 1393d0407baSopenharmony_ci * to restart the system. 1403d0407baSopenharmony_ci */ 1413d0407baSopenharmony_cistatic ATOMIC_NOTIFIER_HEAD(restart_handler_list); 1423d0407baSopenharmony_ci 1433d0407baSopenharmony_ci/** 1443d0407baSopenharmony_ci * register_restart_handler - Register function to be called to reset 1453d0407baSopenharmony_ci * the system 1463d0407baSopenharmony_ci * @nb: Info about handler function to be called 1473d0407baSopenharmony_ci * @nb->priority: Handler priority. Handlers should follow the 1483d0407baSopenharmony_ci * following guidelines for setting priorities. 1493d0407baSopenharmony_ci * 0: Restart handler of last resort, 1503d0407baSopenharmony_ci * with limited restart capabilities 1513d0407baSopenharmony_ci * 128: Default restart handler; use if no other 1523d0407baSopenharmony_ci * restart handler is expected to be available, 1533d0407baSopenharmony_ci * and/or if restart functionality is 1543d0407baSopenharmony_ci * sufficient to restart the entire system 1553d0407baSopenharmony_ci * 255: Highest priority restart handler, will 1563d0407baSopenharmony_ci * preempt all other restart handlers 1573d0407baSopenharmony_ci * 1583d0407baSopenharmony_ci * Registers a function with code to be called to restart the 1593d0407baSopenharmony_ci * system. 1603d0407baSopenharmony_ci * 1613d0407baSopenharmony_ci * Registered functions will be called from machine_restart as last 1623d0407baSopenharmony_ci * step of the restart sequence (if the architecture specific 1633d0407baSopenharmony_ci * machine_restart function calls do_kernel_restart - see below 1643d0407baSopenharmony_ci * for details). 1653d0407baSopenharmony_ci * Registered functions are expected to restart the system immediately. 1663d0407baSopenharmony_ci * If more than one function is registered, the restart handler priority 1673d0407baSopenharmony_ci * selects which function will be called first. 1683d0407baSopenharmony_ci * 1693d0407baSopenharmony_ci * Restart handlers are expected to be registered from non-architecture 1703d0407baSopenharmony_ci * code, typically from drivers. A typical use case would be a system 1713d0407baSopenharmony_ci * where restart functionality is provided through a watchdog. Multiple 1723d0407baSopenharmony_ci * restart handlers may exist; for example, one restart handler might 1733d0407baSopenharmony_ci * restart the entire system, while another only restarts the CPU. 1743d0407baSopenharmony_ci * In such cases, the restart handler which only restarts part of the 1753d0407baSopenharmony_ci * hardware is expected to register with low priority to ensure that 1763d0407baSopenharmony_ci * it only runs if no other means to restart the system is available. 1773d0407baSopenharmony_ci * 1783d0407baSopenharmony_ci * Currently always returns zero, as atomic_notifier_chain_register() 1793d0407baSopenharmony_ci * always returns zero. 1803d0407baSopenharmony_ci */ 1813d0407baSopenharmony_ciint register_restart_handler(struct notifier_block *nb) 1823d0407baSopenharmony_ci{ 1833d0407baSopenharmony_ci return atomic_notifier_chain_register(&restart_handler_list, nb); 1843d0407baSopenharmony_ci} 1853d0407baSopenharmony_ciEXPORT_SYMBOL(register_restart_handler); 1863d0407baSopenharmony_ci 1873d0407baSopenharmony_ci/** 1883d0407baSopenharmony_ci * unregister_restart_handler - Unregister previously registered 1893d0407baSopenharmony_ci * restart handler 1903d0407baSopenharmony_ci * @nb: Hook to be unregistered 1913d0407baSopenharmony_ci * 1923d0407baSopenharmony_ci * Unregisters a previously registered restart handler function. 1933d0407baSopenharmony_ci * 1943d0407baSopenharmony_ci * Returns zero on success, or %-ENOENT on failure. 1953d0407baSopenharmony_ci */ 1963d0407baSopenharmony_ciint unregister_restart_handler(struct notifier_block *nb) 1973d0407baSopenharmony_ci{ 1983d0407baSopenharmony_ci return atomic_notifier_chain_unregister(&restart_handler_list, nb); 1993d0407baSopenharmony_ci} 2003d0407baSopenharmony_ciEXPORT_SYMBOL(unregister_restart_handler); 2013d0407baSopenharmony_ci 2023d0407baSopenharmony_ci/** 2033d0407baSopenharmony_ci * do_kernel_restart - Execute kernel restart handler call chain 2043d0407baSopenharmony_ci * 2053d0407baSopenharmony_ci * Calls functions registered with register_restart_handler. 2063d0407baSopenharmony_ci * 2073d0407baSopenharmony_ci * Expected to be called from machine_restart as last step of the restart 2083d0407baSopenharmony_ci * sequence. 2093d0407baSopenharmony_ci * 2103d0407baSopenharmony_ci * Restarts the system immediately if a restart handler function has been 2113d0407baSopenharmony_ci * registered. Otherwise does nothing. 2123d0407baSopenharmony_ci */ 2133d0407baSopenharmony_civoid do_kernel_restart(char *cmd) 2143d0407baSopenharmony_ci{ 2153d0407baSopenharmony_ci atomic_notifier_call_chain(&restart_handler_list, reboot_mode, cmd); 2163d0407baSopenharmony_ci} 2173d0407baSopenharmony_ci 2183d0407baSopenharmony_ci#ifdef CONFIG_NO_GKI 2193d0407baSopenharmony_cistatic ATOMIC_NOTIFIER_HEAD(pre_restart_handler_list); 2203d0407baSopenharmony_ci 2213d0407baSopenharmony_ciint register_pre_restart_handler(struct notifier_block *nb) 2223d0407baSopenharmony_ci{ 2233d0407baSopenharmony_ci return atomic_notifier_chain_register(&pre_restart_handler_list, nb); 2243d0407baSopenharmony_ci} 2253d0407baSopenharmony_ciEXPORT_SYMBOL(register_pre_restart_handler); 2263d0407baSopenharmony_ci 2273d0407baSopenharmony_ciint unregister_pre_restart_handler(struct notifier_block *nb) 2283d0407baSopenharmony_ci{ 2293d0407baSopenharmony_ci return atomic_notifier_chain_unregister(&pre_restart_handler_list, nb); 2303d0407baSopenharmony_ci} 2313d0407baSopenharmony_ciEXPORT_SYMBOL(unregister_pre_restart_handler); 2323d0407baSopenharmony_ci 2333d0407baSopenharmony_civoid do_kernel_pre_restart(char *cmd) 2343d0407baSopenharmony_ci{ 2353d0407baSopenharmony_ci atomic_notifier_call_chain(&pre_restart_handler_list, reboot_mode, cmd); 2363d0407baSopenharmony_ci} 2373d0407baSopenharmony_ci#endif 2383d0407baSopenharmony_ci 2393d0407baSopenharmony_civoid migrate_to_reboot_cpu(void) 2403d0407baSopenharmony_ci{ 2413d0407baSopenharmony_ci /* The boot cpu is always logical cpu 0 */ 2423d0407baSopenharmony_ci int cpu = reboot_cpu; 2433d0407baSopenharmony_ci 2443d0407baSopenharmony_ci cpu_hotplug_disable(); 2453d0407baSopenharmony_ci 2463d0407baSopenharmony_ci /* Make certain the cpu I'm about to reboot on is online */ 2473d0407baSopenharmony_ci if (!cpu_online(cpu)) { 2483d0407baSopenharmony_ci cpu = cpumask_first(cpu_online_mask); 2493d0407baSopenharmony_ci } 2503d0407baSopenharmony_ci 2513d0407baSopenharmony_ci /* Prevent races with other tasks migrating this task */ 2523d0407baSopenharmony_ci current->flags |= PF_NO_SETAFFINITY; 2533d0407baSopenharmony_ci 2543d0407baSopenharmony_ci /* Make certain I only run on the appropriate processor */ 2553d0407baSopenharmony_ci set_cpus_allowed_ptr(current, cpumask_of(cpu)); 2563d0407baSopenharmony_ci} 2573d0407baSopenharmony_ci 2583d0407baSopenharmony_ci/** 2593d0407baSopenharmony_ci * kernel_restart - reboot the system 2603d0407baSopenharmony_ci * @cmd: pointer to buffer containing command to execute for restart 2613d0407baSopenharmony_ci * or %NULL 2623d0407baSopenharmony_ci * 2633d0407baSopenharmony_ci * Shutdown everything and perform a clean reboot. 2643d0407baSopenharmony_ci * This is not safe to call in interrupt context. 2653d0407baSopenharmony_ci */ 2663d0407baSopenharmony_civoid kernel_restart(char *cmd) 2673d0407baSopenharmony_ci{ 2683d0407baSopenharmony_ci kernel_restart_prepare(cmd); 2693d0407baSopenharmony_ci migrate_to_reboot_cpu(); 2703d0407baSopenharmony_ci syscore_shutdown(); 2713d0407baSopenharmony_ci if (!cmd) { 2723d0407baSopenharmony_ci pr_emerg("Restarting system\n"); 2733d0407baSopenharmony_ci } else { 2743d0407baSopenharmony_ci pr_emerg("Restarting system with command '%s'\n", cmd); 2753d0407baSopenharmony_ci } 2763d0407baSopenharmony_ci kmsg_dump(KMSG_DUMP_SHUTDOWN); 2773d0407baSopenharmony_ci machine_restart(cmd); 2783d0407baSopenharmony_ci} 2793d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(kernel_restart); 2803d0407baSopenharmony_ci 2813d0407baSopenharmony_cistatic void kernel_shutdown_prepare(enum system_states state) 2823d0407baSopenharmony_ci{ 2833d0407baSopenharmony_ci blocking_notifier_call_chain(&reboot_notifier_list, (state == SYSTEM_HALT) ? SYS_HALT : SYS_POWER_OFF, NULL); 2843d0407baSopenharmony_ci system_state = state; 2853d0407baSopenharmony_ci usermodehelper_disable(); 2863d0407baSopenharmony_ci device_shutdown(); 2873d0407baSopenharmony_ci} 2883d0407baSopenharmony_ci/** 2893d0407baSopenharmony_ci * kernel_halt - halt the system 2903d0407baSopenharmony_ci * 2913d0407baSopenharmony_ci * Shutdown everything and perform a clean system halt. 2923d0407baSopenharmony_ci */ 2933d0407baSopenharmony_civoid kernel_halt(void) 2943d0407baSopenharmony_ci{ 2953d0407baSopenharmony_ci kernel_shutdown_prepare(SYSTEM_HALT); 2963d0407baSopenharmony_ci migrate_to_reboot_cpu(); 2973d0407baSopenharmony_ci syscore_shutdown(); 2983d0407baSopenharmony_ci pr_emerg("System halted\n"); 2993d0407baSopenharmony_ci kmsg_dump(KMSG_DUMP_SHUTDOWN); 3003d0407baSopenharmony_ci machine_halt(); 3013d0407baSopenharmony_ci} 3023d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(kernel_halt); 3033d0407baSopenharmony_ci 3043d0407baSopenharmony_ci/** 3053d0407baSopenharmony_ci * kernel_power_off - power_off the system 3063d0407baSopenharmony_ci * 3073d0407baSopenharmony_ci * Shutdown everything and perform a clean system power_off. 3083d0407baSopenharmony_ci */ 3093d0407baSopenharmony_civoid kernel_power_off(void) 3103d0407baSopenharmony_ci{ 3113d0407baSopenharmony_ci kernel_shutdown_prepare(SYSTEM_POWER_OFF); 3123d0407baSopenharmony_ci if (pm_power_off_prepare) { 3133d0407baSopenharmony_ci pm_power_off_prepare(); 3143d0407baSopenharmony_ci } 3153d0407baSopenharmony_ci migrate_to_reboot_cpu(); 3163d0407baSopenharmony_ci syscore_shutdown(); 3173d0407baSopenharmony_ci pr_emerg("Power down\n"); 3183d0407baSopenharmony_ci kmsg_dump(KMSG_DUMP_SHUTDOWN); 3193d0407baSopenharmony_ci machine_power_off(); 3203d0407baSopenharmony_ci} 3213d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(kernel_power_off); 3223d0407baSopenharmony_ci 3233d0407baSopenharmony_ciDEFINE_MUTEX(system_transition_mutex); 3243d0407baSopenharmony_ci 3253d0407baSopenharmony_ci/* 3263d0407baSopenharmony_ci * Reboot system call: for obvious reasons only root may call it, 3273d0407baSopenharmony_ci * and even root needs to set up some magic numbers in the registers 3283d0407baSopenharmony_ci * so that some mistake won't make this reboot the whole machine. 3293d0407baSopenharmony_ci * You can also set the meaning of the ctrl-alt-del-key here. 3303d0407baSopenharmony_ci * 3313d0407baSopenharmony_ci * reboot doesn't sync: do that yourself before calling this. 3323d0407baSopenharmony_ci */ 3333d0407baSopenharmony_ciSYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd, void __user *, arg) 3343d0407baSopenharmony_ci{ 3353d0407baSopenharmony_ci struct pid_namespace *pid_ns = task_active_pid_ns(current); 3363d0407baSopenharmony_ci char buffer[256]; 3373d0407baSopenharmony_ci int ret = 0; 3383d0407baSopenharmony_ci 3393d0407baSopenharmony_ci /* We only trust the superuser with rebooting the system. */ 3403d0407baSopenharmony_ci if (!ns_capable(pid_ns->user_ns, CAP_SYS_BOOT)) { 3413d0407baSopenharmony_ci return -EPERM; 3423d0407baSopenharmony_ci } 3433d0407baSopenharmony_ci 3443d0407baSopenharmony_ci /* For safety, we require "magic" arguments. */ 3453d0407baSopenharmony_ci if (magic1 != LINUX_REBOOT_MAGIC1 || (magic2 != LINUX_REBOOT_MAGIC2 && magic2 != LINUX_REBOOT_MAGIC2A && 3463d0407baSopenharmony_ci magic2 != LINUX_REBOOT_MAGIC2B && magic2 != LINUX_REBOOT_MAGIC2C)) { 3473d0407baSopenharmony_ci return -EINVAL; 3483d0407baSopenharmony_ci } 3493d0407baSopenharmony_ci 3503d0407baSopenharmony_ci /* 3513d0407baSopenharmony_ci * If pid namespaces are enabled and the current task is in a child 3523d0407baSopenharmony_ci * pid_namespace, the command is handled by reboot_pid_ns() which will 3533d0407baSopenharmony_ci * call do_exit(). 3543d0407baSopenharmony_ci */ 3553d0407baSopenharmony_ci ret = reboot_pid_ns(pid_ns, cmd); 3563d0407baSopenharmony_ci if (ret) { 3573d0407baSopenharmony_ci return ret; 3583d0407baSopenharmony_ci } 3593d0407baSopenharmony_ci 3603d0407baSopenharmony_ci /* Instead of trying to make the power_off code look like 3613d0407baSopenharmony_ci * halt when pm_power_off is not set do it the easy way. 3623d0407baSopenharmony_ci */ 3633d0407baSopenharmony_ci if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off) { 3643d0407baSopenharmony_ci cmd = LINUX_REBOOT_CMD_HALT; 3653d0407baSopenharmony_ci } 3663d0407baSopenharmony_ci 3673d0407baSopenharmony_ci mutex_lock(&system_transition_mutex); 3683d0407baSopenharmony_ci switch (cmd) { 3693d0407baSopenharmony_ci case LINUX_REBOOT_CMD_RESTART: 3703d0407baSopenharmony_ci kernel_restart(NULL); 3713d0407baSopenharmony_ci break; 3723d0407baSopenharmony_ci 3733d0407baSopenharmony_ci case LINUX_REBOOT_CMD_CAD_ON: 3743d0407baSopenharmony_ci C_A_D = 1; 3753d0407baSopenharmony_ci break; 3763d0407baSopenharmony_ci 3773d0407baSopenharmony_ci case LINUX_REBOOT_CMD_CAD_OFF: 3783d0407baSopenharmony_ci C_A_D = 0; 3793d0407baSopenharmony_ci break; 3803d0407baSopenharmony_ci 3813d0407baSopenharmony_ci case LINUX_REBOOT_CMD_HALT: 3823d0407baSopenharmony_ci kernel_halt(); 3833d0407baSopenharmony_ci do_exit(0); 3843d0407baSopenharmony_ci panic("cannot halt"); 3853d0407baSopenharmony_ci 3863d0407baSopenharmony_ci case LINUX_REBOOT_CMD_POWER_OFF: 3873d0407baSopenharmony_ci kernel_power_off(); 3883d0407baSopenharmony_ci do_exit(0); 3893d0407baSopenharmony_ci break; 3903d0407baSopenharmony_ci 3913d0407baSopenharmony_ci case LINUX_REBOOT_CMD_RESTART2: 3923d0407baSopenharmony_ci ret = strncpy_from_user(&buffer[0], arg, sizeof(buffer) - 1); 3933d0407baSopenharmony_ci if (ret < 0) { 3943d0407baSopenharmony_ci ret = -EFAULT; 3953d0407baSopenharmony_ci break; 3963d0407baSopenharmony_ci } 3973d0407baSopenharmony_ci buffer[sizeof(buffer) - 1] = '\0'; 3983d0407baSopenharmony_ci 3993d0407baSopenharmony_ci kernel_restart(buffer); 4003d0407baSopenharmony_ci break; 4013d0407baSopenharmony_ci 4023d0407baSopenharmony_ci#ifdef CONFIG_KEXEC_CORE 4033d0407baSopenharmony_ci case LINUX_REBOOT_CMD_KEXEC: 4043d0407baSopenharmony_ci ret = kernel_kexec(); 4053d0407baSopenharmony_ci break; 4063d0407baSopenharmony_ci#endif 4073d0407baSopenharmony_ci 4083d0407baSopenharmony_ci#ifdef CONFIG_HIBERNATION 4093d0407baSopenharmony_ci case LINUX_REBOOT_CMD_SW_SUSPEND: 4103d0407baSopenharmony_ci ret = hibernate(); 4113d0407baSopenharmony_ci break; 4123d0407baSopenharmony_ci#endif 4133d0407baSopenharmony_ci 4143d0407baSopenharmony_ci default: 4153d0407baSopenharmony_ci ret = -EINVAL; 4163d0407baSopenharmony_ci break; 4173d0407baSopenharmony_ci } 4183d0407baSopenharmony_ci mutex_unlock(&system_transition_mutex); 4193d0407baSopenharmony_ci return ret; 4203d0407baSopenharmony_ci} 4213d0407baSopenharmony_ci 4223d0407baSopenharmony_cistatic void deferred_cad(struct work_struct *dummy) 4233d0407baSopenharmony_ci{ 4243d0407baSopenharmony_ci kernel_restart(NULL); 4253d0407baSopenharmony_ci} 4263d0407baSopenharmony_ci 4273d0407baSopenharmony_ci/* 4283d0407baSopenharmony_ci * This function gets called by ctrl-alt-del - ie the keyboard interrupt. 4293d0407baSopenharmony_ci * As it's called within an interrupt, it may NOT sync: the only choice 4303d0407baSopenharmony_ci * is whether to reboot at once, or just ignore the ctrl-alt-del. 4313d0407baSopenharmony_ci */ 4323d0407baSopenharmony_civoid ctrl_alt_del(void) 4333d0407baSopenharmony_ci{ 4343d0407baSopenharmony_ci static DECLARE_WORK(cad_work, deferred_cad); 4353d0407baSopenharmony_ci 4363d0407baSopenharmony_ci if (C_A_D) { 4373d0407baSopenharmony_ci schedule_work(&cad_work); 4383d0407baSopenharmony_ci } else { 4393d0407baSopenharmony_ci kill_cad_pid(SIGINT, 1); 4403d0407baSopenharmony_ci } 4413d0407baSopenharmony_ci} 4423d0407baSopenharmony_ci 4433d0407baSopenharmony_cichar poweroff_cmd[POWEROFF_CMD_PATH_LEN] = "/sbin/poweroff"; 4443d0407baSopenharmony_cistatic const char reboot_cmd[] = "/sbin/reboot"; 4453d0407baSopenharmony_ci 4463d0407baSopenharmony_cistatic int run_cmd(const char *cmd) 4473d0407baSopenharmony_ci{ 4483d0407baSopenharmony_ci char **argv; 4493d0407baSopenharmony_ci static char *envp[] = {"HOME=/", "PATH=/sbin:/bin:/usr/sbin:/usr/bin", NULL}; 4503d0407baSopenharmony_ci int ret; 4513d0407baSopenharmony_ci argv = argv_split(GFP_KERNEL, cmd, NULL); 4523d0407baSopenharmony_ci if (argv) { 4533d0407baSopenharmony_ci ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC); 4543d0407baSopenharmony_ci argv_free(argv); 4553d0407baSopenharmony_ci } else { 4563d0407baSopenharmony_ci ret = -ENOMEM; 4573d0407baSopenharmony_ci } 4583d0407baSopenharmony_ci 4593d0407baSopenharmony_ci return ret; 4603d0407baSopenharmony_ci} 4613d0407baSopenharmony_ci 4623d0407baSopenharmony_cistatic int __orderly_reboot(void) 4633d0407baSopenharmony_ci{ 4643d0407baSopenharmony_ci int ret; 4653d0407baSopenharmony_ci 4663d0407baSopenharmony_ci ret = run_cmd(reboot_cmd); 4673d0407baSopenharmony_ci if (ret) { 4683d0407baSopenharmony_ci pr_warn("Failed to start orderly reboot: forcing the issue\n"); 4693d0407baSopenharmony_ci emergency_sync(); 4703d0407baSopenharmony_ci kernel_restart(NULL); 4713d0407baSopenharmony_ci } 4723d0407baSopenharmony_ci 4733d0407baSopenharmony_ci return ret; 4743d0407baSopenharmony_ci} 4753d0407baSopenharmony_ci 4763d0407baSopenharmony_cistatic int __orderly_poweroff(bool force) 4773d0407baSopenharmony_ci{ 4783d0407baSopenharmony_ci int ret; 4793d0407baSopenharmony_ci 4803d0407baSopenharmony_ci ret = run_cmd(poweroff_cmd); 4813d0407baSopenharmony_ci if (ret && force) { 4823d0407baSopenharmony_ci pr_warn("Failed to start orderly shutdown: forcing the issue\n"); 4833d0407baSopenharmony_ci 4843d0407baSopenharmony_ci /* 4853d0407baSopenharmony_ci * I guess this should try to kick off some daemon to sync and 4863d0407baSopenharmony_ci * poweroff asap. Or not even bother syncing if we're doing an 4873d0407baSopenharmony_ci * emergency shutdown? 4883d0407baSopenharmony_ci */ 4893d0407baSopenharmony_ci emergency_sync(); 4903d0407baSopenharmony_ci kernel_power_off(); 4913d0407baSopenharmony_ci } 4923d0407baSopenharmony_ci 4933d0407baSopenharmony_ci return ret; 4943d0407baSopenharmony_ci} 4953d0407baSopenharmony_ci 4963d0407baSopenharmony_cistatic bool poweroff_force; 4973d0407baSopenharmony_ci 4983d0407baSopenharmony_cistatic void poweroff_work_func(struct work_struct *work) 4993d0407baSopenharmony_ci{ 5003d0407baSopenharmony_ci __orderly_poweroff(poweroff_force); 5013d0407baSopenharmony_ci} 5023d0407baSopenharmony_ci 5033d0407baSopenharmony_cistatic DECLARE_WORK(poweroff_work, poweroff_work_func); 5043d0407baSopenharmony_ci 5053d0407baSopenharmony_ci/** 5063d0407baSopenharmony_ci * orderly_poweroff - Trigger an orderly system poweroff 5073d0407baSopenharmony_ci * @force: force poweroff if command execution fails 5083d0407baSopenharmony_ci * 5093d0407baSopenharmony_ci * This may be called from any context to trigger a system shutdown. 5103d0407baSopenharmony_ci * If the orderly shutdown fails, it will force an immediate shutdown. 5113d0407baSopenharmony_ci */ 5123d0407baSopenharmony_civoid orderly_poweroff(bool force) 5133d0407baSopenharmony_ci{ 5143d0407baSopenharmony_ci if (force) { /* do not override the pending "true" */ 5153d0407baSopenharmony_ci poweroff_force = true; 5163d0407baSopenharmony_ci } 5173d0407baSopenharmony_ci schedule_work(&poweroff_work); 5183d0407baSopenharmony_ci} 5193d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(orderly_poweroff); 5203d0407baSopenharmony_ci 5213d0407baSopenharmony_cistatic void reboot_work_func(struct work_struct *work) 5223d0407baSopenharmony_ci{ 5233d0407baSopenharmony_ci __orderly_reboot(); 5243d0407baSopenharmony_ci} 5253d0407baSopenharmony_ci 5263d0407baSopenharmony_cistatic DECLARE_WORK(reboot_work, reboot_work_func); 5273d0407baSopenharmony_ci 5283d0407baSopenharmony_ci/** 5293d0407baSopenharmony_ci * orderly_reboot - Trigger an orderly system reboot 5303d0407baSopenharmony_ci * 5313d0407baSopenharmony_ci * This may be called from any context to trigger a system reboot. 5323d0407baSopenharmony_ci * If the orderly reboot fails, it will force an immediate reboot. 5333d0407baSopenharmony_ci */ 5343d0407baSopenharmony_civoid orderly_reboot(void) 5353d0407baSopenharmony_ci{ 5363d0407baSopenharmony_ci schedule_work(&reboot_work); 5373d0407baSopenharmony_ci} 5383d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(orderly_reboot); 5393d0407baSopenharmony_ci 5403d0407baSopenharmony_cistatic int __init reboot_setup(char *str) 5413d0407baSopenharmony_ci{ 5423d0407baSopenharmony_ci for (;;) { 5433d0407baSopenharmony_ci enum reboot_mode *mode; 5443d0407baSopenharmony_ci 5453d0407baSopenharmony_ci /* 5463d0407baSopenharmony_ci * Having anything passed on the command line via 5473d0407baSopenharmony_ci * reboot= will cause us to disable DMI checking 5483d0407baSopenharmony_ci * below. 5493d0407baSopenharmony_ci */ 5503d0407baSopenharmony_ci reboot_default = 0; 5513d0407baSopenharmony_ci 5523d0407baSopenharmony_ci if (!strncmp(str, "panic_", 6)) { 5533d0407baSopenharmony_ci mode = &panic_reboot_mode; 5543d0407baSopenharmony_ci str += 6; 5553d0407baSopenharmony_ci } else { 5563d0407baSopenharmony_ci mode = &reboot_mode; 5573d0407baSopenharmony_ci } 5583d0407baSopenharmony_ci 5593d0407baSopenharmony_ci switch (*str) { 5603d0407baSopenharmony_ci case 'w': 5613d0407baSopenharmony_ci *mode = REBOOT_WARM; 5623d0407baSopenharmony_ci break; 5633d0407baSopenharmony_ci 5643d0407baSopenharmony_ci case 'c': 5653d0407baSopenharmony_ci *mode = REBOOT_COLD; 5663d0407baSopenharmony_ci break; 5673d0407baSopenharmony_ci 5683d0407baSopenharmony_ci case 'h': 5693d0407baSopenharmony_ci *mode = REBOOT_HARD; 5703d0407baSopenharmony_ci break; 5713d0407baSopenharmony_ci 5723d0407baSopenharmony_ci case 's': 5733d0407baSopenharmony_ci if (isdigit(*(str + 1))) { 5743d0407baSopenharmony_ci reboot_cpu = simple_strtoul(str + 1, NULL, 0); 5753d0407baSopenharmony_ci } else if (str[1] == 'm' && str[2] == 'p' && isdigit(*(str + 3))) { 5763d0407baSopenharmony_ci reboot_cpu = simple_strtoul(str + 3, NULL, 0); 5773d0407baSopenharmony_ci } else { 5783d0407baSopenharmony_ci *mode = REBOOT_SOFT; 5793d0407baSopenharmony_ci } 5803d0407baSopenharmony_ci if (reboot_cpu >= num_possible_cpus()) { 5813d0407baSopenharmony_ci pr_err("Ignoring the CPU number in reboot= option. " 5823d0407baSopenharmony_ci "CPU %d exceeds possible cpu number %d\n", 5833d0407baSopenharmony_ci reboot_cpu, num_possible_cpus()); 5843d0407baSopenharmony_ci reboot_cpu = 0; 5853d0407baSopenharmony_ci break; 5863d0407baSopenharmony_ci } 5873d0407baSopenharmony_ci break; 5883d0407baSopenharmony_ci 5893d0407baSopenharmony_ci case 'g': 5903d0407baSopenharmony_ci *mode = REBOOT_GPIO; 5913d0407baSopenharmony_ci break; 5923d0407baSopenharmony_ci 5933d0407baSopenharmony_ci case 'b': 5943d0407baSopenharmony_ci case 'a': 5953d0407baSopenharmony_ci case 'k': 5963d0407baSopenharmony_ci case 't': 5973d0407baSopenharmony_ci case 'e': 5983d0407baSopenharmony_ci case 'p': 5993d0407baSopenharmony_ci reboot_type = *str; 6003d0407baSopenharmony_ci break; 6013d0407baSopenharmony_ci 6023d0407baSopenharmony_ci case 'f': 6033d0407baSopenharmony_ci reboot_force = 1; 6043d0407baSopenharmony_ci break; 6053d0407baSopenharmony_ci } 6063d0407baSopenharmony_ci 6073d0407baSopenharmony_ci str = strchr(str, ','); 6083d0407baSopenharmony_ci if (str) { 6093d0407baSopenharmony_ci str++; 6103d0407baSopenharmony_ci } else { 6113d0407baSopenharmony_ci break; 6123d0407baSopenharmony_ci } 6133d0407baSopenharmony_ci } 6143d0407baSopenharmony_ci return 1; 6153d0407baSopenharmony_ci} 6163d0407baSopenharmony_ci__setup("reboot=", reboot_setup); 617