使用方式:

1)编译
在Kernel hacking中,选中Magic SysRq key (CONFIG_MAGIC_SYSRQ) 。
2)使用方法
通常有两种方式:a、通过/proc接口;b、通过键盘输入组合键
通过键盘组合键输入的规则是:
串口:按住break键,然后5秒内输入command字符
键盘:alt + sysrq +command键
下面是通过/proc实现意义的说明。
立即重启计算机 echo “b” > /proc/sysrq-trigger
立即关闭计算机 echo “o” > /proc/sysrq-trigger
导出内存分配的信息 echo “m” > proc/sysrq-trigger (可以用/var/log/message查看)Outputs memory statistics to the console
导出当前CPU寄存器信息和标志位的信息 echo “p” > proc/sysrq-trigger (outputs all flags and registers to the console)
导出线程状态信息 echo “t” > proc/sysrq-trigger (outputs a list of processes to the console)
故意让系统崩溃 echo “c” > proc/sysrq-trigger (crashes the system without first unmounting file systems or syncing disks attached to the system)
立即重新挂载所有的文件系统 echo “s” > proc/sysrq-trigger (attempts to sync disks attached to the system)
立即重新挂载所有的文件系统为只读 echo “u” > proc/sysrq-trigger (attempts to unmount and remount all file systems as read-only)
此外,还有两个类似于强制注销的功能
e ---- kills all processes except init using SIGTERM
i ---- kills all processes except init using SIGKILL

基本原理

Sysrq实现的基本原理为:在键盘或串口驱动中(如果是/proc接口方式,则直接定义/proc的相关写入接口即可),对按键进行判断过滤,然后根据不同的按键进行相应的处理。普通键盘和串口的流程不尽相同,主要差别在键盘和串口驱动的具体实现上,总体流程一致。
对于普通键盘来说 ,其底层的处理(从硬件中断到键盘驱动)过程依赖于内核中的输入(input)子系统。键盘处理的大致流程如下:
1)键盘中断调用中断服务程序
2)键盘中断服务程序调用输入子系统
3)输入子系统调用键盘设备对应的键盘事件处理器
4)键盘事件处理器完成键码的转换分类工作,根据按键类型的不同,执行不同的操作。对于输入类按键,先将按键值存放到临时缓冲区,激活临时缓冲区的工作队列,然后结束。对于控制类按键,激活对应此次控制操作的工作队列,然后结束。
5)系统在适当的时机调度工作队列执行,完成剩下的操作
而Sysrq魔术键的处理比较特殊,在内核主分支的代码中,在上述步骤4中的键盘事件处理器中进行相应的处理,不依赖于工作队列,相当于直接在硬件中断中处理。而在3.10内核版本的分支代码中,处理流程不太一样,其合入了相应的补丁,使sysrq的处理剥离出来,放在input子系统进行处理,而脱离了键盘事件的处理流程,其还是在中断上下文中处理的,不依赖于工作队列等。主要是通过注册input_handler实现,具体见后面的代码分析。
另一方面,对于串口设备来说,其sysrq的处理流程根据各串口驱动的实现而稍有不同,但基本都是直接在硬件中断中直接处理的。
所以,总的来说,sysrq魔术键基本都在中断上下文中处理,优先级很高,能在关键时刻发挥重要作用。

驱动部分

代码位置: drivers/tty/sysrq.c

static struct sysrq_key_op sysrq_unraw_op = {.handler   = sysrq_handle_unraw,.help_msg = "unraw(r)",.action_msg = "Keyboard mode set to system default",.enable_mask = SYSRQ_ENABLE_KEYBOARD,
};

其中:
handler表示相应键码所对应的处理函数;
action_msg是执行处理函数前打印的信息;
help_msg指相应键码的帮助信息;
enable_mask指该功能是否打开,仅限于键盘输入方式。
另外,sysrq还定义了一个静态全局数组sysrq_key_table,共有36个元素,其中0~9用于命令字09,10到36用于命令字az。当从/proc/得到输入的命令字后,可以根据这个规则计算出他在sysrq_key_table中的index,然后判断对应handler是否为空,如果不为空的话,则调用handler函数处理。下面列出几个例子:

static struct sysrq_key_op sysrq_reboot_op = {.handler  = sysrq_handle_reboot,.help_msg    = "reboot(b)",.action_msg    = "Resetting",.enable_mask   = SYSRQ_ENABLE_BOOT,
};
static struct sysrq_key_op sysrq_sync_op = {.handler   = sysrq_handle_sync,.help_msg  = "sync(s)",.action_msg  = "Emergency Sync",.enable_mask  = SYSRQ_ENABLE_SYNC,
};
........
static struct sysrq_key_op *sysrq_key_table[36] = {&sysrq_loglevel_op,     /* 0 */&sysrq_loglevel_op,      /* 1 */&sysrq_loglevel_op,      /* 2 */&sysrq_loglevel_op,      /* 3 */&sysrq_loglevel_op,      /* 4 */&sysrq_loglevel_op,      /* 5 */&sysrq_loglevel_op,      /* 6 */&sysrq_loglevel_op,      /* 7 */&sysrq_loglevel_op,      /* 8 */&sysrq_loglevel_op,      /* 9 *//** a: Don't use for system provided sysrqs, it is handled specially on* sparc and will never arrive.*/NULL,                /* a */&sysrq_reboot_op,        /* b */&sysrq_crash_op,     /* c */&sysrq_showlocks_op,     /* d */&sysrq_term_op,          /* e */&sysrq_moom_op,          /* f */........}

键盘其它按键的处理代码流程:
atkbd_interrupt() //键盘中断ISR
input_event() //输入子系统相关处理
input_handle_event()
input_pass_values()
input_to_handler()
handler->events() //键盘初始化是预先注册好的handler(kbd_handler)的event接口(kbd_event)
kbd_event()
kbd_keycode()
put_queue()
tty_insert_flip_char() //将键盘键值对应的编码数据写入缓冲区
tty_schedule_flip() //激活工作队列处理,处理函数为flush_to_ldisc
最终在kbd_keycode()函数进行相应的键码处理,主要完成键码的转换分类工作,根据按键类型的不同,执行不同的操作。对于输入类按键,先将按键值存放到临时缓冲区,激活临时缓冲区的工作队列,然后结束。对于控制类按键,激活对应此次控制操作 的工作队列,然后结束。

通过/proc接口触发Sysrq魔术键的主要函数流程(write_sysrq_trigger()为/proc/sysrq-trigger接口的write接口):
write_sysrq_trigger()
__handle_sysrq()

代码流程:串口函数

438 #ifdef SUPPORT_SYSRQ
439 static inline int
440 uart_handle_sysrq_char(struct uart_port *port, unsigned int ch)
441 {
442         if (port->sysrq) {
443                 if (ch && time_before(jiffies, port->sysrq)) {
444                         handle_sysrq(ch);
445                         port->sysrq = 0;
446                         return 1;
447                 }
448                 port->sysrq = 0;
449         }
450         return 0;
451 }
452 #else
453 #define uart_handle_sysrq_char(port,ch) ({ (void)port; 0; })
454 #endif

这个函数一般在uart rx的中断函数中调用uart_handle_sysrq_char 最好的是第二个参数ch表示用户当前按下key的ascll码
uart_handle_sysrq_char 继续调用handle_sysrq出来按下的key

source/drivers/tty/sysrq.c
577 void handle_sysrq(int key)
578 {
579         if (sysrq_on())
580                 __handle_sysrq(key, true);
581 }

继续调用__handle_sysrq

void __handle_sysrq(int key, bool check_mask)
{struct sysrq_key_op *op_p;* Raise the apparent loglevel to maximum so that the sysrq header* is shown to provide the user with positive feedback.  We do not* simply emit this at KERN_EMERG as that would change message* routing in the consumers of /proc/kmsg.*/***************orig_log_level = console_loglevel;console_loglevel = CONSOLE_LOGLEVEL_DEFAULT;pr_info("SysRq : ");op_p = __sysrq_get_key_op(key);
}

__sysrq_get_key_op(key) 拿到对应key的函数,例如按下0~9 来改变log lever.对应的hanler为sysrq_handle_loglever 然后调用这个handle。
我们看看最重要的__sysrq_get_key_op实现.

504 struct sysrq_key_op *__sysrq_get_key_op(int key)
505 {
506         struct sysrq_key_op *op_p = NULL;
507         int i;
508
509         i = sysrq_key_table_key2index(key);
510         if (i != -1)
511                 op_p = sysrq_key_table[i];
512
513         return op_p;
514 }
其中sysrq_key_table_key2index将key转成index,很简单
488 static int sysrq_key_table_key2index(int key)
489 {
490         int retval;
491
492         if ((key >= '') && (key <= '9'))
493                 retval = key - '';
494         else if ((key >= 'a') && (key <= 'z'))
495                 retval = key + 10 - 'a';
496         else
497                 retval = -1;
498         return retval;
499 }
得到这个index后就查询sysrq_key_table 数组得到对应key的handle。
 static struct sysrq_key_op *sysrq_key_table[36] = {
429         &sysrq_loglevel_op,             /* 0 */
430         &sysrq_loglevel_op,             /* 1 */
431         &sysrq_loglevel_op,             /* 2 */

例如1对应的op是sysrq_loglevel_op

 93 static struct sysrq_key_op sysrq_loglevel_op = {94         .handler        = sysrq_handle_loglevel,95         .help_msg       = "loglevel(0-9)",96         .action_msg     = "Changing Loglevel",97         .enable_mask    = SYSRQ_ENABLE_LOG,98 };

可以看到handler是sysrq_handle_loglevel,
我们再来看看sysrq_handle_loglevel具体是怎么改变log level的

 84 static void sysrq_handle_loglevel(int key)85 {86         int i;87 88         i = key - '';89         console_loglevel = CONSOLE_LOGLEVEL_DEFAULT;90         pr_info("Loglevel set to %d\n", i);91         console_loglevel = i;92 }

可以看到是通过console_loglevel 来改变kernel log level的.
如果想要定制key对应的handler,就需要来修改sysrq_key_table。改法很简单的。只要替换对应key的handle就行了

llinux 内核 sysrq的功能说明相关推荐

  1. Linux 内核抓包功能实现基础(四) 手动查找邻居缓存填充MAC地址

    之前写了三篇关于内核抓包功能的实现,包括抓包原理.实现以及抓包服务器的实现.基本的功能都已经有了,但是还有些小问题有待解决.今天有空就解决一下. 开发版本基于内核3.4.39. 先介绍一下问题背景,抓 ...

  2. Linux 内核抓包功能实现基础(三) 抓包服务器的实现

    上回博客我们讲到了内核抓包内核端的实现,通过上篇博客的例子我们就能够开始抓包了,整个抓包的拓扑图如下: 当开始抓包后,抓包机器将抓到的报文送到服务器上,假设服务器地址是192.168.199.123: ...

  3. linux 内核抓包功能实现基础(一)设计思路

    linux平台下面已经有了抓包工具tcpdump, 非常经典,使用起来也非常方便.但是因为某些系统架构上或者其它方面的原因,有时候tcpdump并不能满足产品实际需要,公司的产品是电信运营商相关的软硬 ...

  4. Linux内核sysrq调试调优

    1.sysrq机制的文件系统节点 2.内核注册: 在drivers/tty/sysrq.c中注册的此文件节点, 系统依赖配置CONFIG_MAGIC_SYSRQ. 3. 实现接口 ops table的 ...

  5. linux内核7大功能,Linux Kernel5.10十个值得关注的功能

    Linux Kernel 5.10 有望在本周末发布,外媒 Phoronix 盘点了 10 个值得关注的改进和新功能.5.10 不仅是 2020 年最后一个内核版本,而且还是长期支持(LTS)版本. ...

  6. Linux 内核抓包功能实现基础(五) 常见问题解析

    之前在部门产品上开发了内核抓包模块,基于openwrt平台,通过netfilter框架实现相关功能.核心功能就是在netfilter 的PRE_ROUTING 和 POST_ROUTING链上增加两个 ...

  7. linux 内核抓包功能实现基础(二) netfilter处理

    上篇博客主要介绍了内核抓包设计思路与效果,并没有给出详细的设计实现,看起来就像一个花架子,华而不实.本篇博客就结合具体的代码介绍一下抓包的实现过程.先大致概括一下代码的思路,抓包模块启动后,就去net ...

  8. linux内核4.0,新闻|Linux内核4.0功能:实时内核补丁,支持PS3

    Linux Torvalds 在Linux内核邮件列表里发布了Linux内核新的稳定版. Linux 4.0,代号为'Hurr durr I'm a sheep',带来了一小系列新硬件支持,驱动改进, ...

  9. 编译内核启用KASan动态检测内核内存错误功能(ubuntu16.04 4.4.0内核编译升级到linux-4.4.252版本)

    目录 一.编译内核并配置支持KAsan 1.下载源码 2.安装编译内核必须的库 3.清理之前内核编译生成及相关配置 4.配置内核参数 5.开始编译 6.模块(驱动)安装 7.安装新编译的内核 8.修改 ...

最新文章

  1. [CQOI2014]数三角形 组合数 + 容斥 + gcd
  2. 【BZOJ】 3238: [Ahoi2013]差异
  3. 计算机操作系统——处理机调度算法
  4. 【STL学习】堆相关算法详解与C++编程实现(Heap)
  5. Python命令行实现—查全国7天天气
  6. 销售订单获取不到即时库存
  7. php 5.6 mysql con,最新版的程序,支持PHP5.6和MYSQL5.6的环境吗
  8. Android将库导入到build.gradle
  9. C#保存CookieContainer到文件
  10. IP地址的分类,五分类编制CIDR以及子网的划分和子网掩码
  11. 程序设计语言及其文法
  12. PCL八叉树的包围盒研究
  13. 使用GoldWave制作“淡入/淡出”效果
  14. win10安装visio2010出错_为何我安装Visio 2010时会安装不上,提示下面的错误
  15. RayVentory updated
  16. 红米Android降级,红米Note 5(安卓9.0 不要降级刷低版本)纯净ROOT线刷包分享,一键救砖教程,轻松刷回官方系统,流畅如初!...
  17. 安卓之软键盘监听与切换软键盘状态和重新获取EditText焦点
  18. 基于视觉信息的网页分块算法(VIPS) - yysdsyl的专栏 - 博客频道 - CSDN.NET
  19. 火狐浏览器改变书签栏位置_通过书签改善生活
  20. 医疗信息系统HIS如何配置短信提醒?

热门文章

  1. 2022(一等奖)B1048基于土地利用强度指标的中国城镇化时空演变规律研究
  2. 进程调度 RR 时间片轮转调度 java实现
  3. screen的常用命令和运行程序的操作步骤
  4. C#编译出现Program does not contain a static ‘Main‘ method suitable for an entry point 如何解决
  5. Redis实现锁机制
  6. PHP - 理论篇-1
  7. GCC编译器优化选项分析及具体优化了什么
  8. JAVA WEB如何让没有WebContent的eclipse可以正常在浏览器显示图片
  9. Python判断中文字符个数
  10. 实训四:路由器带内管理