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