18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *	Linux Magic System Request Key Hacks
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *	(c) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
68c2ecf20Sopenharmony_ci *	based on ideas by Pavel Machek <pavel@atrey.karlin.mff.cuni.cz>
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci *	(c) 2000 Crutcher Dunnavant <crutcher+kernel@datastacks.com>
98c2ecf20Sopenharmony_ci *	overhauled to use key registration
108c2ecf20Sopenharmony_ci *	based upon discusions in irc://irc.openprojects.net/#kernelnewbies
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci *	Copyright (c) 2010 Dmitry Torokhov
138c2ecf20Sopenharmony_ci *	Input handler conversion
148c2ecf20Sopenharmony_ci */
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include <linux/sched/signal.h>
198c2ecf20Sopenharmony_ci#include <linux/sched/rt.h>
208c2ecf20Sopenharmony_ci#include <linux/sched/debug.h>
218c2ecf20Sopenharmony_ci#include <linux/sched/task.h>
228c2ecf20Sopenharmony_ci#include <linux/ctype.h>
238c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
248c2ecf20Sopenharmony_ci#include <linux/mm.h>
258c2ecf20Sopenharmony_ci#include <linux/fs.h>
268c2ecf20Sopenharmony_ci#include <linux/mount.h>
278c2ecf20Sopenharmony_ci#include <linux/kdev_t.h>
288c2ecf20Sopenharmony_ci#include <linux/major.h>
298c2ecf20Sopenharmony_ci#include <linux/reboot.h>
308c2ecf20Sopenharmony_ci#include <linux/sysrq.h>
318c2ecf20Sopenharmony_ci#include <linux/kbd_kern.h>
328c2ecf20Sopenharmony_ci#include <linux/proc_fs.h>
338c2ecf20Sopenharmony_ci#include <linux/nmi.h>
348c2ecf20Sopenharmony_ci#include <linux/quotaops.h>
358c2ecf20Sopenharmony_ci#include <linux/perf_event.h>
368c2ecf20Sopenharmony_ci#include <linux/kernel.h>
378c2ecf20Sopenharmony_ci#include <linux/module.h>
388c2ecf20Sopenharmony_ci#include <linux/suspend.h>
398c2ecf20Sopenharmony_ci#include <linux/writeback.h>
408c2ecf20Sopenharmony_ci#include <linux/swap.h>
418c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
428c2ecf20Sopenharmony_ci#include <linux/vt_kern.h>
438c2ecf20Sopenharmony_ci#include <linux/workqueue.h>
448c2ecf20Sopenharmony_ci#include <linux/hrtimer.h>
458c2ecf20Sopenharmony_ci#include <linux/oom.h>
468c2ecf20Sopenharmony_ci#include <linux/slab.h>
478c2ecf20Sopenharmony_ci#include <linux/input.h>
488c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
498c2ecf20Sopenharmony_ci#include <linux/moduleparam.h>
508c2ecf20Sopenharmony_ci#include <linux/jiffies.h>
518c2ecf20Sopenharmony_ci#include <linux/syscalls.h>
528c2ecf20Sopenharmony_ci#include <linux/of.h>
538c2ecf20Sopenharmony_ci#include <linux/rcupdate.h>
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci#include <asm/ptrace.h>
568c2ecf20Sopenharmony_ci#include <asm/irq_regs.h>
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci/* Whether we react on sysrq keys or just ignore them */
598c2ecf20Sopenharmony_cistatic int __read_mostly sysrq_enabled = CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE;
608c2ecf20Sopenharmony_cistatic bool __read_mostly sysrq_always_enabled;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_cistatic bool sysrq_on(void)
638c2ecf20Sopenharmony_ci{
648c2ecf20Sopenharmony_ci	return sysrq_enabled || sysrq_always_enabled;
658c2ecf20Sopenharmony_ci}
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci/**
688c2ecf20Sopenharmony_ci * sysrq_mask - Getter for sysrq_enabled mask.
698c2ecf20Sopenharmony_ci *
708c2ecf20Sopenharmony_ci * Return: 1 if sysrq is always enabled, enabled sysrq_key_op mask otherwise.
718c2ecf20Sopenharmony_ci */
728c2ecf20Sopenharmony_ciint sysrq_mask(void)
738c2ecf20Sopenharmony_ci{
748c2ecf20Sopenharmony_ci	if (sysrq_always_enabled)
758c2ecf20Sopenharmony_ci		return 1;
768c2ecf20Sopenharmony_ci	return sysrq_enabled;
778c2ecf20Sopenharmony_ci}
788c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sysrq_mask);
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci/*
818c2ecf20Sopenharmony_ci * A value of 1 means 'all', other nonzero values are an op mask:
828c2ecf20Sopenharmony_ci */
838c2ecf20Sopenharmony_cistatic bool sysrq_on_mask(int mask)
848c2ecf20Sopenharmony_ci{
858c2ecf20Sopenharmony_ci	return sysrq_always_enabled ||
868c2ecf20Sopenharmony_ci	       sysrq_enabled == 1 ||
878c2ecf20Sopenharmony_ci	       (sysrq_enabled & mask);
888c2ecf20Sopenharmony_ci}
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_cistatic int __init sysrq_always_enabled_setup(char *str)
918c2ecf20Sopenharmony_ci{
928c2ecf20Sopenharmony_ci	sysrq_always_enabled = true;
938c2ecf20Sopenharmony_ci	pr_info("sysrq always enabled.\n");
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	return 1;
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci__setup("sysrq_always_enabled", sysrq_always_enabled_setup);
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_cistatic void sysrq_handle_loglevel(int key)
1028c2ecf20Sopenharmony_ci{
1038c2ecf20Sopenharmony_ci	int i;
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	i = key - '0';
1068c2ecf20Sopenharmony_ci	console_loglevel = CONSOLE_LOGLEVEL_DEFAULT;
1078c2ecf20Sopenharmony_ci	pr_info("Loglevel set to %d\n", i);
1088c2ecf20Sopenharmony_ci	console_loglevel = i;
1098c2ecf20Sopenharmony_ci}
1108c2ecf20Sopenharmony_cistatic const struct sysrq_key_op sysrq_loglevel_op = {
1118c2ecf20Sopenharmony_ci	.handler	= sysrq_handle_loglevel,
1128c2ecf20Sopenharmony_ci	.help_msg	= "loglevel(0-9)",
1138c2ecf20Sopenharmony_ci	.action_msg	= "Changing Loglevel",
1148c2ecf20Sopenharmony_ci	.enable_mask	= SYSRQ_ENABLE_LOG,
1158c2ecf20Sopenharmony_ci};
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci#ifdef CONFIG_VT
1188c2ecf20Sopenharmony_cistatic void sysrq_handle_SAK(int key)
1198c2ecf20Sopenharmony_ci{
1208c2ecf20Sopenharmony_ci	struct work_struct *SAK_work = &vc_cons[fg_console].SAK_work;
1218c2ecf20Sopenharmony_ci	schedule_work(SAK_work);
1228c2ecf20Sopenharmony_ci}
1238c2ecf20Sopenharmony_cistatic const struct sysrq_key_op sysrq_SAK_op = {
1248c2ecf20Sopenharmony_ci	.handler	= sysrq_handle_SAK,
1258c2ecf20Sopenharmony_ci	.help_msg	= "sak(k)",
1268c2ecf20Sopenharmony_ci	.action_msg	= "SAK",
1278c2ecf20Sopenharmony_ci	.enable_mask	= SYSRQ_ENABLE_KEYBOARD,
1288c2ecf20Sopenharmony_ci};
1298c2ecf20Sopenharmony_ci#else
1308c2ecf20Sopenharmony_ci#define sysrq_SAK_op (*(const struct sysrq_key_op *)NULL)
1318c2ecf20Sopenharmony_ci#endif
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci#ifdef CONFIG_VT
1348c2ecf20Sopenharmony_cistatic void sysrq_handle_unraw(int key)
1358c2ecf20Sopenharmony_ci{
1368c2ecf20Sopenharmony_ci	vt_reset_unicode(fg_console);
1378c2ecf20Sopenharmony_ci}
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_cistatic const struct sysrq_key_op sysrq_unraw_op = {
1408c2ecf20Sopenharmony_ci	.handler	= sysrq_handle_unraw,
1418c2ecf20Sopenharmony_ci	.help_msg	= "unraw(r)",
1428c2ecf20Sopenharmony_ci	.action_msg	= "Keyboard mode set to system default",
1438c2ecf20Sopenharmony_ci	.enable_mask	= SYSRQ_ENABLE_KEYBOARD,
1448c2ecf20Sopenharmony_ci};
1458c2ecf20Sopenharmony_ci#else
1468c2ecf20Sopenharmony_ci#define sysrq_unraw_op (*(const struct sysrq_key_op *)NULL)
1478c2ecf20Sopenharmony_ci#endif /* CONFIG_VT */
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_cistatic void sysrq_handle_crash(int key)
1508c2ecf20Sopenharmony_ci{
1518c2ecf20Sopenharmony_ci	/* release the RCU read lock before crashing */
1528c2ecf20Sopenharmony_ci	rcu_read_unlock();
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	panic("sysrq triggered crash\n");
1558c2ecf20Sopenharmony_ci}
1568c2ecf20Sopenharmony_cistatic const struct sysrq_key_op sysrq_crash_op = {
1578c2ecf20Sopenharmony_ci	.handler	= sysrq_handle_crash,
1588c2ecf20Sopenharmony_ci	.help_msg	= "crash(c)",
1598c2ecf20Sopenharmony_ci	.action_msg	= "Trigger a crash",
1608c2ecf20Sopenharmony_ci	.enable_mask	= SYSRQ_ENABLE_DUMP,
1618c2ecf20Sopenharmony_ci};
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_cistatic void sysrq_handle_reboot(int key)
1648c2ecf20Sopenharmony_ci{
1658c2ecf20Sopenharmony_ci	lockdep_off();
1668c2ecf20Sopenharmony_ci	local_irq_enable();
1678c2ecf20Sopenharmony_ci	emergency_restart();
1688c2ecf20Sopenharmony_ci}
1698c2ecf20Sopenharmony_cistatic const struct sysrq_key_op sysrq_reboot_op = {
1708c2ecf20Sopenharmony_ci	.handler	= sysrq_handle_reboot,
1718c2ecf20Sopenharmony_ci	.help_msg	= "reboot(b)",
1728c2ecf20Sopenharmony_ci	.action_msg	= "Resetting",
1738c2ecf20Sopenharmony_ci	.enable_mask	= SYSRQ_ENABLE_BOOT,
1748c2ecf20Sopenharmony_ci};
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ciconst struct sysrq_key_op *__sysrq_reboot_op = &sysrq_reboot_op;
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_cistatic void sysrq_handle_sync(int key)
1798c2ecf20Sopenharmony_ci{
1808c2ecf20Sopenharmony_ci	emergency_sync();
1818c2ecf20Sopenharmony_ci}
1828c2ecf20Sopenharmony_cistatic const struct sysrq_key_op sysrq_sync_op = {
1838c2ecf20Sopenharmony_ci	.handler	= sysrq_handle_sync,
1848c2ecf20Sopenharmony_ci	.help_msg	= "sync(s)",
1858c2ecf20Sopenharmony_ci	.action_msg	= "Emergency Sync",
1868c2ecf20Sopenharmony_ci	.enable_mask	= SYSRQ_ENABLE_SYNC,
1878c2ecf20Sopenharmony_ci};
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_cistatic void sysrq_handle_show_timers(int key)
1908c2ecf20Sopenharmony_ci{
1918c2ecf20Sopenharmony_ci	sysrq_timer_list_show();
1928c2ecf20Sopenharmony_ci}
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_cistatic const struct sysrq_key_op sysrq_show_timers_op = {
1958c2ecf20Sopenharmony_ci	.handler	= sysrq_handle_show_timers,
1968c2ecf20Sopenharmony_ci	.help_msg	= "show-all-timers(q)",
1978c2ecf20Sopenharmony_ci	.action_msg	= "Show clockevent devices & pending hrtimers (no others)",
1988c2ecf20Sopenharmony_ci};
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_cistatic void sysrq_handle_mountro(int key)
2018c2ecf20Sopenharmony_ci{
2028c2ecf20Sopenharmony_ci	emergency_remount();
2038c2ecf20Sopenharmony_ci}
2048c2ecf20Sopenharmony_cistatic const struct sysrq_key_op sysrq_mountro_op = {
2058c2ecf20Sopenharmony_ci	.handler	= sysrq_handle_mountro,
2068c2ecf20Sopenharmony_ci	.help_msg	= "unmount(u)",
2078c2ecf20Sopenharmony_ci	.action_msg	= "Emergency Remount R/O",
2088c2ecf20Sopenharmony_ci	.enable_mask	= SYSRQ_ENABLE_REMOUNT,
2098c2ecf20Sopenharmony_ci};
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci#ifdef CONFIG_LOCKDEP
2128c2ecf20Sopenharmony_cistatic void sysrq_handle_showlocks(int key)
2138c2ecf20Sopenharmony_ci{
2148c2ecf20Sopenharmony_ci	debug_show_all_locks();
2158c2ecf20Sopenharmony_ci}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_cistatic const struct sysrq_key_op sysrq_showlocks_op = {
2188c2ecf20Sopenharmony_ci	.handler	= sysrq_handle_showlocks,
2198c2ecf20Sopenharmony_ci	.help_msg	= "show-all-locks(d)",
2208c2ecf20Sopenharmony_ci	.action_msg	= "Show Locks Held",
2218c2ecf20Sopenharmony_ci};
2228c2ecf20Sopenharmony_ci#else
2238c2ecf20Sopenharmony_ci#define sysrq_showlocks_op (*(const struct sysrq_key_op *)NULL)
2248c2ecf20Sopenharmony_ci#endif
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci#ifdef CONFIG_SMP
2278c2ecf20Sopenharmony_cistatic DEFINE_RAW_SPINLOCK(show_lock);
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_cistatic void showacpu(void *dummy)
2308c2ecf20Sopenharmony_ci{
2318c2ecf20Sopenharmony_ci	unsigned long flags;
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	/* Idle CPUs have no interesting backtrace. */
2348c2ecf20Sopenharmony_ci	if (idle_cpu(smp_processor_id())) {
2358c2ecf20Sopenharmony_ci		pr_info("CPU%d: backtrace skipped as idling\n", smp_processor_id());
2368c2ecf20Sopenharmony_ci		return;
2378c2ecf20Sopenharmony_ci	}
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&show_lock, flags);
2408c2ecf20Sopenharmony_ci	pr_info("CPU%d:\n", smp_processor_id());
2418c2ecf20Sopenharmony_ci	show_stack(NULL, NULL, KERN_INFO);
2428c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&show_lock, flags);
2438c2ecf20Sopenharmony_ci}
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_cistatic void sysrq_showregs_othercpus(struct work_struct *dummy)
2468c2ecf20Sopenharmony_ci{
2478c2ecf20Sopenharmony_ci	smp_call_function(showacpu, NULL, 0);
2488c2ecf20Sopenharmony_ci}
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_cistatic DECLARE_WORK(sysrq_showallcpus, sysrq_showregs_othercpus);
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_cistatic void sysrq_handle_showallcpus(int key)
2538c2ecf20Sopenharmony_ci{
2548c2ecf20Sopenharmony_ci	/*
2558c2ecf20Sopenharmony_ci	 * Fall back to the workqueue based printing if the
2568c2ecf20Sopenharmony_ci	 * backtrace printing did not succeed or the
2578c2ecf20Sopenharmony_ci	 * architecture has no support for it:
2588c2ecf20Sopenharmony_ci	 */
2598c2ecf20Sopenharmony_ci	if (!trigger_all_cpu_backtrace()) {
2608c2ecf20Sopenharmony_ci		struct pt_regs *regs = NULL;
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci		if (in_irq())
2638c2ecf20Sopenharmony_ci			regs = get_irq_regs();
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci		pr_info("CPU%d:\n", get_cpu());
2668c2ecf20Sopenharmony_ci		if (regs)
2678c2ecf20Sopenharmony_ci			show_regs(regs);
2688c2ecf20Sopenharmony_ci		else
2698c2ecf20Sopenharmony_ci			show_stack(NULL, NULL, KERN_INFO);
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci		schedule_work(&sysrq_showallcpus);
2728c2ecf20Sopenharmony_ci		put_cpu();
2738c2ecf20Sopenharmony_ci	}
2748c2ecf20Sopenharmony_ci}
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_cistatic const struct sysrq_key_op sysrq_showallcpus_op = {
2778c2ecf20Sopenharmony_ci	.handler	= sysrq_handle_showallcpus,
2788c2ecf20Sopenharmony_ci	.help_msg	= "show-backtrace-all-active-cpus(l)",
2798c2ecf20Sopenharmony_ci	.action_msg	= "Show backtrace of all active CPUs",
2808c2ecf20Sopenharmony_ci	.enable_mask	= SYSRQ_ENABLE_DUMP,
2818c2ecf20Sopenharmony_ci};
2828c2ecf20Sopenharmony_ci#endif
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_cistatic void sysrq_handle_showregs(int key)
2858c2ecf20Sopenharmony_ci{
2868c2ecf20Sopenharmony_ci	struct pt_regs *regs = NULL;
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	if (in_irq())
2898c2ecf20Sopenharmony_ci		regs = get_irq_regs();
2908c2ecf20Sopenharmony_ci	if (regs)
2918c2ecf20Sopenharmony_ci		show_regs(regs);
2928c2ecf20Sopenharmony_ci	perf_event_print_debug();
2938c2ecf20Sopenharmony_ci}
2948c2ecf20Sopenharmony_cistatic const struct sysrq_key_op sysrq_showregs_op = {
2958c2ecf20Sopenharmony_ci	.handler	= sysrq_handle_showregs,
2968c2ecf20Sopenharmony_ci	.help_msg	= "show-registers(p)",
2978c2ecf20Sopenharmony_ci	.action_msg	= "Show Regs",
2988c2ecf20Sopenharmony_ci	.enable_mask	= SYSRQ_ENABLE_DUMP,
2998c2ecf20Sopenharmony_ci};
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_cistatic void sysrq_handle_showstate(int key)
3028c2ecf20Sopenharmony_ci{
3038c2ecf20Sopenharmony_ci	show_state();
3048c2ecf20Sopenharmony_ci	show_workqueue_state();
3058c2ecf20Sopenharmony_ci}
3068c2ecf20Sopenharmony_cistatic const struct sysrq_key_op sysrq_showstate_op = {
3078c2ecf20Sopenharmony_ci	.handler	= sysrq_handle_showstate,
3088c2ecf20Sopenharmony_ci	.help_msg	= "show-task-states(t)",
3098c2ecf20Sopenharmony_ci	.action_msg	= "Show State",
3108c2ecf20Sopenharmony_ci	.enable_mask	= SYSRQ_ENABLE_DUMP,
3118c2ecf20Sopenharmony_ci};
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_cistatic void sysrq_handle_showstate_blocked(int key)
3148c2ecf20Sopenharmony_ci{
3158c2ecf20Sopenharmony_ci	show_state_filter(TASK_UNINTERRUPTIBLE);
3168c2ecf20Sopenharmony_ci}
3178c2ecf20Sopenharmony_cistatic const struct sysrq_key_op sysrq_showstate_blocked_op = {
3188c2ecf20Sopenharmony_ci	.handler	= sysrq_handle_showstate_blocked,
3198c2ecf20Sopenharmony_ci	.help_msg	= "show-blocked-tasks(w)",
3208c2ecf20Sopenharmony_ci	.action_msg	= "Show Blocked State",
3218c2ecf20Sopenharmony_ci	.enable_mask	= SYSRQ_ENABLE_DUMP,
3228c2ecf20Sopenharmony_ci};
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci#ifdef CONFIG_TRACING
3258c2ecf20Sopenharmony_ci#include <linux/ftrace.h>
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_cistatic void sysrq_ftrace_dump(int key)
3288c2ecf20Sopenharmony_ci{
3298c2ecf20Sopenharmony_ci	ftrace_dump(DUMP_ALL);
3308c2ecf20Sopenharmony_ci}
3318c2ecf20Sopenharmony_cistatic const struct sysrq_key_op sysrq_ftrace_dump_op = {
3328c2ecf20Sopenharmony_ci	.handler	= sysrq_ftrace_dump,
3338c2ecf20Sopenharmony_ci	.help_msg	= "dump-ftrace-buffer(z)",
3348c2ecf20Sopenharmony_ci	.action_msg	= "Dump ftrace buffer",
3358c2ecf20Sopenharmony_ci	.enable_mask	= SYSRQ_ENABLE_DUMP,
3368c2ecf20Sopenharmony_ci};
3378c2ecf20Sopenharmony_ci#else
3388c2ecf20Sopenharmony_ci#define sysrq_ftrace_dump_op (*(const struct sysrq_key_op *)NULL)
3398c2ecf20Sopenharmony_ci#endif
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_cistatic void sysrq_handle_showmem(int key)
3428c2ecf20Sopenharmony_ci{
3438c2ecf20Sopenharmony_ci	show_mem(0, NULL);
3448c2ecf20Sopenharmony_ci}
3458c2ecf20Sopenharmony_cistatic const struct sysrq_key_op sysrq_showmem_op = {
3468c2ecf20Sopenharmony_ci	.handler	= sysrq_handle_showmem,
3478c2ecf20Sopenharmony_ci	.help_msg	= "show-memory-usage(m)",
3488c2ecf20Sopenharmony_ci	.action_msg	= "Show Memory",
3498c2ecf20Sopenharmony_ci	.enable_mask	= SYSRQ_ENABLE_DUMP,
3508c2ecf20Sopenharmony_ci};
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci/*
3538c2ecf20Sopenharmony_ci * Signal sysrq helper function.  Sends a signal to all user processes.
3548c2ecf20Sopenharmony_ci */
3558c2ecf20Sopenharmony_cistatic void send_sig_all(int sig)
3568c2ecf20Sopenharmony_ci{
3578c2ecf20Sopenharmony_ci	struct task_struct *p;
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	read_lock(&tasklist_lock);
3608c2ecf20Sopenharmony_ci	for_each_process(p) {
3618c2ecf20Sopenharmony_ci		if (p->flags & PF_KTHREAD)
3628c2ecf20Sopenharmony_ci			continue;
3638c2ecf20Sopenharmony_ci		if (is_global_init(p))
3648c2ecf20Sopenharmony_ci			continue;
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci		do_send_sig_info(sig, SEND_SIG_PRIV, p, PIDTYPE_MAX);
3678c2ecf20Sopenharmony_ci	}
3688c2ecf20Sopenharmony_ci	read_unlock(&tasklist_lock);
3698c2ecf20Sopenharmony_ci}
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_cistatic void sysrq_handle_term(int key)
3728c2ecf20Sopenharmony_ci{
3738c2ecf20Sopenharmony_ci	send_sig_all(SIGTERM);
3748c2ecf20Sopenharmony_ci	console_loglevel = CONSOLE_LOGLEVEL_DEBUG;
3758c2ecf20Sopenharmony_ci}
3768c2ecf20Sopenharmony_cistatic const struct sysrq_key_op sysrq_term_op = {
3778c2ecf20Sopenharmony_ci	.handler	= sysrq_handle_term,
3788c2ecf20Sopenharmony_ci	.help_msg	= "terminate-all-tasks(e)",
3798c2ecf20Sopenharmony_ci	.action_msg	= "Terminate All Tasks",
3808c2ecf20Sopenharmony_ci	.enable_mask	= SYSRQ_ENABLE_SIGNAL,
3818c2ecf20Sopenharmony_ci};
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_cistatic void moom_callback(struct work_struct *ignored)
3848c2ecf20Sopenharmony_ci{
3858c2ecf20Sopenharmony_ci	const gfp_t gfp_mask = GFP_KERNEL;
3868c2ecf20Sopenharmony_ci	struct oom_control oc = {
3878c2ecf20Sopenharmony_ci		.zonelist = node_zonelist(first_memory_node, gfp_mask),
3888c2ecf20Sopenharmony_ci		.nodemask = NULL,
3898c2ecf20Sopenharmony_ci		.memcg = NULL,
3908c2ecf20Sopenharmony_ci		.gfp_mask = gfp_mask,
3918c2ecf20Sopenharmony_ci		.order = -1,
3928c2ecf20Sopenharmony_ci	};
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	mutex_lock(&oom_lock);
3958c2ecf20Sopenharmony_ci	if (!out_of_memory(&oc))
3968c2ecf20Sopenharmony_ci		pr_info("OOM request ignored. No task eligible\n");
3978c2ecf20Sopenharmony_ci	mutex_unlock(&oom_lock);
3988c2ecf20Sopenharmony_ci}
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_cistatic DECLARE_WORK(moom_work, moom_callback);
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_cistatic void sysrq_handle_moom(int key)
4038c2ecf20Sopenharmony_ci{
4048c2ecf20Sopenharmony_ci	schedule_work(&moom_work);
4058c2ecf20Sopenharmony_ci}
4068c2ecf20Sopenharmony_cistatic const struct sysrq_key_op sysrq_moom_op = {
4078c2ecf20Sopenharmony_ci	.handler	= sysrq_handle_moom,
4088c2ecf20Sopenharmony_ci	.help_msg	= "memory-full-oom-kill(f)",
4098c2ecf20Sopenharmony_ci	.action_msg	= "Manual OOM execution",
4108c2ecf20Sopenharmony_ci	.enable_mask	= SYSRQ_ENABLE_SIGNAL,
4118c2ecf20Sopenharmony_ci};
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_cistatic void sysrq_handle_thaw(int key)
4148c2ecf20Sopenharmony_ci{
4158c2ecf20Sopenharmony_ci	emergency_thaw_all();
4168c2ecf20Sopenharmony_ci}
4178c2ecf20Sopenharmony_cistatic const struct sysrq_key_op sysrq_thaw_op = {
4188c2ecf20Sopenharmony_ci	.handler	= sysrq_handle_thaw,
4198c2ecf20Sopenharmony_ci	.help_msg	= "thaw-filesystems(j)",
4208c2ecf20Sopenharmony_ci	.action_msg	= "Emergency Thaw of all frozen filesystems",
4218c2ecf20Sopenharmony_ci	.enable_mask	= SYSRQ_ENABLE_SIGNAL,
4228c2ecf20Sopenharmony_ci};
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_cistatic void sysrq_handle_kill(int key)
4258c2ecf20Sopenharmony_ci{
4268c2ecf20Sopenharmony_ci	send_sig_all(SIGKILL);
4278c2ecf20Sopenharmony_ci	console_loglevel = CONSOLE_LOGLEVEL_DEBUG;
4288c2ecf20Sopenharmony_ci}
4298c2ecf20Sopenharmony_cistatic const struct sysrq_key_op sysrq_kill_op = {
4308c2ecf20Sopenharmony_ci	.handler	= sysrq_handle_kill,
4318c2ecf20Sopenharmony_ci	.help_msg	= "kill-all-tasks(i)",
4328c2ecf20Sopenharmony_ci	.action_msg	= "Kill All Tasks",
4338c2ecf20Sopenharmony_ci	.enable_mask	= SYSRQ_ENABLE_SIGNAL,
4348c2ecf20Sopenharmony_ci};
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_cistatic void sysrq_handle_unrt(int key)
4378c2ecf20Sopenharmony_ci{
4388c2ecf20Sopenharmony_ci	normalize_rt_tasks();
4398c2ecf20Sopenharmony_ci}
4408c2ecf20Sopenharmony_cistatic const struct sysrq_key_op sysrq_unrt_op = {
4418c2ecf20Sopenharmony_ci	.handler	= sysrq_handle_unrt,
4428c2ecf20Sopenharmony_ci	.help_msg	= "nice-all-RT-tasks(n)",
4438c2ecf20Sopenharmony_ci	.action_msg	= "Nice All RT Tasks",
4448c2ecf20Sopenharmony_ci	.enable_mask	= SYSRQ_ENABLE_RTNICE,
4458c2ecf20Sopenharmony_ci};
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci/* Key Operations table and lock */
4488c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(sysrq_key_table_lock);
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_cistatic const struct sysrq_key_op *sysrq_key_table[62] = {
4518c2ecf20Sopenharmony_ci	&sysrq_loglevel_op,		/* 0 */
4528c2ecf20Sopenharmony_ci	&sysrq_loglevel_op,		/* 1 */
4538c2ecf20Sopenharmony_ci	&sysrq_loglevel_op,		/* 2 */
4548c2ecf20Sopenharmony_ci	&sysrq_loglevel_op,		/* 3 */
4558c2ecf20Sopenharmony_ci	&sysrq_loglevel_op,		/* 4 */
4568c2ecf20Sopenharmony_ci	&sysrq_loglevel_op,		/* 5 */
4578c2ecf20Sopenharmony_ci	&sysrq_loglevel_op,		/* 6 */
4588c2ecf20Sopenharmony_ci	&sysrq_loglevel_op,		/* 7 */
4598c2ecf20Sopenharmony_ci	&sysrq_loglevel_op,		/* 8 */
4608c2ecf20Sopenharmony_ci	&sysrq_loglevel_op,		/* 9 */
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	/*
4638c2ecf20Sopenharmony_ci	 * a: Don't use for system provided sysrqs, it is handled specially on
4648c2ecf20Sopenharmony_ci	 * sparc and will never arrive.
4658c2ecf20Sopenharmony_ci	 */
4668c2ecf20Sopenharmony_ci	NULL,				/* a */
4678c2ecf20Sopenharmony_ci	&sysrq_reboot_op,		/* b */
4688c2ecf20Sopenharmony_ci	&sysrq_crash_op,		/* c */
4698c2ecf20Sopenharmony_ci	&sysrq_showlocks_op,		/* d */
4708c2ecf20Sopenharmony_ci	&sysrq_term_op,			/* e */
4718c2ecf20Sopenharmony_ci	&sysrq_moom_op,			/* f */
4728c2ecf20Sopenharmony_ci	/* g: May be registered for the kernel debugger */
4738c2ecf20Sopenharmony_ci	NULL,				/* g */
4748c2ecf20Sopenharmony_ci	NULL,				/* h - reserved for help */
4758c2ecf20Sopenharmony_ci	&sysrq_kill_op,			/* i */
4768c2ecf20Sopenharmony_ci#ifdef CONFIG_BLOCK
4778c2ecf20Sopenharmony_ci	&sysrq_thaw_op,			/* j */
4788c2ecf20Sopenharmony_ci#else
4798c2ecf20Sopenharmony_ci	NULL,				/* j */
4808c2ecf20Sopenharmony_ci#endif
4818c2ecf20Sopenharmony_ci	&sysrq_SAK_op,			/* k */
4828c2ecf20Sopenharmony_ci#ifdef CONFIG_SMP
4838c2ecf20Sopenharmony_ci	&sysrq_showallcpus_op,		/* l */
4848c2ecf20Sopenharmony_ci#else
4858c2ecf20Sopenharmony_ci	NULL,				/* l */
4868c2ecf20Sopenharmony_ci#endif
4878c2ecf20Sopenharmony_ci	&sysrq_showmem_op,		/* m */
4888c2ecf20Sopenharmony_ci	&sysrq_unrt_op,			/* n */
4898c2ecf20Sopenharmony_ci	/* o: This will often be registered as 'Off' at init time */
4908c2ecf20Sopenharmony_ci	NULL,				/* o */
4918c2ecf20Sopenharmony_ci	&sysrq_showregs_op,		/* p */
4928c2ecf20Sopenharmony_ci	&sysrq_show_timers_op,		/* q */
4938c2ecf20Sopenharmony_ci	&sysrq_unraw_op,		/* r */
4948c2ecf20Sopenharmony_ci	&sysrq_sync_op,			/* s */
4958c2ecf20Sopenharmony_ci	&sysrq_showstate_op,		/* t */
4968c2ecf20Sopenharmony_ci	&sysrq_mountro_op,		/* u */
4978c2ecf20Sopenharmony_ci	/* v: May be registered for frame buffer console restore */
4988c2ecf20Sopenharmony_ci	NULL,				/* v */
4998c2ecf20Sopenharmony_ci	&sysrq_showstate_blocked_op,	/* w */
5008c2ecf20Sopenharmony_ci	/* x: May be registered on mips for TLB dump */
5018c2ecf20Sopenharmony_ci	/* x: May be registered on ppc/powerpc for xmon */
5028c2ecf20Sopenharmony_ci	/* x: May be registered on sparc64 for global PMU dump */
5038c2ecf20Sopenharmony_ci	NULL,				/* x */
5048c2ecf20Sopenharmony_ci	/* y: May be registered on sparc64 for global register dump */
5058c2ecf20Sopenharmony_ci	NULL,				/* y */
5068c2ecf20Sopenharmony_ci	&sysrq_ftrace_dump_op,		/* z */
5078c2ecf20Sopenharmony_ci	NULL,				/* A */
5088c2ecf20Sopenharmony_ci	NULL,				/* B */
5098c2ecf20Sopenharmony_ci	NULL,				/* C */
5108c2ecf20Sopenharmony_ci	NULL,				/* D */
5118c2ecf20Sopenharmony_ci	NULL,				/* E */
5128c2ecf20Sopenharmony_ci	NULL,				/* F */
5138c2ecf20Sopenharmony_ci	NULL,				/* G */
5148c2ecf20Sopenharmony_ci	NULL,				/* H */
5158c2ecf20Sopenharmony_ci	NULL,				/* I */
5168c2ecf20Sopenharmony_ci	NULL,				/* J */
5178c2ecf20Sopenharmony_ci	NULL,				/* K */
5188c2ecf20Sopenharmony_ci	NULL,				/* L */
5198c2ecf20Sopenharmony_ci	NULL,				/* M */
5208c2ecf20Sopenharmony_ci	NULL,				/* N */
5218c2ecf20Sopenharmony_ci	NULL,				/* O */
5228c2ecf20Sopenharmony_ci	NULL,				/* P */
5238c2ecf20Sopenharmony_ci	NULL,				/* Q */
5248c2ecf20Sopenharmony_ci	NULL,				/* R */
5258c2ecf20Sopenharmony_ci	NULL,				/* S */
5268c2ecf20Sopenharmony_ci	NULL,				/* T */
5278c2ecf20Sopenharmony_ci	NULL,				/* U */
5288c2ecf20Sopenharmony_ci	NULL,				/* V */
5298c2ecf20Sopenharmony_ci	NULL,				/* W */
5308c2ecf20Sopenharmony_ci	NULL,				/* X */
5318c2ecf20Sopenharmony_ci	NULL,				/* Y */
5328c2ecf20Sopenharmony_ci	NULL,				/* Z */
5338c2ecf20Sopenharmony_ci};
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci/* key2index calculation, -1 on invalid index */
5368c2ecf20Sopenharmony_cistatic int sysrq_key_table_key2index(int key)
5378c2ecf20Sopenharmony_ci{
5388c2ecf20Sopenharmony_ci	int retval;
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	if ((key >= '0') && (key <= '9'))
5418c2ecf20Sopenharmony_ci		retval = key - '0';
5428c2ecf20Sopenharmony_ci	else if ((key >= 'a') && (key <= 'z'))
5438c2ecf20Sopenharmony_ci		retval = key + 10 - 'a';
5448c2ecf20Sopenharmony_ci	else if ((key >= 'A') && (key <= 'Z'))
5458c2ecf20Sopenharmony_ci		retval = key + 36 - 'A';
5468c2ecf20Sopenharmony_ci	else
5478c2ecf20Sopenharmony_ci		retval = -1;
5488c2ecf20Sopenharmony_ci	return retval;
5498c2ecf20Sopenharmony_ci}
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci/*
5528c2ecf20Sopenharmony_ci * get and put functions for the table, exposed to modules.
5538c2ecf20Sopenharmony_ci */
5548c2ecf20Sopenharmony_cistatic const struct sysrq_key_op *__sysrq_get_key_op(int key)
5558c2ecf20Sopenharmony_ci{
5568c2ecf20Sopenharmony_ci        const struct sysrq_key_op *op_p = NULL;
5578c2ecf20Sopenharmony_ci        int i;
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	i = sysrq_key_table_key2index(key);
5608c2ecf20Sopenharmony_ci	if (i != -1)
5618c2ecf20Sopenharmony_ci	        op_p = sysrq_key_table[i];
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci        return op_p;
5648c2ecf20Sopenharmony_ci}
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_cistatic void __sysrq_put_key_op(int key, const struct sysrq_key_op *op_p)
5678c2ecf20Sopenharmony_ci{
5688c2ecf20Sopenharmony_ci        int i = sysrq_key_table_key2index(key);
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci        if (i != -1)
5718c2ecf20Sopenharmony_ci                sysrq_key_table[i] = op_p;
5728c2ecf20Sopenharmony_ci}
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_civoid __handle_sysrq(int key, bool check_mask)
5758c2ecf20Sopenharmony_ci{
5768c2ecf20Sopenharmony_ci	const struct sysrq_key_op *op_p;
5778c2ecf20Sopenharmony_ci	int orig_log_level;
5788c2ecf20Sopenharmony_ci	int orig_suppress_printk;
5798c2ecf20Sopenharmony_ci	int i;
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	orig_suppress_printk = suppress_printk;
5828c2ecf20Sopenharmony_ci	suppress_printk = 0;
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci	rcu_sysrq_start();
5858c2ecf20Sopenharmony_ci	rcu_read_lock();
5868c2ecf20Sopenharmony_ci	/*
5878c2ecf20Sopenharmony_ci	 * Raise the apparent loglevel to maximum so that the sysrq header
5888c2ecf20Sopenharmony_ci	 * is shown to provide the user with positive feedback.  We do not
5898c2ecf20Sopenharmony_ci	 * simply emit this at KERN_EMERG as that would change message
5908c2ecf20Sopenharmony_ci	 * routing in the consumers of /proc/kmsg.
5918c2ecf20Sopenharmony_ci	 */
5928c2ecf20Sopenharmony_ci	orig_log_level = console_loglevel;
5938c2ecf20Sopenharmony_ci	console_loglevel = CONSOLE_LOGLEVEL_DEFAULT;
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci        op_p = __sysrq_get_key_op(key);
5968c2ecf20Sopenharmony_ci        if (op_p) {
5978c2ecf20Sopenharmony_ci		/*
5988c2ecf20Sopenharmony_ci		 * Should we check for enabled operations (/proc/sysrq-trigger
5998c2ecf20Sopenharmony_ci		 * should not) and is the invoked operation enabled?
6008c2ecf20Sopenharmony_ci		 */
6018c2ecf20Sopenharmony_ci		if (!check_mask || sysrq_on_mask(op_p->enable_mask)) {
6028c2ecf20Sopenharmony_ci			pr_info("%s\n", op_p->action_msg);
6038c2ecf20Sopenharmony_ci			console_loglevel = orig_log_level;
6048c2ecf20Sopenharmony_ci			op_p->handler(key);
6058c2ecf20Sopenharmony_ci		} else {
6068c2ecf20Sopenharmony_ci			pr_info("This sysrq operation is disabled.\n");
6078c2ecf20Sopenharmony_ci			console_loglevel = orig_log_level;
6088c2ecf20Sopenharmony_ci		}
6098c2ecf20Sopenharmony_ci	} else {
6108c2ecf20Sopenharmony_ci		pr_info("HELP : ");
6118c2ecf20Sopenharmony_ci		/* Only print the help msg once per handler */
6128c2ecf20Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(sysrq_key_table); i++) {
6138c2ecf20Sopenharmony_ci			if (sysrq_key_table[i]) {
6148c2ecf20Sopenharmony_ci				int j;
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci				for (j = 0; sysrq_key_table[i] !=
6178c2ecf20Sopenharmony_ci						sysrq_key_table[j]; j++)
6188c2ecf20Sopenharmony_ci					;
6198c2ecf20Sopenharmony_ci				if (j != i)
6208c2ecf20Sopenharmony_ci					continue;
6218c2ecf20Sopenharmony_ci				pr_cont("%s ", sysrq_key_table[i]->help_msg);
6228c2ecf20Sopenharmony_ci			}
6238c2ecf20Sopenharmony_ci		}
6248c2ecf20Sopenharmony_ci		pr_cont("\n");
6258c2ecf20Sopenharmony_ci		console_loglevel = orig_log_level;
6268c2ecf20Sopenharmony_ci	}
6278c2ecf20Sopenharmony_ci	rcu_read_unlock();
6288c2ecf20Sopenharmony_ci	rcu_sysrq_end();
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ci	suppress_printk = orig_suppress_printk;
6318c2ecf20Sopenharmony_ci}
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_civoid handle_sysrq(int key)
6348c2ecf20Sopenharmony_ci{
6358c2ecf20Sopenharmony_ci	if (sysrq_on())
6368c2ecf20Sopenharmony_ci		__handle_sysrq(key, true);
6378c2ecf20Sopenharmony_ci}
6388c2ecf20Sopenharmony_ciEXPORT_SYMBOL(handle_sysrq);
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_ci#ifdef CONFIG_INPUT
6418c2ecf20Sopenharmony_cistatic int sysrq_reset_downtime_ms;
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci/* Simple translation table for the SysRq keys */
6448c2ecf20Sopenharmony_cistatic const unsigned char sysrq_xlate[KEY_CNT] =
6458c2ecf20Sopenharmony_ci        "\000\0331234567890-=\177\t"                    /* 0x00 - 0x0f */
6468c2ecf20Sopenharmony_ci        "qwertyuiop[]\r\000as"                          /* 0x10 - 0x1f */
6478c2ecf20Sopenharmony_ci        "dfghjkl;'`\000\\zxcv"                          /* 0x20 - 0x2f */
6488c2ecf20Sopenharmony_ci        "bnm,./\000*\000 \000\201\202\203\204\205"      /* 0x30 - 0x3f */
6498c2ecf20Sopenharmony_ci        "\206\207\210\211\212\000\000789-456+1"         /* 0x40 - 0x4f */
6508c2ecf20Sopenharmony_ci        "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
6518c2ecf20Sopenharmony_ci        "\r\000/";                                      /* 0x60 - 0x6f */
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_cistruct sysrq_state {
6548c2ecf20Sopenharmony_ci	struct input_handle handle;
6558c2ecf20Sopenharmony_ci	struct work_struct reinject_work;
6568c2ecf20Sopenharmony_ci	unsigned long key_down[BITS_TO_LONGS(KEY_CNT)];
6578c2ecf20Sopenharmony_ci	unsigned int alt;
6588c2ecf20Sopenharmony_ci	unsigned int alt_use;
6598c2ecf20Sopenharmony_ci	unsigned int shift;
6608c2ecf20Sopenharmony_ci	unsigned int shift_use;
6618c2ecf20Sopenharmony_ci	bool active;
6628c2ecf20Sopenharmony_ci	bool need_reinject;
6638c2ecf20Sopenharmony_ci	bool reinjecting;
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci	/* reset sequence handling */
6668c2ecf20Sopenharmony_ci	bool reset_canceled;
6678c2ecf20Sopenharmony_ci	bool reset_requested;
6688c2ecf20Sopenharmony_ci	unsigned long reset_keybit[BITS_TO_LONGS(KEY_CNT)];
6698c2ecf20Sopenharmony_ci	int reset_seq_len;
6708c2ecf20Sopenharmony_ci	int reset_seq_cnt;
6718c2ecf20Sopenharmony_ci	int reset_seq_version;
6728c2ecf20Sopenharmony_ci	struct timer_list keyreset_timer;
6738c2ecf20Sopenharmony_ci};
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci#define SYSRQ_KEY_RESET_MAX	20 /* Should be plenty */
6768c2ecf20Sopenharmony_cistatic unsigned short sysrq_reset_seq[SYSRQ_KEY_RESET_MAX];
6778c2ecf20Sopenharmony_cistatic unsigned int sysrq_reset_seq_len;
6788c2ecf20Sopenharmony_cistatic unsigned int sysrq_reset_seq_version = 1;
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_cistatic void sysrq_parse_reset_sequence(struct sysrq_state *state)
6818c2ecf20Sopenharmony_ci{
6828c2ecf20Sopenharmony_ci	int i;
6838c2ecf20Sopenharmony_ci	unsigned short key;
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci	state->reset_seq_cnt = 0;
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	for (i = 0; i < sysrq_reset_seq_len; i++) {
6888c2ecf20Sopenharmony_ci		key = sysrq_reset_seq[i];
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_ci		if (key == KEY_RESERVED || key > KEY_MAX)
6918c2ecf20Sopenharmony_ci			break;
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci		__set_bit(key, state->reset_keybit);
6948c2ecf20Sopenharmony_ci		state->reset_seq_len++;
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci		if (test_bit(key, state->key_down))
6978c2ecf20Sopenharmony_ci			state->reset_seq_cnt++;
6988c2ecf20Sopenharmony_ci	}
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci	/* Disable reset until old keys are not released */
7018c2ecf20Sopenharmony_ci	state->reset_canceled = state->reset_seq_cnt != 0;
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci	state->reset_seq_version = sysrq_reset_seq_version;
7048c2ecf20Sopenharmony_ci}
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_cistatic void sysrq_do_reset(struct timer_list *t)
7078c2ecf20Sopenharmony_ci{
7088c2ecf20Sopenharmony_ci	struct sysrq_state *state = from_timer(state, t, keyreset_timer);
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci	state->reset_requested = true;
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci	orderly_reboot();
7138c2ecf20Sopenharmony_ci}
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_cistatic void sysrq_handle_reset_request(struct sysrq_state *state)
7168c2ecf20Sopenharmony_ci{
7178c2ecf20Sopenharmony_ci	if (state->reset_requested)
7188c2ecf20Sopenharmony_ci		__handle_sysrq(sysrq_xlate[KEY_B], false);
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci	if (sysrq_reset_downtime_ms)
7218c2ecf20Sopenharmony_ci		mod_timer(&state->keyreset_timer,
7228c2ecf20Sopenharmony_ci			jiffies + msecs_to_jiffies(sysrq_reset_downtime_ms));
7238c2ecf20Sopenharmony_ci	else
7248c2ecf20Sopenharmony_ci		sysrq_do_reset(&state->keyreset_timer);
7258c2ecf20Sopenharmony_ci}
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_cistatic void sysrq_detect_reset_sequence(struct sysrq_state *state,
7288c2ecf20Sopenharmony_ci					unsigned int code, int value)
7298c2ecf20Sopenharmony_ci{
7308c2ecf20Sopenharmony_ci	if (!test_bit(code, state->reset_keybit)) {
7318c2ecf20Sopenharmony_ci		/*
7328c2ecf20Sopenharmony_ci		 * Pressing any key _not_ in reset sequence cancels
7338c2ecf20Sopenharmony_ci		 * the reset sequence.  Also cancelling the timer in
7348c2ecf20Sopenharmony_ci		 * case additional keys were pressed after a reset
7358c2ecf20Sopenharmony_ci		 * has been requested.
7368c2ecf20Sopenharmony_ci		 */
7378c2ecf20Sopenharmony_ci		if (value && state->reset_seq_cnt) {
7388c2ecf20Sopenharmony_ci			state->reset_canceled = true;
7398c2ecf20Sopenharmony_ci			del_timer(&state->keyreset_timer);
7408c2ecf20Sopenharmony_ci		}
7418c2ecf20Sopenharmony_ci	} else if (value == 0) {
7428c2ecf20Sopenharmony_ci		/*
7438c2ecf20Sopenharmony_ci		 * Key release - all keys in the reset sequence need
7448c2ecf20Sopenharmony_ci		 * to be pressed and held for the reset timeout
7458c2ecf20Sopenharmony_ci		 * to hold.
7468c2ecf20Sopenharmony_ci		 */
7478c2ecf20Sopenharmony_ci		del_timer(&state->keyreset_timer);
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci		if (--state->reset_seq_cnt == 0)
7508c2ecf20Sopenharmony_ci			state->reset_canceled = false;
7518c2ecf20Sopenharmony_ci	} else if (value == 1) {
7528c2ecf20Sopenharmony_ci		/* key press, not autorepeat */
7538c2ecf20Sopenharmony_ci		if (++state->reset_seq_cnt == state->reset_seq_len &&
7548c2ecf20Sopenharmony_ci		    !state->reset_canceled) {
7558c2ecf20Sopenharmony_ci			sysrq_handle_reset_request(state);
7568c2ecf20Sopenharmony_ci		}
7578c2ecf20Sopenharmony_ci	}
7588c2ecf20Sopenharmony_ci}
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci#ifdef CONFIG_OF
7618c2ecf20Sopenharmony_cistatic void sysrq_of_get_keyreset_config(void)
7628c2ecf20Sopenharmony_ci{
7638c2ecf20Sopenharmony_ci	u32 key;
7648c2ecf20Sopenharmony_ci	struct device_node *np;
7658c2ecf20Sopenharmony_ci	struct property *prop;
7668c2ecf20Sopenharmony_ci	const __be32 *p;
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ci	np = of_find_node_by_path("/chosen/linux,sysrq-reset-seq");
7698c2ecf20Sopenharmony_ci	if (!np) {
7708c2ecf20Sopenharmony_ci		pr_debug("No sysrq node found");
7718c2ecf20Sopenharmony_ci		return;
7728c2ecf20Sopenharmony_ci	}
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_ci	/* Reset in case a __weak definition was present */
7758c2ecf20Sopenharmony_ci	sysrq_reset_seq_len = 0;
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_ci	of_property_for_each_u32(np, "keyset", prop, p, key) {
7788c2ecf20Sopenharmony_ci		if (key == KEY_RESERVED || key > KEY_MAX ||
7798c2ecf20Sopenharmony_ci		    sysrq_reset_seq_len == SYSRQ_KEY_RESET_MAX)
7808c2ecf20Sopenharmony_ci			break;
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci		sysrq_reset_seq[sysrq_reset_seq_len++] = (unsigned short)key;
7838c2ecf20Sopenharmony_ci	}
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_ci	/* Get reset timeout if any. */
7868c2ecf20Sopenharmony_ci	of_property_read_u32(np, "timeout-ms", &sysrq_reset_downtime_ms);
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci	of_node_put(np);
7898c2ecf20Sopenharmony_ci}
7908c2ecf20Sopenharmony_ci#else
7918c2ecf20Sopenharmony_cistatic void sysrq_of_get_keyreset_config(void)
7928c2ecf20Sopenharmony_ci{
7938c2ecf20Sopenharmony_ci}
7948c2ecf20Sopenharmony_ci#endif
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_cistatic void sysrq_reinject_alt_sysrq(struct work_struct *work)
7978c2ecf20Sopenharmony_ci{
7988c2ecf20Sopenharmony_ci	struct sysrq_state *sysrq =
7998c2ecf20Sopenharmony_ci			container_of(work, struct sysrq_state, reinject_work);
8008c2ecf20Sopenharmony_ci	struct input_handle *handle = &sysrq->handle;
8018c2ecf20Sopenharmony_ci	unsigned int alt_code = sysrq->alt_use;
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci	if (sysrq->need_reinject) {
8048c2ecf20Sopenharmony_ci		/* we do not want the assignment to be reordered */
8058c2ecf20Sopenharmony_ci		sysrq->reinjecting = true;
8068c2ecf20Sopenharmony_ci		mb();
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_ci		/* Simulate press and release of Alt + SysRq */
8098c2ecf20Sopenharmony_ci		input_inject_event(handle, EV_KEY, alt_code, 1);
8108c2ecf20Sopenharmony_ci		input_inject_event(handle, EV_KEY, KEY_SYSRQ, 1);
8118c2ecf20Sopenharmony_ci		input_inject_event(handle, EV_SYN, SYN_REPORT, 1);
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci		input_inject_event(handle, EV_KEY, KEY_SYSRQ, 0);
8148c2ecf20Sopenharmony_ci		input_inject_event(handle, EV_KEY, alt_code, 0);
8158c2ecf20Sopenharmony_ci		input_inject_event(handle, EV_SYN, SYN_REPORT, 1);
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci		mb();
8188c2ecf20Sopenharmony_ci		sysrq->reinjecting = false;
8198c2ecf20Sopenharmony_ci	}
8208c2ecf20Sopenharmony_ci}
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_cistatic bool sysrq_handle_keypress(struct sysrq_state *sysrq,
8238c2ecf20Sopenharmony_ci				  unsigned int code, int value)
8248c2ecf20Sopenharmony_ci{
8258c2ecf20Sopenharmony_ci	bool was_active = sysrq->active;
8268c2ecf20Sopenharmony_ci	bool suppress;
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_ci	switch (code) {
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci	case KEY_LEFTALT:
8318c2ecf20Sopenharmony_ci	case KEY_RIGHTALT:
8328c2ecf20Sopenharmony_ci		if (!value) {
8338c2ecf20Sopenharmony_ci			/* One of ALTs is being released */
8348c2ecf20Sopenharmony_ci			if (sysrq->active && code == sysrq->alt_use)
8358c2ecf20Sopenharmony_ci				sysrq->active = false;
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci			sysrq->alt = KEY_RESERVED;
8388c2ecf20Sopenharmony_ci
8398c2ecf20Sopenharmony_ci		} else if (value != 2) {
8408c2ecf20Sopenharmony_ci			sysrq->alt = code;
8418c2ecf20Sopenharmony_ci			sysrq->need_reinject = false;
8428c2ecf20Sopenharmony_ci		}
8438c2ecf20Sopenharmony_ci		break;
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci	case KEY_LEFTSHIFT:
8468c2ecf20Sopenharmony_ci	case KEY_RIGHTSHIFT:
8478c2ecf20Sopenharmony_ci		if (!value)
8488c2ecf20Sopenharmony_ci			sysrq->shift = KEY_RESERVED;
8498c2ecf20Sopenharmony_ci		else if (value != 2)
8508c2ecf20Sopenharmony_ci			sysrq->shift = code;
8518c2ecf20Sopenharmony_ci		break;
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_ci	case KEY_SYSRQ:
8548c2ecf20Sopenharmony_ci		if (value == 1 && sysrq->alt != KEY_RESERVED) {
8558c2ecf20Sopenharmony_ci			sysrq->active = true;
8568c2ecf20Sopenharmony_ci			sysrq->alt_use = sysrq->alt;
8578c2ecf20Sopenharmony_ci			/* either RESERVED (for released) or actual code */
8588c2ecf20Sopenharmony_ci			sysrq->shift_use = sysrq->shift;
8598c2ecf20Sopenharmony_ci			/*
8608c2ecf20Sopenharmony_ci			 * If nothing else will be pressed we'll need
8618c2ecf20Sopenharmony_ci			 * to re-inject Alt-SysRq keysroke.
8628c2ecf20Sopenharmony_ci			 */
8638c2ecf20Sopenharmony_ci			sysrq->need_reinject = true;
8648c2ecf20Sopenharmony_ci		}
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ci		/*
8678c2ecf20Sopenharmony_ci		 * Pretend that sysrq was never pressed at all. This
8688c2ecf20Sopenharmony_ci		 * is needed to properly handle KGDB which will try
8698c2ecf20Sopenharmony_ci		 * to release all keys after exiting debugger. If we
8708c2ecf20Sopenharmony_ci		 * do not clear key bit it KGDB will end up sending
8718c2ecf20Sopenharmony_ci		 * release events for Alt and SysRq, potentially
8728c2ecf20Sopenharmony_ci		 * triggering print screen function.
8738c2ecf20Sopenharmony_ci		 */
8748c2ecf20Sopenharmony_ci		if (sysrq->active)
8758c2ecf20Sopenharmony_ci			clear_bit(KEY_SYSRQ, sysrq->handle.dev->key);
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_ci		break;
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ci	default:
8808c2ecf20Sopenharmony_ci		if (sysrq->active && value && value != 2) {
8818c2ecf20Sopenharmony_ci			unsigned char c = sysrq_xlate[code];
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_ci			sysrq->need_reinject = false;
8848c2ecf20Sopenharmony_ci			if (sysrq->shift_use != KEY_RESERVED)
8858c2ecf20Sopenharmony_ci				c = toupper(c);
8868c2ecf20Sopenharmony_ci			__handle_sysrq(c, true);
8878c2ecf20Sopenharmony_ci		}
8888c2ecf20Sopenharmony_ci		break;
8898c2ecf20Sopenharmony_ci	}
8908c2ecf20Sopenharmony_ci
8918c2ecf20Sopenharmony_ci	suppress = sysrq->active;
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_ci	if (!sysrq->active) {
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_ci		/*
8968c2ecf20Sopenharmony_ci		 * See if reset sequence has changed since the last time.
8978c2ecf20Sopenharmony_ci		 */
8988c2ecf20Sopenharmony_ci		if (sysrq->reset_seq_version != sysrq_reset_seq_version)
8998c2ecf20Sopenharmony_ci			sysrq_parse_reset_sequence(sysrq);
9008c2ecf20Sopenharmony_ci
9018c2ecf20Sopenharmony_ci		/*
9028c2ecf20Sopenharmony_ci		 * If we are not suppressing key presses keep track of
9038c2ecf20Sopenharmony_ci		 * keyboard state so we can release keys that have been
9048c2ecf20Sopenharmony_ci		 * pressed before entering SysRq mode.
9058c2ecf20Sopenharmony_ci		 */
9068c2ecf20Sopenharmony_ci		if (value)
9078c2ecf20Sopenharmony_ci			set_bit(code, sysrq->key_down);
9088c2ecf20Sopenharmony_ci		else
9098c2ecf20Sopenharmony_ci			clear_bit(code, sysrq->key_down);
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_ci		if (was_active)
9128c2ecf20Sopenharmony_ci			schedule_work(&sysrq->reinject_work);
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci		/* Check for reset sequence */
9158c2ecf20Sopenharmony_ci		sysrq_detect_reset_sequence(sysrq, code, value);
9168c2ecf20Sopenharmony_ci
9178c2ecf20Sopenharmony_ci	} else if (value == 0 && test_and_clear_bit(code, sysrq->key_down)) {
9188c2ecf20Sopenharmony_ci		/*
9198c2ecf20Sopenharmony_ci		 * Pass on release events for keys that was pressed before
9208c2ecf20Sopenharmony_ci		 * entering SysRq mode.
9218c2ecf20Sopenharmony_ci		 */
9228c2ecf20Sopenharmony_ci		suppress = false;
9238c2ecf20Sopenharmony_ci	}
9248c2ecf20Sopenharmony_ci
9258c2ecf20Sopenharmony_ci	return suppress;
9268c2ecf20Sopenharmony_ci}
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_cistatic bool sysrq_filter(struct input_handle *handle,
9298c2ecf20Sopenharmony_ci			 unsigned int type, unsigned int code, int value)
9308c2ecf20Sopenharmony_ci{
9318c2ecf20Sopenharmony_ci	struct sysrq_state *sysrq = handle->private;
9328c2ecf20Sopenharmony_ci	bool suppress;
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_ci	/*
9358c2ecf20Sopenharmony_ci	 * Do not filter anything if we are in the process of re-injecting
9368c2ecf20Sopenharmony_ci	 * Alt+SysRq combination.
9378c2ecf20Sopenharmony_ci	 */
9388c2ecf20Sopenharmony_ci	if (sysrq->reinjecting)
9398c2ecf20Sopenharmony_ci		return false;
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_ci	switch (type) {
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci	case EV_SYN:
9448c2ecf20Sopenharmony_ci		suppress = false;
9458c2ecf20Sopenharmony_ci		break;
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci	case EV_KEY:
9488c2ecf20Sopenharmony_ci		suppress = sysrq_handle_keypress(sysrq, code, value);
9498c2ecf20Sopenharmony_ci		break;
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci	default:
9528c2ecf20Sopenharmony_ci		suppress = sysrq->active;
9538c2ecf20Sopenharmony_ci		break;
9548c2ecf20Sopenharmony_ci	}
9558c2ecf20Sopenharmony_ci
9568c2ecf20Sopenharmony_ci	return suppress;
9578c2ecf20Sopenharmony_ci}
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_cistatic int sysrq_connect(struct input_handler *handler,
9608c2ecf20Sopenharmony_ci			 struct input_dev *dev,
9618c2ecf20Sopenharmony_ci			 const struct input_device_id *id)
9628c2ecf20Sopenharmony_ci{
9638c2ecf20Sopenharmony_ci	struct sysrq_state *sysrq;
9648c2ecf20Sopenharmony_ci	int error;
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_ci	sysrq = kzalloc(sizeof(struct sysrq_state), GFP_KERNEL);
9678c2ecf20Sopenharmony_ci	if (!sysrq)
9688c2ecf20Sopenharmony_ci		return -ENOMEM;
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_ci	INIT_WORK(&sysrq->reinject_work, sysrq_reinject_alt_sysrq);
9718c2ecf20Sopenharmony_ci
9728c2ecf20Sopenharmony_ci	sysrq->handle.dev = dev;
9738c2ecf20Sopenharmony_ci	sysrq->handle.handler = handler;
9748c2ecf20Sopenharmony_ci	sysrq->handle.name = "sysrq";
9758c2ecf20Sopenharmony_ci	sysrq->handle.private = sysrq;
9768c2ecf20Sopenharmony_ci	timer_setup(&sysrq->keyreset_timer, sysrq_do_reset, 0);
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci	error = input_register_handle(&sysrq->handle);
9798c2ecf20Sopenharmony_ci	if (error) {
9808c2ecf20Sopenharmony_ci		pr_err("Failed to register input sysrq handler, error %d\n",
9818c2ecf20Sopenharmony_ci			error);
9828c2ecf20Sopenharmony_ci		goto err_free;
9838c2ecf20Sopenharmony_ci	}
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci	error = input_open_device(&sysrq->handle);
9868c2ecf20Sopenharmony_ci	if (error) {
9878c2ecf20Sopenharmony_ci		pr_err("Failed to open input device, error %d\n", error);
9888c2ecf20Sopenharmony_ci		goto err_unregister;
9898c2ecf20Sopenharmony_ci	}
9908c2ecf20Sopenharmony_ci
9918c2ecf20Sopenharmony_ci	return 0;
9928c2ecf20Sopenharmony_ci
9938c2ecf20Sopenharmony_ci err_unregister:
9948c2ecf20Sopenharmony_ci	input_unregister_handle(&sysrq->handle);
9958c2ecf20Sopenharmony_ci err_free:
9968c2ecf20Sopenharmony_ci	kfree(sysrq);
9978c2ecf20Sopenharmony_ci	return error;
9988c2ecf20Sopenharmony_ci}
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_cistatic void sysrq_disconnect(struct input_handle *handle)
10018c2ecf20Sopenharmony_ci{
10028c2ecf20Sopenharmony_ci	struct sysrq_state *sysrq = handle->private;
10038c2ecf20Sopenharmony_ci
10048c2ecf20Sopenharmony_ci	input_close_device(handle);
10058c2ecf20Sopenharmony_ci	cancel_work_sync(&sysrq->reinject_work);
10068c2ecf20Sopenharmony_ci	del_timer_sync(&sysrq->keyreset_timer);
10078c2ecf20Sopenharmony_ci	input_unregister_handle(handle);
10088c2ecf20Sopenharmony_ci	kfree(sysrq);
10098c2ecf20Sopenharmony_ci}
10108c2ecf20Sopenharmony_ci
10118c2ecf20Sopenharmony_ci/*
10128c2ecf20Sopenharmony_ci * We are matching on KEY_LEFTALT instead of KEY_SYSRQ because not all
10138c2ecf20Sopenharmony_ci * keyboards have SysRq key predefined and so user may add it to keymap
10148c2ecf20Sopenharmony_ci * later, but we expect all such keyboards to have left alt.
10158c2ecf20Sopenharmony_ci */
10168c2ecf20Sopenharmony_cistatic const struct input_device_id sysrq_ids[] = {
10178c2ecf20Sopenharmony_ci	{
10188c2ecf20Sopenharmony_ci		.flags = INPUT_DEVICE_ID_MATCH_EVBIT |
10198c2ecf20Sopenharmony_ci				INPUT_DEVICE_ID_MATCH_KEYBIT,
10208c2ecf20Sopenharmony_ci		.evbit = { [BIT_WORD(EV_KEY)] = BIT_MASK(EV_KEY) },
10218c2ecf20Sopenharmony_ci		.keybit = { [BIT_WORD(KEY_LEFTALT)] = BIT_MASK(KEY_LEFTALT) },
10228c2ecf20Sopenharmony_ci	},
10238c2ecf20Sopenharmony_ci	{ },
10248c2ecf20Sopenharmony_ci};
10258c2ecf20Sopenharmony_ci
10268c2ecf20Sopenharmony_cistatic struct input_handler sysrq_handler = {
10278c2ecf20Sopenharmony_ci	.filter		= sysrq_filter,
10288c2ecf20Sopenharmony_ci	.connect	= sysrq_connect,
10298c2ecf20Sopenharmony_ci	.disconnect	= sysrq_disconnect,
10308c2ecf20Sopenharmony_ci	.name		= "sysrq",
10318c2ecf20Sopenharmony_ci	.id_table	= sysrq_ids,
10328c2ecf20Sopenharmony_ci};
10338c2ecf20Sopenharmony_ci
10348c2ecf20Sopenharmony_cistatic inline void sysrq_register_handler(void)
10358c2ecf20Sopenharmony_ci{
10368c2ecf20Sopenharmony_ci	int error;
10378c2ecf20Sopenharmony_ci
10388c2ecf20Sopenharmony_ci	sysrq_of_get_keyreset_config();
10398c2ecf20Sopenharmony_ci
10408c2ecf20Sopenharmony_ci	error = input_register_handler(&sysrq_handler);
10418c2ecf20Sopenharmony_ci	if (error)
10428c2ecf20Sopenharmony_ci		pr_err("Failed to register input handler, error %d", error);
10438c2ecf20Sopenharmony_ci}
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_cistatic inline void sysrq_unregister_handler(void)
10468c2ecf20Sopenharmony_ci{
10478c2ecf20Sopenharmony_ci	input_unregister_handler(&sysrq_handler);
10488c2ecf20Sopenharmony_ci}
10498c2ecf20Sopenharmony_ci
10508c2ecf20Sopenharmony_cistatic int sysrq_reset_seq_param_set(const char *buffer,
10518c2ecf20Sopenharmony_ci				     const struct kernel_param *kp)
10528c2ecf20Sopenharmony_ci{
10538c2ecf20Sopenharmony_ci	unsigned long val;
10548c2ecf20Sopenharmony_ci	int error;
10558c2ecf20Sopenharmony_ci
10568c2ecf20Sopenharmony_ci	error = kstrtoul(buffer, 0, &val);
10578c2ecf20Sopenharmony_ci	if (error < 0)
10588c2ecf20Sopenharmony_ci		return error;
10598c2ecf20Sopenharmony_ci
10608c2ecf20Sopenharmony_ci	if (val > KEY_MAX)
10618c2ecf20Sopenharmony_ci		return -EINVAL;
10628c2ecf20Sopenharmony_ci
10638c2ecf20Sopenharmony_ci	*((unsigned short *)kp->arg) = val;
10648c2ecf20Sopenharmony_ci	sysrq_reset_seq_version++;
10658c2ecf20Sopenharmony_ci
10668c2ecf20Sopenharmony_ci	return 0;
10678c2ecf20Sopenharmony_ci}
10688c2ecf20Sopenharmony_ci
10698c2ecf20Sopenharmony_cistatic const struct kernel_param_ops param_ops_sysrq_reset_seq = {
10708c2ecf20Sopenharmony_ci	.get	= param_get_ushort,
10718c2ecf20Sopenharmony_ci	.set	= sysrq_reset_seq_param_set,
10728c2ecf20Sopenharmony_ci};
10738c2ecf20Sopenharmony_ci
10748c2ecf20Sopenharmony_ci#define param_check_sysrq_reset_seq(name, p)	\
10758c2ecf20Sopenharmony_ci	__param_check(name, p, unsigned short)
10768c2ecf20Sopenharmony_ci
10778c2ecf20Sopenharmony_ci/*
10788c2ecf20Sopenharmony_ci * not really modular, but the easiest way to keep compat with existing
10798c2ecf20Sopenharmony_ci * bootargs behaviour is to continue using module_param here.
10808c2ecf20Sopenharmony_ci */
10818c2ecf20Sopenharmony_cimodule_param_array_named(reset_seq, sysrq_reset_seq, sysrq_reset_seq,
10828c2ecf20Sopenharmony_ci			 &sysrq_reset_seq_len, 0644);
10838c2ecf20Sopenharmony_ci
10848c2ecf20Sopenharmony_cimodule_param_named(sysrq_downtime_ms, sysrq_reset_downtime_ms, int, 0644);
10858c2ecf20Sopenharmony_ci
10868c2ecf20Sopenharmony_ci#else
10878c2ecf20Sopenharmony_ci
10888c2ecf20Sopenharmony_cistatic inline void sysrq_register_handler(void)
10898c2ecf20Sopenharmony_ci{
10908c2ecf20Sopenharmony_ci}
10918c2ecf20Sopenharmony_ci
10928c2ecf20Sopenharmony_cistatic inline void sysrq_unregister_handler(void)
10938c2ecf20Sopenharmony_ci{
10948c2ecf20Sopenharmony_ci}
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_ci#endif /* CONFIG_INPUT */
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_ciint sysrq_toggle_support(int enable_mask)
10998c2ecf20Sopenharmony_ci{
11008c2ecf20Sopenharmony_ci	bool was_enabled = sysrq_on();
11018c2ecf20Sopenharmony_ci
11028c2ecf20Sopenharmony_ci	sysrq_enabled = enable_mask;
11038c2ecf20Sopenharmony_ci
11048c2ecf20Sopenharmony_ci	if (was_enabled != sysrq_on()) {
11058c2ecf20Sopenharmony_ci		if (sysrq_on())
11068c2ecf20Sopenharmony_ci			sysrq_register_handler();
11078c2ecf20Sopenharmony_ci		else
11088c2ecf20Sopenharmony_ci			sysrq_unregister_handler();
11098c2ecf20Sopenharmony_ci	}
11108c2ecf20Sopenharmony_ci
11118c2ecf20Sopenharmony_ci	return 0;
11128c2ecf20Sopenharmony_ci}
11138c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sysrq_toggle_support);
11148c2ecf20Sopenharmony_ci
11158c2ecf20Sopenharmony_cistatic int __sysrq_swap_key_ops(int key, const struct sysrq_key_op *insert_op_p,
11168c2ecf20Sopenharmony_ci                                const struct sysrq_key_op *remove_op_p)
11178c2ecf20Sopenharmony_ci{
11188c2ecf20Sopenharmony_ci	int retval;
11198c2ecf20Sopenharmony_ci
11208c2ecf20Sopenharmony_ci	spin_lock(&sysrq_key_table_lock);
11218c2ecf20Sopenharmony_ci	if (__sysrq_get_key_op(key) == remove_op_p) {
11228c2ecf20Sopenharmony_ci		__sysrq_put_key_op(key, insert_op_p);
11238c2ecf20Sopenharmony_ci		retval = 0;
11248c2ecf20Sopenharmony_ci	} else {
11258c2ecf20Sopenharmony_ci		retval = -1;
11268c2ecf20Sopenharmony_ci	}
11278c2ecf20Sopenharmony_ci	spin_unlock(&sysrq_key_table_lock);
11288c2ecf20Sopenharmony_ci
11298c2ecf20Sopenharmony_ci	/*
11308c2ecf20Sopenharmony_ci	 * A concurrent __handle_sysrq either got the old op or the new op.
11318c2ecf20Sopenharmony_ci	 * Wait for it to go away before returning, so the code for an old
11328c2ecf20Sopenharmony_ci	 * op is not freed (eg. on module unload) while it is in use.
11338c2ecf20Sopenharmony_ci	 */
11348c2ecf20Sopenharmony_ci	synchronize_rcu();
11358c2ecf20Sopenharmony_ci
11368c2ecf20Sopenharmony_ci	return retval;
11378c2ecf20Sopenharmony_ci}
11388c2ecf20Sopenharmony_ci
11398c2ecf20Sopenharmony_ciint register_sysrq_key(int key, const struct sysrq_key_op *op_p)
11408c2ecf20Sopenharmony_ci{
11418c2ecf20Sopenharmony_ci	return __sysrq_swap_key_ops(key, op_p, NULL);
11428c2ecf20Sopenharmony_ci}
11438c2ecf20Sopenharmony_ciEXPORT_SYMBOL(register_sysrq_key);
11448c2ecf20Sopenharmony_ci
11458c2ecf20Sopenharmony_ciint unregister_sysrq_key(int key, const struct sysrq_key_op *op_p)
11468c2ecf20Sopenharmony_ci{
11478c2ecf20Sopenharmony_ci	return __sysrq_swap_key_ops(key, NULL, op_p);
11488c2ecf20Sopenharmony_ci}
11498c2ecf20Sopenharmony_ciEXPORT_SYMBOL(unregister_sysrq_key);
11508c2ecf20Sopenharmony_ci
11518c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_FS
11528c2ecf20Sopenharmony_ci
11538c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(sysrq_mutex);
11548c2ecf20Sopenharmony_ci
11558c2ecf20Sopenharmony_ci/*
11568c2ecf20Sopenharmony_ci * writing 'C' to /proc/sysrq-trigger is like sysrq-C
11578c2ecf20Sopenharmony_ci */
11588c2ecf20Sopenharmony_cistatic ssize_t write_sysrq_trigger(struct file *file, const char __user *buf,
11598c2ecf20Sopenharmony_ci				   size_t count, loff_t *ppos)
11608c2ecf20Sopenharmony_ci{
11618c2ecf20Sopenharmony_ci	if (count) {
11628c2ecf20Sopenharmony_ci		char c;
11638c2ecf20Sopenharmony_ci
11648c2ecf20Sopenharmony_ci		if (get_user(c, buf))
11658c2ecf20Sopenharmony_ci			return -EFAULT;
11668c2ecf20Sopenharmony_ci
11678c2ecf20Sopenharmony_ci		mutex_lock(&sysrq_mutex);
11688c2ecf20Sopenharmony_ci		__handle_sysrq(c, false);
11698c2ecf20Sopenharmony_ci		mutex_unlock(&sysrq_mutex);
11708c2ecf20Sopenharmony_ci	}
11718c2ecf20Sopenharmony_ci
11728c2ecf20Sopenharmony_ci	return count;
11738c2ecf20Sopenharmony_ci}
11748c2ecf20Sopenharmony_ci
11758c2ecf20Sopenharmony_cistatic const struct proc_ops sysrq_trigger_proc_ops = {
11768c2ecf20Sopenharmony_ci	.proc_write	= write_sysrq_trigger,
11778c2ecf20Sopenharmony_ci	.proc_lseek	= noop_llseek,
11788c2ecf20Sopenharmony_ci};
11798c2ecf20Sopenharmony_ci
11808c2ecf20Sopenharmony_cistatic void sysrq_init_procfs(void)
11818c2ecf20Sopenharmony_ci{
11828c2ecf20Sopenharmony_ci	if (!proc_create("sysrq-trigger", S_IWUSR, NULL,
11838c2ecf20Sopenharmony_ci			 &sysrq_trigger_proc_ops))
11848c2ecf20Sopenharmony_ci		pr_err("Failed to register proc interface\n");
11858c2ecf20Sopenharmony_ci}
11868c2ecf20Sopenharmony_ci
11878c2ecf20Sopenharmony_ci#else
11888c2ecf20Sopenharmony_ci
11898c2ecf20Sopenharmony_cistatic inline void sysrq_init_procfs(void)
11908c2ecf20Sopenharmony_ci{
11918c2ecf20Sopenharmony_ci}
11928c2ecf20Sopenharmony_ci
11938c2ecf20Sopenharmony_ci#endif /* CONFIG_PROC_FS */
11948c2ecf20Sopenharmony_ci
11958c2ecf20Sopenharmony_cistatic int __init sysrq_init(void)
11968c2ecf20Sopenharmony_ci{
11978c2ecf20Sopenharmony_ci	sysrq_init_procfs();
11988c2ecf20Sopenharmony_ci
11998c2ecf20Sopenharmony_ci	if (sysrq_on())
12008c2ecf20Sopenharmony_ci		sysrq_register_handler();
12018c2ecf20Sopenharmony_ci
12028c2ecf20Sopenharmony_ci	return 0;
12038c2ecf20Sopenharmony_ci}
12048c2ecf20Sopenharmony_cidevice_initcall(sysrq_init);
1205