WDM Driver Design
1. Introduction to WDM
Microsoft continues to launch new operating systems. Now Windows98 and Windows2000 have become mainstream. The VxD technology originally used to implement drivers will gradually exit the historical stage as Win95 fades out, in Windows 98 and windows, the device driver is designed based on the Windows Driver Model (WDM. WDM simplifies driver development by providing a flexible way, reducing and reducing the number and complexity of necessary drivers based on the implementation of new hardware support.
The Windows Driver Model has two aspects: apart from the standard structure of the device driver described by the core model, WDM also implements a modular and hierarchical bus driver and class driver for common types of devices. The bus driver supports Universal Serial Bus (USB) and ieee1394 (FireWire) protocols. A class driver is a condition for implementing standard Windows functions. WDM's support for standard interfaces reduces the number and complexity of device drivers required for Windows 95 and Windows NT. On Windows, WDM will become the mainstream driving mode in the 21st century.
WDM supports all new hardware standards such as USB, IEEE 1394, and ACPI. In the past, when running on two platforms at the same time, we had to write two very different drivers. Now we only need to write one WDM driver. WDM drivers are also hierarchical, that is, drivers on different layers have different priorities, while VxD on Windows 9x does not have this structure.
Writing WDM is basically the same as other drivers. The main difference in the Code is how to create a device.
In the WDM driver, the plug-and-play (PNP) manager informs you when to add a device to or delete the device from the system. The PnP Manager uses the installed inf file to find the correct driver for the new device. Drivers in other modes must find their own device and use a dedicated installer for installation.
In addition, there are many differences in details. Driver parameters in other modes are generally provided by the Registry. In DriverEntry, the Registry-reading function is called and createdevice is called Based on the registry. However, this is not the case for WDM, this is because PNP is supported in Windows 2000. When loading, the PNP manager calls the adddevice entry point to create a device. Generally, a virtual device is created in DriverEntry that has no relationship with the device or object and is used to manage communications with Win32. If you do not want to perform any special processing on the device, or the device is not complex, adddevice can simply return nt_success without calling createdevice.
In addition, the entire device driver tree has also changed, which greatly changes the installation program. The PnP Manager of WDM itself is abstracted to the root position. The PnP Manager is responsible for loading all bus drivers. The bus driver traverses all the devices on the bus and creates corresponding device objects for each device. When the PnP Manager finds a device object, it looks for the driver corresponding to the object. And call the add device routine of the driver. If the driver is not in the memory, load the driver first and then call the add device routine.
Of course, the bus itself does not send any signal to inform the PnP Manager of its own existence, so the bus driver is set during NT installation. The ISA Device is not standardized, because KMD needs to check the hardware existence and status by itself, so it is the only reason for the existence of the old-fashioned KMD. This is one of the reasons why Microsoft is trying to cancel the ISA bus in the new specification. WDM supports the PNP and PM protocols, and you only need to add some routines in the major function to respond to the PNP and PM events.
A complete driver must complete the following tasks: initialization, device creation and deletion, application Open and Close handle requests, and application input/output requests; serializes access to devices, accesses hardware, calls other drivers, cancels I/O requests, times out I/O requests, and processes events that can be added or deleted by hot swapping devices; power Management and WMI.
2. Develop Device Drivers
2.1 install the design tool DDK
To write drivers for WDM devices, we need the Microsoft driver development kit DDK. Although Microsoft claims that the WDM driver is Binary compatible between Windows 98 and Windows 2000, we only install the corresponding DDK in different systems for security reasons.
(1) install Windows 98 DDK
This section describes how to install Windows 98 DDK. We agree that % 98ddk % is the root directory for installing Windows 98 DDK; % mstools % is the root directory of the Microsoft SDK platform; % vcppdev % is the root directory of the installed VC ++ development environment.
The DDK software platform is usually Windows 98 and VC ++ 4.2 or 5.0. To compile a video capture example, you need VC ++ 5.0. You must install the VC ++ compiling/development environment before installing Windows 98 DDK. Otherwise, the setenv. BAT file of Windows 98 DDK will not be able to establish a correct compiling environment. To read the DDK documentation, you need IE 4.01 or later. If you want to test the drive program on a CD, you need an optical drive. 16 MB of memory is indispensable, full installation requires 82 MB hard disk space (32 MB hard disk space is required for minimum installation ).
All driver examples in Windows 98 DDK do not need to be constructed on the platform where the SDK is installed. However, if you start to develop your own driver, you may need the header file not included in Windows 98 DDK but in the SDK platform. Therefore, you can consider either of the following methods: copy the required header file or SDK platform file to the appropriate include directory under % 98ddk % and % vcppdev %. You can also directly install the SDK platform, edit setenv in % 98ddk %/bin. BAT file and run setenv installed in % mstools %. BAT file.
Use the setup program to install DDK. The steps are as follows:
(1) run the setup. EXE file in Windows 98 DDK and follow the prompts in the dialog box to install Windows 98 DDK to % 98ddk %.
(2) install VC ++ 5.0 to % vcppdev %.
(3) Modify config. sys to increase the environment variable space. Add a line at the end of the config. SYS file:
Shell = C:/Windows/command. com/P/E: 4096
Before installing Windows 98 DDK, you must first install the VC ++ Compiler/development environment. Otherwise
The correct environment cannot be created for the dows 98 DDK setenv. bat batch file.
The following describes how to build the Windows 98 driver construction environment and how to use the construction environment and tools to construct the driver.
1. Use setenv. BAT to install the driver to construct the environment
The Start menu contains the "Development Kits/Windows 98 DDK" directory. This directory includes the free construction environment items and check the construction environment items. Every time you restart the operating system, click the appropriate item in these program folders before creating the driver. These parameters call the setenv. bat batch file in % 98ddk %/bin to create the correct environment variable driver build environment.
2. Manually run setenv. bat
Use the following statement at a MS-DOS prompt or in Start/run:
Setenv % 98ddk % [Free | checked]
For example, at the C:/98ddk/bin> prompt, type setenv C:/98ddk free. The first parameter specifies the folder where the DDK is installed. Note that the default installation is/98ddk; the second optional parameter indicates the target construction environment. The default type is free.
3. Construct a WDM Driver
Use a series of rules to specify how the driver is created. The constructor can be used to construct a WDM driver on Windows 98 and Windows NT platforms.
After Windows 98 DDK is installed, the working example of the WDM driver construction tree and part of the file can be obtained on the hard disk. The driver constructs the root directory in % 98ddk %/src. View the contents of makefile. Def in % 98ddk %/INC and the dirs files and source files that run through the driver construction tree. You can use the code as a working instance.
4. Construct the driver
Create a subdirectory in the driver construction tree of the current directory and run the construction utility. In the current directory of the build tree, the build utility can automatically create the source code of the driver. The constructor runs in the root directory (% 98ddk %/src) of the driver constructor tree in the Windows 98 DDK example. For example, if you are only interested in the example driver constructed for the sound device class, you can set the current directory to % 98ddk %/src/audio, and then run the build utility.
5. Check Windows 98 DDK Installation
The frequently used constructor commands are in the form of build-CZ. This allows the constructor to scan related files, perform complete creation, and generate error records. Check the installation method by running build-CZ in the/<destination>/src directory to construct the complete set of driver source code for the installation example. This utility constructs all related files before constructing the driver and Automatically Establishes file associations. This process may take more than 30 minutes. If the build is incomplete or too many compilation errors are reported, check whether the above installation steps are correctly performed. By installing DDK and corresponding development software, we have constructed the development environment of the WDM driver. Next, we will go deep into the design and development work.
After DDK is installed, check and free Free compiling environments are available in the DDK Program Group. Check environment is used to compile the driver with debugging information, and free is the environment for compiling the officially released version. Generally, the compilation of the device driver uses the command line method. Some settings can be used to compile in the integration environment of VC ++.
Generally, it takes four files to compile the most basic device driver. The first one is the driver, that is, the C language source program file (such as isousb. c. Note that all the examples below are described using isousb. The second is the RC file (for example, isousb. RC); the third is the sources file; the fourth is the MAKEFILE file. The sources file is similar to the Make file, which is used to specify the files to be compiled and the library files to be connected. These three auxiliary files are very simple. In every routine of DDK samples, there are three such files, and they can be understood in the form of samples.
1. Example Analysis
Take the isousb program as an example. Set the isousb. RC code:
# Include <windows. h>
# Include <ntverp. h>
# Define ver_filetype vft_dll
# Define ver_filesubtype vft2_unknown
# Define ver_filedescription_str "i82930 isochronous Io test driver"
# Define ver_internalname_str "isousb. sys"
# Define ver_originalfilename_str "isousb. sys"
# Include "common. Ver"
The build utility is generally used for device drivers. Build is only an outer packaging program outside nmake. Build itself is actually quite simple. Most of the compilation work is actually passed to nmake by build.
Targetname = isousb
Targettype = driver
Targetpath = $ (basedir)/lib
Drivertype = WDM
Supported des = $ (basedir)/INC ;/
$ (Basedir)/src/USB/INC ;/
$ (Basedir)/src/WDM/USB/INC ;/
Targetlibs = $ (basedir)/lib/*/free/usbd. Lib
Use_mapsym = 1
/End of sources/
Note that the sources file name does not have any extension.
# Copyright (c) Microsoft Corporation 1995
# All Rights Reserved.
# Makefile for WDM Device Driver Kit
# Do not edit this file !!! Edit./sources. If you want to add a new source
# File to this component. This file merely indirects to the real make File
# That is shared by all the driver components of the Windows NT DDK
! Include $ (ntmakeenv)/makefile. Def
# End of makefile
Makefile is the same for all drivers, and Microsoft also warns against editing this file. If necessary, you can edit and modify the sources file to achieve the same effect. For device drivers, the C compiler used basically selects VC ++ without exception.
2. Basic compilation steps
(1) first enter the check or free compiling environment and initialize the DDK compiling environment.
(2) Run vcvars32.bat in the bin directory under the VC installation directory to initialize the VC ++ compiling environment.
(32.16run build.exe for compilation.
(2) install Windows2000 DDK
As we have introduced in detail the installation of Windows 98 DDK, we will introduce the differences between Windows DDK and Windows 98 DDK.
The two have different requirements on the system. Windows2000 DDK requires Windows2000 or Windows98 operating system, VC ++ 5.0 or 6.0 professional or Enterprise Edition, with at least 64 MB memory. We recommend MB or more memory, 200 MB is required for full installation. If you install Windows, you must log on as an administrator.
2.2 Device Driver Design
The I/O Request Packet (IRP) is the center of driver operations. IRP is a kernel object and a pre-defined data structure, contains a set of I/O manager routines that operate on it. The I/O manager receives an I/O Request and then allocates and initializes an IRP. An IRP has a fixed header and variable IRP stack unit. Each I/O Request has a primary function code (irp_mj_xxx) and may have a function code (irp_mn_xxx ). Design a device driver that must support the same irp_mj_xxx and IOCTL request codes as the drivers of other devices of the same type. If you design an intermediate driver, you should first confirm the device managed by the underlying driver, because a high-level driver must have the entry to the vast majority of the underlying drivers irp_mj_xxx routine. When receiving an I/O Request, the High-level driver sets the stack unit of the next low-level driver in the IRP, while determining that the current stack unit parameter of the IRP is valid, then call iocalldriver to pass the request to the underlying driver for processing. Once you decide which irp_mj_xxx driver should handle, you can start to determine how many dispatch routines the driver should have. Of course, you can also consider merging some irp_mj_xxx processing routines into the same processing routines.
A driver must create a device object for each physical and logical device that may be the target of an I/O Request. Some low-level drivers may also need to create uncertain number of Device objects. For example, a hard drive must create a device object for each physical hard disk and a device object for each logical partition on each physical disk.
A high-level driver must create a device object for the virtual device it represents so that higher-level drivers can connect their device objects to the device object of the driver. In addition, a high-level driver usually creates a series of virtual or logical device objects for the device objects created by its low-level drivers.
Although the driver can be designed in stages so that a driver in the development stage does not have to create all the device objects it will process at the beginning, however, from the very beginning, identifying all the device objects to be created will help the designer solve any synchronization problems. In addition, determining the device object to be created also helps to define the content and data structure of the device extension of the device object.
The development of the driver is a process from rough to refined. The src/directory of DDK has a huge template code that covers almost all types of device drivers, high-level drivers, and filter drivers. Before you start developing the driver, you can search for a similar type of routine under the sample library.
The following describes the basic steps of driver development:
L. Compile the driver framework
(1) first write a DriverEntry routine and call iocreatedevice in this routine to create
Device objects. In this routine, you must set a series of callback routines to process IRP.
(2) write the basic framework of a routine for processing irp_mj_create requests. If the driver creates more than one device object, you must write a routine for the irp_mj_close request.
(3) Compile the connection driver.
2. Test the driver
(1) first install the driver in the system.
(2) establish a symbolic link between the logical device name and the target device object name. It is known that the device object name is invisible to Win32 user mode, it cannot be accessed directly through APIS. Win32 APIs can only access symbolic link names. You can modify the Registry to create a symbolic link between the two names. Run regedt32.exe to create a symbolic link under/HKEY_LOCAL_MACHINE/system/CurrentControlSet/control/Session Manager/DOS devices. You can also call iocreatesymboliclink in the driver, use parameters to pass the appropriate symbolic link name and kernel device name.
(3) After all the above settings are completed and the check is correct, we must restart the Windows system.
(4) Compile a simple test program to call the createfile function in Win32 API and open the device with a symbolic link name. If it is successfully enabled, a simple driver is successfully written. Supports more device I/O requests. For example, the driver may need to respond to the irp_mj_read request (the readfile function can be used for testing after completion ). If the driver needs to be manually uninstalled, you must also respond to irp_mj_close. Write the processing routines for the irp_mj_xxx to be processed, and initialize these routine entries in DriverEntry. A low-layer driver requires a startio, ISR, and dpcforisr routine. A synchcritsection routine may be required. If the device uses DMA, an adaptercontrol routine may be required.
One or more iocompletion routines may be required for high-level drivers, at least completing the I/O status check
And then call iocompleterequest. If necessary, modify the data structure and content of device extension. One thing that must be clear is the code running level, namely IRQL. The most common levels are passive_level, apc_level, dispatch_level, and dirql.
When reading the function description in DDK help, pay attention to the runable level of the function. For example, some functions can only run under passive_level, and some functions can run at or below dispatch_level, the higher the level, the stricter the Code requirements. For example, when dispatch_level is used, paging memory cannot be used. Generally, you should try to run the code at a low level such as passive_level. If the code runs at a high level for a long time, the system efficiency will be reduced and the system response timeliness will be affected. However, sometimes you cannot control the running level. For example, if you use iocalldriver when calling the lower-layer driver, the lower-layer driver will execute the completion routine after the response is complete. The running level of this routine is determined by the lower-layer driver. Therefore, when writing a completion routine, try to design this function to run at the dispatch_level level.
Based on the above development steps, we can design a new WDM device driver.
2.3 install the device driver
(1). Install the WDM Driver
The driver installs the file according to the commands of the INF file, copies the executable file to the correct location, and creates various registry entries. Some drivers need to occupy some hardware resources, mainly I/O addresses and interrupt numbers, which will be allocated by the PnP Manager. Copy the used inf file to the Windows INF subdirectory.
The inf file contains all the information required to install a WDM Device Driver, including the file to be copied and the registry key to be created. The inf file is a text file consisting of sections. Each section starts with the section name in square brackets. Each row in the future is a simple item or a value. The following describes the INF file with an example in DDK.
Signature = "$ Chicago $"
Class = USB
Provider = % MSFT %
Layoutfile = layout. inf
1 = "DDK bulkusb sample", "", 1
Bulkusb. sys = 1
% Mfgname % = Microsoft
% USB/vid_045e & pid_930a.devicedesc % = bulkusb. Dev, USB/vid_045e & pid_930a
Hkr, nosetupui, 1
Bulkusb. Files. Ext = 10, system32/Drivers
Bulkusb. Files. inf = 10, INF
Copyfiles = bulkusb. Files. Ext, bulkusb. Files. inf
Addreg = bulkusb. addreg
[Bulkusb. Dev. nt]
Copyfiles = bulkusb. Files. Ext, bulkusb. Files. inf
Addreg = bulkusb. addreg
[Bulkusb. Dev. nt. Services]
Addservice = bulkusb, 0x00000002, bulkusb. addservice
Displayname = % bulkusb. svcdesc %
Servicetype = 1; service_kernel_driver
Starttype = 2; service_auto_start
Errorcontrol = 1; service_error_normal
Servicebinary = % 10%/system32/Drivers/bulkusb. sys
Loadordergroup = base
Hkr, devloader, * ntkern
Hkr, ntmpdriver, bulkusb. sys
HKLM, "system/CurrentControlSet/services/bulkusb/parameters", "maximumtransfersize", 0x10001,4096
HKLM, "system/CurrentControlSet/services/bulkusb/parameters", "debuglevel", 0x10001,2
[Bulkusb. Files. Ext]
[Bulkusb. Files. inf]
MSFT = "Microsoft"
Mfgname = "Intel"
USB/vid_045e & pid_930a.devicedesc = "bulkusb. sys intel 82930 USB bulk Io test board"
Bulkusb. svcdesc = "bulkusb. sys i82930 bulk Io test driver"
We will introduce common sections:
Signature is $ Windows NT $, $ Windows 95 $, or $ Chicago $;
The class item is a class name defined by the system (USB in this example) or a new class name specified by the user;
The provider item is the creator of the INF file;
For each release floppy disk or CD-ROM, specify its description and possible packaging files and directories;
Specify the file name, source disk ID, and optional subdirectories and file size. If all files are in the root directory, this section can be blank;
Specify the vendor name;
Specifies the directory for copying default files and specified files;
Specify the name of the List section (bulkusb. Files. Ext, bulkusb. Files. inf) to copy files; specify the name of the addreg section (bulkusb. addreg;
Specifies the driver service details;
Add a new key value to the Registry;
(2) install the NT driver
1. Add a key value in the Registry
During Windows boot, the driver list is constructed by scanning the registry. This list includes both self-started drivers and drivers to be manually started. This list is actually all the devices listed in the device Applet in the control panel. All device drivers should have corresponding key values in the HKEY_LOCAL_MACHINE/system/currentcontrol-set/services/Registry. The name here should be the same as your driver name. The following key values are generally used:
1 indicates the kernel-mode driver; 2 indicates the file system driver.
The value of errorcontrol is 0, indicating logging errors and ignoring them. The value of 1 indicates logging errors and displaying
Dialog Box; value 2 indicates logging errors and restarts with the correct configuration; Value 3 indicates Logging
Error. If the correct configuration has been used, an error is returned.
In any device driver, the first three parameters in the preceding table are required.
2. Control the loading sequence of the driver.
Sometimes it is necessary to control the Loading Order of multiple drivers. Sometimes some programs in a set of drivers must be started with other programs.
3. Start value of the driver
The start value of the driver in the above registry controls the start time of the driver in the system. Currently, start can take the following values, and leave room for expansion for this value to apply to new requirements:
(L) 0x0 (service_boot_start): This value specifies that the driver should be started by the operating system loader.
. The general driver does not use this value, because the system is barely started at this time, and most systems are not available yet.
(2) 0x1 (service_system_start): The value indicates that the driver is started after the operating system is loaded but initialized.
(3) 0x2 (service_auto_start): This value indicates that it is loaded by the Service Control Manager after the entire system is started and run.
(4) 0x3 (service_demand_start): The value indicates that the driver must be started manually. You can use the control panel device applet or Win32 API programming to start the program.
(5) 0x4 (service_disabled): indicates that the driver is disabled.
Note that when debugging the driver, it is best to set the start value to 3 for manual start, because if it is set to automatic start, if an exception occurs during the startup of the driver, the system may fail to start.
If you do not need to restore the disk urgently, You can first try to start the system with the known configuration at startup to check whether the system can be started successfully. If the driver fails, you can delete the problematic driver in the/% SystemRoot %/system32/DRIVERS directory after DOS is started, and then the system can start.
You can set start to control the startup of the driver at different times. To solve the dependency problem, use the group and dependongroup values.
First, determine the group name used by your driver. The system has some defined group names. For the group names existing in the current system, observe the key values of/HKEY_LOCAL_MACHINE/system/currentcontrol-set/control/servicegrouporder/list in the registry. For example, this value can be set:
Scsi cdrom class
Boot File System
Each row is a group name. Generally, a driver belongs to a group. When the system starts, the drivers in each group are started according to the order of the groups in the list. The dependongroup value must start another group of drivers when controlling the startup of the driver.
4. Modify the Registry
You can manually modify these values in the registry, or use the Win32 API to add them.
You can use an INI file to add the file. Run regini. EXE with the name of the INI file. The corresponding items are automatically added to the Registry. After these items are added to the Registry, you must restart the system so that the added device driver can be listed in the device Applet of the control panel and then perform other operations.
5. Start the device driver.
After adding and modifying the registry, restart the system. If the selected Start values are 0, 1, and 2, if everything is normal, the driver should have been started. You can view the device list in the device Applet of the control panel. If start is set to 3, it can be started directly.
Because the driver runs at a high level, we cannot give users a program that has not been strictly tested. The driver test can be completed by defining some Output Macros in the program, or by using some tools for source code-level debugging. There are some tracking tools to help us, such as the driver Monitor of compuware numbench and osrtracer of open system resources. DDK also provides a windbg debugging program, but to use this program, two PCs connected through a serial cable or a network are required to run the inspection structure and free construction respectively. The numbench mentioned above also provides a SoftICE debugging program. I believe many people use it to crack the software password.
At this point, we have roughly introduced the design method of the WDM program. In the actual compilation process, we can help us compile our own driver with the help of the DDK documentation and examples.
Author member name: tliwant