加载中

The Microsoft Devices team is excited to announce the release of an open source framework for Windows driver developers — Driver Module Framework (DMF). With DMF, not only can you easily develop simple and structured Windows Driver Framework (WDF) drivers but also share code amongst your drivers.

微软设备团队很高兴地宣布为Windows驱动程序开发人员发布一个开源框架——驱动程序模块框架(DMF)。使用DMF,不仅可以轻松地开发简单且结构化的Windows驱动程序框架(WDF)驱动程序,还可以在驱动程序之间共享代码。

Background

Over the years Surface organization developed many products such as Pro, Studio, Laptop, Book with unique, innovative hardware capabilities. To light up these capabilities, we often needed to write drivers and firmware. Even though these products had commonalities in terms of how they interfaced with the hardware, individual product teams worked in isolation and built either their own drivers from scratch or copied based on their awareness of existing code and modified to suit their needs. This did help in meeting their immediate business priorities, but led to tremendous duplication of code and maintenance overhead. Developers with varied level of experience often created many divergent solutions to solve the same problem and the code lacked structure and quality.

背景

多年来,Surface 团队开发了许多产品,如 Pro,Studio,Laptop,Book,具有独特创新硬件功能。为了实现这些功能,我们经常需要编写驱动程序和固件。尽管这些产品在与硬件接口方面具有共性,但各个产品团队独立工作,从头开始构建自己的驱动程序,或者根据他们对现有代码的认识进行复制,并根据他们的需求进行修改。这确实有助于满足他们的直接业务优先级,但却导致了巨大的代码重复和维护开销。具有不同经验水平的开发人员经常创建许多不同的解决方案来解决相同的问题,并且代码结构和质量堪忧。

About three years ago, the team decided to take a holistic look at drivers written for various Surface products and started an effort to structure code in a way that allows for maximum reuse of code with goals to improve the efficiency, serviceability, and scalability of teams to build new products.

We started by breaking down individual functionalities in drivers into a shareable code base. This iterative effort led to the creation of DMF: an extension to WDF that provides you with a library of new WDF Objects called DMF Modules. Modules allow interaction with one another, WDF, and hardware in a structured manner.

大约三年前,该团队决定全面审视为各种 Surface 产品编写驱动程序,并开始尝试以最大程度重用代码的方式重构代码,以提高团队的效率,可维护性和可扩展性。建立新产品。

我们首先将驱动程序中的各个功能分解为可共享的代码库。这种迭代尝试催生了 DMF 的创建:WDF 的扩展,并提供了一个名为 DMF 模块的新 WDF 对象库。 模块允许以结构化方式让 WDF 和硬件彼此交互。

Today, all WDF drivers on the team are written by using DMF. Modules are well tested and can be reused or extended later to meet new requirements. Besides having the benefit of well-architected drivers, bug fixes are now efficient. A bug fix in a Module is automatically applied to all the drivers that were built using the Module.

As part of the open source effort, we have shared many Modules that provide solutions for commonly faced problems.

如今,团队中的所有 WDF 驱动程序都是使用 DMF 编写的。模块经过良好测试,可以在以后重复使用或扩展,以满足新的要求。除了具有良好架构的驱动程序之外,错误修复现在也很有效。模块中的错误修复会自动应用于使用该模块构建的所有驱动程序。

作为开源工作的一部分,我们共享了许多模块,为常见问题提供解决方案。

Architecture of DMF

Let’s start by looking at a typical design of WDF driver.

In this design, the driver maintains state in a device context and the code is divided into units that access the device context and communicate among themselves. You, as the driver developer, are responsible for making sure that accesses to the device context are synchronized and strict locking hierarchy is adhered to when units communicate with each other to avoid corruption and deadlock. As WDF calls into the driver, you are also responsible for dispatching work to each of the units as needed. It is hard to know the flow of communication and keep access to the device context properly synchronized.

DMF 架构

首先让我们看一下 WDF 驱动程序的典型设计.



在此设计中,驱动程序在设备上下文中处于维护状态,并且代码被分成访问设备上下文并在它们之间进行通信的单元。作为驱动程序开发人员,你负责确保对设备上下文的访问进行同步,并在单元相互通信时遵守严格的锁定层次结构,以避免损坏和死锁。当 WDF 调用驱动程序时,你还要负责根据需要将工作分派给每个单元。因为很难知道通信的流程,并保持对设备上下文的正确同步访问。

If you want to reuse for example FIFO code in another driver. You need to understand the complex interaction between the units before extracting the code and the fields used to store the state. Often times, that iserror prone.

Now let’s improve the architecture by using DMF. Here the driver is built by using a client Module and several prebuilt generic utility Modules. We are going to refer to code that uses a Module as the client driver. Between WDF and individual Modules, there is a thin arbitration layer (DMF) to bind Modules and dispatch WDF events to each Module. Now, Modules communicate with each other and the client driver in a well-defined manner as shown by the arrows. Instead of all the Modules sharing the device context, each one uses its own context area to maintain its state.

如果要在另一个驱动程序中重用 FIFO 代码。在提取代码和用于存储状态的字段之前,您需要了解单元之间的复杂交互。而这在很多时候往往容易出错。

现在让我们使用 DMF 来改进架构。这里的驱动程序是使用客户端模块和几个预构建的通用实用程序模块构建的。我们将参考使用 Module 作为客户端驱动程序的代码。在 WDF 和各个模块之间,有一个中间层(DMF)来绑定模块并将 WDF 事件分派给每个模块。现在,模块以明确定义的方式相互通信并与客户端驱动程序通信,如箭头所示。而不是所有模块共享设备上下文,每个模块使用自己的上下文区域来维护其状态。

Here are some key differences between a traditional WDF and DMF-based WDF driver:

  • WDF communicates with DMF, while DMF communicates with the driver.

  • The device context (shown in green) exists independently in each Module and in the client driver-specific code. Each smaller device context holds only the elements that are needed for that Module. No Module can access another Module’s device context.

  • The WDF callbacks (shown in red) now exist independently in each Module and in the client-specific code. WDF calls into the client driver. DMF intercepts that call and dispatches it to each Module in the tree of instantiated Modules. Each Module handles each callback as it sees fit. Finally, DMF dispatches the callbacks to the client driver’s callbacks.

  • Finally, note the arrows. The arrows specifically show the flow among Modules and the client-specific code. In this example, client-specific code can only communicate with three Modules: ACPI, Button, and Stream. It cannot communicate with GPIO, FIFO, List, or Thread. ACPI cannot communicate with FIFO, etc. Even without looking at source code, we have a good idea of how data flows in this driver.

To summarize, each Module is a self-contained single unit. It has its own code, context, and callbacks. This makes the code easy to reuse. Organizing drivers in this way solves many problems.

以下是传统的 WDF 和基于 DMF 的 WDF 驱动程序之间的一些关键区别:

  • WDF 与 DMF通信,DMF 与驱动程序通信。

  • 设备上下文(用绿色表示)独立存在于每个模块和特定于客户端的驱动程序代码中。每个较小的设备上下文仅包含该模块所需的元素。没有模块可以访问另一个模块的设备上下文。

  • WDF 回调(用红色表示)现在独立存在于每个模块和特定于客户端的代码中。WDF 调用客户端驱动程序。DMF 拦截调用并将其分派到实例化模块树中的每个模块。每个模块根据需要处理每个回调。最后,DMF 将回调分派到客户机驱动程序的回调。

  • 最后,注意箭头。箭头特别地显示了模块之间的流和特定于客户端的代码。在本例中,特定于客户端的代码只能与三个模块通信:ACPI、Button 和 Stream。它不能与 GPIO、FIFO、List 或线程通信。ACPI 不能与 FIFO 等进行通信。即使不查看源代码,我们也对这个驱动程序中的数据流有很好的了解。

总之,每个模块都是一个独立的单元。它有自己的代码、上下文和回调。这使得代码易于重用。以这种方式组织驱动程序可以解决许多问题。

Design of DMF Modules

DMF follows design and interaction patterns of WDF. DMF does not replace WDF nor does it restrict the driver from using OS interfaces directly. DMF makes it easier for you to break down the tasks that a device driver must perform into smaller units. Then, those smaller, self-contained units that perform a single task can be written as Modules.

1. DMF Modules use interaction patterns consistent with existing WDF objects. Just like any WDF object, a DMF Module:

  • Has a CONFIG structure, methods, and event callbacks.

  • Can be parented to other WDF objects for

    life time

    management.

2. Modules within a client driver are organized into a tree structure that is maintained by the core of DMF. The core is responsible for creating, opening, closing, and destroying Modules. In turn each Module is responsible allocating and freeing its own resources.

DMF 模块设计

DMF 遵循 WDF 的设计和交互模式。DMF 不会替换 WDF,也不会限制驱动程序直接使用 OS 接口。DMF 使你可以更轻松地将设备驱动程序必须执行的任务分解为更小的单元。然后,执行单个任务的那些较小的自包含单元可以被编写为模块。

1.DMF 模块使用与现有 WDF 对象一致的交互模式。就像任何 WDF 对象一样,一个 DMF 模块包含:

  • 有一个 CONFIG 结构,方法和事件回调。

  • 可以作为其他 WDF 对象的子节点,用于生命周期管理


2.客户端驱动程序中的模块被组织成由 DMF 内核所维护的树结构。内核负责创建、打开、关闭和销毁模块。反过来,每个模块负责分配和释放自身的资源。

3. Modules that are siblings of each other cannot communicate directly. Only Modules in a parent-child relationship can communicate with each other; only parent Modules can communicate with their children Modules (with the exception of callbacks).

4. Modules can be extended to meet new requirements, or a new Module can be created by combining multiple Modules.

5. Module design is analogous to a class in an object-oriented programming pattern. If you are familiar with the Universal Extensible Firmware Interface (UEFI) Driver Execution Environment (DXE), you will find similarity with Modules.)

DMF Module

C++ Analogous Concept

ModuleC++ Object
Module ContextC++ Object Private Data (members). Also, importantly this is analogous to WDF drivers’ “device context”.
Module ConfigC++ Object Constructor Parameters
Module Public MethodsC++ Object Public Functions
Module Private MethodsC++ Object Private Functions
Module HandleC++ “this” pointer
Client driverThe code that instantiates the C++ object.

3.彼此互为兄妹的模块无法直接通信。只有处于父子关系中的模块才能相互通信;只有父模块可以与其子模块通信(回调除外)。

4.可扩展模块以满足新的要求,或者可通过组合多个模块来创建新模块。

5.模块设计类似于面向对象编程模式中的类。如果你熟悉通用可扩展固件接口(UEFI)的驱动程序执行环境(DXE),你会发现它与模块的相似性。)

DMF Module

C++ 中类似概念

ModuleC++ 对象
Module ContextC++ 对象的私有数据(成员)。同时这也与 WDF 驱动中的“device context”类似
Module ConfigC++ 对象的构造函数的参数
Module Public MethodsC++ 对象的公共函数
Module Private MethodsC++ 对象的私有函数
Module HandleC++ 中的"this"指针
Client driver实例化 C++ 对象的代码

6. Each Module has its own locks. Each Module is responsible for locking its own private context. Thus, locking is granular but, at the same time, efficient and easy to understand.

7. Modules can be used by the client driver or by other Modules; are agnostic about the code that uses them.

8. Modules can use any number of child Modules. Child Modules, in turn, can use any number of Child Modules.

9. DMF provides default implementations for many driver routines such as DriverEntry, AddDevice, WDF Queue creation, so that simple driver (aka Container driver) can be created with as little code as possible.

10. The client driver only needs to instantiate the Module that the driver needs. Child Modules (if any) required are automatically instantiated by DMF on behalf of the driver.

6.每个模块都有自己的锁。每个模块负责对其私有上下文进行加锁。因此,锁定是粒状的,但同时又是高效且易于理解的。

7.模块可以由客户端驱动器或其他模块使用; 与使用它们的代码无关。

8.模块可以使用任意数量的子模块。反过来,子模块可以使用任意数量的子模块。

9. DMF为许多驱动器例程提供了默认实现,例如DriverEntry、AddDevice、WDF Queue创建,因此可以使用尽可能少的代码创建简单的驱动器(也称为Container驱动器)。

10.客户端驱动器只需要实例化驱动器所需的模块。所需的子模块(如果有的话)由DMF代表驱动器来自动实例化。

返回顶部
顶部