Device Drivers

 < Day Day Up > 

To integrate with the I/O manager and other I/O system components, a device driver must conform to implementation guidelines specific to the type of device it manages and the role it plays in managing the device. In this section, we'll look at the types of device drivers Windows supports as well as the internal structure of a device driver.

Types of Device Drivers

Windows supports a wide range of device driver types and programming environments. Even within a type of device driver, programming environments can differ, depending on the specific type of device for which a driver is intended. The broadest classification of a driver is whether it is a user-mode or kernel-mode driver. Windows supports several types of user- mode drivers:

  • Virtual device drivers (VDDs) are used to emulate 16-bit MS-DOS applications. They trap what an MS-DOS application thinks are references to I/O ports and translate them into native Windows I/O functions, which are then passed to the actual device driver. Because Windows is a fully protected operating system, user-mode MS-DOS applications can't access hardware directly and thus must go through a real kernel-mode device driver.

  • Windows subsystem printer drivers translate device-independent graphics requests to printer-specific commands. These commands are then typically forwarded to a kernel- mode port driver such as the parallel port driver (Parport.sys) or the universal serial bus (USB) printer port driver (Usbprint.sys).

In this chapter, the focus is on kernel-mode device drivers. There are many types of kernel- mode drivers, which can be divided into the following basic categories:

  • File system drivers accept I/O requests to files, and satisfy the requests by issuing their own, more explicit requests to mass storage or network device drivers.

  • Plug and Play drivers work with hardware and integrate with the Windows power manager and PnP manager. They include drivers for mass storage devices, video adapters, input devices and network adapters.

  • Non Plug and Play drivers, also called kernel extensions, extend the functionality of the system by providing user-mode access to kernel-mode services and drivers. They do not integrate with the PnP or power managers. Examples include network API and protocol drivers. Regmon's driver, described in Chapter 4, is also an example.

Within the category of kernel-mode drivers are further classifications based on the driver model that the driver adheres to and its role in servicing device requests.

WDM Drivers

WDM drivers are device drivers that adhere to the Windows Driver Model (WDM). WDM includes support for Windows power management, Plug and Play, and WMI, and most Plug and Play drivers adhere to WDM. WDM is implemented on Windows, Windows 98, and Windows Millennium Edition, so WDM drivers are source-compatible between these operating systems and in many cases are also binary compatible. There are three types of WDM drivers:

  • Bus drivers manage a logical or physical bus. Examples of buses include PCMCIA, PCI, USB, IEEE 1394, and ISA. A bus driver is responsible for detecting and informing the PnP manager of devices attached to the bus it controls as well as managing the power setting of the bus.

  • Function drivers manage a particular type of device. Bus drivers present devices to function drivers via the PnP manager. The function driver is the driver that exports the operational interface of the device to the operating system. In general, it's the driver with the most knowledge about the operation of the device.

  • Filter drivers logically layer above or below function drivers, augmenting or changing the behavior of a device or another driver. For example, a keyboard capture utility could be implemented with a keyboard filter driver that layers above the keyboard function driver.

In WDM, no one driver is responsible for controlling all aspects of a particular device. The bus driver is responsible for detecting bus membership changes (device addition or removal), assisting the PnP manager in enumerating the devices on the bus, accessing bus-specific configuration registers, and in some cases, controlling power to devices on the bus. The function driver is generally the only driver that accesses the device's hardware.

Note

The role of the HAL in Windows 2000, Windows XP, and Windows Server 2003 differs from the role it had in Windows NT. Prior to Windows 2000, third-party hardware vendors that wanted to add support for hardware buses not natively supported had to implement a custom HAL. Windows 2000, Windows XP, and Windows Server 2003 allow third parties to implement a bus driver to provide support for hardware buses not natively supported.


Layered Drivers

Support for an individual piece of hardware is often divided among several drivers, each providing a part of the functionality required to make the device work properly. In addition to WDM bus drivers, function drivers, and filter drivers, hardware support might be split between the following components:

  • Class drivers implement the I/O processing for a particular class of devices, such as disk, tape, or CD-ROM, where the hardware interfaces have been standardized and so one driver can serve devices from a wide variety of manufacturers.

  • Port drivers implement the processing of an I/O request specific to a type of I/O port, such as SCSI, and are implemented as kernel-mode libraries of functions rather than actual device drivers.

  • Miniport drivers map a generic I/O request to a type of port into an adapter type, such as a specific SCSI adapter. Miniport drivers are actual device drivers that import the functions supplied by a port driver.

An example will help demonstrate how device drivers work. A file system driver accepts a request to write data to a certain location within a particular file. It translates the request into a request to write a certain number of bytes to the disk at a particular "logical" location. It then passes this request (via the I/O manager) to a simple disk driver. The disk driver, in turn, translates the request into a physical location (cylinder/track/sector) on the disk and manipulates the disk heads to write the data. This layering is illustrated in Figure 9-3.

Figure 9-3. Layering of a file system driver and a disk driver


This figure illustrates the division of labor between two layered drivers. The I/O manager receives a write request that is relative to the beginning of a particular file. The I/O manager passes the request to the file system driver, which translates the write operation from a file-relative operation to a starting location (a sector boundary on the disk) and a number of bytes to read. The file system driver calls the I/O manager to pass the request to the disk driver, which translates the request to a physical disk location and transfers the data.

Because all drivers both device drivers and file system drivers present the same framework to the operating system, another driver can easily be inserted into the hierarchy without altering the existing drivers or the I/O system. For example, several disks can be made to seem like a very large single disk by adding a driver. Such a driver exists in Windows to provide fault-tolerant disk support. (Whereas the driver is present on all versions of Windows, fault-tolerant disk support is available only on Windows Server versions.) This logical, volume manager driver is located between the file system and the disk drivers, as shown in Figure 9-4. Volume manager drivers are described in more detail in Chapter 10.

Figure 9-4. Adding a layered driver


EXPERIMENT: Viewing the Loaded Driver List

You can see a list of registered drivers on a Windows 2000 system by going to the Drivers section of the Computer Management Microsoft Management Console (MMC) snap- in or by right-clicking the My Computer icon on the desktop and selecting Manage from the context menu. (The Computer Management snap-in is in the Programs/Administrative Tools folder of the Start menu.) Navigate to the Drivers section within Computer Management by expanding System Tools, System Information, Software Environment and selecting Drivers, as shown here:



In Windows XP and Windows Server 2003, you can obtain the identical information as reported by the Windows 2000 Computer Management MMC snap-in by executing the Msinfo32.exe utility from the Run dialog box of the Start menu. Select the System Drivers entry under Software Environment to see the list of drivers configured on the system. Those that are loaded have the text "Yes" in the Started column.

You can also view the list of loaded kernel-mode drivers with Process Explorer from http://www.sysinternals.com. Run Process Explorer, select the System process, and select DLLs from the Lower Pane menu entry in the View menu. Process Explorer lists the loaded drivers, their names, version information including company and description, and load address (assuming you have configured Process Explorer to display the corresponding columns):



Finally, if you're looking at a crash dump (or live system) with the kernel debugger, you can get a similar display with the kernel debugger lm kv command:

kd>lmkv start     end          module  name 804d4000  806aa280     nt        (pdb  symbols)                c: \Symbols\ntoskrnl.pdb\ FB1EDACE71FB4812A5D5132819D72E523\ntoskrnl.pdb     Loadedsymbolimage  file:  ntoskrnl.exe     Imagepath:  ntoskrnl.exe     Timestamp:  Thu  Apr  24  10:57:43  2003  (3EA80977)     Checksum:  001E311B     ImageSize:  001D6280     File  version:       5.1.2600.1151     Product  version:    5.1.2600.1151     File  flags:         0(Mask  3F)     File  OS:            40004NTWindows     File  type:          1.0  App     File  date:          00000000.00000000     Translations:        0409.04b0     CompanyName:         MicrosoftCorporation     ProductName:         Microsoft" Windows«Operating  System     InternalName:        ntoskrnl.exe     OriginalFilename:    ntoskrnl.exe     ProductVersion:      5.1.2600.1151     FileVersion:         5.1.2600.1151(xpsp2.030422-1633)     FileDescription:     NTKernel&  System     LegalCopyright:       Microsoft  Corporation .Allrightsreserved. 806ab000 806bde80   hal                (deferred)     Imagepath:  halacpi.dll     Timestamp: Thu  Aug29  03:05:022002     (3D6DD5AE)  Checksum:      000203BD     ImageSize : 00012E80     Translations:     0000.04b0  0000.04e00409.04b00409.04e0 a8b8e000a8bb4e80    kmixer           (deferred)     Imagepath: \SystemRoot\system32\drivers\kmixer.sys     Timestamp: Thu  Aug29  03:32:282002     (3D6DDC1C)  Checksum:      00032574     ImageSize : 00026E80     Translations:     0000.04b0  0000.04e00409.04b00409.04e0


Structure of a Driver

The I/O system drives the execution of device drivers. Device drivers consist of a set of routines that are called to process the various stages of an I/O request. Figure 9-5 illustrates the key driver-function routines.

Figure 9-5. Primary device driver routines


  • An initialization routine The I/O manager executes a driver's initialization routine, which is typically named DriverEntry, when it loads the driver into the operating system. The routine fills in system data structures to register the rest of the driver's routines with the I/O manager and performs any global driver initialization that's necessary.

  • An add-device routine A driver that supports Plug and Play implements an add-device routine. The PnP manager sends a driver notification via this routine whenever a device for which the driver is responsible is detected. In this routine, a driver typically allocates a device object (described later in this chapter) to represent the device.

  • A set of dispatch routines Dispatch routines are the main functions that a device driver provides. Some examples are open, close, read, and write and any other capabilities the device, file system, or network supports. When called on to perform an I/O operation, the I/O manager generates an IRP and calls a driver through one of the driver's dispatch routines.

  • A start I/O routine The driver can use a start I/O routine to initiate a data transfer to or from a device. This routine is defined only in drivers that rely on the I/O manager to queue its incoming I/O requests. The I/O manager serializes IRPs for a driver by ensuring that the driver processes only one IRP at a time. Most drivers process multiple IRPs concurrently, but serialization makes sense for some drivers, such as a keyboard driver.

  • An interrupt service routine (ISR) When a device interrupts, the kernel's interrupt dispatcher transfers control to this routine. In the Windows I/O model, ISRs run at device interrupt request level (DIRQL), so they perform as little work as possible to avoid blocking lower-level interrupts unnecessarily. (See Chapter 3 for more information on IRQLs.) An ISR queues a deferred procedure call (DPC), which runs at a lower IRQL (DPC/dispatch level), to execute the remainder of interrupt processing. (Only drivers for interrupt- driven devices have ISRs; a file system driver, for example, doesn't have one.)

  • An interrupt-servicing DPC routine A DPC routine performs most of the work involved in handling a device interrupt after the ISR executes. The DPC routine executes at a lower IRQL (DPC/dispatch level) than that of the ISR, which runs at device level, to avoid blocking other interrupts unnecessarily. A DPC routine initiates I/O completion and starts the next queued I/O operation on a device.

Although the following routines aren't shown in Figure 9-5, they're found in many types of device drivers:

  • One or more I/O completion routines A layered driver might have I/O completion routines that will notify it when a lower-level driver finishes processing an IRP. For example, the I/O manager calls a file system driver's I/O completion routine after a device driver finishes transferring data to or from a file. The completion routine notifies the file system driver about the operation's success, failure, or cancellation, and it allows the file system driver to perform cleanup operations.

  • A cancel I/O routine If an I/O operation can be canceled, a driver can define one or more cancel I/O routines. When the driver receives an IRP for an I/O request that can be canceled, it assigns a cancel routine to the IRP. If a thread that issues an I/O request exits before the request is completed or cancels the operation (with the CancelIo Windows function, for example), the I/O manager executes the IRP's cancel routine if one is assigned to it. A cancel routine is responsible for performing whatever steps are necessary to release any resources acquired during the processing that has already taken place for the IRP as well as completing the IRP with a canceled status.

  • An unload routine An unload routine releases any system resources a driver is using so that the I/O manager can remove them from memory. Any resources acquired in the initialization routine are usually released in the unload routine. A driver can be loaded and unloaded while the system is running.

  • A system shutdown notification routine This routine allows driver cleanup on system shutdown.

  • Error-logging routines When unexpected errors occur (for example, when a disk block goes bad), a driver's error-logging routines note the occurrence and notify the I/O manager. The I/O manager writes this information to an error log file.

Note

Most device drivers are written in C. Use of assembly language is highly discouraged because of the complexity it introduces and its effect of making a driver difficult to port between hardware architectures such as the x86, x64, and IA64.


Driver Objects and Device Objects

When a thread opens a handle to a file object (described in the "I/O Processing" section later in this chapter), the I/O manager must determine from the file object's name which driver (or drivers) it should call to process the request. Furthermore, the I/O manager must be able to locate this information the next time a thread uses the same file handle. The following system objects fill this need:

  • A driver object represents an individual driver in the system. The I/O manager obtains the address of each of the driver's dispatch routines (entry points) from the driver object.

  • A device object represents a physical or logical device on the system and describes its characteristics, such as the alignment it requires for buffers and the location of its device queue to hold incoming IRPs.

The I/O manager creates a driver object when a driver is loaded into the system, and it then calls the driver's initialization routine (for example, DriverEntry), which fills in the object attributes with the driver's entry points.

After loading, a driver can create device objects to represent devices, or even an interface to the driver, at any time by calling IoCreateDevice or IoCreateDeviceSecure. However, most Plug and Play drivers create devices with their add-device routine when the PnP manager informs them of the presence of a device for them to manage. Non Plug and Play drivers, on the other hand, usually create device objects when the I/O manager invokes their initialization routine. The I/O manager unloads a driver when its last device object has been deleted and no references to the device remain.

When a driver creates a device object, the driver can optionally assign the device a name. A name places the device object in the object manager namespace, and a driver can either explicitly define a name or let the I/O manager autogenerate one. (The object manager namespace is described in Chapter 3.) By convention, device objects are placed in the \Device directory in the namespace, which is inaccessible by applications using the Windows API.

Note

Some drivers place device objects in directories other than \Device. For example, the Windows Logical Disk Manager volume manager creates device objects that represent disk partitions in the \Device\HarddiskDmVolumes directory. See Chapter 10 for a description of storage architecture, including the way storage drivers use device objects.


If a driver needs to make it possible for applications to open the device object, it must create a symbolic link in the \Global?? directory (or \?? on Windows 2000) to the device object's name in the \Device directory. (See Chapter 3 for more information on \??.) Non Plug and Play and file system drivers typically create a symbolic link with a well-known name (for example, \Device\Hardware2). Because well-known names don't work well in an environment in which hardware appears and disappears dynamically, PnP drivers expose one or more interfaces by calling the IoRegisterDeviceInterface function, specifying a GUID (globally unique identifier) that represents the type of functionality exposed. GUIDs are 128-bit values that you can generate by using a tool included with the DDK and the Platform SDK, called Guidgen. Given the range of values that 128 bits represents, it's statistically almost certain that each GUID that Guidgen creates will be forever and globally unique.

IoRegisterDeviceInterface determines the symbolic link that is associated with a device instance; however, a driver must call IoSetDeviceInterfaceState to enable the interface to the device before the I/O manager actually creates the link. Drivers usually do this when the PnP manager starts the device by sending the driver a start-device command.

An application wanting to open a device object represented with a GUID can call Plug and Play setup functions in user space, such as SetupDiEnumDeviceInterfaces, to enumerate the interfaces present for a particular GUID and to obtain the names of the symbolic links it can use to open the device objects. For each device reported by SetupDiEnumDeviceInterfaces, an application executes SetupDiGetDeviceInterfaceDetail to obtain additional information about the device, such as its autogenerated name. After obtaining a device's name from SetupDiGet- DeviceInterfaceDetail, the application can execute the Windows function CreateFile to open the device and obtain a handle.

EXPERIMENT: Looking at the \Device Directory

You can use the Winobj tool from http://www.sysinternals.com or the !object kernel debugger command to view the device names under \Device in the object manager namespace. The following screen shot shows an I/O manager assigned symbolic link that points to a device object in \Device with an autogenerated name:



When you run the !object kernel debugger command and specify the \Device directory, you should see output similar to the following:

kd> !object \device Object: e100c4a0   Type:(8a4f3178)Directory     ObjectHeader:  e100c488     HandleCount:0    PointerCount: 301     Directory Object:  e10011e8   Name: Device     65535 symbolic  links snapped  through this directory         Hash Address    Type         Name         ---- -------    ----         ----          00  8a437398   Device       KsecDD              8a4a56f0   Device       Ndis              8a0ed5c0   Device       ProcExp              8a1ddb40   Device       Beep              8a336d38   Device       0000008e              8a4ed730   Device       00000032              8a4ee4f0   Device       00000025              8a4b5030   Device       00000019          01  8a2303e8   Device       Netbios              8a258030   Device       0000008f              8a4ed4f0   Device       00000033              8a4ee2b0   Device       00000026          02  8a1756d8   Device       KSENUM#00000001              8a4ec730   Device       00000040              8a20fd58   Device       Ip              8a2ef660   Device       RDP_CONSOLE0              8a4ed2b0   Device       00000034              8a4b4030   Device       00000027          03  8a4ec4f0   Device       00000041              8a15bf18   Device       0000009e              8a2947d8   Device        {EFF45047-C948-4D32-86B5-736480DDBB9C}              8a1b38e0   Device       Fips              8a0b6038   Device       Video0              8a288b48   Device       RDP_CONSOLE1              8a2501f8   Device       KeyboardClass0              8a4b3030   Device       00000035              8a4b4df0   Device       00000028          04  8a181030   Device       NDProxy              8a4ec2b0   Device       00000042              8a00b038   Device       Video1              8a189030   Device       KeyboardClass1          §

When you execute !object and specify an object manager directory object, the kernel debugger dumps the contents of the directory according to the way the object manager organizes it internally. For fast lookups, a directory stores objects in a hash table based on a hash of the object names, so the output shows the objects stored in each bucket of the directory's hash table.


As Figure 9-6 illustrates, a device object points back to its driver object, which is how the I/O manager knows which driver routine to call when it receives an I/O request. It uses the device object to find the driver object representing the driver that services the device. It then indexes into the driver object by using the function code supplied in the original request; each function code corresponds to a driver entry point. (The function codes shown in Figure 9-6 are described in the section "IRP Stack Locations" later in this chapter.)

Figure 9-6. The driver object


A driver object often has multiple device objects associated with it. The list of device objects represents the physical and logical devices that the driver controls. For example, each partition of a hard disk has a separate device object that contains partition-specific information. However, the same hard disk driver is used to access all partitions. When a driver is unloaded from the system, the I/O manager uses the queue of device objects to determine which devices will be affected by the removal of the driver.

EXPERIMENT: Displaying Driver and Device Objects

You can display driver and device objects with the kernel debugger !drvobj and !devobj commands, respectively. In the following example, the driver object for the keyboard class driver is examined, and its lone device object viewed:

kd> !drvobjkbdclass Driver  object  (81869cb0) isfor:   \Driver\Kbdclass Driver  ExtensionList:(id,  addr) Device  Object  list: 81869310 kd>  !devobj  81869310 Device  object  (81869310) is for:  KeyboardClass0 \Driver\Kbdclass  DriverObject 81869cb0 Current  Irp a57a0e90 RefCount  0  Type  0000000b Flags 00002044 DevExt  818693c8 DevObjExt  818694b8 ExtensionFlags  (0000000000)     AttachedDevice  (Upper) 818691e0  \Driver\Ctrl2cap AttachedTo  (Lower) 81869500  \Driver\i8042prt Device queue  is busy -- Queue  empty.

Notice that the !devobj command also shows you the addresses and names of any device objects that the object you're viewing is layered over (the AttachedTo line) as well as the device objects layered on top of the object specified (the AttachedDevice line).


Using objects to record information about drivers means that the I/O manager doesn't need to know details about individual drivers. The I/O manager merely follows a pointer to locate a driver, thereby providing a layer of portability and allowing new drivers to be loaded easily. Representing devices and drivers with different objects also makes it easy for the I/O system to assign drivers to control additional or different devices if the system configuration changes.

Opening Devices

File objects are the kernel-mode constructs for handles to files or devices. File objects clearly fit the criteria for objects in Windows: they are system resources that two or more user-mode processes can share, they can have names, they are protected by object-based security, and they support synchronization. Although most shared resources in Windows are memory- based resources, most of those that the I/O system manages are located on physical devices or represent actual physical devices. Despite this difference, shared resources in the I/O system, like those in other components of the Windows executive, are manipulated as objects. (See Chapter 3 for a description of the object manager and Chapter 8 for information on object security.)

File objects provide a memory-based representation of resources that conform to an I/O-centric interface, in which they can be read from or written to. Table 9-1 lists some of the file object's attributes. For specific field declarations and sizes, see the structure definition for FILE_OBJECT in Ntddk.h.

Table 9-1. File Object Attributes

Attribute

Purpose

Filename

Identifies the physical file that the file object refers to

Current byte offset

Identifies the current location in the file (valid only for synchronous I/O)

Share modes

Indicate whether other callers can open the file for read, write, or delete operations while the current caller is using it

Open mode flags

Indicate whether I/O will be synchronous or asynchronous, cached or noncached, sequential or random, and so on

Pointer to device object

Indicates the type of device the file resides on

Pointer to the volume parameter block (VPB)

Indicates the volume, or partition, that the file resides on

Pointer to section object pointers

Indicates a root structure that describes a mapped file

Pointer to private cache map

Identifies which parts of the file are cached by the cache manager and where they reside in the cache


EXPERIMENT: Viewing the File Object Data Structure

You can view the contents of the kernel-mode file object data structure with the kernel- debuggers dt command:

kd>  dt  nt!_file_object nt!_FILE_OBJECT    +0x000 Type             :  Int2B    +0x002 Size             :  Int2B    +0x004 DeviceObject     :  Ptr32_DEVICE_OBJECT    +0x008 Vpb              :  Ptr32_VPB    +0x00c FsContext        :  Ptr32Void    +0x010 FsContext2       :  Ptr32Void    +0x014 SectionObjectPointer :  Ptr32_SECTION_OBJECT_POINTERS    +0x018 PrivateCacheMap  :  Ptr32Void    +0x01c FinalStatus      :  Int4B    +0x020 RelatedFileObject :  Ptr32  _FILE_OBJECT    +0x024 LockOperation    :  UChar    +0x025 DeletePending    :  UChar    +0x026 ReadAccess       :  UChar    +0x027 WriteAccess      :  UChar    +0x028 DeleteAccess     :  UChar    +0x029 SharedRead       :  UChar    +0x02a SharedWrite      :  UChar    +0x02b SharedDelete     :  UChar    +0x02c Flags            :  Uint4B    +0x030 FileName         :  _UNICODE_STRING    +0x038 CurrentByteOffset :  _LARGE_INTEGER    +0x040 Waiters          :   Uint4B    +0x044 Busy             :   Uint4B    +0x048 LastLock         :   Ptr32Void    +0x04c Lock             :  _KEVENT    +0x05c Event            :  _KEVENT    +0x06c CompletionContext :  Ptr32  _IO_COMPLETION_CONTEXT


When a caller opens a file or a simple device, the I/O manager returns a handle to a file object. Figure 9-7 illustrates what occurs when a file is opened.

Figure 9-7. Opening a file object


In this example, (1) a C program calls the run-time library function fopen, which in turn (2) calls the Windows CreateFile function. The Windows subsystem DLL (in this case, Kernel32.dll) then (3) calls the native NtCreateFile function in Ntdll.dll. The routine in Ntdll.dll contains the appropriate instruction to cause a transition into kernel mode to the system service dispatcher, which then (4) calls the real NtCreateFile routine in Ntoskrnl.exe. (See Chapter 3 for more information about system service dispatching.)

Note

File objects represent open instances of files, not files themselves. Unlike UNIX systems, which use vnodes, Windows does not define the representation of a file; Windows system drivers define their own representations.


Like other executive objects, files are protected by a security descriptor that contains an access-control list (ACL). The I/O manager consults the security subsystem to determine whether the file's ACL allows the process to access the file in the way its thread is requesting. If it does, (5,6) the object manager grants the access and associates the granted access rights with the file handle that it returns. If this thread or another thread in the process needs to perform additional operations not specified in the original request, the thread must open another handle, which prompts another security check. (See Chapter 8 for more information about object protection.)

EXPERIMENT: Viewing Device Handles

Any process that has an open handle to a device will have a file object in its handle table corresponding to the open instance. You can view these handles with Process Explorer from http://www.sysinternals.com by selecting a process, checking Show Lower Pane in the View menu and Handles in the Lower Pane View submenu of the View menu. Sort by the Type column and scroll to where you see the handles that represent file objects, which are labeled as "File":



In this example the Csrss process has handles open to file objects that represent open instances of devices with autogenerated names as well as ones that belong to the Terminal Server Driver. You can look at the specific file object in the kernel debugger by first identifying the address of the object. The following command reports information on the highlighted handle (handle value 0xB8) in the preceding screen shot, which is in the Csrss.exe process that has a process ID of 2332 (0x91c):

0: kd>  !handle  b8  f91c processor number 0 Searching for  Process  with Cid == 91c PROCESS 86a6c020   SessionId: 0  Cid:  091c   Peb: 7ffde000   ParentCid: 028c     DirBase: 1158a000   ObjectTable:  e1b5d080 HandleCount: 643.     Image:  csrss.exe New version of handle table at e2b44000 with 643 Entries in use 00B8: Object: 866ae9e8   GrantedAccess: 0012019f Object: 866ae9e8   Type: (86fe8ad0) File     ObjectHeader:  866ae9d0         HandleCount:  1  PointerCount: 3

Because the object is a file object, you can get information about it with the !fileobj command:

0: kd> !fileobj  866ae9e8 File object name: Device Object: 0x86d0c8b8 \Driver\TermDD Vpb is NULL Flags:  0x40000         Handle Created FsContext: 0x866a31d8  FsContext2: 0x00000001 CurrentByteOffset:  0


Because a file object is a memory-based representation of a shareable resource and not the resource itself, it's different from other executive objects. A file object contains only data that is unique to an object handle, whereas the file itself contains the data or text to be shared. Each time a thread opens a file handle, a new file object is created with a new set of handle- specific attributes. For example, the current byte offset attribute refers to the location in the file at which the next read or write operation using that handle will occur. Each handle to a file has a private byte offset even though the underlying file is shared. A file object is also unique to a process, except when a process duplicates a file handle to another process (by using the Windows DuplicateHandle function) or when a child process inherits a file handle from a parent process. In these situations, the two processes have separate handles that refer to the same file object.

Although a file handle might be unique to a process, the underlying physical resource is not. Therefore, as with any shared resource, threads must synchronize their access to shareable files, file directories, and devices. If a thread is writing to a file, for example, it should specify exclusive write access when opening the file handle to prevent other threads from writing to the file at the same time. Alternatively, by using the Windows LockFile function, the thread could lock a portion of the file while writing to it.

When a file is opened, the filename includes the name of the device object on which the file resides. For example, the name \Device\Floppy0\Myfile.dat refers to the file Myfile.dat on floppy disk drive A. The substring \Device\Floppy0 is the name of the internal Windows device object representing that floppy disk drive. When opening Myfile.dat, the I/O manager creates a file object and stores a pointer to the Floppy0 device object in the file object and then returns a file handle to the caller. Thereafter, when the caller uses the file handle, the I/O manager can find the Floppy0 device object directly. Keep in mind that internal Windows device names can't be used in Windows applications instead, the device name must appear in a special directory in the object manager's namespace, which is \?? on Windows 2000 and \Global?? on Windows XP and Windows Server 2003. This directory contains symbolic links to the real, internal Windows device names. Device drivers are responsible for creating links in this directory so that their devices will be accessible to Windows applications. You can examine or even change these links programmatically with the Windows QueryDosDevice and DefineDosDevice functions.

EXPERIMENT: Viewing Windows Device Name to Windows Device Name Mappings

You can examine the symbolic links that define the Windows device namespace with the Winobj utility from http://www.sysinternals.com. Run Winobj, and click on the \?? Directory on Windows 2000 or \Global?? on Windows XP or Windows Server 2003, as shown here:



Notice the symbolic links on the right. Try double-clicking on the device C:. You should see something like this:



C: is a symbolic link to the internal device named \Device\HarddiskVolume1, or the first volume on the first hard drive in the system. The COM1 entry in Winobj is a symbolic link to \Device\Serial0, and so forth. Try creating your own links with the subst command at a command prompt.


     < Day Day Up > 


    Microsoft Windows Internals
    Microsoft Windows Internals (4th Edition): Microsoft Windows Server 2003, Windows XP, and Windows 2000
    ISBN: 0735619174
    EAN: 2147483647
    Year: 2004
    Pages: 158

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net