CHAPTER 9: I/O System

advertisement
CHAPTER 9: I/O System
538
551
558
560
563
565
568
578
589
Viewing the Loaded Driver List
Viewing the System Power Capabilities and Policy
Looking at the \Device Directory
Viewing Win32 Device Name to W2K Device Name Mappings
Displaying Driver and Device Objects
Looking at Driver Dispatch Routines
Examining IRPs and the Thread IRP Queue
Dumping the Device Tree
Looking at a Driver's Registered Fast I/O Routines
EXPERIMENT
Viewing the Loaded Driver List
You can see a list of registered drivers 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.) You can view the Drivers section within Computer Management by
expanding System Tools, System Information, Software Environment and selecting
Drivers, as shown here:
You can also obtain a list of loaded kernel-mode drivers with the Drivers utility in the
Windows 2000 resource kits or the Pstat utility (ships in the Platform SDK and is
available for download from the Windows 2000 Resource Kits Web site at
www.microsoft.com/windows2000/library/resources/reskit.) Pstat lists the drivers at the
end of its display. (It first lists all the processes and threads in the system.) The only
difference in the output of the two utilities is that Pstat shows the load address of the
driver in system address space. The following output is a partial display of the driver
information from Pstat:
C:\>pstat
ModuleName Load Addr
Code
Data
Paged
LinkDate
----------------------------------------------------------------------ntoskrnl.exe 80400000 429184
96896 775360 Tue Dec 07 18:41:11 1999
hal.dll 80062000
25856
6016
16160 Tue Nov 02 20:14:22 1999
BOOTVID.DLL EE010000
5664
2464
0 Wed Nov 03 20:24:33 1999
ACPI.sys BFFD8000
92096
8960
43488 Wed Nov 10 20:06:04 1999
WMILIB.SYS EE1C8000
512
0
1152 Sat Sep 25 14:36:47 1999
pci.sys EDC00000
12704
1536
31264 Wed Oct 27 19:11:08 1999
isapnp.sys EDC10000
14368
832
22944 Sat Oct 02 16:00:35 1999
compbatt.sys EE014000
2496
0
2880 Fri Oct 22 18:32:49 1999
BATTC.SYS EE100000
800
0
2976 Sun Oct 10 19:45:37 1999
intelide.sys EE1C9000
1760
32
0 Thu Oct 28 19:20:03 1999
PCIIDEX.SYS EDE80000
4544
480
10944 Wed Oct 27 19:02:19 1999
pcmcia.sys BFFBD000
32800
8864
23680 Fri Oct 29 19:20:08 1999
ftdisk.sys BFFA0000
4640
32
95072 Mon Nov 22 14:36:23 1999
Diskperf.sys EE102000
1728
32
2016 Thu Sep 30 20:30:40 1999
dmio.sys BFF7E000 104672
15168
0 Tue Nov 30 14:47:49 1999
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 !drivers command.
EXPERIMENT
Viewing the System Power Capabilities and Policy
You can view a computer's system power capabilities by using the !pocaps kernel
debugger command. Here's the output of the command when run on an ACPI-compliant
laptop running Windows 2000 Professional:
kd> !pocaps
PopCapabilities @ 0x8046adc0
Misc Supported Features: PwrButton SlpButton Lid S1 S3 S4 S5
HiberFile FullWake
Processor Features:
Thermal Throttle (MinThrottle = 03, Scale = 08)
Disk Features:
SpinDown
Battery Features:
BatteriesPresent
Battery 0 - Capacity: 00000000 Granularity: 00000000
Battery 1 - Capacity: 00000000 Granularity: 00000000
Battery 2 - Capacity: 00000000 Granularity: 00000000
Wake Caps
Ac OnLine Wake:
Sx
Soft Lid Wake:
Sx
RTC Wake:
S3
Min Device Wake:
Sx
Default Wake:
Sx
The Misc Supported Features line reports that, in addition to S0 (fully on), the system
supports system power states S1, S3, S4, and S5 (it doesn't implement S2) and has a valid
hibernation file to which it can save system memory when it hibernates (state S4).
The Power Options Properties dialog box, shown below (available by selecting Power
Options in Control Panel), lets you configure various aspects of the system's power
policy. The exact properties you can configure depends on the system's power
capabilities, which we just examined.
Windows 2000 Professional on an ACPI-compliant laptop (such as the system on which
we captured the following screen shot) generally provides the most power-management
features. On such systems, you can set the idle detection timeouts that control when the
system turns off the monitor, spins down hard disks, goes to standby mode (moves to
system power state S1), and hibernates (moves the system to power state S4). In addition,
the Advanced tab in Power Options lets you specify the power-related behavior of the
system when you press the power or sleep buttons or close a laptop's lid.
The settings you configure in Power Options directly affect values in the system's power
policy, which you can display with the !popolicy debugger command. Here's the output
of the command on the same system:
kd> !popolicy
SYSTEM_POWER_POLICY (R.1) @ 0x80469180
PowerButton:
Off Flags: 00000003
SleepButton:
Sleep Flags: 00000003
LidClose:
Hibernate Flags: 00000001
Idle:
None Flags: 00000001
OverThrottled:
Sleep Flags: c0000004
NoWakes Critical
IdleTimeout:
00000000 IdleSensitivity:
MinSleep:
S1 MaxSleep:
LidOpenWake:
S0 FastSleep:
WinLogonFlags: 00000000 S4Timeout:
VideoTimeout:
00000000 VideoDim:
SpinTimeout:
00000708 OptForPower:
FanTolerance:
64 ForcedThrottle:
MinThrottle:
19
Event:
Event:
Event:
Event:
Event:
00000000
00000000
00000000
00000000
00000000
32
S3
S1
00000000
6e
01
64
Query UI
Query UI
Query
Query
Override
The first lines of the display correspond to the button behaviors specified on the
Advanced tab of Power Options, and on this system the power button is interpreted as an
off switch, the sleep button moves the system to a sleep state, and the closing of the
laptop lid causes the system to hibernate.
The timeout values shown at the end of the output are expressed in seconds and displayed
in hexadecimal notation. The values reported here directly correspond to the settings you
can see configured in the Power Options screen shot. (The laptop is plugged in.) For
example, the video timeout is 0, meaning the monitor never turns off, and the hard disk
spin-down timeout is 0x708, which corresponds to 1800 seconds, or 30 minutes.
EXPERIMENT
Looking at the \Device Directory
You can use the Winobj tool, included as \Sysint\Winobj.exe on the companion CD, 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: 81a8e170 Type: (81ab6120) Directory
ObjectHeader: 81a8e158
HandleCount: 0 PointerCount: 198
Directory Object: 81a914d0 Name: Device
9 symbolic links snapped through this directory
HashBucket[ 00 ]: 81a6de10 Device 'KsecDD'
819c43f0 Device 'Beep'
81a6d6d0 Device 'Ndis'
81a61030 Device '00000019'
81aa7830 Device '003018'
81aa7a30 Device '002918'
HashBucket[ 01 ]: 817c3c70 Device '00000026'
819c3d90 Device 'Netbios'
HashBucket[ 02 ]: 818d1850 Device 'KSENUM#00000001'
81966890 Device 'Ip'
HashBucket[ 03 ]: 818c5b70 Device 'KSENUM#00000002'
81a31038 Device 'Video0'
81a4fc70 Device 'KeyboardClass0'
HashBucket[ 04 ]: 819d4410 Device 'NDProxy'
819c0040 Device 'Video1'
HashBucket[ 05 ]: 817e7650 Device 'PcCard0-0'
819c70d0 Device 'Eawdmfd'
81a2aa50 Device
'{13199AF4-86FA-48C2-8074-468CA06AFB6C}'
819c0ce0 Device 'Video2'
81a52040 Device 'Serial0'
81a6cbb0 Device 'PointerClass0'
81a215f0 Device '0000000a'
HashBucket[ 06 ]: 817cb8c0 Device 'Serial1'
81900570 Device 'DebugMessageDevice'
81a277d0 Device 'USBPDO-0'
81a5e030 Device 'CompositeBattery'
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.
EXPERIMENT
Viewing Win32 Device Name to Windows 2000 Device Name Mappings
You can examine the symbolic links that define the Win32 device namespace with the
Winobj utility included on the companion CD (\Sysint\Winobj.exe). Run Winobj, and
click on the \?? directory, 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.
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> !drvobj kbdclass
Driver object (81869cb0) is for:
\Driver\Kbdclass
Driver Extension List: (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).
EXPERIMENT
Looking at Driver Dispatch Routines
You can obtain a listing of the functions a driver has defined for its dispatch routines by
entering a 2 after the driver object's name (or address) in the !drvobj kernel debugger
command:
kd> !drvobj kbdclass 2
Driver object (81869cb0) is for:
\Driver\Kbdclass
Dispatch routines:
[00] IRP_MJ_CREATE
kbdclass!KeyboardClassCreate
[01] IRP_MJ_CREATE_NAMED_PIPE
ntoskrnl!IopInvalidDeviceRequest
[02] IRP_MJ_CLOSE
kbdclass!KeyboardClassClose
[03] IRP_MJ_READ
kbdclass!KeyboardClassRead
[04] IRP_MJ_WRITE
ntoskrnl!IopInvalidDeviceRequest
[05] IRP_MJ_QUERY_INFORMATION
ntoskrnl!IopInvalidDeviceRequest
[06] IRP_MJ_SET_INFORMATION
ntoskrnl!IopInvalidDeviceRequest
[07] IRP_MJ_QUERY_EA
ntoskrnl!IopInvalidDeviceRequest
[08] IRP_MJ_SET_EA
ntoskrnl!IopInvalidDeviceRequest
edf0866e
80425354
edf088ec
edf08b1c
80425354
80425354
80425354
80425354
80425354
[09] IRP_MJ_FLUSH_BUFFERS
edf085d4
kbdclass!KeyboardClassFlush
[0a] IRP_MJ_QUERY_VOLUME_INFORMATION
80425354
ntoskrnl!IopInvalidDeviceRequest
[0b] IRP_MJ_SET_VOLUME_INFORMATION
80425354
ntoskrnl!IopInvalidDeviceRequest
[0c] IRP_MJ_DIRECTORY_CONTROL
80425354
ntoskrnl!IopInvalidDeviceRequest
[0d] IRP_MJ_FILE_SYSTEM_CONTROL
80425354
ntoskrnl!IopInvalidDeviceRequest
[0e] IRP_MJ_DEVICE_CONTROL
edf0a8ec
kbdclass!KeyboardClassDeviceControl
[0f] IRP_MJ_INTERNAL_DEVICE_CONTROL
edf0a380
kbdclass!KeyboardClassPassThrough
[10] IRP_MJ_SHUTDOWN
80425354
ntoskrnl!IopInvalidDeviceRequest
[11] IRP_MJ_LOCK_CONTROL
80425354
ntoskrnl!IopInvalidDeviceRequest
[12] IRP_MJ_CLEANUP
edf084b6
kbdclass!KeyboardClassCleanup
[13] IRP_MJ_CREATE_MAILSLOT
80425354
ntoskrnl!IopInvalidDeviceRequest
[14] IRP_MJ_QUERY_SECURITY
80425354
ntoskrnl!IopInvalidDeviceRequest
[15] IRP_MJ_SET_SECURITY
80425354
ntoskrnl!IopInvalidDeviceRequest
[16] IRP_MJ_POWER
edf0b5e2
kbdclass!KeyboardClassPower
[17] IRP_MJ_SYSTEM_CONTROL
edf0bbfe
kbdclass!KeyboardClassSystemControl
[18] IRP_MJ_DEVICE_CHANGE
80425354
ntoskrnl!IopInvalidDeviceRequest
[19] IRP_MJ_QUERY_QUOTA
80425354
ntoskrnl!IopInvalidDeviceRequest
[1a] IRP_MJ_SET_QUOTA
80425354
ntoskrnl!IopInvalidDeviceRequest
[1b] IRP_MJ_PNP
edf09168
kbdclass!KeyboardPnP
EXPERIMENT
Examining IRPs and the Thread IRP Queue
You can examine the pending IRPs for a thread with the !thread kernel debugger
command. One thread that almost always has a pending IRP is the Win32 environment
subsystem's keyboard-input thread. To find this thread, execute the !stacks kernel
debugger command and locate the thread in Csrss that is listed as having started in the
Win32k RawInputThread function:
kd> !stacks
Proc.Thread
Thread
ThreadState
8.000004
8.00000c
8.000010
8.000014
8.000018
8.00001c
8.000020
8.000024
fe504a60
fe503ce0
fe503a60
fe5037e0
fe503560
fe5032e0
fe502020
fe502da0
BLOCKED
BLOCKED
BLOCKED
BLOCKED
BLOCKED
BLOCKED
BLOCKED
BLOCKED
c0.0000c4
c0.0000c8
c0.0000cc
c0.0000d0
c0.0000d4
c0.0000dc
c0.00007c
c0.0000e0
ff2d5020
ff2d5d80
ff2d4820
ff2d4460
ff2d4120
ff2cfda0
ff2cbc40
ff2cb480
BLOCKED
BLOCKED
BLOCKED
BLOCKED
BLOCKED
BLOCKED
BLOCKED
BLOCKED
Blocker
[System]
ntoskrnl!MmZeroPageThread+0x5f
ntoskrnl!ExpWorkerThread+0x73
ntoskrnl!ExpWorkerThread+0x73
ntoskrnl!ExpWorkerThread+0x73
ntoskrnl!ExpWorkerThread+0x73
ntoskrnl!ExpWorkerThread+0x73
ntoskrnl!ExpWorkerThread+0x73
ntoskrnl!ExpWorkerThread+0x73
[csrss.exe]
?? Kernel stack not resident ??
?? Kernel stack not resident ??
ntdll+0xaaa7
?? Kernel stack not resident ??
?? Kernel stack not resident ??
ntdll+0xaaa7
win32k!RawInputThread+0x3c2
win32k!xxxMsgWaitForMultipleObjects+0x92
Then perform the !thread command on the thread's address (the second column):
kd> !thread ff2cbc40
THREAD ff2cbc40 Cid c0.7c Teb: 00000000 Win32Thread: a20836e8
WAIT: (WrUserRequest) KernelMode Alertable
ff2cc1a0 SynchronizationEvent
ff2cbb28 SynchronizationEvent
ff2cbae8 NotificationTimer
ff2cbb68 SynchronizationEvent
IRP List:
fee25388: (0006,0100) Flags: 00000970 Mdl: 00000000
Not impersonating
Owning Process ff2d9020
WaitTime (seconds)
15420441
Context Switch Count
328592
UserTime
0:00:00.0000
KernelTime
0:00:00.0721
Start Address win32k!RawInputThread (0xa000c0b0)
Stack Init f20d0000 Current f20cfaf0 Base f20d0000 Limit f20cd000 Call 0
Priority 19 BasePriority 13 PriorityDecrement 0 DecrementCount 0
ChildEBP RetAddr Args to Child
f20cfb08 8042d33d 80400b46 00000001 00000000 ntoskrnl!KiSwapThread+0xc5
f20cfb3c a000c3f3 00000004 ff2cbc08 00000001
ntoskrnl!KeWaitForMultipleObjects+0x266
f20cfda8 804524f6 00000002 00000000 00000000 win32k!RawInputThread+0x3c2
f20cfddc 80465b62 a000c0b0 f1caf7d0 00000000
ntoskrnl!PspSystemThreadStartup+0x69
00000000 00000000 00000000 00000000 00000000 ntoskrnl!KiThreadStartup+0x16
The sample output shows that the thread's IRP list contains one pending IRP. If you use
the !irp command on this IRP, you're likely to see something like this:
kd> !irp fee25388
Irp is active with 4 stacks 4 is current (= 0xfee25440)
No Mdl System buffer = ff0acc48 Thread ff2cbc40: Irp stack trace.
cmd flg cl Device
File
Completion-Context
[ 0, 0]
0 0 00000000 00000000 00000000-00000000
[
0, 0]
Args: 00000000 00000000 00000000 00000000
0 0 00000000 00000000 00000000-00000000
[
0, 0]
Args: 00000000 00000000 00000000 00000000
0 0 00000000 00000000 00000000-00000000
>[
4, 0]
Args: 00000000 00000000 00000000 00000000
0 e1 ff43b390 ff2cb928 00000000-00000000
\Driver\Kbdclass
Args: 00000078 00000000 00000000 00000000
This output shows that the IRP has four stack locations and that the keyboard class driver,
which is waiting for keyboard input before it completes the IRP, currently owns it.
Another IRP-related debugger command, !irpfind, lets you see all the pending IRPs on
the system:
kd> !irpfind
Scanning large pool allocation table for Tag: Irp?
Searching NonPaged pool (fe314000 : fe52c000) for Tag: Irp?
Irp
[ Thread ]
fe4f0568 [00000000]
fe4f22e8 [fe5028a0]
fe4f3b28 [fe5028a0]
fe4fdf68 [ff2ae8c0]
0xff2c9780
fe50b6a8 [00000000]
fe50d648 [00000000]
fe513e68 [fe5028a0]
fe515e68 [fe5028a0]
irpStack:
irpStack:
irpStack:
irpStack:
irpStack:
(Mj,Mn)
( 0, 0)
( e, 0)
( e, 0)
( e, 0)
DevObj
ff453790
fe4f13b0
fe4f33f0
ff3f45f0
[Driver]
[ \Driver\Cdrom]
[ \Driver\Ftdisk]
[ \Driver\Ftdisk]
[ \Driver\NetBT]
Irp is complete (CurrentLocation 3 > StackCount 2)
irpStack: ( f, 0) ff4526f0 [ \Driver\openhci]
irpStack: ( e, 0) fe4f3690 [ \Driver\Ftdisk]
irpStack: ( e, 0) fe4f2570 [ \Driver\Ftdisk]
Searching NonPaged pool (fe52c000 : ffb7f000) for Tag: Irp?
fefa4848 [ff1124e0] irpStack: ( e, 9)
fefcc2e8 [ff0ecda0] irpStack: ( 3, 0)
ff2b3490 [ \Driver\AFD]
ff3f3e70 [ \FileSystem\Npfs]
EXPERIMENT
Dumping the Device Tree
A more detailed way to view the device tree than using Device Manager is to use the
!devnode kernel debugger command. Specifying 0 1 as command options dumps the
internal device tree devnode structures, indenting entries to show their hierarchical
relationships, as shown here:
kd> !devnode 0 1
Dumping IopRootDeviceNode (= 0x818a78e8)
DevNode 0x818a78e8 for PDO 0x818a79e0
Parent 0000000000
Sibling 0000000000
Child 0x818a74c8
InstancePath is "HTREE\ROOT\0"
Flags (0x00040459) DNF_MADEUP, DNF_PROCESSED,
DNF_ENUMERATED, DNF_ADDED,
DNF_NO_RESOURCE_REQUIRED, DNF_STARTED
DisableableDepends = 10 (from children)
DevNode 0x818a74c8 for PDO 0x818a75d0
Parent 0x818a78e8
Sibling 0x818a7248
Child 0x81883228
InstancePath is "Root\ACPI_HAL\0000"
Flags (0x000405dd) DNF_MADEUP, DNF_HAL_NODE,
DNF_PROCESSED, DNF_ENUMERATED,
DNF_ADDED, DNF_HAS_BOOT_CONFIG,
DNF_BOOT_CONFIG_RESERVED, DNF_NO_RESOURCE_REQUIRED,
DNF_STARTED
DisableableDepends = 1 (from children)
DevNode 0x81883228 for PDO 0x818838d0
Parent 0x818a74c8
Sibling 0000000000
Child 0x81819408
InstancePath is "ACPI_HAL\PNP0C08\0"
ServiceName is "ACPI"
Flags (0x000421d8) DNF_PROCESSED, DNF_ENUMERATED,
DNF_ADDED, DNF_HAS_BOOT_CONFIG,
DNF_BOOT_CONFIG_RESERVED, DNF_RESOURCE_ASSIGNED,
DNF_STARTED
CapabilityFlags (0x000000c0) UniqueID, SilentInstall
DisableableDepends = 10 (from children)
DevNode 0x81819408 for PDO 0x81891530
Parent 0x81883228
Sibling 0x818910c8
Child 0000000000
InstancePath is "ACPI\PNP0C0B\1"
Flags (0x00040458) DNF_PROCESSED, DNF_ENUMERATED,
DNF_ADDED, DNF_NO_RESOURCE_REQUIRED,
DNF_STARTED
UserFlags (0x00000008) DNUF_NOT_DISABLEABLE
CapabilityFlags (0x000001c0) UniqueID, SilentInstall,
RawDeviceOK
DisableableDepends = 1 (including self)
Information shown for each devnode includes the InstancePath, which is the name of the
device's enumeration registry key stored under
HKLM\SYSTEM\CurrentControlSet\Enum, and the ServiceName, which corresponds to
the device's driver registry key under HKLM\SYSTEM\CurrentControlSet\Services. To
see the resources, such as interrupts, ports, and memory assigned to each devnode,
specify 0 3 as the command options for the !devnode command.
EXPERIMENT
Looking at a Driver's Registered Fast I/O Routines
The !drvobj kernel debugger command can list the fast I/O routines that a driver registers
in its driver object. However, typically only file system drivers have any use for fast I/O
routines. The following output shows the fast I/O table for the NTFS file system driver
object:
kd> !drvobj \filesystem\ntfs 2
Driver object (ff432670) is for:
\FileSystem\Ntfs
Dispatch routines:
[00] IRP_MJ_CREATE
Fast I/O routines:
FastIoCheckIfPossible
be3263ef
Ntfs!NtfsPostUsnChange+0xd8c
FastIoRead
be31869e
Ntfs!NtfsCreateInternalStreamCommon+0x1b43
FastIoWrite
be318df9
Ntfs!NtfsCreateInternalStreamCommon+0x229e
FastIoQueryBasicInfo
be3020fa
Ntfs!NtfsRaiseStatus+0x105a8
FastIoQueryStandardInfo
be317d1e
Ntfs!NtfsCreateInternalStreamCommon+0x11c3
FastIoLock
be32622d
Ntfs!NtfsPostUsnChange+0xbca
FastIoUnlockSingle
be326139
Ntfs!NtfsPostUsnChange+0xad6
The output shows that NTFS has registered its NtfsPostUsnChange routine as the fast I/O
table's FastIoCheckIfPossible entry. As the name of this fast I/O entry implies, the I/O
manager sometimes calls this function before issuing a fast I/O request, giving a driver an
opportunity to indicate when fast I/O operations on a file are not feasible.
Download