Enterprise Just Builder

Solution for Enterprise Software Architecture

driver

为 QEMU 虚拟设备编写 Linux PCI 设备驱动

本文将以 QEMU 的 ivshmem 虚拟设备作为硬件平台,逐步演示如何为其编写 Linux PCI 设备驱动。该驱动通过的测试环境为 QEMU 版本V1.0,主机操作系统 Ubuntu 12.04,客户机(VM)操作系统 Linux v3.x,此外它在 QEMU v1.0.1, v2.2.0 和 v2.7.0-rc4 中也表现良好。例子中所引用的头文件和其他源文件如 drivers/pci/pci.c 是以 Linux 内核源文件的根目录为搜索路径的。如 即意指 include/linux/pci.h。

背景
要特别强调的是虚拟平台不能替代实际的物理硬件。但在演示、培训、实验等场景,虚拟平台就特别适合:配置虚拟硬件则相当便捷,且可提供一个一致的可供使用的硬件平台。而且添加、扩展或者移除虚拟平台组件也十分方便。 1

本文选用的是 InterVM SHared MEMory (ivshmem) 这个 QEMU PCI 设备。选择该设备的原因有很多, 包括设备构造简单,可以在主机上使用代码和它进行交互和测试。主机 SHM 共享内存被映射为客户机的 MMIO 区域,通过模拟的物理设备(ivshmem 设备)的 MMIO 访问,客户机操作系统就可以访问主机上的 POSIX SHM 共享内存。此外 ivshmem 框架还允许其他启用 ivshmem 的客户机 (或主机上的程序) 通过 eventfd (2) 机制将 irq 发送给虚拟机。如图1-1 所示。

由于 ivshmem 不是默认启用的 QEMU PC 字符设备, 因此需要在 QEMU 启动命令行中指定相应的设备选项。要查看所支持的设备的列表, 请运行 (以 X64 为例):

$ qemu-system-x86_64 -device ?

注: 编写 PCI 设备驱动所用的 Linux API 通常可以支持 PCI 族,包括 PCI, PCI-X 和 PCI-E。ivshmem 设备模拟的是 PCI 设备。

>>> 阅读全文

 

, , ,

WDF 驱动程序开发

设备驱动程序是硬件设备连接到计算机系统的软件接口,任何设备都必须有相应的驱动程序才能在计算机系统上正常工作。设备驱动程序的优劣直接关系到整个系统的性能和稳定性,因此,设计和开发稳定高效的驱动程序具有重要意义。

WDF (Windows Driver Foundation) 是微软新一代驱动程序模型,它在 WDM (Windows Driver Model) 的基础上发展而来,支持面向对象、事件驱动的驱动程序开发,提供了比 WDM 更高层次的抽象,是高度灵活、可扩展、可诊断的驱动程序框架。WDF 框架接管了驱动和操作系统内核的大多数交互,驱动和操作系统的交互交给框架内封装的方法(函数)完成,从而对二者进行了隔离,这样驱动开发者只需专注处理硬件的行为即可。另外 WDF 还将大多数驱动中都需要处理的 PnP (即插即用)和电源管理封装进了框架,成为了公用的驱动程序功能。

WDF 可以开发内核模式驱动, 也可以开发用户模式驱动,二者采用同一套对象模型构建,即 WDF。对于内核模式对象和用户模式对象来说,WDF 是它们的父对象。换言之两者都是从 WDF 派生而来的。针对内核模式派生出来的对象称为 KMDF;针对于户模式派生出来的对象称为 UMDF。无论何种模式的框架,其内部封装的方法、执行的行为其实还是用 WDM 来完成的。

本文主要针对 KMDF 框架展开讨论。

KMDF 对象模型
KMDF 驱动程序模型支持面向对象、事件驱动。它定义了一系列的对象用于表示设备、驱动、中断等,每个对象有其相应的属性、方法和事件。驱动程序利用这些方法创建对象、设置属性和响应事件。该框架定义的主要对象有:

>>> 阅读全文

 

, , ,

SPB 设备和驱动简介

现在有许多文章介绍 Windows 8 操作系统层级的功能。其中之一就是支持简单外设总线 (SPB) 连接的设备。SPB 总线具有低成本、低功耗、低速度的特点,经常用于连接如传感器之类的相对简单的外设。Windows 8 支持的 SPB 设备包括 I2C 和 SPI。之前这类设备受到 BIOS 的限制而很少使用。从 Windows 8 开始,支持这些设备则成为了主流。

如果你对 SPB 总线以及如何编写 SPB 设备驱动感兴趣,可以跟随本文1来深入探讨这些话题。

SPB 总线 — 拓扑和设备枚举
和 SCSI、 SATA 和 USB 总线一样,SPB 是协议式(protocol-based ) 总线。也就是说,有一个控制器会根据总线定义的规则使用正确的协议来请求开关总线。连接到协议式总线上的设备被称为客户端设备,简称客户端。如图1-1.

SPB 总线最让人困惑的地方是如何发现和枚举总线上的设备。 SPB 总线无法动态枚举,这意味着在运行时接上 SPB 总线的设备都无法被发现。那么 Windows PnP 过程如何侦测 SPB 客户端的呢?答案很简单:哪个 SPB 设备挂在哪条 SPB 总线,这些描述被静态添加到一个表中,作为 ACPI BIOS 一部分。所以,枚举 SPB 客户端是由 ACPI 驱动而不是 SPB 控制器驱动负责的。SPB 控制器是典型的背板总线(backplane-bus )类型的设备,总被 PCI 总线驱动所枚举。详细可以参考图1-2 和图1-3。

包含该描述的 ACPI 表格被称为差异系统描述符表(Differentiated System Descriptor Table)简称 DSDT。DSDT 通常由系统集成商(一般是 OEM ) 随 ROM 一起提供的。由于 SPB 设备通常都被永久集成在系统平台上 — 大部分被焊在主板上,所以无法动态枚举不会有任何问题。 少数情况下,SPB 设备可能会被动态地接上系统(比如平板电脑的 I2C 键盘),此时设备信息仍由 ACPI BIOS 提供并由 ACPI 驱动枚举。

>>> 阅读全文

 

, , , , ,

Windows 连接管理器和 NCM 驱动

从 Windows 8 开始,微软引入了自动连接管理器,它负责查看系统的网络连接如以太网、Wi-Fi 和移动网络,从中选择最合适的网络并自动连接,同时断开其他连接。(注:Windows 会响应以太网,但不会自动管理其连接。另外:拨号上网或者虚拟网络接口如 VPN 不在其管理范围中)。1

连接管理器策略
Windows 内置了许多策略来控制连接管理器,Windows 并未提供用户界面来查看这些策略,但可利用 WcmSetProperty API 或组策略来进行配置。这些策略包括:

最少并发连接数
该策略在 Windows 8 或 8.1 中是默认打开的。如果禁用该策略,操作系统行为将与 Windows 7 类似:每个网络接口都选择其所辖的首选网络,而不管其他接口的连接状态。

如果启动该策略,Windows 会尝试用最小并发连接来提供最佳的可用网络,Windows 将保持下列连接:

  • 任何以太网
  • 当前用户会话中手动连接的任何网络
  • 连接到 Internet 的首选连接
  • 连接到活动目录域的首选网络(入域的机器)

其他的所有网络则被“软”断开,有关“软”断开请见下一节。这也用于评估未被连接的可用网络。Windows will not connect to a new network from which it would immediately soft-disconnect.

>>> 阅读全文

 

,

Linux和Windows设备驱动架构比较

本文将带你了解广泛使用的 Windows 和 Linux 操作系统的设备驱动架构的差异。文章将首先比较这两个平台上实现设备驱动所需的组件,然后讨论实现驱动程序的过程,包括如何对内核缓冲区执行 I/O 操作等等。最后我们还将了解这两个操作系统所提供的开发环境和基础工具。1

1.引言
现代操作系统一般都包含多个模块,如内存管理器、进程调度器、硬件抽象层和安全管理器等等。这里提供一些参考资料以方便你进一步了解这两种操作系统的内核:关于 Windows 内核的细节,可翻阅 Russinovich 著的《Windows Internal》一书;而 Linux 内核则可以参考 Rusling 的《The Linux Kernel》或者 Beck et al 等合著的《Linux Kernel Internal》。内核可被视为一个黑盒,它知道如何去和市面现有的或将要推出的各种设备交互。能否让内核内建就支持所有市面上的已知设备呢?这是有可能实现的,但没有实际意义,因为这会无谓地消耗过多的系统资源。

1.1. 内核模块化
内核无法在创建伊始就预见到要如何与尚未面世的新设备交互。现代操作系统的内核允许在运行时添加设备驱动模块来扩展系统功能,该模块实现的功能使得内核可以与特定的某种新设备交互。这些模块通常都会实现一个例程供内核在加载模块时调用,此外还有一个例程供移除模块时调用。模块还会实现其他各种不同的例程以便实现 I/O 功能,如将数据传送到设备或从设备接收数据;同时还有例程以便向设备发送 I/O 控制指令。这些对 Linux 和 Windows 两种驱动架构均适用。

1.2. 本文的组织结构
本论文分成下面几节:

  • 对两种驱动架构的一般介绍 (第二节)
  • 详细论述两种驱动架构的各个组件 (第三节)
  • 驱动程序范例,包括如何对内核缓冲区执行 I/O 操作(第四节)
  • 相关驱动开发环境和基础工具(第五节)

1.3. 相关著作
有关 Windows 设备驱动架构相关文档可在 Windows 驱动开发包(DDK)中找到. 此外 Walter Oney 和 Chris Cant 在 《Writing Windows WDM Device Drivers》一书中对 Windows 驱动架构进行了详细介绍。Linux 设备驱动架构可以参考 Rubini 的《Linux Device Drivers》,该书可免费获取。

>>> 阅读全文

 

, , , , ,

Windows 驱动开发 <1> 理解 Windows 驱动的执行上下文

要理解 Windows 内核驱动,很重要的是要了解一个驱动函数是在哪一种”上下文”中执行的。如果你从事文件系统的开发、或 Windows 内核驱动的编写,透彻理解执行上下文将使你获益匪浅。了解上下文并小心使用,可以让你设计出高性能、低开销的内核驱动。

本文将探讨执行上下文的概念。在文章末尾,沃恩还会介绍一个驱动作为概念演示,该驱动可以允许用户态程序运行在内核模式中,因此拥有内核模式的所有权限与特权。此外,我们还将讨论设备驱动程序的执行上下文及其实际用途。1

什么是上下文
当提到某个例程的上下文时,其实指的是它的线程和进程执行环境。在 Windows NT 中,该环境是由当前的 TEB (Thread Environment Block) 和 PEB (Processes Environment Block) 所建立的。因此,上下文中将包括虚拟内存配置 ( virtual memory settings — 用于说明物理内存页与虚拟内存地址的对应关系) 、句柄对照表 (handle translations, 因为句柄是特定于进程的)、分发器信息( dispatcher information)、栈(stacks) 、通用和浮点寄存器集等内容。

如果我们问“某个内核例程所运行的上下文是什么”,实际上的问题是“内核分发器所建立的当前线程是什么”。由于每个线程仅可属于一个进程,所以当前线程同时也就意味着某个当前进程。当前线程和当前进程合在一起,就意味着我们前面提到的句柄、虚拟内存、调度状态等等,这些东西使得线程和进程具有唯一性。

对于内核驱动程序员来说, 上下文中最有用的也许就是虚拟内存上下文。如果你还记得 Windows 将用户进程空间映射到低 2GB 的虚拟内存地址中,而操作系统代码则被映射到高 2GB 虚拟内存空间中。当用户进程中的某个线程被执行时,其虚拟地址将位于 0~2GB 的范围中。所有高于 2GB 的地址都被设置为“不可访问”,以防用户直接访问操作系统的代码和数据结构。当操作系统代码被执行时,其虚拟地址范围是 2~4GB。

>>> 阅读全文

 

,

利用总线接口进行驱动间通讯

这里我们将讨论高级 WDF 驱动开发中最常见的话题之一: 驱动间的通信。当引入 Windows 驱动开发其他话题,貌似简单的驱动间调用很快就变成一系列无穷无尽的选项、功能以及晦涩难懂的 WDM 琐事。1

不过从这些讨论中我们看到了希望之光:总线接口还存在着并活跃在 Windows 中,它不但提供了简洁的、定义良好的方式用于驱动间通信,而且 KDMF 还提供了帮助例程用来快速生产或消费这些接口。

什么是总线接口?
正如其名称所示,总线接口是总线驱动为其子驱动提供的一种标准程序调用接口。总线驱动可以有多个总线接口,每个接口通过 GUID 标识。接口的使用者通过 PnP IRP 来查询接口并返回一个总线定义的数据结构,该数据结构可以包含任何总线驱动想要共享的数据或函数 (如图1-1)。

当总线驱动向其子驱动的提供总线接口时,我们预期只有该 PDO 设备栈中的驱动将使用此接口。这样在卸载驱动时就可以消除任何可能存在的竞态。因为设备栈是从顶向下被逐一销毁的,因此 PDO 总是最后一个被删除的设备。假如总线接口被其设备栈内的驱动所使用,我们就无需担心在 PDO 被删除之后,还有程序试图使用该接口。

总线接口不只是给总线的
显然在总线驱动之外总线接口也相当有用,驱动间通信很常见且不是所有的驱动间通信都只涉及到与自己的 PDO 交互。还好,操作系统中对总线驱动的支持相当普遍,因此过滤型驱动或 FDO 可以对适当的 PnP IRP 进行处理,并发布自己的总线接口。这意味着我们可以使用由另一不同的设备栈 (图 2) 产生的总线接口。

>>> 阅读全文

 

, ,

编写虚拟 Storport 微端口驱动(一)

Storport 广受虚拟存储设备驱动编写者的欢迎。在 Storport 出现前,要完成类似的工作,你不得不修改(hack) SCSIport 微端口驱动,或者自己写个完整的 SCSI 端口驱动。修改微端口的方法十分复杂 (由于锁的问题)、 难以获得支持或者维护,而且性能较差。而编写完整的 SCSI 端口驱动的方法虽然性能不错,但技术难度高,而且也不支持 Windows 徽标认证。因此,这一领域的开发工作只限于那些愿意冒险、敢于尝试、而且不打算过徽标认证的公司和个人。1

Storport 是跟着 Windows Server 2003 被引入的,用来满足 RAID 和 SAN 环境的性能要求,这是以前的 SCSIport 驱动所不具备的。后续在 Windows Vista SP1 和 Server 2008 中,微软又更新了 Storport,提供了对 Storport 虚拟微端口驱动的支持。这个更新终于让存储驱动编写者拥有了一个能导出虚拟设备的模型。

对于虚拟微端口驱动的编写来说,Storport 模型相当不错。它提供了诸如 I/O 队列管理 (如队列深度、到达队列深度阀值时对 I/O 进行处理)、 I/O 错误处理 (如重置、重试等)、 启动或停止 PnP 设备 (LUN) 所需的所有操作以及总线驱动的所有职能。它只是无法提供硬件管理方面的帮助,因为我们开发的是虚拟微端口,所以并未存在任何硬件。另一方面,虚拟微端口驱动则要完全负责处理 I/O 请求。虽然听起来令人生畏,不过作为虚拟微端口驱动,你有全套的内核 API 和其它驱动程序来帮助完成这一工作。

开始
可能你从未接触过 Storport ,所以这里先了解一些基础知识。当你利用 Storport 模型进行开发时,这意味着你的驱动需要将接口暴露给 Storport 驱动 (Storport.sys),这是通过预定义的 API 和数据结构完成的,而不是基于 IRP。与 SCSI 端口/微端口模型类似,Storport 驱动被称为端口驱动,提供了微端口驱动进行操作的环境和支持例程,如此我们的适配器才对 Windows 存储子系统可见。这里适配器可以是物理设备或者虚拟设备,可以控制多条 SCSI 总线或多个 SCSI 设备。基于该模型所开发驱动即微端口驱动,图1-1 显示了 Storport 模型。

Storport 微端口驱动必须符合预定义的 Storport 规则以便将适配器(虚拟或物理)的服务提供给操作系统。Storport 通过 SCSI_REQUEST_BLOCKS (SRB — SCSI 请求块) 来调用微端口驱动, SRB 描述了要执行的操作。与 IRP 类似,SRB 包含了微端口驱动执行操作需要的所有信息。它包含一个操作码、 缓冲区以及用来描述请求的参数。驱动执行 SRB 描述的操作、将完成状态放入 SRB ,并完成请求时通知 Storport。该过程与普通驱动处理 IRP 不一样。

>>> 阅读全文

 

, , ,

Linux 设备驱动(一) PCI 设备枚举

本文将讨论 Linux 内核如何初始化系统的 PCI 总线和 PCI 设备。所谓 PCI — Peripheral Component Interconnect 即外部设备互联,PCI 标准是描述如何将系统中的设备以一种结构化、可控制的方式连接在一起的规范,包括系统外部设备的连接方式以及符合标准的设备组件应具备的行为规范。PCI 总线作为处理器系统的局部总线,主要目的是为了连接外部设备。较之前的存在其他总线如 ISA、EISA 和 MCA 总线相比,PCI 具有许多突出的优点:

  • PCI 总线空间与处理器空间隔离。PCI 设备具有独立的地址空间,该空间与存储器地址空间通过 HOST 主桥隔离。
  • 可扩展性。在 PCI 总线中,HOST 主桥可以通过 PCI 桥(PCI Bridge)扩展出一系列 PCI 总线,形成以 HOST 主桥为根节点的 PCI 总线树。该总线树上最多能挂接 256 个 PCI 设备(包括 PCI 桥)。
  • 动态配置机制。每个 PCI 设备都有独立的配置空间,包含设备在 PCI 总线中使用的基地址。基地址由系统软件动态配置并保证唯一性,从而解决了地址冲突的问题,实现了“即插即用” 的功能。PCI 桥的配置空间中则含有其 PCI 子树所能使用的地址范围。
  • 总线带宽。与之前的局部总线相比,PCI 总线极大提高了数据传送带宽,如 32位/33MHz 的 PCI 总线可以提供 132MB/s 的峰值带宽,而 64位/66MHz 的 PCI 总线可提供的峰值带宽为 532MB/s。
  • 共享总线的仲裁机制。PCI 设备通过仲裁获得 PCI 总线的使用权后才能进行数据传送;在 PCI 总线上进行数据传送,并不需要处理器进行干预。
  • 中断机制。PCI 总线上的设备可以通过四根中断请求信号线 INTA~D# 向处理器提交中断请求。PCI 总线上的设备可以共享这些中断请求信号。

一、PCI 总线组成结构
PCI 总线作为处理器系统的局部总线,是处理器系统的一个组成部件。讲述 PCI 总线的组成结构不能离开处理器系统这个大环境。在一个处理器系统中,与 PCI 总线相关的模块如图1‑1所示。

在一个处理器系统中,与 PCI 总线相关的模块包括:HOST 主桥、PCI 总线、PCI 桥接器和 PCI 设备。对于一些简单的系统,可能不含有 PCI 桥接器,这时所有设备都连接在 HOST 主桥引出的 PCI 总线上;而有些处理器系统中可能有多个 HOST 主桥,比如图1‑1中的处理器系统中就含有 HOST 主桥 X 和 HOST 主桥 Y。

PCI 总线由 HOST 主桥和 PCI 桥接器引出,HOST 主桥与主内存控制器在同一级总线上,PCI 设备可以方便地通过 HOST 主桥访问主内存,即进行 DMA 操作。

值得注意的是,PCI 设备的 DMA 操作需要与处理器系统的 Cache 进行一致性操作,当 PCI 设备通过 HOST 主桥访问主内存时,Cache 一致性模块将进行地址监听,并根据监听结果改变 Cache 的状态。

>>> 阅读全文

 

, ,

基于 UMDF 编写虚拟读卡器驱动

智能卡和 PKI 是有趣的领域。这里你可以看到最先进的计算机安全技术及其在现实环境中的运用。但是,调试测试与智能卡相关的应用有时候十分痛苦,尤其是在运行负面测试用例的时候,很多时候,你手上没有太多的智能卡以供测试。一旦 PIN 码被屏蔽或 CSP 发出错误命令都可能导致智能卡状态不一致。这类问题相当普遍,所以我意识到,从事智能卡开发第一要务就是:你需要个模拟器来进行各种试验而不会有任何损失。本文并不准备谈论该如何实现智能卡的操作系统仿真(也许以后吧),而是先从开发虚拟智能卡阅读器的驱动程序入手。1

在网上搜索“虚拟驱动程序”可以找到很多有用的资源,但大多不是我想要的“傻瓜式指导”。我不是驱动开发专家;所以本文主旨不是“如何编写驱动程序”。而只是展示我在这个新领域里的一些探索,并希望对其他人有所帮助。

还有一种编写智能卡驱动的方法是编写自己的 winscard.dll 版本,并将它保存在要调试的应用程序的目录下。这种方法更简单,但也有一些缺点:

  • 要完全模拟 Windows 智能卡资源管理器,需要自己实现一些缺失的函数。
  • 要实现诸如 SCardGetStatusChange 等函数十分痛苦,特别要同时考虑真实的读卡器和模拟读卡器
  • 由于系统文件保护机制,你无法覆盖掉系统的 winscard.dll,对有些应用来说,想跳过它得大费周章。

尝试了两种做法之后,我认为重新编写个驱动的做法更为妥帖,并从中学习了不少有益的经验。要实现它,通过 Google 可以得到很多有用的资料。为了简单期间,我选用 UMDF (User Mode Driver Framework) 作为开发驱动的基础。我个人认为,它有以下优势:

  • 驱动中的错误不会导致蓝屏死机,开发更容易
  • 可以用你熟悉的调试器,比如 VS2008 来调试代码,而无需内核调试器,调试更容易
  • 在此用例中性能不是关键需求,一点性能开销不会有任何问题。

这里的代码是从 WDK 7.1中的示例 UMDFSkeleton 修改而来的。我会对代码中的重点部分进行解释,然后说明安装流程。

>>> 阅读全文

 

, , , , , , ,

WDDM 编程与调试 (1) — GPU 架构概览

从 Vista 开始, Windows 的显示驱动全面采用新的编程框架,WDDM 即 Windows Display Driver Model。 WDDM 在 Windows 中之所以不可或缺,是因为 WDDM 与全新的桌面窗口管理器 DWM (Desktop Window Manager) 紧密相联。从技术的角度上来看, DWM 与 Mac OS X 中的 Quartz Compositor 类似。在 DWM 中,应用窗口不再像以前的 Windows 被直接绘制在屏幕上,而是经后台渲染后放入缓存中,再由 DWM 进行组合并最终呈现在屏幕上,即所谓“桌面组合”的概念。由于每个窗口分别在不同的视频内存区进行渲染,这使得 Aero 能够将窗口与桌面背景图像混合创建出类似霜冻玻璃之类的图形效果,为此,在设计上需要对每个窗口都使用图形加速,而不再仅限于 DirectX® 应用程序。

在 Vista 中,最终呈现操作是由 DWM 中的独立线程处理,而应用程序窗口的呈现则由窗口的 UI 线程负责操作。DWM 通过窗口列表,在树结构中管理各个窗口位图,然后将其组合到最终桌面。换言之,应用程序的主窗口线程呈现其场景,DWM 呈现线程对该场景进行访问,并通过其 DirectX 接口更新桌面。为了实现这一点,DWM 需要与 WDDM 通信,后者是图形处理器和显存的最终所有者。

WDDM 引入了显存管理器 ( VidMM — Video Memory Manager),可以在系统内存和显存之间进行交换。这意味着 WDDM 可以虚拟化显卡的资源,因而在共享和交换显存方面以及在线程间对 GPU 进行上下文切换方面可以做得更好。

WDDM 的版本随 Windows 有所不同:Windows Vista 支持 WDDM 1.0 ,而 Window7 支持 WDDM 1.1, Windows 8 支持 1.2版本。Windows 8.1 则将 WDDM 的版本更新到 1.3。目前最新的 windows10 中,WDDM 更新至 2.0 版本,将支持 DX12。

WDDM 的新变化
要了解 WDDM 有什么新变化,我们先看一下在 Windows XP 显卡驱动程序是如何工作的。对于 Windows XP 来说,绝大多数显示驱动程序都驻留在操作系统的内核空间,以便直接与图形硬件进行通讯,只有一小部分组件(如驱动程序中的 OpenGL) 留在了用户空间中且不直接访问硬件。这个模型的问题在于,操作系统内核空间的错误(包括驱动)可能会导致整个系统崩溃。图 1-1 是 ATI 显卡的 XP 驱动程序模型。

>>> 阅读全文

 

, , , , , , ,

Windows 下如何实现键盘记录器

首先强调的是本文不提供任何键盘记录器的源代码,我们所要侧重了解的是键盘记录器背后所涉及的系统机制,从而更好地了解 Windows 操作系统是如何与硬件协调工作的。本文适合那些对内核或驱动开发有经验的用户。1

在 Windows 中处理键盘输入数据
有多种技术可以截取键盘和鼠标事件,而键盘记录器或多或少都用到了这些技术。因此在剖析某款键盘记录器之前,有必要先了解一下 Windows 是如何处理键盘输入数据的。这个过程可以简单描述为:

  • 1. 键盘上某一个键被按下;
  • 2. 键盘系统中断控制器被激活;
  • 3. WM_KEYDOWN 消息出现;

有关内容可以参考:

  • “Apparatnoe obeshpechenie IBM PC” 作者 Alexander Frolov 和 Grigory Frolov, 第2卷, 第 1 册。 Dialog-MIFI出版社, 1992 年出版。第二章 “键盘” 介绍了键盘的工作原理、使用的端口和键盘硬件中断。
  • MSDN 上 “HID / Human Input Devices” 小节内介绍了键盘输入处理过程的底层部分(驱动)。
  • Jeffrey Richter 的著作 《Creating effective Win32 applications for 64-bit Windows》 第 27 章 “A model of hardware input and the local input condition” 中谈到了键盘输入处理过程的顶层部分(用户模式)。

作为物理设备的键盘是如何工作的。
大多数键盘都是独立设备,通过 PS/2 或 USB 接口连接到计算机上。有两个微控制器负责处理从键盘输入数据,i8042 在主板上,i8048 在键盘内。可以说 PC 键盘本身就是个小型计算机系统,其所使用的 i8048 微控制器独立于中央 CPU,负责不断地扫描被按下的按键。

每个按键都会被指定某一特定值,具体值和按键矩阵图强相关,而与按键上印刷的字符无关。这些数值被称为“扫描码”(这个名称凸显了计算机通过扫描键盘来搜索敲键的事实)。扫描码是 IBM 公司在为其 PC 创造出第一个键盘时选择的随机数。对单个按键来说,其扫描码并不是和 ASCII 码一一对应,相反它可以对应于多个 ASCII 码值。扫描码表可以在《汇编语言程序设计的艺术》一书的第 21 章中找到。

>>> 阅读全文

 

, , ,

Windows 驱动开发(二)实现 IOCTLs

这是关于编写设备驱动程序系列教程的第二篇。我们会从上一篇谈到的东西继续下去。这一系列文章的主旨一点点打造编写设备驱动程序所需的知识。我们会利用上一篇文章的代码进行修改构建。在本文中,我们扩展这些代码以提供包括读取功能,处理输入/输出控制(也称为 IOCTL)并且更多地了解 IRP。

在开始之前,我先澄清一些常见问题。

哪里可以下载 DDK 或 WDK?
每一版 Windows 的发布,微软会同步推出驱动程序工具包,目前最新的是 WDK8,可以用来为 Vista, Windows 7 和 Windows 8 开发驱动。你可以在微软站点上下载该工具包。

我可以在驱动中使用 windows.h 头文件吗?
不要混用 Windows SDK 与 Windows DDK 的头文件。定义冲突会让代码编译变得十分困难。如果用户模式程序用到部分 DDK 的内容,通常我们会将需要的 DDK 或 SDK 的定义抽取出来放到源代码中。你还可以将 DDK 和 SDK 相关的文件隔离开来,每一个 .C 文件都可以包含正确的头文件而不会冲突。

可以用同样的方式实现某种特定类型的驱动吗?
这里谈的是适用大多数 Windows 驱动程序开发的通用框架。驱动程序不需要紧贴着硬件实现,而是通常有一个驱动程序栈。如果想实现某种特定类型的驱动程序,本文是了解驱动程序通常是如何工作的起点。后续的不同之处在于如何向系统宣告设别、 要实现哪些 IOCTL、 需要和哪些下层驱动进行通讯、以及其他一些要求实现的部分如配套驱动或用户模式组件。具体实现某种特定类型的驱动时,你应该在 MSDN 、DDK 多阅读一些与该类型驱动相关的内容。有些框架封装了我们在这里谈到的大部分内容,利用这些框架写起例子来会更简单。

>>> 阅读全文

 

, , ,

Windows 驱动开发 (一) 什么是驱动?

文章评价:
本系列文章将从头开始教你如何编写简单的 Windows NT 设备驱动程序。的确,你可以在互联网上找到各种有关编写设备驱动程序的资源和教程,不过,其中大部分都是编写 “Hello,World” 之类的入门程序,这也导致了在真正编写设备驱动程序时,很难搜索到有用的信息。也许你手边也有些教程,为啥你还需要阅读本文呢?我个人认为,信息越多总是越好,尤其对于那些第一次接触到的概念。能从多角度来观察同一个事物总是会带来新的观点。不同的人会用不同的方式写作,并从自己的角度描述信息,这取决于作者熟悉哪一方面或他觉得哪一方面值得说明。这种情况下,我个人建议任何想要编写设备驱动程序的人不要拘泥于本文或者其他文章。你应该多看看各种的示例和代码段,并研究其中的差异。

本教程会介绍如何创建一个简单的设备驱动,然后动态加载/卸载这个驱动,最后我们会涉及如何在用户模式下与驱动进行通讯。

创建简单的设备驱动

首先我们先来了解什么是子系统。

什么是子系统?
在解释如何编写设备驱动前,我会引入一些基础知识。我们将从编译器开始。编译器和链接器会按操作系统可以理解的格式生成二进制文件。在 Windows 中,这种格式称为 “PE”,即”可移植的可执行文件- Portable Executable”格式。在该格式中,有个称为子系统的概念。子系统 和 PE 头部信息中的其他选项一起描述了如何加载可执行文件,其中也包括了二进制文件的入口点的信息。(注:在 PE 可选头部中包含了很多关于可执行映像的重要信息,例如初始的堆栈大小、程序入口点的位置、首选基地址、操作系统版本、段对齐的信息等等。)

>>> 阅读全文

 

, , ,

WDF USB设备驱动开发指南

USB 的全称是 Universal Serial BUS(通用串行总线), 它有两个重要的特点:串行数据传输、支持热拔插。从 1996 年 1 月至今,USB 已经经历了四个版本:1.0、1.1、2.0 和 3.0。其应用遍及各个领域, USB 采用主从结构。两个可以互联的设备,一定有主从之分。这导致了两台主机(主设备)或者两个 U 盘之间没有办法互联,只能在设备(U盘)和主机之间建立主从互联关系。

要成为 USB 主机,就一定有两种设备:USB 主控制器、USB 根集线器。主控制器用来处理根集线器上的数据,交给系统处理;根集线器用来连接多个外部设备。请注意:根集线器和普通 USB 集线器是不同的,普通 USB 集线器也是 USB 外部设备的一种,不是主机的组成部分。

我们在使用的电脑,每台电脑都有若干个控制器,控制器上有一个或多个根集线器,集线器上又对外暴露出一个或多个 USB A 型接口让外部设备连接。在设备管理器的视图模式选择 “按连接排序设备” 后,可看到和图 1-1 类似的”设备->集线器–>控制器->系统”层次结构。

最上层是 USB EHCI 接口的控制器,中间层是控制器上唯一的根集线器,最下层是连接在根集线器上的设备(包括普通集线器)。 每个 USB 控制器是一个 USB 族群的核心,其驱动程序负责为子设备分配总线地址。总线地址为 7 位宽,由于控制器自己占一个地址,故而最多可提供(2^7 -1 = 127)个子设备地址,也就是说,每个控制器上最多能连接 127 个子设备。并且这个数目包含了根集线器。

USB 电气特性和枚举
标准 USB 接口有 4 个金属针脚,对应着 USB 线中,就是 4 根金属线:两根电源线(5V的 VBus 和地线 GND )和两根数据线(D+ 和 D-)。这两根数据线实现了数据的差分传输,其实等于是一根线,但是提高了稳定性,这也就是“串行”之由来了。 USB 设备可以自己供电,也可以从总线获取电源,即通过 5V 电源线传过来的。像 U 盘、鼠键这类小型设备,5V 电源或者 100mA 电流足以满足其设备需求,故而多从总线获取电源;移动硬盘、打印机、USB 声卡这种较大设备,往往需要外置电源。

>>> 阅读全文

 

, ,

Previous Posts