Windows® Driver Model History And Architectural Overview

Download Report

Transcript Windows® Driver Model History And Architectural Overview

®
Windows Driver Model
History And Architectural
Overview
Bob Rinne
Director
Windows Operating System Base
Microsoft Corporation
Purpose Of This Talk

The WDM reality





Discuss what is covered in WDM
It has taken a long time
Get an overview of its history
and versions
Get an overview of the architectures
Basic information for navigating
through WDM
Technical Outline




Goals of WDM
History of WDM
Current state
Overview of WDM
Goals Of WDM




Common development environment
for Windows NT® and Windows 9x
family products
Method of bringing Plug and Play and
Power Management to Windows NT
Binary compatibility between products
Broad coverage of new
technology busses
What Is WDM

NDIS/SCSI




Pre-WDM, but satisfies goals
System environment
Bus support
Device class support
History Of WDM




Introduced after Windows 95 launch
First available in Windows 98
Now available in Windows 2000
Is present on Windows ME with
enhancements from Windows 98
History Of WDM

Windows 98 versions




Started from a device oriented
Plug and Play operating system
Added portable abstractions and
I/O subsystem from Windows NT
Provided definition for Plug and Play
and power management mapping to
Windows NT
Work done as a mapper between WDM
and Windows 95 core
Windows 98 And Me
System VM
Applications
System services
Windows NT
I/O Manager
Installable
file system
FSD
Virtual
Memory
Manager
Windows 95
I/O subsystem
Services
Device drivers
Drivers
FSD
Device drivers
HAL
MS-DOS
VM
MS-DOS
VM
MS-DOS
VM
History Of WDM

Windows NT version



Started from non-Plug and Play,
“driver”-oriented operating system
Made WDM interfaces native
Converted to Plug and Play/“device”oriented operating system
Windows NT
Daemons
Services
Other
Spooler
File server
Security
Session manager
Applications
Other
Replicator
Logon
Alerter
Event logger
LPC
Environments
Windows
LPC
LPC
LPC
Windows NT System
I/O manager
Security
monitor
Executive
Power
Management
Memory
Management
Process
support
File systems
Object management/executive run time
Device drivers
Kernel
Hardware abstraction layer
Platform interface
I/O
devices
DMA
control
Bus
mapping
Clocks/
timers
Cache
control
Interrupt
dispatch
Privileged
architecture
Current State



WDM is real
There now is a common
development environment
Binary compatibility is possible


Unfortunately it is harder than we wanted
Requires extensive testing on all versions
of all operating systems
Current State

Busses covered




Still have NDIS and SCSI
USB
1394
New ones coming
Current State

Devices covered







Input
Cameras/Scanners
Audio
WinModem
Storage (*)
Many more
New ones coming
Current State

What’s not there



Video
Generic storage
Super I/O chip
Overview Of WDM

Breakdown the components


What do those first two characters in
DDI calls mean?
Definition of functionality
Components In WDM

wdm.h




ks.h


Ke Ob Ex Io Mm Ps Rtl Po Pnp
Hal (platform support)
Zw (magic)
Ks
Wmi
Ke - Kernel




Minimal set of items exported here
in WDM
Synchronization primitives
Performance counters and timers
Stall and Irq control
Ob - Object Manager


Very minimal set
Used only for object reference
count maintenance
Ex - The System Executive




Memory allocations
Interlocked operations
List operations
Work items

There is a better set in the IO manager (Io*)
Io - I/O Manager

I/O Request Packet (IRP) Handling



Device Object Plumbing






The routines that pass Irps
Global locks
The routines that set device relationships
Work items
Registry access routines
System state notifications
DMA assistance
Interrupt assistance
Mm - Memory Manager




Virtual to Physical mapping
Physical memory commit/locking
Driver image memory locking
Portable I/O space handling
Ps - Process Service


System thread support
Just creation and deletion
Rtl - Run-Time Library



Bulk memory activity support
Unicode support
Conversion support



Unicode to Ansi
Integer to Unicode
Etc.
Po - Power Manager



Power state change support
Power Irp handling
Device idle detection support
PnP - Plug And Play
Subsystem



There are no Plug and Play
decorated routine names
Exists as part of the I/O manager
Actually implemented as an entity in
the system
Hal - Hardware Abstraction
Layer

Device manipulation



I/O port access and usage
Memory mapped device access
and usage
Platform abstraction

Component owner of interrupts
Zw - Magic


Kernel mode map to system APIs
Registry access




Open/Close keys
Create/Delete keys
Query values
Minimal file access
Ks - Kernel Streaming



Separate component on both platforms
Definitions of interfaces located in ks.h
Provides plumbing for streaming data
device connections
WMI - Windows
Management Infrastructure




Similar to Plug and Play as a
component of Io
GUID support - wmidata.h
Structure definitions - wmistr.h
Support library definitions - wmilib.h
Conclusion




Its taken awhile
Some of it is simple; Some of it isn’t
Develop driver first under
Windows 2000
Test, test, test, on all releases of all
supported operating systems
WDM Driver
Implementation Guide
Adrian J. Oney
Software Engineer
Windows Core OS
Microsoft Corporation
Preview

Writing an Windows NT 4.0 skeleton
driver required mastery of many
concepts






Scheduling
Synchronization
DeviceObjects, DriverObjects
I/O theory (IRP handling, queuing,
asynchronous I/O)
Security
Debugging
Preview

Writing a WDM driver requires mastery
of all of those concepts plus:





Plug and Play
Power Management
WMI (Windows® Management Interface)
Windows 9x/Windows 2000 differences
And don’t forget technology specific
issues


Device class specific: Audio, Modem, …
Bus specific: USB, 1394, PCI, …
Scheduling Basics
WDM presents two types of scheduling
 Thread-based scheduling


Kernel support for semaphores, mutexes, event objects
Windows 2000 adds new high-level support for reader/writer
operations to WDM


(For instance ExAcquireSharedStarveExclusive)
Interrupt Level-based scheduling

Code running at a higher IRQ Level (IRQL) immediately
preempts code running at a lower IRQL


The lowest three IRQL’s are scheduling constructs, unrelated
to hardware:


Code runs on same thread, no switching!
PASSIVE_LEVEL, APC_LEVEL, DISPATCH_LEVEL
Multiple processors can each run at a different IRQL!
Callbacks

PASSIVE_LEVEL (IRQL 0)

“Work Item”



APC_LEVEL (IRQL 1)

Asynchronous Procedure Call aka “APC”




Queue-able from DISPATCH_LEVEL or lower
Two types, Ex-WorkItems and Io-WorkItems
Thread specific
No WDM function to queue these
I/O Manager queues them to get back into correct
process during I/O
DISPATCH_LEVEL (IRQL 2)

Deferred Procedure Call aka “DPC”

Queue-able anytime and anywhere, including ISRs
Scheduling Basics

PASSIVE_LEVEL (IRQL 0)





APC_LEVEL (IRQL 1)




Drivers typically run at this level
Drivers can touch pageable memory
Drivers can do file I/O
Blocking causes a processor to switch threads
When switching into a new thread, the processor will
run any pending APC’s at APC_LEVEL
Blocking lets other threads run at PASSIVE_LEVEL
Restriction: Drivers cannot use file functions
DISPATCH_LEVEL (IRQL 2)


A processor never switches threads when running
driver code at DISPATCH_LEVEL
Restrictions: A driver cannot touch pagable memory,
or use file functions
IRQs And IRQLs On 8259 PIC
CLOCK
31
IRQL 
Hardware Interrupt 0
Hardware Interrupt 1
IDE
ISR queues DPC
…
Hardware Interrupt 14
Hardware Interrupt 15
2 – DISPATCH_LEVEL
1 – APC_LEVEL
0 – PASSIVE_LEVEL
DPC
executes
Thread
Switches
IO-APIC Example
From an 8-Way server machine down the hall,
other machines will be different!
Device
IRQ
IRQL
USB Controller
SCSI Controller
Network Adapter
SCSI Controller
Network Adapter
SCSI Controller
IDE Controller
SCSI Controller
Floppy Controller
Video Controller
Com Port
Network Adapter
0xB4
0xA3
0xA
9
0xA4
9
0x93
0x94
8
8
0x83
0x72
0x73
0x62
0x63
0x51
0x53
7
6
6
5
5
4
4
Synchronization

PASSIVE_LEVEL (IRQL 0)




APC_LEVEL (IRQL 1)



Fast Mutexes (automatically raises IRQL to APC_LEVEL)
Semaphores, Events, Resources (note: none raise IRQL)
DISPATCH_LEVEL (IRQL 2)



Semaphores
Events
Resources (a kind of Mutex)
Spinlocks
No reentrant primitives (i.e., mutexes)
Hardware levels (IRQL > 2)

KeSynchronizeExecution
Security Attack

A user mode application may choose to
“freeze” a thread. User mode does this
by queuing an APC to the appropriate
thread. Security is compromised if your
driver gets frozen holding a sync object



Use synchronization objects that raise
to APC_LEVEL or above, or
Move such operations into a system
thread, or
Use KeEnterCriticalRegion and
KeLeaveCriticalRegion
Drivers And Devices


Every driver has a DriverObject associated with it
DriverObject(s) represent driver-specific information



Each driver creates one or more DeviceObject(s) via
IoCreateDevice(…)
DeviceObject(s) contain per-device information




Dispatch table
DeviceExtension
Name
Flags (e.g., DO_POWER_PAGABLE)
A WDM driver is typically unloaded when all it’s
DeviceObject(s) have been deleted
Drivers And Devices
DRIVER_OBJECT
Scanner.sys
DEVICE_OBJECT
(Scanner #3)
DRIVER_OBJECT
Toaster.sys
DEVICE_OBJECT
(Toaster #1)
DEVICE_OBJECT
(Scanner #2)
DEVICE_OBJECT
(Scanner #1)
Device Stacks


Doing an operation often requires
multiple drivers
DeviceObjects are arranged into
chains called Device Stack
DEVICE_OBJECT
DRIVER_OBJECT
Scanner.sys
DEVICE_OBJECT
(Scanner #2)
DEVICE_OBJECT
DEVICE_OBJECT DEVICE_OBJECT
(Scanner #1)
DEVICE_OBJECT
I/O Request Packets


The OS communicates with drivers
by sending I/O Request Packets (IRPs)
to a device stack
IRPs are WDM’s solution
to asynchronous I/O
IRP
DEVICE_OBJECT
DEVICE_OBJECT
(Scanner #2)
DEVICE_OBJECT
DEVICE_OBJECT
Asynchronous I/O

Goal: Let applications queue one or more
requests without blocking


Two dedicated application threads
is not an optimal solution


Example: Decompressing GIF frames
from a CD
Thread switches are expensive
Policy needs to be in the driver stack

Only it knows whether a given request should be
handled synchronously or asynchronously
Synchronous OS design
App
User Mode
Kernel Mode
Driver A
Driver B
Driver C
Instruction Pointer
Stack Pointer
Thread Stack
Param for A
Param for A
Return address to App
…
Param for B
Param for B
Return address to A
…
Param for C
Param for C
Return address to B
I/O Request Packets
Thread Stack
Param for A
Param for A
Return address to App
…
Param for B
Param for B
Return address to A
…
Param for C
Param for C
Return address to B
IRP Header
(Contains Status and Stack Pointer)
Param A
Param A
Callback for Initator
Param B
Param B
Callback for A
Param C
Param C
Callback for B
I/O Request Packets
Thread Stack Concept
IRP Stack Concept
Stack Frame
IO_STACK_LOCATION
Stack Pointer
IoGetCurrentIrpStackLocation
(and IoGetNextIrpStackLocation)
Subroutine call
IoCallDriver
Return from subroutine
IoCompleteRequest
Return Address/Callback
Completion routine
(IoSetCompletionRoutine)
Return Value
Irp->IoStatus.Status/Information
I/O Request Packets


Each IRP must be targeted at a specific
device stack
IRPs typically have just enough stack
locations to traverse the device stack

You must allocate a new IRP if you need to forward
the request to another stack
Device A
IRP Header
3
(Contains Status and Stack Pointer)
Device B
Device C
2
1
Param A
Param A
Callback for Initiator
Param B
Param B
Callback for A
Param C
Param C
Callback for B
I/O Request Packets
IRP Header
Thread
UserIoStatus
UserEvent
Stack Pointer
IoStatus
CancelRoutine
Major
Code
Minor
Code
Param
Param
Param
Param
Completion
Routine
Completion
Context
IRP_MJ_
IRP_MN_
…
…
…
…
func(…)
PVOID
IRP_MJ_CREATE
IRP_MJ_CLOSE
IRP_MJ_READ
DEVICE_OBJECT
DRIVER_OBJECT
Dispatch Table
IRP_MJ_WRITE
IRP_MJ_DEVICE_CONTROL
IRP_MJ_PNP
IRP_MJ_POWER
I/O Request Packets

What do I return from my dispatch
routine?
Caller on thread stack
status = IoCallDriver(...);

Callers completion routine
status = Irp->IoStatus.Status;
Return same value completion routine would
see, else return STATUS_PENDING
I/O Request Packets

Correct value returned from dispatch handler:
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
IoCompleteRequest( Irp, IO_NO_INCREMENT );
return STATUS_UNSUCCESSFUL;
Irp->IoStatus.Status = STATUS_SUCCESS;
IoSkipCurrentIrpStackLocation( Irp );
return IoCallDriver( deviceBeneathMe, Irp );

Incorrect value returned from dispatch handler:
Irp->IoStatus.Status = STATUS_SUCCESS;
IoSkipCurrentIrpStackLocation( Irp );
IoCallDriver( deviceBeneathMe, Irp );
return STATUS_SUCCESS;
// Be extra careful when changing status in completion routines!
The Two Types Of I/O

Buffered I/O



Driver writes into Irp->AssociatedIrp.SystemBuffer
OS queues an APC in the requesting process
context where it performs a copy
Direct I/O




Doesn’t require a copy
Memory pages are locked during the duration
of the operation
Pages are described by the IRPs Memory
Descriptor List (Irp->MdlAddress)
Driver use DMA functions or get a kernel address
via MmGetSystemAddressForMdlSafe(Irp->MdlAddress)
WDM Device Stacks

A WDM driver stack can
contain several different
kinds of device objects:




Functional Device Object
( “FDO” )
Physical Device Object
(“PDO”)
Filters
The stack and the OS data
associated with it is called
a “DevNode”
Upper Class Filters
Upper Device Filters
FDO
Functional Device Object
Lower Class Filters
Lower Device Filters
PDO
Physical Device Object
Device Node
(“DevNode”)
WDM Device Stacks

I/O IRPs are typically handled
by the FDO



PnP and Power IRPs traverse
the entire stack except if there
is an error


Create, Close, Read, Write, etc.
Drivers must fail any such IRP
explicitly if it’s not handled
Drivers do not modify these
IRPs if they do not implement
the request
WMI IRPs are targeted at
specific device objects in
the stack

Drivers do not modify
WMI IRPs if they do not
implement WMI
Upper Class Filters
Upper Device Filters
FDO
Functional Device Object
Lower Class Filters
Lower Device Filters
PDO
Physical Device Object
DevNode
WDM Device Stacks

A PDO is created by the
bus driver


Only the PDO has a name!


This is done in response to an
OS enumeration request
More on this later
FDO’s and Filters are created
in AddDevice routines



Drivers do not find their hardware,
rather their hardware finds them
Plug and Play passes the PDO
to AddDevice
Drivers attach new device objects
to the stack via
IoAttachDeviceToDeviceStack
Upper Class Filters
Upper Device Filters
FDO
Functional Device Object
Lower Class Filters
Lower Device Filters
PDO
Physical Device Object
DevNode
[Version]
Signature =
Provider
PNP Manager
IRP
Information
3
IRP_MN_QUERY_ID
4
Search INF Files
5
Call Class Installers
and Co-Installers
Upper Filters
FDO
USBFLOP.SYS
Registry
Lower Filters
PDO
USBHUB.SYS
6
IRP
Information
2
USB Floppy DevNode
FDO
USBHUB.SYS
PDO
USB Hub DevNode
Load drivers
IRP_MN_QUERY_DEVICE_RELATIONS
1
IoInvalidateDeviceRelations
Plug And Play

The Plug and Play Manager queries the stack
to get a list of all possible resource solutions:



The PDO responds to
IRP_MN_QUERY_RESOURCE_REQUIREMENTS
The FDO can adjust these requirements by
responding to
IRP_MN_FILTER_RESOURCE_REQUIREMENTS
The Plug and Play Manager sends the best
resource settings in IRP_MN_START_DEVICE


The card is configured to use the “Raw’ resource
set
The driver communicates with the card via the
“Translated” resource set
Plug And Play

FDO’s must respond to the following Plug and Play
events:

“Remove” events occur when a device is removed or disabled





“Stop” events occur when a device is to be paused for
resource rebalancing




IRP_MN_REMOVE_DEVICE
IRP_MN_SURPRISE_REMOVAL
IRP_MN_QUERY_REMOVE_DEVICE
IRP_MN_CANCEL_REMOVE_DEVICE
IRP_MN_QUERY_STOP_DEVICE
IRP_MN_STOP_DEVICE
IRP_MN_CANCEL_STOP_DEVICE
Other Plug and Play events FDO’s typically respond to:


IRP_MN_START_DEVICE (We hope)
IRP_MN_QUERY_CAPABILITIES
Plug And Play

PDO’s must respond to even more messages:

“Who” are you, “What” are you?



“Where are you, and where can you go today?”



IRP_MN_QUERY_RESOURCES
IRP_MN_QUERY_RESOURCE_REQUIREMENTS
Settings, capabilities, and location:



IRP_MN_QUERY_ID
IRP_MN_QUERY_DEVICE_TEXT
IRP_MN_QUERY_CAPABILITIES
IRP_MN_QUERY_BUS_INFORMATION
Misc.

IRP_MN_QUERY_DEVICE_RELATIONS (TargetRelations)
“Finding” Plug And Play
Devices

Applications often need a list of devices to manipulate
or display to the user



Using “well known names” (i.e., LptX) doesn’t
work well in a Plug and Play environment
Applications often need a list of devices that share a
given property, and properties can be hierarchical


Printers, Scanners, etc
(E.g., all storage devices, just CDROMs, just Zip drives, etc.)
WDM drivers expose one or more “Interfaces”,
identified via GUID

Note: Only started devices can expose interfaces
Interfaces



Drivers register support for a given Interface
by calling IoRegisterDeviceInterface
Drivers dynamically enable and disable an
interface via IoSetDeviceInterfaceState
IoSetDeviceInterfaceState creates a symbolic
link so that user mode applications can
communicate with the device


More on this later
Applications enumerate devices by passing an
interface GUID to various SetupApi functions
Kernel mode security




User mode can attempt to open
a device with Read, Write, and
Execute privileges
By default, all users get full
access to a WDM device stack
Security checks are done at
Create/Open time
Access to a device can be
restricted via INF

Search DDK for “INF AddReg”,
or stay tuned…
Upper Class Filters
Upper Device Filters
FDO
Functional Device Object
Lower Class Filters
Lower Device Filters
PDO
Physical Device Object
Kernel Mode Security
[MyDevice.NTx86]
CopyFiles = ...
[MyDevice.NTx86.Services]
AddService = ...
[MyDevice.NTx86.HW]
AddReg = MyDevice.Security
[MyDevice.Security]
HKR,,DeviceCharacteristics,0x10001,0x100
HKR,,Security,,”security-descriptor-string”
"D:P( ;;
A: Allow
D: Deny
;;;
GA: All
GR: Read
GW: Write
) (...)"
SY: System
LA: Local Administrator
PU: Power user
WD: World
"D:P(A;;GA;;;SY)"
Allow All
System
(Example: System only access)
Security Attacks


Security constraints are applied
to named device objects
In a WDM stack, only the PDO
should be named



If another device is named, it might
compromise system security
A device doesn’t have to expose
a symbolic link to be opened!
Be sure to pass in
FILE_DEVICE_SECURE_OPEN
when creating PDO’s
Upper Class Filters
Upper Device Filters
FDO
Functional Device Object
Lower Class Filters
Lower Device Filters
PDO
Physical Device Object
IOCTL Security
31
15
Device Number


Access
2
Function
Method
Drivers encode the security requirements of
Device IOCTLs in the 32bit code itself
The Access mask can specify one of four
different privilege levels:





13
Openable
Opened with read access
Opened with write access
Opened with both read and write access
The IO Manager prevents applications from
forming IOCTL codes their privileges don’t allow
Security Attacks
31
15
Device Number


Function
Method
Masking out the Access bits lets lower privileged
Ioctl’s succeed
Do not use the IoGetFunctionCodeFromCtlCode macro
Drivers should always check the buffer size of
incoming Ioctl’s


Access
2
Drivers should always check the full 32bit Ioctl code!


13
Malicious applications can attempt to crash the system via
malformed requests
Do not implement IOCTLs that allow an application to
read or write any piece of virtual or physical memory


Don’t ship with debugging IOCTLs enabled
Don’t pass back “pointers” as handles
Power Management

To implement power management,
a driver needs code to:





Save and restore the state of its hardware
Disable and enable the device
Queue incoming requests
Convert System states to Device states
A driver must not touch it’s hardware
while it’s device is off

Memory and I/O typically return
0xFFFFFFFF when off, fooling badly
written ISR’s
System States

S0: Working


S1: Standby


Typically only memory remains powered
S4: Hibernation


Greater power conservation, recovery time more
than two seconds
S3: Standby


Processor and bus clocks are off, recovery time typically
two seconds
S2: Standby


Machine is fully powered and responsive
Machine is off, memory is written to persistent storage
S5: Off
Device States

D0


D1




Less power consumption than D0
Transition to fully powered happens quickly
Driver cannot access device until powered up
D2




Hardware is fully powered
Less power consumption than D1
Longer power-up time than D1
Driver cannot access device until powered up
D3: Off

Device is completely off (inaccessable)
Converting S IRPs To D
IRPs
The WDM Power Manager sends S IRPs:




Each device stack has a “Power Policy Owner” who
converts S IRPs to D IRPs






IRP_MN_QUERY_POWER
IRP_MN_SET_POWER
The Power Policy Owner is typically the FDO
The mapping comes from the S  D array stored in the
IRP_MN_QUERY_CAPABILITIES structure
Each entry calls out the lightest possible D state for
a given S state
Mappings can be rounded down (deeper)
The Power Policy Owner then uses
PoRequestPowerIrp to request the appropriate D IRP
The conversion code is complicated, but most drivers
can use the boilerplate code in the WDM DDK
System State S0 –
Working
PCI Bus
S0  D0
Modem
D3
D2
D1
D0
HDD
D0
CDROM
D3
D2
D1
D3
D2
D1
D0
D3
D2
D1
D0
C0
PCI.SYS
ACPI.SYS
IDE Controller
S0  D0
IDE Channel
S0  D0
HDD
S0  D0
PCIIDE.SYS
SCSI Card
S0  D0
SCSIPORT.SYS
Net Card
S0  D0
NDIS.SYS
ACPI.SYS
ACPI.SYS
ACPI.SYS
PCI.SYS
PCI.SYS
PCI.SYS
ATAPI.SYS
PCIIDE.SYS
DISK.SYS
ATAPI.SYS
CDROM
S0  D0
Net Card
CDROM.SYS
SCSIPORT.SYS
S0  D0
System State S1 –
Standby
PCI Bus
S1  D1
Modem
D3
D2
D1
D0
HDD
D0
CDROM
D3
D2
D1
D3
D2
D1
D0
D3
D2
D1
D0
C0
PCI.SYS
ACPI.SYS
IDE Controller
S1  D1
IDE Channel
S1  D1
HDD
S1  D1
PCIIDE.SYS
SCSI Card
S1  D3
SCSIPORT.SYS
Net Card
S1  D3
NDIS.SYS
ACPI.SYS
ACPI.SYS
ACPI.SYS
PCI.SYS
PCI.SYS
PCI.SYS
ATAPI.SYS
PCIIDE.SYS
DISK.SYS
ATAPI.SYS
CDROM
S1  D3
Net Card
CDROM.SYS
SCSIPORT.SYS
S1  D?
System State S3 –
Standby
PCI Bus
S3  D3
Modem
D3
D2
D1
D0
HDD
D0
CDROM
D3
D2
D1
D3
D2
D1
D0
D3
D2
D1
D0
C0
PCI.SYS
ACPI.SYS
IDE Controller
S3  D3
IDE Channel
S3  D3
HDD
S3  D3
PCIIDE.SYS
SCSI Card
S3  D3
SCSIPORT.SYS
Net Card
S3  D3
NDIS.SYS
ACPI.SYS
ACPI.SYS
ACPI.SYS
PCI.SYS
PCI.SYS
PCI.SYS
ATAPI.SYS
PCIIDE.SYS
DISK.SYS
ATAPI.SYS
CDROM
S3  D3
Net Card
CDROM.SYS
SCSIPORT.SYS
S3  D?
System State S4 –
Hibernate
PCI Bus
S4  D3
Modem
D3
D2
D1
D0
HDD
D0
CDROM
D3
D2
D1
D3
D2
D1
D0
D3
D2
D1
D0
C0
PCI.SYS
ACPI.SYS
IDE Controller
S4  D3
IDE Channel
S4  D3
HDD
S4  D3
PCIIDE.SYS
SCSI Card
S4  D3
SCSIPORT.SYS
Net Card
S4  D3
NDIS.SYS
ACPI.SYS
ACPI.SYS
ACPI.SYS
PCI.SYS
PCI.SYS
PCI.SYS
ATAPI.SYS
PCIIDE.SYS
DISK.SYS
ATAPI.SYS
CDROM
S4  D3
Net Card
CDROM.SYS
SCSIPORT.SYS
S4  D3
System State S5 –
Off
PCI Bus
S5  D3
Modem
D3
D2
D1
D0
HDD
D0
CDROM
D3
D2
D1
D3
D2
D1
D0
D3
D2
D1
D0
C0
PCI.SYS
ACPI.SYS
IDE Controller
S5  D3
IDE Channel
S5  D3
HDD
S5  D3
PCIIDE.SYS
SCSI Card
S5  D3
SCSIPORT.SYS
Net Card
S5  D3
NDIS.SYS
ACPI.SYS
ACPI.SYS
ACPI.SYS
PCI.SYS
PCI.SYS
PCI.SYS
ATAPI.SYS
PCIIDE.SYS
DISK.SYS
ATAPI.SYS
CDROM
S5  D3
Net Card
CDROM.SYS
SCSIPORT.SYS
S5  D3
Converting S IRPs To D
IRPs
( Simplified from Toaster Sample in the WDM DDK )
NTSTATUS
ToasterDispatchPower( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
PIO_STACK_LOCATION stackLocation;
//
// Not shown: Are we deleted? If so, fail IRP.
// Not shown: Are we started? If not, pass on IRP untouched.
//
stackLocation = IoGetCurrentIrpStackLocation( Irp );
switch(stackLocation->MinorFunction) {
case IRP_MN_QUERY_POWER:
return ToasterQueryPowerState( DeviceObject, Irp );
case IRP_MN_SET_POWER:
return ToasterSetPowerState( DeviceObject, Irp );
default:
// Not shown: default logic
}
}
Converting S IRPs To D
IRPs
NTSTATUS
ToasterQueryPowerState( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp )
{
PIO_STACK_LOCATION stackLocation;
if (stackLocation->Parameters.Power.Type == SystemPowerState) {
S  D routine
return HandleSystemPowerIrp( DeviceObject, Irp );
}
return HandleDeviceQueryPower( DeviceObject, Irp );
}
Converting S IRPs To D
IRPs
NTSTATUS
ToasterSetPowerState( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp )
{
PIO_STACK_LOCATION stackLocation;
if (stackLocation->Parameters.Power.Type == SystemPowerState) {
S  D routine
return HandleSystemPowerIrp( DeviceObject, Irp );
}
return HandleDeviceSetPower( DeviceObject, Irp );
}
Converting S IRPs To D
IRPs
NTSTATUS
HandleSystemPowerIrp( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp )
{
//
// Forward IRP *asynchronously*, catch it on way up
//
IoMarkIrpPending( Irp );
IoCopyCurrentIrpStackLocationToNext( Irp );
IoSetCompletionRoutine( Irp,
(PIO_COMPLETION_ROUTINE) OnFinishSystemPowerUp,
NULL, TRUE, TRUE, TRUE);
PoCallDriver( fdoData->NextLowerDriver, Irp );
return STATUS_PENDING;
}
PPO
Converting S IRPs To D
IRPs
NTSTATUS
OnFinishSystemPowerUp(
IN PDEVICE_OBJECT
Fdo,
IN PIRP
Irp,
IN PVOID
NotUsed
)
{
NTSTATUS status = Irp->IoStatus.Status;
if (!NT_SUCCESS(status)) {
PoStartNextPowerIrp(Irp);
return STATUS_SUCCESS;
}
PPO
QueueCorrespondingDeviceIrp( Irp, Fdo );
return STATUS_MORE_PROCESSING_REQUIRED;
}
Converting S IRPs To D
IRPs
VOID
QueueCorrespondingDeviceIrp( IN PIRP SIrp, IN PDEVICE_OBJECT DeviceObject )
{
POWER_STATE
dState;
PFDO_DATA
fdoData = (PFDO_DATA) DeviceObject->DeviceExtension;
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(SIrp);
SYSTEM_POWER_STATE sState = stack->Power.State.SystemState;
if ((sState == PowerSystemWorking) || (fdoData->ArmedForWake)) {
dState.DeviceState = fdoData->DeviceCaps.DeviceState[sState];
} else {
dState.DeviceState = PowerDeviceD3;
}
status = PoRequestPowerIrp(
fdoData->UnderlyingPDO,
stack->MinorFunction,
dState, OnPowerRequestComplete,
SIrp, NULL);
}
// Not shown: Handle case where PoRequestPowerIrp fails
}
PPO
Converting S IRPs To D
IRPs
VOID
OnPowerRequestComplete(
IN PDEVICE_OBJECT
IN UCHAR
IN POWER_STATE
IN PVOID
DeviceObject,
MinorFunction,
State,
PowerContext,
IN PIO_STATUS_BLOCK IoStatus
)
{
PIRP sIrp = (PIRP) PowerContext;
//
// Copy status from D IRP to S IRP
//
sIrp->IoStatus.Status = IoStatus->Status;
PoStartNextPowerIrp( sIrp );
IoCompleteRequest( sIrp, IO_NO_INCREMENT );
}
PPO
Converting S IRPs To D
IRPs
VOID
OnPowerRequestComplete(
IN PDEVICE_OBJECT
DeviceObject,
IN UCHAR
MinorFunction,
IN POWER_STATE
State,
IN PVOID
PowerContext,
IN PIO_STATUS_BLOCK IoStatus
)
{
PIRP sIrp = (PIRP) PowerContext;
//
// Copy status from D IRP to S IRP
//
sIrp->IoStatus.Status = IoStatus->Status;
PoStartNextPowerIrp( sIrp );
IoCompleteRequest( sIrp, IO_NO_INCREMENT );
}
PPO
Power Management
Gotcha’s





Drivers cannot block a thread and wait for a
power IRP to complete on Windows 2000
S  D state mapping for non-power manageable
PCI devices may contain invalid D states on
Windows 2000
Drivers cannot safely complete power IRPs at
DISPATCH_LEVEL on Windows 9x
Drivers cannot safely do “idle time” power
management on Windows 9x
PCI supports two types of D3 which WDM
doesn’t distinguish
WDM And Hardware – DSP
Bad design:
1.
2.
3.
4.
OS loads DSP driver
against “DSP device”
Driver uploads software
into volatile DSP RAM
“DSP device”
disappears from bus
New device appears in
it’s place
Problem: What happens
when the device is
turned off?
Correct design:
1.
2.
3.
4.
OS loads DSP bus driver
against “DSP device”
DSP bus driver uploads
DSP software into
volatile DSP RAM
Bus driver exposes new
functionality by creating
a child device
Bus driver reprograms
DSP when appropriate