diff --git a/sources/talk/20160531 Linux vs. Windows device driver model.md b/sources/talk/20160531 Linux vs. Windows device driver model.md deleted file mode 100644 index 706c18dd09..0000000000 --- a/sources/talk/20160531 Linux vs. Windows device driver model.md +++ /dev/null @@ -1,192 +0,0 @@ -Editing by FrankXinqi - -Linux vs. Windows device driver model : architecture, APIs and build environment comparison -============================================================================================ - -Device drivers are parts of the operating system that facilitate usage of hardware devices via certain programming interface so that software applications can control and operate the devices. As each driver is specific to a particular operating system, you need separate Linux, Windows, or Unix device drivers to enable the use of your device on different computers. This is why when hiring a driver developer or choosing an R&D service provider, it is important to look at their experience of developing drivers for various operating system platforms. - -![](https://c2.staticflickr.com/8/7289/26775594584_d2fe7483f9_c.jpg) - -The first step in driver development is to understand the differences in the way each operating system handles its drivers, underlying driver model and architecture it uses, as well as available development tools. For example, Linux driver model is very different from the Windows one. While Windows facilitates separation of the driver development and OS development and combines drivers and OS via a set of ABI calls, Linux device driver development does not rely on any stable ABI or API, with the driver code instead being incorporated into the kernel. Each of these models has its own set of advantages and drawbacks, but it is important to know them all if you want to provide a comprehensive support for your device. - -In this article we will compare Windows and Linux device drivers and explore the differences in terms of their architecture, APIs, build development, and distribution, in hopes of providing you with an insight on how to start writing device drivers for each of these operating systems. - -### 1. Device Driver Architecture - -Windows device driver architecture is different from the one used in Linux drivers, with either of them having their own pros and cons. Differences are mainly influenced by the fact that Windows is a closed-source OS while Linux is open-source. Comparison of the Linux and Windows device driver architectures will help us understand the core differences behind Windows and Linux drivers. - -#### 1.1. Windows driver architecture - -While Linux kernel is distributed with drivers themselves, Windows kernel does not include device drivers. Instead, modern Windows device drivers are written using the Windows Driver Model (WDM) which fully supports plug-and-play and power management so that the drivers can be loaded and unloaded as necessary. - -Requests from applications are handled by a part of Windows kernel called IO manager which transforms them into IO Request Packets (IRPs) which are used to identify the request and convey data between driver layers. - -WDM provides three kinds of drivers, which form three layers: - -- Filter drivers provide optional additional processing of IRPs. -- Function drivers are the main drivers that implement interfaces to individual devices. -- Bus drivers service various adapters and bus controllers that host devices. - -An IRP passes these layers as it travels from the IO manager down to the hardware. Each layer can handle an IRP by itself and send it back to the IO manager. At the bottom there is Hardware Abstraction Layer (HAL) which provides a common interface to physical devices. - -#### 1.2. Linux driver architecture - -The core difference in Linux device driver architecture as compared to the Windows one is that Linux does not have a standard driver model or a clean separation into layers. Each device driver is usually implemented as a module that can be loaded and unloaded into the kernel dynamically. Linux provides means for plug-and-play support and power management so that drivers can use them to manage devices correctly, but this is not a requirement. - -Modules export functions they provide and communicate by calling these functions and passing around arbitrary data structures. Requests from user applications come from the filesystem or networking level, and are converted into data structures as necessary. Modules can be stacked into layers, processing requests one after another, with some modules providing a common interface to a device family such as USB devices. - -Linux device drivers support three kinds of devices: - -- Character devices which implement a byte stream interface. -- Block devices which host filesystems and perform IO with multibyte blocks of data. -- Network interfaces which are used for transferring data packets through the network. - -Linux also has a Hardware Abstraction Layer that acts as an interface to the actual hardware for the device drivers. - -### 2. Device Driver APIs - -Both Linux and Windows driver APIs are event-driven: the driver code executes only when some event happens: either when user applications want something from the device, or when the device has something to tell to the OS. - -#### 2.1. Initialization - -On Windows, drivers are represented by a DriverObject structure which is initialized during the execution of the DriverEntry function. This entry point also registers a number of callbacks to react to device addition and removal, driver unloading, and handling the incoming IRPs. Windows creates a device object when a device is connected, and this device object handles all application requests on behalf of the device driver. - -As compared to Windows, Linux device driver lifetime is managed by kernel module's module_init and module_exit functions, which are called when the module is loaded or unloaded. They are responsible for registering the module to handle device requests using the internal kernel interfaces. The module has to create a device file (or a network interface), specify a numerical identifier of the device it wishes to manage, and register a number of callbacks to be called when the user interacts with the device file. - -#### 2.2. Naming and claiming devices - -##### **Registering devices on Windows** - -Windows device driver is notified about newly connected devices in its AddDevice callback. It then proceeds to create a device object used to identify this particular driver instance for the device. Depending on the driver kind, device object can be a Physical Device Object (PDO), Function Device Object (FDO), or a Filter Device Object (FIDO). Device objects can be stacked, with a PDO in the bottom. - -Device objects exist for the whole time the device is connected to the computer. DeviceExtension structure can be used to associate global data with a device object. - -Device objects can have names of the form **\Device\DeviceName**, which are used by the system to identify and locate them. An application opens a file with such name using CreateFile API function, obtaining a handle, which then can be used to interact with the device. - -However, usually only PDOs have distinct names. Unnamed devices can be accessed via device class interfaces. The device driver registers one or more interfaces identified by 128-bit globally unique identifiers (GUIDs). User applications can then obtain a handle to such device using known GUIDs. - -##### **Registering devices on Linux** - -On Linux user applications access the devices via file system entries, usually located in the /dev directory. The module creates all necessary entries during module initialization by calling kernel functions like register_chrdev. An application issues an open system call to obtain a file descriptor, which is then used to interact with the device. This call (and further system calls with the returned descriptor like read, write, or close) are then dispatched to callback functions installed by the module into structures like file_operations or block_device_operations. - -The device driver module is responsible for allocating and maintaining any data structures necessary for its operation. A file structure passed into the file system callbacks has a private_data field, which can be used to store a pointer to driver-specific data. The block device and network interface APIs also provide similar fields. - -While applications use file system nodes to locate devices, Linux uses a concept of major and minor numbers to identify devices and their drivers internally. A major number is used to identify device drivers, while a minor number is used by the driver to identify devices managed by it. The driver has to register itself in order to manage one or more fixed major numbers, or ask the system to allocate some unused number for it. - -Currently, Linux uses 32-bit values for major-minor pairs, with 12 bits allocated for the major number allowing up to 4096 distinct drivers. The major-minor pairs are distinct for character and block devices, so a character device and a block device can use the same pair without conflicts. Network interfaces are identified by symbolic names like eth0, which are again distinct from major-minor numbers of both character and block devices. - -#### 2.3. Exchanging data - -Both Linux and Windows support three ways of transferring data between user-level applications and kernel-level drivers: - -- **Buffered Input-Output** which uses buffers managed by the kernel. For write operations the kernel copies data from a user-space buffer into a kernel-allocated buffer, and passes it to the device driver. Reads are the same, with kernel copying data from a kernel buffer into the buffer provided by the application. -- **Direct Input-Output** which does not involve copying. Instead, the kernel pins a user-allocated buffer in physical memory so that it remains there without being swapped out while data transfer is in progress. -- **Memory mapping** can also be arranged by the kernel so that the kernel and user space applications can access the same pages of memory using distinct addresses. - -##### **Driver IO modes on Windows** - -Support for Buffered IO is a built-in feature of WDM. The buffer is accessible to the device driver via the AssociatedIrp.SystemBuffer field of the IRP structure. The driver simply reads from or writes to this buffer when it needs to communicate with the userspace. - -Direct IO on Windows is mediated by memory descriptor lists (MDLs). These are semi-opaque structures accessible via MdlAddress field of the IRP. They are used to locate the physical address of the buffer allocated by the user application and pinned for the duration of the IO request. - -The third option for data transfer on Windows is called METHOD_NEITHER. In this case the kernel simply passes the virtual addresses of user-space input and output buffers to the driver, without validating them or ensuring that they are mapped into physical memory accessible by the device driver. The device driver is responsible for handling the details of the data transfer. - -##### **Driver IO modes on Linux** - -Linux provides a number of functions like clear_user, copy_to_user, strncpy_from_user, and some others to perform buffered data transfers between the kernel and user memory. These functions validate pointers to data buffers and handle all details of the data transfer by safely copying the data buffer between memory regions. - -However, drivers for block devices operate on entire data blocks of known size, which can be simply moved between the kernel and user address spaces without copying them. This case is automatically handled by Linux kernel for all block device drivers. The block request queue takes care of transferring data blocks without excess copying, and Linux system call interface takes care of converting file system requests into block requests. - -Finally, the device driver can allocate some memory pages from kernel address space (which is non-swappable) and then use the remap_pfn_range function to map the pages directly into the address space of the user process. The application can then obtain the virtual address of this buffer and use it to communicate with the device driver. - -### 3. Device Driver Development Environment - -#### 3.1. Device driver frameworks - -##### **Windows Driver Kit** - -Windows is a closed-source operating system. Microsoft provides a Windows Driver Kit to facilitate Windows device driver development by non-Microsoft vendors. The kit contains all that is necessary to build, debug, verify, and package device drivers for Windows. - -Windows Driver Model defines a clean interface framework for device drivers. Windows maintains source and binary compatibility of these interfaces. Compiled WDM drivers are generally forward-compatible: that is, an older driver can run on a newer system as is, without being recompiled, but of course it will not have access to the new features provided by the OS. However, drivers are not guaranteed to be backward-compatible. - -##### **Linux source code** - -In comparison to Windows, Linux is an open-source operating system, thus the entire source code of Linux is the SDK for driver development. There is no formal framework for device drivers, but Linux kernel includes numerous subsystems that provide common services like driver registration. The interfaces to these subsystems are described in kernel header files. - -While Linux does have defined interfaces, these interfaces are not stable by design. Linux does not provide any guarantees about forward or backward compatibility. Device drivers are required to be recompiled to work with different kernel versions. No stability guarantees allow rapid development of Linux kernel as developers do not have to support older interfaces and can use the best approach to solve the problems at hand. - -Such ever-changing environment does not pose any problems when writing in-tree drivers for Linux, as they are a part of the kernel source, because they are updated along with the kernel itself. However, closed-source drivers must be developed separately, out-of-tree, and they must be maintained to support different kernel versions. Thus Linux encourages device driver developers to maintain their drivers in-tree. - -#### 3.2. Build system for device drivers - -Windows Driver Kit adds driver development support for Microsoft Visual Studio, and includes a compiler used to build the driver code. Developing Windows device drivers is not much different from developing a user-space application in an IDE. Microsoft also provides an Enterprise Windows Driver Kit, which enables command-line build environment similar to the one of Linux. - -Linux uses Makefiles as a build system for both in-tree and out-of-tree device drivers. Linux build system is quite developed and usually a device driver needs no more than a handful of lines to produce a working binary. Developers can use any [IDE][5] as long as it can handle Linux source code base and run make, or they can easily compile drivers manually from terminal. - -#### 3.3. Documentation support - -Windows has excellent documentation support for driver development. Windows Driver Kit includes documentation and sample driver code, abundant information about kernel interfaces is available via MSDN, and there exist numerous reference and guide books on driver development and Windows internals. - -Linux documentation is not as descriptive, but this is alleviated with the whole source code of Linux being available to driver developers. The Documentation directory in the source tree documents some of the Linux subsystems, but there are [multiple books][4] concerning Linux device driver development and Linux kernel overviews, which are much more elaborate. - -Linux does not provide designated samples of device drivers, but the source code of existing production drivers is available and can be used as a reference for developing new device drivers. - -#### 3.4. Debugging support - -Both Linux and Windows have logging facilities that can be used to trace-debug driver code. On Windows one would use DbgPrint function for this, while on Linux the function is called printk. However, not every problem can be resolved by using only logging and source code. Sometimes breakpoints are more useful as they allow to examine the dynamic behavior of the driver code. Interactive debugging is also essential for studying the reasons of crashes. - -Windows supports interactive debugging via its kernel-level debugger WinDbg. This requires two machines connected via a serial port: a computer to run the debugged kernel, and another one to run the debugger and control the operating system being debugged. Windows Driver Kit includes debugging symbols for Windows kernel so Windows data structures will be partially visible in the debugger. - -Linux also supports interactive debugging by means of KDB and KGDB. Debugging support can be built into the kernel and enabled at boot time. After that one can either debug the system directly via a physical keyboard, or connect to it from another machine via a serial port. KDB offers a simple command-line interface and it is the only way to debug the kernel on the same machine. However, KDB lacks source-level debugging support. KGDB provides a more complex interface via a serial port. It enables usage of standard application debuggers like GDB for debugging Linux kernel just like any other userspace application. - -### 4. Distributing Device Drivers - -##### 4.1. Installing device drivers - -On Windows installed drivers are described by text files called INF files, which are typically stored in C:\Windows\INF directory. These files are provided by the driver vendor and define which devices are serviced by the driver, where to find the driver binaries, the version of the driver, etc. - -When a new device is plugged into the computer, Windows looks though -installed drivers and loads an appropriate one. The driver will be automatically unloaded as soon as the device is removed. - -On Linux some drivers are built into the kernel and stay permanently loaded. Non-essential ones are built as kernel modules, which are usually stored in the /lib/modules/kernel-version directory. This directory also contains various configuration files, like modules.dep describing dependencies between kernel modules. - -While Linux kernel can load some of the modules at boot time itself, generally module loading is supervised by user-space applications. For example, init process may load some modules during system initialization, and the udev daemon is responsible for tracking the newly plugged devices and loading appropriate modules for them. - -#### 4.2. Updating device drivers - -Windows provides a stable binary interface for device drivers so in some cases it is not necessary to update driver binaries together with the system. Any necessary updates are handled by the Windows Update service, which is responsible for locating, downloading, and installing up-to-date versions of drivers appropriate for the system. - -However, Linux does not provide a stable binary interface so it is necessary to recompile and update all necessary device drivers with each kernel update. Obviously, device drivers, which are built into the kernel are updated automatically, but out-of-tree modules pose a slight problem. The task of maintaining up-to-date module binaries is usually solved with [DKMS][3]: a service that automatically rebuilds all registered kernel modules when a new kernel version is installed. - -#### 4.3. Security considerations - -All Windows device drivers must be digitally signed before Windows loads them. It is okay to use self-signed certificates during development, but driver packages distributed to end users must be signed with valid certificates trusted by Microsoft. Vendors can obtain a Software Publisher Certificate from any trusted certificate authority authorized by Microsoft. This certificate is then cross-signed by Microsoft and the resulting cross-certificate is used to sign driver packages before the release. - -Linux kernel can also be configured to verify signatures of kernel modules being loaded and disallow untrusted ones. The set of public keys trusted by the kernel is fixed at the build time and is fully configurable. The strictness of checks performed by the kernel is also configurable at build time and ranges from simply issuing warnings for untrusted modules to refusing to load anything with doubtful validity. - -### 5. Conclusion - -As shown above, Windows and Linux device driver infrastructure have some things in common, such as approaches to API, but many more details are rather different. The most prominent differences stem from the fact that Windows is a closed-source operating system developed by a commercial corporation. This is what makes good, documented, stable driver ABI and formal frameworks a requirement for Windows while on Linux it would be more of a nice addition to the source code. Documentation support is also much more developed in Windows environment as Microsoft has resources necessary to maintain it. - -On the other hand, Linux does not constrain device driver developers with frameworks and the source code of the kernel and production device drivers can be just as helpful in the right hands. The lack of interface stability also has an implications as it means that up-to-date device drivers are always using the latest interfaces and the kernel itself carries lesser burden of backwards compatibility, which results in even cleaner code. - -Knowing these differences as well as specifics for each system is a crucial first step in providing effective driver development and support for your devices. We hope that this Windows and Linux device driver development comparison was helpful in understanding them, and will serve as a great starting point in your study of device driver development process. - -Download this article as ad-free PDF (made possible by [your kind donation][2]): [Download PDF][1] - --------------------------------------------------------------------------------- - -via: http://xmodulo.com/linux-vs-windows-device-driver-model.html - -作者:[Dennis Turpitka][a] -译者:[译者ID](https://github.com/译者ID) -校对:[校对者ID](https://github.com/校对者ID) - -本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出 - -[a]: http://xmodulo.com/author/dennis -[1]: http://xmodulo.com/linux-vs-windows-device-driver-model.html?format=pdf -[2]: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=PBHS9R4MB9RX4 -[3]: http://xmodulo.com/build-kernel-module-dkms-linux.html -[4]: http://xmodulo.com/go/linux_device_driver_books -[5]: http://xmodulo.com/good-ide-for-c-cpp-linux.html diff --git a/translated/talk/【翻译完成】20160531 Linux vs. Windows device driver model.md b/translated/talk/【翻译完成】20160531 Linux vs. Windows device driver model.md new file mode 100644 index 0000000000..db542c9380 --- /dev/null +++ b/translated/talk/【翻译完成】20160531 Linux vs. Windows device driver model.md @@ -0,0 +1,195 @@ +Finish Translated + +Linux vs. Windows 设备驱动模型:架构,APIs 和开发环境比较 +============================================================================================ +API Application Program Interface 应用程序接口 +ABI application binary interfaces 应用系统二进制接口 + + + +设备驱动是操作系统的一部分,他能够通过一些特定的编程接口提升硬件设备的使用,这样软件就可以控制并且运行那些设备了。因为每个驱动都对应不同的操作系统,所以你就需要不同的 Linux,Windows 或 Unix 设备驱动,以便能够在不同的计算机上使用你的设备。这就是当雇佣一个驱动开发者或者选择一个研发服务商提供者的时候,查看他们为各种操作系统平台开发驱动的经验是非常重要的。 + +![](https://c2.staticflickr.com/8/7289/26775594584_d2fe7483f9_c.jpg) + +驱动开发的第一步是理解每个操作系统处理它驱动的不同方式、底层驱动模型、它使用的架构、以及可用的开发工具。例如,Linux 驱动程序模型就与 Windows 非常不同。虽然 Windows 提倡驱动程序开发和操作系统开发分别进行,并通过一组 ABI 调用来结合驱动程序和操作系统,但是 Linux 设备驱动程序开发不依赖任何稳定的 ABI 或 API,所以它的驱动代码并没有被纳入内核中。每一个模型都有自己的优点和缺点,但是如果你想为你的设备提供全面支持,那么重要的是要全面的了解他们,。 + +在本文中,我们将比较 Windows 和 Linux 设备驱动程序,探索不同的架构,API,开发和分布,希望为您提供一个比较深入理解关于如何开始为每一个操作系统编写设备驱动程序。 + +### 1. 设备驱动架构 + +Windows 设备驱动程序的体系结构和 Linux 中使用的是不同,他们有自己的优点和缺点。差异主要受以下原因的影响:Windows 是闭源操作系统,而 Linux 是开源操作系统。比较 Linux 和 Windows 设备驱动程序架构将帮助我们理解 Windows 和 Linux 驱动程序背后的核心差异。 + +#### 1.1. Windows 驱动架构 + +虽然 Linux 内核由 Linux 驱动来分配,但 Windows 内核不包括设备驱动程序。相反的是,现代 Windows 设备驱动程序编写使用 Windows 驱动模型(WDM),这是一种完全支持即插即用和电源管理的模型,所以可以根据需要加载和卸载驱动程序。 + +处理来自应用的请求,是由 Windows 内核的一部分调用 I/O 管理器来完成的。I/O 管理器的作用是是转换这些请求到 I/O 请求数据包(IRPs),IRPs 可以被用来在驱动层识别请求并且传输数据。 + +Windows 驱动模型 WDM 提供三中驱动, 他们形成了三个层: + +- 过滤驱动提供关于 IRPs 的可选附加处理。 +- 功能驱动是实现接口和每个设备通信的主要驱动。 +- 总线驱动服务不同的配适器和不同的总线控制器,来实现主机模式控制设备。 + +An IRP 通过这些层就像他们经过 I/O 管理器到达底层硬件那样。每个层能够独立的处理一个 IRP 并且把他们送回 I/O 管理器。在硬件底层中有硬件抽象层(HAL),它提供一个通用的接口到物理设备。 + +#### 1.2. Linux 驱动架构 + +相比于 Windows 设备驱动,Linux 设备驱动架构核心的不同就是 Linux 没有一个标准的驱动模型也没有一个干净独立的层。每一个设备驱动都被当做一个能够自动的从内核中加载和卸载模块来实现。Linux 为即插即用设备和电源管理设备提供一些方式,以便那些驱动可以使用它们来正确地管理这些设备,但这并不是必须的。 + +Linux 提供的外部模块和通信功能通过调用那些函数并且传送在随机数据结构中。来自用户应用的请求实际来自文件系统层或者网络层,它们被转化为需要的数据结构。模块能够被存储在层中,通过一些提供接口到一个设备群的模块处理一个一个的请求,例如 USB 设备。 + +Linux 设备驱动程序支持三种设备: + +- 实现一个字节流接口的字符设备。 +- 主机文件系统和支持多字节块的数据展示的块设备。 +- 用于通过网络转换数据包的网络接口。 + +Linux 也有一个硬件抽象层(HAL),它像一个接口一样连接硬件和设备驱动。 + +### 2. 设备驱动 APIs + +Linux 和 Windows 驱动 API 都属于事件驱动类型:只有当某些事件发生的时候,驱动代码才执行:当用户的应用程序希望从设备获取一些东西,或者当设备有某些请求需要告知操作系统。 + +#### 2.1. 初始化 + +在 Windows 上,驱动被表示为驱动对象结构,驱动对象结构在驱动入口函数的执行过程中被初始化。这些入口点也注册一些回调函数对设备的添加和移除、驱动卸载,和处理新进入的 IRP 做出回应。当一个设备连接的时候,Windows 创建一个设备对象,这个设备对象处理所有应用请求来代表设备驱动。 + +相比于 Windows,Linux 设备驱动生命周期由内核模块的 module_init 和 module_exit 函数负责管理,他们分别用于模块的加载和卸载。他们负责注册模块并通过使用内核接口来处理设备的请求。这个模块需要穿件一个设备文件(或者一个网络接口),说明一些它希望管理的数字识别器,和注册一些回调函数,当用户和设备文件交互的时候使用。 + +#### 2.2. 命名和声明设备 + +##### **在 Windows 上注册设备** + +Windows 设备驱动是由回调函数 AddDevice 在新连接设备时被通知的。它接下来就超过去创建一个用于识别这种特殊驱动的设备对象。取决于驱动的类型,设备对象可以是物理设备对象(PDO),函数设备对象(FDO),或者过滤设备对象(FIDO)。设备对象能够使用PDO来存储在底层。 + +设备对象在这个设备连接在计算机的时候一直存在。设备扩展结构能够被用于使用一个设备对象来辅助全局设备。 + +设备对象可以有如下形式的名字 **\Device\DeviceName**, 这些被系统用来识别和定位他们。一个应用使用 CreateFile API 函数来打开一个有上述名字的文件,获得一个可以用于和设备交互的句柄。 + +然而,通常只有 PDO 有自己的名字。未命名的设备能够通过设备级结构来访问。设备驱动寄存器的一个或多个结构能够通过 128 位全局唯一标识符(GUIDs)来识别他们。用户应用能够使用全局唯一标识符来获取一个句柄。 + +##### **在 Linux 上注册设备** + +在 Linux 平台上,用户应用通过位于 /dev 目录的文件系统入口访问设备。在模块初始化的时候,它通过调用内核函数 register_chrdev,创建了所有需要的入口。这个调用后来被发送到回调函数,这个回调函数(以及具有返回的描述符的进一步的系统调用,例如读、写或关闭)是通过模块安装在结构中,就像file_operations 或者 block_device_operations。 + +设备驱动模块负责分配和保持任何需要用于运行的数据结构。一个传送进入系统文件回调函数的文件结构有一个 private_data 字段,它可以被用来存放指向具体驱动数据的指针。块设备和网络接口 API 也提供类似的字段。 + +虽然其他系统的应用使用文件系统节点来定位设备,但是 Linux 使用一个主设备和次设备号的概念来识别设备和他们的内部驱动。主设备号被用来识别设备驱动,而次设备号由驱动使用来识别被它管理的设备。驱动为了去管理一个或多个固定的主设备号,必须首先注册自己或者让系统来分配未使用的设备号给它。 + +目前,Linux 为主次设备对使用一个32位的值,其中12位分配主设备号并允许多达4096个不同的设备。主次设备对对于字符设备和块设备是不同的,所以一个字符设备和一个块设备能使用相同的设备对而不导致冲突。网络接口是通过像 eth0 的标志名来识别,这些又是区别于主次设备的字符设备和块设备的。 + +#### 2.3. 交换数据 + +Linux 和 Windows 都支持在用户级应用程序和内核级驱动程序之间传输数据的三种方式: + +- **缓冲型输入输出** 它使用由内核管理的缓冲区。对于写操作,内核从用户空间缓冲区中拷贝数据到内核分配缓冲区,并且把它传送到设备驱动中。读操作是一样的,由内核将数据从内核缓冲区中拷贝到应用提供的缓冲区中。 +- **直接型输入输出** 它不使用拷贝功能。代替它的是,内核在物理内存中引导用户分配缓冲区,这样他就能够保存这些数据,在数据传输过程中而不被换出。 +- **内存映射** 它也能够由内核管理,这样内核和用户空间应用就能够通过不同的地址访问同样的内存页。 + +##### **Windows 上的 I/O 模式** + +支持缓冲型 I/O 是 WDM 的一种内置功能。缓冲区能够通过在 IRP 结构中的 AssociatedIrp.SystemBuffer 字符访问设备驱动。当需要和用户空间交流的时候,驱动只需从缓冲区中进行读写操作。 + +Windows 上的直接 I/O 由内存描述符列表(MDLs)介导。这种半透明的结构是通过在 IRP 中的 MdlAddress 字段来访问的。它们被用来定位由用户应用程序分配的缓冲区的物理地址,并在 I/O 请求的持续时间内固定。 + +在 Windows 上进行数据传输的第三个选项称为 METHOD_NEITHER。 在这种情况下,内核需要传送用户空间输入输出缓冲区的虚拟地址到驱动,而不需要确定他们有效或者保证他们映射到一个由设备驱动访问的物理储存器。设备驱动也负责处理数据传输的细节。 + +##### **Linux 上的驱动程序 I/O 模式** + +Linux 提供许多函数例如,clear_user, copy_to_user, strncpy_from_user 和一些其他的用来在内核和用户内存之间展示缓冲区数据传输。这些函数保证了指向数据缓存区指针的有效,并且通过在存储器区域之间安全拷贝数据缓冲区来处理数据传输的所有细节。 + +然而,块设备的驱动对已知大小的整个数据块进行操作,它可以被快速移动在内核和用户地址区域之间而不需要拷贝他们。这些情况都是由 Linux 内核来自动处理所有的块设备驱动。块请求队列处理传送数据块而没有多余的拷贝,而 Linux 系统调用接口来转换文件系统请求到块请求中。 + +最终,设备驱动能够为内核地址区域分配一些存储页面(不可用于交换)并且使用 remap_pfn_range 函数来直接映射页面到用户进程的地址空间。然后应用能获取缓冲区的虚拟地址并且使用它来和设备驱动交流。 + +### 3. 设备驱动开发环境 + +#### 3.1. 设备驱动框架 + +##### **Windows 驱动程序工具包** + +Windows 是一个闭源操作系统。Microsoft 提供 Windows 驱动程序工具包以方便非 Microsoft 供应商开发 Windows 设备驱动。工具包中包含开发,调试,检验和 Windows 设备驱动包等所需的所有内容。 + +Windows 驱动模型为设备驱动定义了一个干净的接口框架。Windows 保持这些接口的源和二进制兼容性。编译 WDM 驱动通常需要前向兼容性:也就是说,一个较旧的驱动能够在没有重新编译的情况下在较新的系统上运行,但是它当然不能够访问系统提供的新功能。但是,驱动不保证后向兼容性。 + +##### **Linux 源代码** + +和 Windows 相对比,Linux 是一个开源操作系统,因此 Linux 的整个源代码是用于驱动开发的 SDK。没有驱动设备的正式框架,但是 Linux 内核包含许多如提供驱动注册的通用服务的子系统。这些子系统的接口被描述为内核头文件。 + +尽管 Linux 有定义接口,这些接口在设计上并不稳定。Linux 不提供有关前向和后向兼容的任何保证。设备驱动对于不同的内核版本需要重新编译。没有稳定性的保证允许 Linux 内核的快速开发,因为开发人员不必去支持旧的借口,并且能够使用最好的方法解决手头的这些问题。 + +当为 Linux 写树内驱动程序时,这种不断变化的环境不会造成任何问题,因为它们作为内核源代码的一部分,与内核本身同步更新。然而,闭源驱动必须单独开发,并且在树外,并且必须维护它们以支持不同的内核版本。因此,Linux 鼓励设备驱动程序开发人员来维持他们的树内驱动。 + +#### 3.2. 为设备驱动构建系统 + +Windows 驱动程序工具包为 Microsoft Visual Studio 添加了驱动开发支持,并包括用来构建驱动程序代码的编译器。开发 Windows 设备驱动程序与在 IDE 中开发用户空间应用程序没有太大的区别。Microsoft 提供了一个企业 Windows 驱动程序工具包,使其能够构建类似于 Linux 的命令行环境。 + +Linux 使用 Makefile 作为树内和树外系统设备驱动程序的构建系统。Linux 构建系统非常发达,通常是一个设备驱动程序只需要少数行就产生一个可工作的二进制代码。开发人员可以使用任何[IDE][5],只要它可以处理 Linux 源代码库和运行 make ,或者他们可以很容易地从终端手动编译驱动程序。 + +#### 3.3. 文档支持 + +Windows 具有对于驱动程序的开发的良好文档支持。Windows 驱动程序工具包包括文档和示例驱动程序代码,通过 MSDN 可获得关于内核接口的大量信息,并存在大量的有关驱动程序开发和 Windows 内部的参考和指南。 + +Linux 文档不是描述性的,但这缓解了整个 Linux 源代码可供驱动开发人员使用。源代码树中的文档目录记录了一些 Linux 的子系统,但是有更详尽的关于 Linux 设备驱动程序开发和 Linux 内核概述的[multiple books][4]。 + +Linux 不提供指定的设备驱动程序的样本,但现有生产驱动程序的源代码可用,可以用作开发新设备驱动程序的参考。 + +#### 3.4. 调试支持 + +Linux 和 Windows 都有可用于追踪调试驱动程序代码的日志记录工具。在 Windows 上将使用 DbgPrint 函数,而在 Linux 上使用的函数称为 printk。然而,并不是每个问题都可以通过只使用日志记录和源代码来解决。有时断点更有用,因为它们允许检查驱动代码的动态行为。交互式调试对于研究崩溃的原因也是必不可少的。 + +Windows 通过其内核级调试器 WinDbg 支持交互式调试。这需要通过一个串行端口连接两台机器:一台计算机运行调试内核,另一台运行调试器和控制被调试的操作系统。Windows 驱动程序工具包包括 Windows 内核的调试符号,因此 Windows 数据结构将在调试器中部分可见。 + +Linux 还支持通过 KDB 和 KGDB 进行的交互式调试。调试支持可以内置到内核,也可以在启动时同时启用。之后,可以直接通过物理键盘调试系统,或通过串行端口从另一台计算机连接到它。KDB 提供了一个简单的命令行界面,这是唯一的在同一台机器上来调试内核的方法。然而,KDB 缺乏源代码级调试支持。KGDB 通过串行端口提供了一个更复杂的接口。它允许使用像 GDB 这样的标准应用程序调试器来调试 Linux 内核,就像任何其他用户空间应用程序一样。 + +### 4. 设备驱动分配 + +##### 4.1. 安装设备驱动 + +在 Windows 上安装的驱动程序,是由被称为为 INF 的文本文件描述的,通常存储在 C:\Windows\INF 目录中。这些文件由驱动供应商提供,并且定义哪些是由驱动程序服务的设备,哪里可以找到驱动程序的二进制文件,和驱动程序的版本等。 + +当一个新设备插入计算机时,Windows 通过查看已经安装的驱动程序并且选择适当的一个加载。当设备被移除的时候,驱动会自动卸载它。 + +在 Linux 上,一些驱动被构建到内核中并且保持永久的加载。非必要的驱动被构建为内核模块,这通常是存储在/lib/modules/kernel-version 目录中。这个目录还包含各种配置文件,如 modules.dep,用于描述内核模块之间的依赖关系。 + +虽然 Linux 内核可以自身在启动时加载一些模块,但通常模块加载由用户空间应用程序监督。例如,init 进程可能在系统初始化期间加载一些模块,udev 守护程序负责跟踪新插入的设备并为它们加载适当的模块。 + +#### 4.2. 更新设备驱动 + +Windows 为设备驱动程序提供了稳定的二进制接口,因此在某些情况下,无需与系统一起更新驱动程序二进制文件。任何必要的更新由 Windows Update 服务处理,Windows 服务负责定位,下载和安装适用于最新版本系统的驱动程序。 + +然而,Linux 不提供稳定的二进制接口,因此有必要在每次内核更新时重新编译和更新所有必需的设备驱动程序。显然,内置在内核中的设备驱动程序会自动更新,但是树外模块会产生轻微的问题。 维护最新的模块二进制文件的任务通常用[DKMS] [3]来解决:一个当安装新的内核版本时自动重建所有注册的内核模块的服务。 + + +#### 4.3. 安全注意事项 + +所有 Windows 设备驱动程序必须在 Windows 加载它们之前进行数字签名。在开发期间可以使用自签名证书,但是分发给终端用户的驱动程序包必须使用 Microsoft 信任的有效证书进行签名。供应商可以从 Microsoft 授权的任何受信任的证书颁发机构获取软件出版商证书。然后,此证书由 Microsoft 交叉签名,并且生成的交叉证书用于在发行之前签署驱动程序包。 + +Linux 内核还可以配置为验证正在加载的内核模块的签名,并禁止不可信的内核模块。被内核所信任的公钥集在构建时是固定的,并且是完全可配置的。由内核执行的检查,它的严格性在构建时也是可配置的,范围从简单地为不可信模块发出警告,到拒绝加载任何可疑的有效性。 + +### 5. 结论 + +如上所示,Windows 和 Linux 设备驱动程序基础设施有一些共同点,例如调用 API 的方法,但更多的细节是相当不同的。最突出的差异源于 Windows 是由商业公司开发的封闭源操作系统这个事实。这是 Windows 上使变的非常好,文档化,稳定的驱动程序 ABI 和正式框架的一个要求,而在 Linux 上,更多的是到源代码的一个很好的补充。文档支持也在 Windows 环境中更加发达,因为 Microsoft 具有所需的资源来维护它。 + +另一方面,Linux 不会使用框架限制设备驱动程序开发人员,并且内核和生产设备驱动程序的源代码可以在需要的时候有所帮助。缺乏接口稳定性也有意义,因为它意味着最新的设备驱动程序总是使用最新的接口,内核本身承载较小的后向兼容性负担,这带来了更干净的代码。 + +了解这些差异以及每个系统的具体情况是为您的设备提供有效的驱动程序开发和支持的关键的第一步。我们希望这篇文章 Windows 和 Linux 设备驱动程序开发的对比,有助于您理解它们,并在设备驱动程序开发过程的研究中,将此作为一个伟大的起点。 + + +-------------------------------------------------------------------------------- + +via: http://xmodulo.com/linux-vs-windows-device-driver-model.html + +作者:[Dennis Turpitka][a] +译者:[译者ID](https://github.com/FrankXinqi(&YangYang)) +校对:[校对者ID](https://github.com/校对者ID) + +本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出 + +[a]: http://xmodulo.com/author/dennis +[1]: http://xmodulo.com/linux-vs-windows-device-driver-model.html?format=pdf +[2]: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=PBHS9R4MB9RX4 +[3]: http://xmodulo.com/build-kernel-module-dkms-linux.html +[4]: http://xmodulo.com/go/linux_device_driver_books +[5]: http://xmodulo.com/good-ide-for-c-cpp-linux.html