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