Main Problems and Solutions in Writing Windows Device Drivers

Publisher:sumigLatest update time:2012-04-18 Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

Combined with the driver design of "Universal High-Speed ​​PCI Bus Target Module", this paper comprehensively discusses the main problems and solutions faced when writing drivers for Windows devices (especially PCI devices), and proposes a method for encapsulating device drivers.

Keywords: PCI device driver port memory interrupt encapsulation

When designing and using PCI devices, it is often necessary to access and control hardware devices in the PC software. However, in order to ensure the security, stability and portability of the system, Windows operating systems (including Windows 95/98, Windows NT, and Windows 2000) restrict application programs from accessing hardware resources. This requires the design of device drivers to enable PC software to access PCI devices.

Windows下的驱动程序不仅仅包括物理设备的驱动程序,也包括为文件系统等非物理设备编写的虚拟设备驱动程序。为了简化问题,下面只讨论硬件物理设备的驱动程序
。本文将以撏ㄓ酶咚伲校茫勺芟吣勘昴?閿[1]的驱动设计为例,探讨PCI设备的驱动程序设计方案。我们开发了一套通用的PCI设备驱动程序,它可以完成一般PCI设备驱动所需的功能,可以作为其它PCI设备驱动开发的框架。

1. Driver mode and development tool selection A device driver is a piece of code that manages a peripheral device. Drivers do not exist independently, but are part of the operating system. Through device drivers, multiple processes can use these resources at the same time, so that multiple processes can run in parallel. In the following, the PC program that calls the device driver is called a user program. Windows 95 and Windows NT use different driver systems, so in most cases, drivers cannot be universal. If a device needs to be used under Windows 9X/NT, generally at least two driver versions, Windows 9X and Windows NT, must be designed. Windows 98 is compatible with Windows 95 drivers, and it also launched a new Win32 Drivers Mode (WDM) driver type. The drivers of some devices in Windows 98 (such as USB devices) must be in WDM mode. This new type actually adds plug-and-play and other content to the Windows NT driver model. WDM drivers can also be used in Windows 2000 (formerly Windows NT5.0). From a long-term perspective. In the future, developers only need to develop WDM drivers, but from the current market situation, Windws 95 cannot be abandoned, so WDM cannot replace other types of device drivers in the next one or two years. Intel 80386 and above microprocessors have four priority levels: 0, 1, 2 and 3. Generally, the operating system runs at priority level 0, while the user program runs at level 3, and there are some restrictions on hardware operations (the specific restrictions are different in different operating systems). Windows 95 supports many types of drivers, but for general hardware devices, they are mainly VxD and printer drivers. VxD refers to Virtual Device Drivers. VxD runs at level 0 of the Intel system, can execute privileged instructions, and has full access to any I/O device, so most hardware drivers are VxD. VxD drivers usually have a .vxd extension and are placed in the Windows\System directory. They can be loaded when Windws 95 is started, or dynamically loaded as needed when the program is running. Dynamic loading helps save system memory and resources. But the printer driver is not a VxD, it runs at level 3. Similar to Windows 95, Windows NT drivers can also be divided into kernel mode (Kernel Mode) that can run at level 0 and user mode (User Mode) that runs at level 3. Since Windows NT prohibits user mode programs from accessing I/O ports (Windows 95/98 allows user programs to directly access I/O ports), drivers that directly control physical devices are all kernel mode. The PCI universal driver we designed requires access to various hardware resources, so we should choose a driver mode that works at level 0. The main development tool used to develop device drivers is the Device Driver Kit (DDK) software package provided by Microsoft for device developers. This software package includes documents related to device development, header files and library files required for compilation, debugging tools and program examples. In the DDK, some system bottom-level services that device drivers can call are also defined, such as DMA services, interrupt services, memory management services, installable file system services, etc. These are all necessary for writing device drivers. However, the DDK of Windows 95 is mainly described in assembly language. It is difficult to develop.










Therefore, we also used Numega's product VtoolsD in Windows 95. VtoolsD is based on C/C++, supports Borland C++ and Visual C++, and is easier to use and maintain than Windows DDK.


2. Characteristics of PCI Drivers Before designing a driver, you must first carefully analyze the hardware device to be controlled, and you need to understand the characteristics of the hardware device in detail. The characteristics of the hardware device will have a significant impact on the driver design. The most important hardware characteristics that need to be understood include:

(1) Bus structure of the device The bus structure used by the device is very important, because different bus types (such as ISA and PCI) have different hardware working mechanisms, so the driver design is also different. (2) Registers You need to understand the control registers, data registers and status registers that are set, as well as the characteristics of these registers. (3) Device errors and status You need to understand how to judge the status and error signals of the device, which are returned to the user through the driver. (4) Interrupt behavior You need to understand the conditions under which the device generates interrupts and the number of interrupts used. (5) Data transfer mechanism The most common data transfer mechanism is through the I/O port (port), that is, through the CPU IN/OUT instructions to read and write data. Another important transmission mechanism of the PC is DMA, but the PCI specification does not include instructions for slave DMA. (6) Device memory Many devices have their own memory, and most PCI devices are mapped to the physical memory of the PC system. Some devices also need to set the device interface registers through the driver. The DDK document stipulates the content of driver loading and responding to user requests, so the main problem faced in designing device drivers is how to perform hardware operations, which varies from device to device. Although the functions of hardware drivers vary greatly, their basic functions are to complete device initialization, port read and write operations, interrupt setting, response and call, and direct memory read and write. As mentioned earlier, the operating system models of Windows 9X and Windows NT are different, but the work that the driver needs to complete is the same, so the following introduction is mainly based on Windows 9X, and the differences between the two operating systems are only pointed out where necessary. The following discusses the ways to solve these problems from the following aspects: (1) Device initialization PCI device drivers need to identify PCI devices, address PCI device resources, and service PCI device interrupts. The PCI system BIOS function provides specific features for BIOS access and control. All software (device drivers, extended ROM code) will call BIOS functions through the standard interrupt number 1AH to access special components. The PCI BIOS specification has a complete description of PCI BIOS functions [3]. During the initialization process of the PCI device driver, the PCI device is searched using the specified device identification number (device_id), vendor identification number (vendor_id), and index. The PCI device is confirmed to exist by calling the PC IBIOS, and its physical location is determined: bus number, device number, and function number, which are the unique addressing marks of the device/function in the system. The bus number, device number, and function number can be used to address the PCI configuration space of the device/function. Next, the device driver needs to obtain the hardware parameters from the configuration space. Many parameters of the PCI device, including the interrupt number used, the range of the port address, I/O mode, memory address, memory mapping mode, etc., can be obtained from the addressing space corresponding to each base address of the PCI configuration space. To read and write the configuration space, you can call BIOS interrupt 1AH, or you can first write the bus and device number obtained when searching for PCI devices in the previous step to the configuration space address register (0CF8H), and then read and write the configuration space data register (0CFCH). For device drivers, the most important thing is to obtain the base address register (BADR). It cannot be assumed that PCI device resources are always the initial values ​​set when designing the device. The system may allocate new resources to the PCI device according to the hardware situation. The base addresses 1-3 used by the PCI device we designed are all mapped according to the I/O space, while the base address 4 is mapped according to the memory mode. To determine how a port is mapped, you can read the configuration register (Configuration Register) of the corresponding port. After reading it out, judge its 0th bit. If the 0th bit is a value of 0, it means that it is set according to the memory mode, otherwise it is set according to the I/O mode. The meaning of the configuration registers of the memory mode and I/O mode can be found in the literature [3]. If you want to obtain the size of the base address, you can write FFFFH to the base address register and then read the base address register. If it is in memory mode, the number of 0s starting from the 4th bit indicates the size of the base address. If it is in I/O mode, the number of 0s starting from the 2nd bit indicates the size of the base address. (2) Port operation On a PC, the I/O port addressing space is different from the memory addressing space, so the processing methods are also different. The I/O space is a 64K-byte addressing space. Unlike memory, which has real mode and protected mode, the addressing method is the same in all modes. Under Windows 9X, user programs can directly use I/O instructions, and do not necessarily have to be completed through a dedicated driver. Therefore, if the software's operation on the hardware is completely completed through I/O port operations, there is no need to design a dedicated driver, and the application can directly control the hardware. Since the PCI bus is a 32-bit bus standard, double-word (DWORD) operations are usually required when performing I/O operations, and most C/C++ compiler software in the past did not provide double-word functions, so it is necessary to construct double-word operation read and write functions inpd/outpd. Under Windows NT, the system does not allow user programs and user-mode drivers at priority level 3 to directly use I/O instructions. If I/O instructions are used, it will cause a privileged instruction exception. Therefore, any I/O operation needs to be completed with the help of a kernel-mode driver. There are two specific methods: one is to use IoReportResourceUsage in the driver to report resource usage, then use READ_PORT_XXX and WRITE_PORT_XXX functions to read and write, and finally use IoReportResourceUsage to cancel resource usage; the other is that the driver modifies NT's I/OPermissions Map (IOPM) to allow the system to allow user programs to operate on the specified I/O port. At this time, the user program uses the usual I/O instructions to operate. The latter has the advantages of fast speed and simple user program design, but it sacrifices portability. The program cannot be ported to non-Intel systems, and if multiple programs read and write the same port at the same time, it is easy to cause conflicts. ?












3. Memory reading and writing Winsows works in 32-bit protected mode. The fundamental difference between protected mode and real mode lies in the difference in CPU addressing mode, which is also a problem that needs to be solved in Windows driver design. Windows uses segmentation and paging mechanisms as shown in Figure 1. This gives the application an illusion that a very large physical storage space can be used in the program. The biggest advantage of this is that a program can easily run on computers with different physical memory capacities and configuration ranges. Programmers can use virtual memory to write programs that are much larger than any actual configured physical memory. Each virtual address consists of a 16-bit segment selector and a 32-bit segment offset. Through the segmentation mechanism, the system generates a linear address from the virtual address. Then through the paging mechanism, the physical address is generated from the linear address. The linear address is divided into three parts: page directory, page table, and page offset. When a new Win32 process is created, the operating system will allocate a piece of memory for it, and create its own page directory and page table. The address of the page directory is also placed in the process's field information. When calculating an address, the system first reads the address of the page directory from the CPU controller CR3, then gets the address of the page table based on the page directory, then gets the page frame of the actual code/data page based on the page table, and finally accesses a specific unit based on the page offset. Hardware devices read and write physical memory, but applications read and write virtual addresses, so there is a problem of mapping physical memory addresses to user program linear addresses.

The conversion from physical address to linear address is also done by the driver. In Windows 95, DDK's VMMCall_MapPhysToLinear is used for address mapping. The memory mapping part of the driver mainly calls the VxD system service MapPhysToLinear. The definition of this function in VtoolsD is as follows:

PVOID MapPhysToLineag(CONST VOID * PhysAddr,DWORD nBytes,DWORD Flags); The first parameter PhysAddr is the starting position of the physical address of the memory to be mapped, and nBytes is the length of the memory area. Flags must be set to 0. This function returns the linear memory address mapped to this physical address. If the specified memory cannot be accessed, the function will return FFFFFFFFH. For example, if you want to map the 4096 bytes starting from ED000000H of physical memory, you can do it like this: PCHAR *PointerToPage=(PCHAR)MapPhysToLinear((PVOID)OxED000000,4096,0); and pass PointerToPage to the user program that calls the driver, and use DWORD *pFIFOBodyBase=(DWORD*)PointerToPage in the user program; and this PFIFOBodyBase pointer can be read and written like a normal pointer, and by operating this pointer, you can read and write physical memory ED000000H. Under Windows NT, first call IoReportResourceUsage to request the use of device memory. Then call HalTranslateBusAddress to convert the bus-related memory to the system's physical memory address. Then use MmMapIoSpace to map the device's memory to the virtual space. When the device driver is unloaded, call MmUnmapIoSpace to disconnect the device's memory and virtual space. ?

(4) Interrupt setting, response and call The interrupt setting, response and call should be completed in the driver. The interrupt call, such as calling the BIOS 1AH interrupt to read the configuration register space, can be completed by DDK's Exec_Int. The PCI device driver should obtain information about the interrupt from the interrupt register (INTLN) and interrupt pin register (INTPIN) of the PCI configuration register. DDK also provides services for responding to interrupt events. For example, in Windows 95, the VPICD service is used to manage all hardware interrupt events. The hardware interrupt of the PC needs to determine the IRQ of the hardware interrupt. For a specific IRQ interrupt source, VPICD either provides a default interrupt processing function or allows other VxDs to overload the interrupt processing function. In VtoolsD, to handle hardware interrupts, a class should be inherited from VHardwareInt. In this class, VtoolsD provides the functions required to write interrupt response programs. In Windows NT, the interrupt service corresponding to VPICD is the interrupt request level (IRQL). The device driver first uses HalGetInterrupuVector to convert the bus-related interrupt vector into the system interrupt vector, and then uses IoConnectInterrupu to specify the interrupt service.


3. Calling the device driver Writing a device driver is not the ultimate goal. It is always necessary for the user program to call the driver and implement certain functions. Generally, calling the device driver is to use the CreateFile function to open the device file and get a file handle. Specifically in our device driver, the following statement can be used to open the file. hVxD=CreateFile("\\\\.\\PCIBIOS.VXD",0,0,0, CREATE-NEW,FILE-FLAG-DELETE-ON-CLOSE,0); After opening the device file, calling the DeviceIoControl function can exchange data with the device driver. After completing the hardware operation, you can call CloseHandle(hVxD); to close the device driver. This calling method is also the standard method for Windows NT to call the device driver. For VxD, there are other calling methods, such as DPMI method, but the use of DeviceIoControl method can ensure the compatibility of the program under Windows NT and Windows 9X. Under the two operating systems, only the CreateFile statement is different. 4. Further encapsulation of the device driver So far, the preliminary design of the driver has been completed. However, considering that the DeviceIoControl function used in calling the device driver is still relatively complex, the program is not easy to be universal. In addition, some development tools, such as Visual Basic, do not include direct read and write statements for I/O ports, so it is possible to consider different encapsulations of the driver according to the needs of different software. At present, we have implemented encapsulation with DLL, ActiveX, VCL and C++ class library. DLL can be called in most software environments. ActiveX can be used in visual programming environments such as Visual Basic. VCL can be used in Delphi and C++ Builder. Considering that many users use Visual C++, a C++ class library method is also provided. References 1 Ma Weiguo, He Peikun. Design of a universal high-speed PCI bus target module. Electronic Technology Application, 1999; 25(1) 2 Art Baker. Windows NT device driver design guide. Beijing: Machinery Industry Press, 1997 3 AMCC S5933 PCI Controller Data Book. Applied Micro Circuits Corporation, 1996 ? (Received: 1999-06-16)








Reference address:Main Problems and Solutions in Writing Windows Device Drivers

Previous article:What is the ps2 interface
Next article:PCI card design experience

Latest Analog Electronics Articles
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号