Linux 内核如何处理键盘按下?

Linux 内核如何处理键盘按下?

我目前正在总体了解 Linux 内核和操作系统,虽然我发现了许多有关 IRQ、驱动程序、调度和其他重要操作系统概念的优秀资源,以及与键盘相关的资源,但我很难将它们放在一起全面概述 Linux 内核如何处理键盘上的按钮按下。在这个阶段,我并不试图理解每一个细节,而是试图在某种程度上全面地连接概念。

我想到了以下场景:

  1. 我使用的是带有单处理器的 x64 机器。
  2. 有几个进程正在运行,特别是编辑器VIM( Process #1) 和 say LibreOffice( Process #2)。
  3. 我在里面VIM并按a-键。但是,当前正在运行的进程Process #2VIM接下来将被安排)。

这就是我想象的事情现在会发生的情况:

  1. 键盘通过一系列步骤生成电信号(USB 协议编码)并通过 USB 线发送。
  2. 信号由 USB 控制器处理,并通过 PCI-e(可能还有其他控制器/总线?)发送到中断控制器 ( APIC)。触发处理器的APICINT Pin
  3. 处理器切换到Kernel ModeIRQ-Number从 请求APIC,并将其用作Interrupt Descriptor Table Register( IDTR) 的偏移量。获得一个描述符,然后使用该描述符来获得中断处理程序例程的地址。据我了解,这个中断处理程序最初是由键盘驱动程序注册的?
  4. 调用中断处理程序(在本例中为键盘处理程序)。

这引出了我的主要问题:中断处理程序例程通过哪种机制将按下的键传达给正确的进程(Process #1)?它实际上是这样做的,还是只是将按下的键写入缓冲区(可通过char-device?),该缓冲区一次对一个进程只读(目前“随附的”Process #1)?我不明白什么时候Process #1 收到钥匙。它是否立即处理数据,作为中断处理程序时间表立即处理,还是下次调度程序调度时处理关键数据?

  1. 当此处理程序返回 ( IRET) 时,上下文将切换回先前执行的进程 ( Process #2)。

答案1

到目前为止,您的理解是正确的,但您错过了在此基础上构建的大部分复杂性。内核中的处理发生在多个层中,并且按键通过这些层“冒泡”。

USB 通信协议本身涉及的内容要多得多。 USB 的中断处理程序例程会处理此问题,并根据需要从多个片段组装一个完整的 USB 数据包。

按键使用所谓的高压气体放电管(“人机接口设备”)协议,构建在 USB 之上。因此较低的USB内核层检测到完整的消息是USB HID事件,并将其传递给内核中的HID层。

HID 层根据初始化时设备所需的 HID 描述符来解释此事件。然后它将事件传递到输入层。单个 HID 事件可以生成多个按键事件。

输入层使用内核键盘布局表将扫描代码(键盘上按键的位置)映射到键代码(如A)并解释ShiftAlt等。此解释的结果可通过/dev/input/event*用户态进程获得。您可以用来evtest实时观看这些事件。

但到这里处理还没有结束。 X Server(负责图形)有一个通用evdev驱动程序,可以从设备读取事件/dev/input/event*,然后映射它们再次根据第二组键盘布局表(您可以部分使用 XKBD 扩展查看这些键盘布局表,xmodmap并完全通过 XKBD 扩展查看这些键盘布局表)。这是因为 X 服务器早于内核输入层,并且在早期有直接处理鼠标和 PS/2 键的驱动程序。

然后,X 服务器向 X 客户端(应用程序)发送包含键盘事件的消息。您可以使用该应用程序查看这些消息xevLibreOffice将直接处理此事件,VIM将在将处理该事件的 an 中运行xterm,并且(您猜对了)再次向其添加一些额外的处理,最后将其传递给VIMvia stdin

够复杂吗?

答案2

它只是将按下的键写入缓冲区(通过字符设备可用吗?)

是的,我应该说。

然后有一种从(低级)控制台到 tty(虚拟)再到伪 tty 的级联。按键操作将写入 /dev/tty1 或 /dev/tty5,具体取决于哪个“控制台”处于活动状态。

在 xterm 中(ps axf 输出):

  467 tty1     Ss     0:38  \_ -bash
 5820 tty1     S+     0:00      \_ xinit fvwm -- vt9
 5821 tty9     S<sl+  54:15          \_ /usr/lib/Xorg :0 vt9
 5831 tty1     S      0:00          \_ xterm -geometry +1+1 -n login fvwm
 5833 pts/0    Ss+    0:38              \_ fvwm
 ...
 ...
  773 pts/0    S      0:07                  \_ xterm
  775 pts/2    Ss+    0:00                  |   \_ bash
14452 pts/0    S      0:04                  \_ xterm
14454 pts/1    Ss     0:00                  |   \_ bash
14507 pts/1    S      0:00                  |       \_ xfontsel
31044 pts/1    R+     0:00                  |       \_ ps ax f
19549 pts/0    S      0:00                  \_ xterm
19551 pts/3    Ss+    0:00                      \_ bash

这显示了 Xorg 如何从 tty1 在 tty9 上启动,以及 fvwm(窗口管理器)和 xterm(终端仿真器)如何“获取”/dev/pts/0,并且是新的 shell 获取 /dev/pts/1、pts /2。 pts/3 等等。

现在,无论我是否通过以下方式激活 pid 19551 pts/3 bash 进程指点在它的 xterm 窗口中,然后按一个键,或者如果我echo hello >/dev/pts/3从像 /dev/tty5 这样的控制台 vt 执行此操作,则字符会转到正确的进程。

man ps在“进程状态代码”下解释(嗯,它确实列出了它们):

S    interruptible sleep (waiting for an event to complete)
s    is a session leader    
+    is in the foreground process group

我给你留下这些关键词...

相关内容