⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 jiurl键盘驱动 5.htm

📁 JIURL键盘驱动
💻 HTM
📖 第 1 页 / 共 5 页
字号:
      CSHORT Size;<BR>/*004*/ LIST_ENTRY InterruptListEntry;<BR>/*00C*/ 
      PKSERVICE_ROUTINE ServiceRoutine;<BR>/*010*/ PVOID 
      ServiceContext;<BR>/*014*/ KSPIN_LOCK SpinLock;<BR>/*018*/ ULONG 
      TickCount;<BR>/*01C*/ PKSPIN_LOCK ActualLock;<BR>/*020*/ PVOID 
      DispatchAddress;<BR>/*024*/ ULONG Vector;<BR>/*028*/ KIRQL 
      Irql;<BR>/*029*/ KIRQL SynchronizeIrql;<BR>/*02A*/ BOOLEAN 
      FloatingSave;<BR>/*02B*/ BOOLEAN Connected;<BR>/*02C*/ CHAR 
      Number;<BR>/*02D*/ UCHAR ShareVector;<BR>/*030*/ KINTERRUPT_MODE 
      Mode;<BR>/*034*/ ULONG ServiceCount;<BR>/*038*/ ULONG 
      DispatchCount;<BR>/*03C*/ ULONG DispatchCode[106];<BR>} KINTERRUPT, 
      *PKINTERRUPT;<BR><BR>我们从中断描述符表中看到的中断向量为 b3 的中断服务例程的入口地址fe4cf264,就是一个 
      KINTERRUPT 中的 DispatchCode 的地址。fe4cf264-3c 就是这个KINTERRUPT 
      的首地址。fe4cf264-3c+c 处就是 KINTERRUPT 中的 ServiceRoutine。我们看到 fe4cf264-3c+c 处为 
      fe1c1750,正是 i8042prt!I8042KeyboardInterruptService 
      的入口地址。<BR><BR>当键盘中断产生时,将会执行 KINTERRUPT 中的 DispatchCode,DispatchCode 会调用 
      nt!KiInterruptDispatch ,nt!KiInterruptDispatch 会调用 KINTERRUPT 结构中的 
      ServiceRoutine ,也就是 i8042prt!I8042KeyboardInterruptService。<BR><BR>7.4 
      按一个普通键-a<BR><BR>7.4.1 调试信息<BR><BR>i8042 isr (kb): enter<BR>i8042 isr (kb): 
      scanCode 0x1e<BR>i8042 isr (kb): real scan code<BR>i8042 isr (kb): MAKE 
      code<BR>8042: I8xWriteDataToKeyboardQueue: enter<BR>8042: 
      I8xWriteDataToKeyboardQueue: DataIn 0xfe4cf710, DataOut 
      0xfe4cf710<BR>8042: I8xWriteDataToKeyboardQueue: InputCount 0<BR>8042: 
      I8xWriteDataToKeyboardQueue: new InputCount 1<BR>8042: 
      I8xWriteDataToKeyboardQueue: exit<BR>i8042 isr (kb): exit<BR><BR>i8042 isr 
      (kb): enter<BR>i8042 isr (kb): scanCode 0x9e<BR>i8042 isr (kb): real scan 
      code<BR>i8042 isr (kb): BREAK code<BR>8042: I8xWriteDataToKeyboardQueue: 
      enter<BR>8042: I8xWriteDataToKeyboardQueue: DataIn 0xfe4cf71c, DataOut 
      0xfe4cf710<BR>8042: I8xWriteDataToKeyboardQueue: InputCount 1<BR>8042: 
      I8xWriteDataToKeyboardQueue: new InputCount 2<BR>8042: 
      I8xWriteDataToKeyboardQueue: exit<BR>i8042 isr (kb): exit<BR><BR>8042: 
      I8042KeyboardIsrDpc: enter<BR><BR>8042: I8xDpcVariableOperation: 
      enter<BR>8042: Performing increment at 0xfe4f529c (current value 
      0xffffffff)<BR>8042: I8xDpcVariableOperation: exit with value 
      0x0<BR><BR>8042: I8xGetDataQueuePointer: enter<BR>8042: 
      I8xGetDataQueuePointer: keyboard<BR>8042: I8xGetDataQueuePointer: DataIn 
      0xfe4cf728, DataOut 0xfe4cf710<BR>8042: I8xGetDataQueuePointer: 
      exit<BR><BR>8042: I8042KeyboardIsrDpc: calling class callback<BR>8042: 
      I8042KeyboardIsrDpc: with Start 0xfe4cf710 and End 
      0xfe4cf728<BR><BR>KBDCLASS-KeyboardClassServiceCallback: 
      enter<BR>KBDCLASS-KeyboardClassServiceCallback: port queue length 0x18, 
      read length 0x78<BR>KBDCLASS-KeyboardClassServiceCallback: number of bytes 
      to move from port to SystemBuffer 
      0x18<BR>KBDCLASS-KeyboardClassServiceCallback: move bytes from 0xfe4cf710 
      to 0xfe385d88<BR>KBDCLASS-KeyboardClassServiceCallback: bytes remaining 
      after move to SystemBuffer 0x0<BR>KBDCLASS-KeyboardClassServiceCallback: 
      exit<BR><BR>8042: I8042KeyboardIsrDpc: Call callback consumed 2 items, 
      left 0<BR><BR>8042: I8xSetDataQueuePointer: enter<BR>8042: 
      I8xSetDataQueuePointer: old keyboard DataOut 0xfe4cf710, InputCount 
      2<BR>8042: I8xSetDataQueuePointer: Okay to log keyboard overflow<BR>8042: 
      I8xSetDataQueuePointer: new keyboard DataOut 0xfe4cf728, InputCount 
      0<BR>8042: I8xSetDataQueuePointer: exit<BR><BR>8042: 
      I8xDpcVariableOperation: enter<BR>8042: Performing decrement at 0xfe4f529c 
      (current value 0x0)<BR>8042: I8xDpcVariableOperation: exit with value 
      0xffffffff<BR><BR>8042: I8042KeyboardIsrDpc: 
      exit<BR><BR>KBDCLASS-KeyboardClassRead: 
      enter<BR>KBDCLASS-KeyboardClassStartIo: 
      enter<BR>KBDCLASS-KeyboardClassStartIo: DataIn 0xfe4f5938, DataOut 
      0xfe4f5938<BR>KBDCLASS-KeyboardClassStartIo: entries in queue 
      0<BR>KBDCLASS-KeyboardClassStartIo: exit<BR>KBDCLASS-KeyboardClassRead: 
      exit<BR><BR>7.4.2 分析<BR><BR>按一个a键,按下时产生一个 Make Code,引发一个键盘中断,松开时产生一个 Break 
      Code,引发一个键盘中断。a键的 Scan Code Set 1 的 Make Code 为 0x1e,Break Code 为 
      0x9e。<BR><BR>按下时产生一个 Make Code,引发键盘中断,最终导致 
      i8042prt!I8042KeyboardInterruptService 
      被执行。i8042prt!I8042KeyboardInterruptService 中,<BR><BR>首先从0x64端口读出 i8042 
      的状态寄存器,确保i8042状态寄存器的 Bit0 为1,然后从0x60端口读出数据,这里是a键的Make Code 0x1e。<BR><BR>检查 
      deviceExtension-&gt;IsrHookCallback 是否为空,不为空就会调用 
      deviceExtension-&gt;IsrHookCallback。<BR>这说明了驱动 i8042prt 
      支持了hook,我们可以通过DeviceIoControl IOCTL_INTERNAL_I8042_HOOK_KEYBOARD 来设置这个 
      deviceExtension-&gt;IsrHookCallback 。<BR>我们这里 
      deviceExtension-&gt;IsrHookCallback 为空,没有hook。<BR><BR>判断是否是 RESEND 或者 
      ACKNOWLEDGE,RESEND 为 0xFE,ACKNOWLEDGE 为 
      0xFA。如果都不是的话,就认为是一个扫描码。我们这里就是扫描码。<BR><BR>判断 
      deviceExtension-&gt;CurrentScanState 
      中保存的状态。当从i8042读出扩展码的0xe0或者0xe1时,会设置这里,随后读入的数据,就知道是扩展码的一部分。<BR><BR>我们这里是普通状态,判断从i8042读入的数据是否为 
      0xe0 或者 0xe1,如果是的话,就设置 deviceExtension-&gt;CurrentScanState 为 GotE0 或者 
      GotE1。我们这里是 0x1e ,都不是。<BR><BR>判断从i8042读入的数据是否大于 0x7F,也就是判断是 Make Code 还是 
      Break Code。<BR><BR>我们这里是 0x1E 小于 0x7F,是 Make Code。<BR>对于 Make Code,仅仅是把这个 
      Make Code 保存在 CurrentInput 的 MakeCode 中。<BR>将 
      deviceExtension-&gt;CurrentScanState 设置为普通。<BR><BR>调用 
      I8xQueueCurrentKeyboardInput。<BR><BR>I8xQueueCurrentKeyboardInput 
      中,<BR><BR>调用 I8xWriteDataToKeyboardQueue 将 CurrentInput 放入 i8042prt 
      的输入数据队列。<BR>调用 KeInsertQueueDpc ,将 deviceExtension-&gt;KeyboardIsrDpc 
      排队,以待执行。deviceExtension-&gt;KeyboardIsrDpc 的 DeferredRoutine 
      在键盘驱动的初始化过程中已经被赋值为 
      i8042prt!I8042KeyboardIsrDpc。<BR><BR>按下时引发键盘中断到此结束。<BR><BR>松开时产生一个 Break 
      Code,引发键盘中断,最终导致 i8042prt!I8042KeyboardInterruptService 
      被执行。i8042prt!I8042KeyboardInterruptService 中,<BR>大致和 Make Code 
      的情况相同直到,<BR><BR>判断从i8042读入的数据是否大于 0x7F,也就是判断是 Make Code 还是 Break 
      Code。<BR><BR>我们这里是 0x9E 大于 0x7F,是 Break Code。<BR>对于 Break Code,把这个 Break 
      Code &amp; 0x7F,也就是最高位清0,然后保存在 CurrentInput 的 MakeCode 中,然后设置 CurrentInput 
      的 Flags 为 KEY_BREAK,表明这是个 Break Code。<BR><BR>然后将 CurrentInput 放入 i8042prt 
      的输入数据队列。将 deviceExtension-&gt;KeyboardIsrDpc 也就是 
      i8042prt!I8042KeyboardIsrDpc 的那个 DPC 
      排队,以待执行。<BR>松开时引发键盘中断到此结束。&nbsp;<BR><BR>当从中断的 IRQL 降下来时,刚才排队的 
      DPC(延迟过程调用)i8042prt!I8042KeyboardIsrDpc 
      就有机会被执行了。<BR><BR>i8042prt!I8042KeyboardIsrDpc 
      中,以i8042prt的设备扩展中的使用i8042prt的输入数据队列的那些指针为参数,调用保存在 
      deviceExtension-&gt;ConnectData.ClassService 中的回调例程 
      kbdclass!KeyboardClassServiceCallback。键盘驱动初始化过程中,kbdclass 告诉 i8042prt ,它使用 
      kbdclass!KeyboardClassServiceCallback 处理输入数据,于是 i8042prt把这个函数的入口地址保存在了 
      deviceExtension-&gt;ConnectData.ClassService 
      中。kbdclass!KeyboardClassServiceCallback 会从 i8042prt的输入数据队列中取走数据。从 
      kbdclass!KeyboardClassServiceCallback 返回之后,根据取走数据的情况,设置i8042prt的设备扩展中的 
      DataOut 和 
      InputCount。整个按a键的驱动处理过程结束。<BR><BR>kbdclass!KeyboardClassServiceCallback 
      中,<BR>判断kbdclass的 deviceExtension-&gt;RequestIsPending ,如果为TRUE,说明已经有 
      IRP_MJ_READ 的 IRP 在等待数据,就满足这个 IRP。绝大多数情况都有一个 IRP 在等待数据。<BR><BR>我们这里就有一个 
      IRP_MJ_READ 的 IRP 在等待数据,而我们这时i8042prt的输入数据队列中有两个数据,一个a键的Make 
      Code,一个a键的Break Code。一个 IRP_MJ_READ 的 IRP 
      最多一次可以读10个数据,所以我们现在的这个情况,可以一次读完。于是调用 RtlMoveMemory 把i8042prt中的两个数据复制到 
      irp-&gt;AssociatedIrp.SystemBuffer 中,之后会调用 IoCompleteRequest 结束这个 
      IRP。<BR><BR>而对于deviceExtension-&gt;RequestIsPending ,为FALSE,说明上一个 IRP 
      结束后,应用层在处理中,还没有再发一个 IRP 到键盘驱动中。或者是i8042prt的输入数据队列中的数据很多,一个IRP读完之后,还有剩余。那么 
      i8042prt 的输入数据队列中剩余的数据将被 kbdclass!KeyboardClassServiceCallback 放入 kbdclass 
      的输入数据队列。<BR><BR>按a键的驱动处理过程中有不少代码是用来解决使用输入数据队列的问题的,关于输入数据队列的问题我们在后面讨论。<BR><BR>7.4.3 
      示意图<BR><BR>按a之前。 
      <P align=center><IMG src="JIURL键盘驱动 5.files/aPic1.gif" border=0> 
      <P>处理,按下a产生的MakeCode,的i8042prt!I8042KeyboardInterruptService结束之后。 
      <P align=center><IMG src="JIURL键盘驱动 5.files/aPic2.gif" border=0> 
      <P>处理,松开a产生的BreakCode,的i8042prt!I8042KeyboardInterruptService结束之后。 
      <P align=center><IMG src="JIURL键盘驱动 5.files/aPic3.gif" border=0> 
      <P>kbdclass!KeyboardClassServiceCallback, 中将 i8042prt 
      的输入数据队列中的数据复制到irp-&gt;AssociatedIrp.SystemBuffer之后。 
      <P align=center><IMG src="JIURL键盘驱动 5.files/aPic4.gif" border=0> 
      <P>kbdclass!KeyboardClassServiceCallback 中调用 IoCompleteRequest 完成这个 IRP 
      之后。 
      <P align=center><IMG src="JIURL键盘驱动 5.files/aPic5.gif" border=0> 
      <P>i8042prt!I8042KeyboardIsrDpc 设置 DataOut 和 InputCount 之后。 
      <P align=center><IMG src="JIURL键盘驱动 5.files/aPic6.gif" border=0> 
      <P>  
      <P>7.5 按一个扩展键-向上箭头<BR><BR>7.5.1 调试信息<BR><BR>i8042 isr (kb): enter<BR>i8042 
      isr (kb): scanCode 0xe0<BR>i8042 isr (kb): real scan code<BR>i8042 isr 
      (kb): change state to GotE0<BR>i8042 isr (kb): exit<BR><BR>i8042 isr (kb): 
      enter<BR>i8042 isr (kb): scanCode 0x48<BR>i8042 isr (kb): real scan 
      code<BR>i8042 isr (kb): MAKE code<BR>8042: I8xWriteDataToKeyboardQueue: 
      enter<BR>8042: I8xWriteDataToKeyboardQueue: DataIn 0xfe4cf60c, DataOut 
      0xfe4cf60c<BR>8042: I8xWriteDataToKeyboardQueue: InputCount 0<BR>8042: 
      I8xWriteDataToKeyboardQueue: new InputCount 1<BR>8042: 
      I8xWriteDataToKeyboardQueue: exit<BR>i8042 isr (kb): exit<BR><BR>i8042 isr 
      (kb): enter<BR>i8042 isr (kb): scanCode 0xe0<BR>i8042 isr (kb): real scan 
      code<BR>i8042 isr (kb): change state to GotE0<BR>i8042 isr (kb): 
      exit<BR><BR>i8042 isr (kb): enter<BR>i8042 isr (kb): scanCode 
      0xc8<BR>i8042 isr (kb): real scan code<BR>i8042 isr (kb): BREAK 
      code<BR>8042: I8xWriteDataToKeyboardQueue: enter<BR>8042: 
      I8xWriteDataToKeyboardQueue: DataIn 0xfe4cf618, DataOut 
      0xfe4cf60c<BR>8042: I8xWriteDataToKeyboardQueue: InputCount 1<BR>8042: 
      I8xWriteDataToKeyboardQueue: new InputCount 2<BR>8042: 
      I8xWriteDataToKeyboardQueue: exit<BR>i8042 isr (kb): exit<BR><BR>8042: 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -