Skip to the content.

sysrq

默认是不打开的,防止误触: echo 1 | sudo tee /proc/sys/kernel/sysrq

如何触发 sysrq

路径 如何触发 条件和特点 ━━━━━━━━━━━━━━━━━━━━━ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ /proc/sysrq-trigger 以 root 权限向文件写入命令字符,如 t 适合本地程序、SSH、脚本;需要用户态还能运行;不受 kernel.sysrq 开关限制 ───────────────────── ───────────────────────────────────────────────────── ───────────────────────────────────────────────────── 键盘 x86 上按 Alt + SysRq/PrintScreen + 命令键 经过内核 input 子系统;受 kernel.sysrq 控制 ───────────────────── ───────────────────────────────────────────────────── ───────────────────────────────────────────────────── 串口控制台 发送 BREAK,再在 5 秒内发送命令字符 当前源码需要 CONFIG_MAGIC_SYSRQ_SERIAL,串口驱动支 持,且该端口是内核 console ───────────────────── ───────────────────────────────────────────────────── ───────────────────────────────────────────────────── HVC 虚拟控制台 对采用通用 HVC 接收路径的控制台,按 Ctrl+O,再输入 仅作用于选中的 HVC console;具体取决于控制台实现 命令字符 ───────────────────── ───────────────────────────────────────────────────── ───────────────────────────────────────────────────── Xen 管理通道 向目标 guest 的 Xenstore control/sysrq 写命令字符 guest 中的 Xen 驱动监听后调用 handle_sysrq() ───────────────────── ───────────────────────────────────────────────────── ───────────────────────────────────────────────────── UML 管理控制台 mconsole 的 sysrq <字符> 命令 仅适用于 User Mode Linux ───────────────────── ───────────────────────────────────────────────────── ───────────────────────────────────────────────────── KDB 调试器 在 KDB 中执行 sr t 等命令 已进入 KDB 时可用

前三种标准入口见 Linux 官方 SysRq 文档 (https://docs.kernel.org/admin-guide/sysrq.html)。

两个容易混淆的地方:

常用排障命令字符:w 查看不可中断睡眠任务,t 查看所有任务,l 查看所有活跃 CPU 的栈,m 查看内存信息。c 会主动触发崩溃,b 会立即重启。

源码入口可看:

Alt + SysRq/PrintScreen + 命令键 ,我理解只有 vt 才有这个机制吧

和键盘完全去掉耦合的,其实关系不大

首先执行 ctrl alt F1 进入到 vt 中

qemu 可以进入到这种 vt 吗? 是可以的

但是,到底什么是

测试 sysrq 也是有相同的问题

dmesg 中可以看到的:

[160673.642166] sysrq: Show Regs

[160673.642701] CPU#11: ctrl:       0001000f000000ff
[160673.642702] CPU#11: status:     0000000000000000
[160673.642702] CPU#11: overflow:   0000000000000000
[160673.642702] CPU#11: fixed:      00000000000000b0
[160673.642703] CPU#11: pebs:       0000000000000000
[160673.642703] CPU#11: debugctl:   0000000000004000
[160673.642704] CPU#11: active:     0000000200000000
[160673.642704] CPU#11:   gen-PMC0 ctrl:  0000000000000000
[160673.642705] CPU#11:   gen-PMC0 count: 0000000000000000
[160673.642705] CPU#11:   gen-PMC0 left:  0000000000000000
[160673.642706] CPU#11:   gen-PMC1 ctrl:  0000000000000000
[160673.642706] CPU#11:   gen-PMC1 count: 0000000000000000
[160673.642706] CPU#11:   gen-PMC1 left:  0000000000000000
[160673.642707] CPU#11:   gen-PMC2 ctrl:  0000000000000000
[160673.642707] CPU#11:   gen-PMC2 count: 0000000000000000
[160673.642708] CPU#11:   gen-PMC2 left:  0000000000000000
[160673.642708] CPU#11:   gen-PMC3 ctrl:  0000000000000000
[160673.642708] CPU#11:   gen-PMC3 count: 0000000000000000
[160673.642709] CPU#11:   gen-PMC3 left:  0000000000000000
[160673.642709] CPU#11:   gen-PMC4 ctrl:  0000000000000000
[160673.642709] CPU#11:   gen-PMC4 count: 0000000000000000
[160673.642710] CPU#11:   gen-PMC4 left:  0000000000000000
[160673.642710] CPU#11:   gen-PMC5 ctrl:  0000000000000000
[160673.642711] CPU#11:   gen-PMC5 count: 0000000000000000
[160673.642711] CPU#11:   gen-PMC5 left:  0000000000000000
[160673.642711] CPU#11:   gen-PMC6 ctrl:  0000000000000000
[160673.642712] CPU#11:   gen-PMC6 count: 0000000000000000
[160673.642712] CPU#11:   gen-PMC6 left:  0000000000000000
[160673.642713] CPU#11:   gen-PMC7 ctrl:  0000000000000000
[160673.642713] CPU#11:   gen-PMC7 count: 0000000000000000
[160673.642713] CPU#11:   gen-PMC7 left:  0000000000000000
[160673.642714] CPU#11: fixed-PMC0 count: 00008004bc8d6009
[160673.642714] CPU#11: fixed-PMC1 count: 0000fffb3f914e2a
[160673.642715] CPU#11: fixed-PMC2 count: 0000000000000000
[160673.642715] CPU#11: fixed-PMC3 count: 0000000000000000

但是在 console 中仅仅可以看到 sysrq: Show Regs

在 vt 中真的可以执行

fgconsole ,继续调查下

当使用 vt 的时候,触发的 backtrace 为这个效果的

@[
    sysrq_handle_showregs+5
    __handle_sysrq+188
    sysrq_filter+736
    input_handle_events_filter+66
    input_pass_values+297
    input_event_dispose+348
    input_event+93
    hidinput_report_event+55
    hid_report_raw_event+202
    __hid_input_report+328
    hid_input_report+21
    hid_irq_in+496
    __usb_hcd_giveback_urb+145
    usb_giveback_urb_bh+188
    process_one_work+399
    bh_worker+371
    tasklet_hi_action+19
    handle_softirqs+272
    __irq_exit_rcu+245
    irq_exit_rcu+14
    common_interrupt+135
    asm_common_interrupt+38
    cpuidle_enter_state+220
    cpuidle_enter+45
    do_idle+459
    cpu_startup_entry+41
    start_secondary+291
    common_startup_64+318
]: 4

l : 展示所有 CPU 的 backtrace

通过 nmi 实现的

[161363.082362] sysrq: Show backtrace of all active CPUs
[161363.082912] NMI backtrace for cpu 11
[161363.082913] CPU: 11 UID: 0 PID: 0 Comm: swapper/11 Not tainted 6.13.2 #1-NixOS
[161363.082914] Hardware name: ASUS System Product Name/TUF GAMING B660-PLUS WIFI D4, BIOS 1620 08/12/2022
[161363.082915] Call Trace:
[161363.082916]  <IRQ>
[161363.082917]  dump_stack_lvl+0x77/0xb0
[161363.082920]  nmi_cpu_backtrace+0xf9/0x140
[161363.082924]  ? __pfx_nmi_raise_cpu_backtrace+0x10/0x10
[161363.082926]  nmi_trigger_cpumask_backtrace+0x11e/0x160
[161363.082928]  __handle_sysrq+0xbc/0x180
[161363.082930]  sysrq_filter+0x2e0/0x560
[161363.082931]  input_handle_events_filter+0x42/0xa0
[161363.082933]  input_pass_values+0x129/0x160
[161363.082933]  input_event_dispose+0x15c/0x170
[161363.082934]  input_event+0x5d/0x90
[161363.082937]  hidinput_report_event+0x37/0x60 [hid]
[161363.082941]  hid_report_raw_event+0xca/0x4c0 [hid]
[161363.082945]  __hid_input_report+0x148/0x210 [hid]
[161363.082948]  hid_input_report+0x15/0x30 [hid]
[161363.082950]  hid_irq_in+0x1f0/0x220 [usbhid]
[161363.082952]  __usb_hcd_giveback_urb+0x91/0x110
[161363.082954]  usb_giveback_urb_bh+0xbc/0x150
[161363.082955]  process_one_work+0x18f/0x3b0
[161363.082956]  bh_worker+0x173/0x1d0
[161363.082957]  tasklet_hi_action+0x13/0x30
[161363.082958]  handle_softirqs+0x110/0x3e0
[161363.082959]  __irq_exit_rcu+0xf5/0x120
[161363.082960]  irq_exit_rcu+0xe/0x20
[161363.082961]  common_interrupt+0x87/0xa0
[161363.082962]  </IRQ>
[161363.082963]  <TASK>
[161363.082963]  asm_common_interrupt+0x26/0x40
[161363.082964] RIP: 0010:cpuidle_enter_state+0xdc/0x450
[161363.082966] Code: 3a ec ff ff 8b 53 04 49 89 c5 0f 1f 44 00 00 31 ff e8 18 c8 3b ff 45 84 ff 0f 85 53 02 00 00 e8
 9a 15 4e ff fb 0f 1f 44 00 00 <45> 85 f6 0f 88 90 01 00 00 49 63 d6 48 8d 04 52 48 8d 04 82 49 8d
[161363.082967] RSP: 0018:ffffb6a1401e7e90 EFLAGS: 00000246
[161363.082967] RAX: 0000000000000000 RBX: ffffd6a13f3a3ed8 RCX: 0000000000000000
[161363.082968] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000
[161363.082968] RBP: 0000000000000002 R08: 0000000000000000 R09: 0000000000000000
[161363.082969] R10: 0000000000000000 R11: 0000000000000000 R12: ffffffffaf9cfae0
[161363.082969] R13: 000092c245340114 R14: 0000000000000002 R15: 0000000000000000
[161363.082970]  cpuidle_enter+0x2d/0x50
[161363.082972]  do_idle+0x1cb/0x220
[161363.082974]  cpu_startup_entry+0x29/0x30
[161363.082975]  start_secondary+0x123/0x140
[161363.082976]  common_startup_64+0x13e/0x141
[161363.082978]  </TASK>
[161363.082978] Sending NMI from CPU 11 to CPUs 0-10,12-31:
[161363.082985] NMI backtrace for cpu 10 skipped: idling at intel_idle+0x59/0xa0
[161363.083025] NMI backtrace for cpu 1 skipped: idling at intel_idle+0x59/0xa0
[161363.083028] NMI backtrace for cpu 0 skipped: idling at intel_idle+0x59/0xa0
[161363.083031] NMI backtrace for cpu 6 skipped: idling at intel_idle+0x59/0xa0
[161363.083034] NMI backtrace for cpu 7 skipped: idling at intel_idle+0x59/0xa0
[161363.083036] NMI backtrace for cpu 2 skipped: idling at intel_idle+0x59/0xa0
[161363.083039] NMI backtrace for cpu 4 skipped: idling at intel_idle+0x59/0xa0
[161363.083042] NMI backtrace for cpu 5 skipped: idling at intel_idle+0x59/0xa0
[161363.083044] NMI backtrace for cpu 3 skipped: idling at intel_idle+0x59/0xa0
[161363.083096] NMI backtrace for cpu 14 skipped: idling at intel_idle+0x59/0xa0
[161363.083099] NMI backtrace for cpu 15 skipped: idling at intel_idle+0x59/0xa0
[161363.083101] NMI backtrace for cpu 13 skipped: idling at intel_idle+0x59/0xa0
[161363.083104] NMI backtrace for cpu 12 skipped: idling at intel_idle+0x59/0xa0
[161363.083106] NMI backtrace for cpu 24 skipped: idling at intel_idle+0x59/0xa0
[161363.083110] NMI backtrace for cpu 26 skipped: idling at intel_idle+0x59/0xa0
[161363.083114] NMI backtrace for cpu 25 skipped: idling at intel_idle+0x59/0xa0
[161363.083120] NMI backtrace for cpu 23 skipped: idling at intel_idle+0x59/0xa0
[161363.083124] NMI backtrace for cpu 9 skipped: idling at intel_idle+0x59/0xa0
[161363.083128] NMI backtrace for cpu 16 skipped: idling at intel_idle+0x59/0xa0
[161363.083132] NMI backtrace for cpu 19 skipped: idling at intel_idle+0x59/0xa0
[161363.083135] NMI backtrace for cpu 8 skipped: idling at intel_idle+0x59/0xa0
[161363.083139] NMI backtrace for cpu 29 skipped: idling at intel_idle+0x59/0xa0
[161363.083143] NMI backtrace for cpu 27 skipped: idling at intel_idle+0x59/0xa0
[161363.083146] NMI backtrace for cpu 17 skipped: idling at intel_idle+0x59/0xa0
[161363.083150] NMI backtrace for cpu 18 skipped: idling at intel_idle+0x59/0xa0
[161363.083153] NMI backtrace for cpu 28 skipped: idling at intel_idle+0x59/0xa0
[161363.083157] NMI backtrace for cpu 31 skipped: idling at intel_idle+0x59/0xa0
[161363.083160] NMI backtrace for cpu 30 skipped: idling at intel_idle+0x59/0xa0
[161363.083164] NMI backtrace for cpu 21 skipped: idling at intel_idle+0x59/0xa0
[161363.083167] NMI backtrace for cpu 20 skipped: idling at intel_idle+0x59/0xa0
[161363.083171] NMI backtrace for cpu 22 skipped: idling at intel_idle+0x59/0xa0

奇怪的方法

curl --unix-socket $API_SOCKET -i \
	-X PUT "http://localhost/actions" \
	-H "Accept: application/json" \
	-H "Content-Type: application/json" \
	-d '{
		"action_type": "SendCtrlAltDel"
		}' || pkill firecracker

当前的 sysrq 的结果

bash-5.3# stackcount __handle_sysrq
Tracing 1 functions for "__handle_sysrq"... Hit Ctrl-C to end.
^C
  # qmp 发送的 keyboard
  __handle_sysrq
  sysrq_filter
  input_handle_events_filter
  input_pass_values
  input_handle_event
  input_event
  virtinput_recv_events
  vring_interrupt
  vp_vring_interrupt
  __handle_irq_event_percpu
  handle_irq_event
  handle_edge_irq
  __common_interrupt
  common_interrupt
  asm_common_interrupt
  pv_native_safe_halt
  default_idle
  default_idle_call
  do_idle
  cpu_startup_entry
  __pfx_kernel_init
  start_kernel
  x86_64_start_reservations
  x86_64_start_kernel
  common_startup_64
    1

	# serial
  __handle_sysrq
  serial8250_handle_irq.part.0
  serial8250_default_handle_irq
  serial8250_interrupt
  __handle_irq_event_percpu
  handle_irq_event
  handle_edge_irq
  __common_interrupt
  common_interrupt
  asm_common_interrupt
  pv_native_safe_halt
  default_idle
  default_idle_call
  do_idle
  cpu_startup_entry
  __pfx_kernel_init
  start_kernel
  x86_64_start_reservations
  x86_64_start_kernel
  common_startup_64
    1

在物理机中测试的结果,的确非常有趣,不过注意,不是所有的键盘都有这个 prtsc 键:

@[
        __handle_sysrq+5
        sysrq_handle_keypress+519
        input_handle_events_filter+96
        input_pass_values+338
        input_event_dispose+391
        input_handle_event+65
        input_event+89
        hidinput_report_event+55
        hid_report_raw_event+227
        __hid_input_report+376
        hid_safe_input_report+20
        hid_irq_in+426
        __usb_hcd_giveback_urb+160
        usb_giveback_urb_bh+179
        process_one_work+414
        bh_worker+459
        tasklet_hi_action+19
        handle_softirqs+238
        __irq_exit_rcu+176
        common_interrupt+133
        asm_common_interrupt+38
        cpuidle_enter_state+205
        cpuidle_enter+49
        cpuidle_idle_call+271
        do_idle+156
        cpu_startup_entry+41
        start_secondary+294
        common_startup_64+318
]: 4

原来 console 的作用体会出现了

• 原因找到了:virtme-03 的 hvc0 没有被配置为内核 console,所以 Ctrl+O,w 被 当作普通输入。

我实际检查到:

随后在 guest 中读取 /dev/hvc0,再执行 sysrq_hvc,读到了:

NEW_BYTES=0f77

这正是 Ctrl+O,w,但内核日志没有新增 SysRq 输出。说明字符确实送到了,内核 没有把它识别成 SysRq。

内核 /home/martins3/data/kernel/linux-drm/drivers/tty/hvc/hvc_console.c 的 __hvc_poll() 只有满足下面条件才解析组合键:

if (hp->index == hvc_console.index)

之前实验 VM 特意加了 console=hvc0,virtme-03 没有。要启用,在它的 /home/ martins3/data/hack/vm/virtme-03/config.ini 的 [vm] 中添加:

cmdline = console=hvc0

然后停止并重新启动 QEMU,使新启动参数生效;仅 guest 内重启不会更新 QEMU 的 -append。

我写的 action 目前只确认字符已发送,没有校验 guest 的 console 配置,因此 这里的 Sent 容易让人误以为已经触发。

看看键盘中,是如何路由的,为什么有时候是 vt 接手,有时候就可以到 wayland 上了?

实际上没有路由,在任何环境中都是可以继续用的。

参考

本站所有文章转发 CSDN 将按侵权追究法律责任,其它情况随意。