Académique Documents
Professionnel Documents
Culture Documents
Dispositivos
Ingeniería en Sistemas Computacionales
Device Hardware
Device Driver
Driver Software
Windows Operating
System
Drivers Modes
run in the non privileged processor
mode
User Mode
Understanding Driver and
Operating System Basics
Overview of System Components for Driver Writers
Windows Component
Overview
◦ The figure shows, the operating
system includes kernel-mode
components and user-mode
components.
◦ User-mode drivers and applications
can use the routines defined in the
Microsoft Win32 application
programming interface (API. The
Win32 API, in turn, calls exported
driver and operating system
kernel routines.
◦ Kernel-mode drivers can use support
routines that are defined and
exported by various components
of the operating system kernel.
These routines support I/O,
configuration, Plug and Play,
power management, memory
management, and numerous other
operating system features.
Understanding Driver and
Operating System Basics
◦ User-Mode Drivers and Kernel-Mode
Drivers
Windows drivers can run in either user mode
or kernel mode.
User-mode drivers run in the non
privileged processor mode
User-mode drivers cannot gain access to
system data except by calling the Win32
API which, in turn, calls system services.
Kernel-mode drivers run as part of the
operating system's executive.
User-mode and kernel-mode drivers have
different structures, different entry points,
Understanding Driver and
Operating System Basics
◦ Windows Driver Model (WDM)
Defined
Any kernel-mode device driver that
conforms to the Windows Driver Model
(WDM) is called a WDM driver.
WDM defines an approach to writing
kernel-mode device drivers for all
Windows operating systems.
Any device driver that will run on
Windows 2000 and later operating
systems must be a WDM driver.
With a few special-case statements in the
code, WDM drivers can be source-
Understanding Driver and
Operating System Basics
◦ Layered Driver
Architecture
Windows operating
systems support a
layered driver
architecture. Every
device is serviced by a
chain of drivers,
typically called a
driver stack. Each
driver in the stack
isolates some
hardware-dependent
features from the
drivers above it.
The following figure
Understanding Driver and
Operating System Basics
◦ Layered Driver
Architecture
◦ Above the driver stack is an application. The
application handles requests from users and
other applications, and calls either the Win32
API or a routine that is exposed by the user-
mode client driver.
◦ A user-mode client driver handles requests from
applications or from the Win32 API. For
requests that require kernel-mode services, the
user-mode client driver calls the Win32 API,
which calls the appropriate kernel-mode client
or support routine to carry out the request.
Understanding Driver and
Operating System Basics
◦ Layered Driver
Architecture
◦ A kernel-mode client driver handles
requests similar to those handled
by the user-mode client, except
that these requests are carried
out in kernel mode, rather than in
user mode.
◦ A device class and miniclass driver
pair provides the bulk of the
device-specific support.
Making Driver Design Decisions
After you determine what kind of driver
your device requires, you can begin
designing your driver. The following
topics describe several design issues
that you should consider:
Choosing a Driver Model
Choosing a Programming Language
Driver Design and Implementation Strategies
Creating Reliable and Secure Drivers
Using the WDK Samples
Upgrading a Legacy Driver
Writing Drivers for Multiple Platforms and Operating
Planning for 64 Bits
Providing Driver Localization
Making Driver Design Decisions
◦ Choosing a Driver Model
Most Windows drivers are kernel-mode
drivers .
Drivers use a set of interfaces that enable
the driver to communicate with kernel-
mode Windows components, such as the
I/O manager and the Plug and Play (PnP)
manager.
Making Driver Design
Decisions
◦ Choosing a Programming
Language
For maximum portability, drivers should
be written in a high-level language,
typically C for kernel-mode drivers,
and C or C++ for user-mode drivers.
Making Driver Design
Decisions
◦ Creating Reliable and Secure
Drivers
Validate input parameters.
Validate registry
contents.
Use safe string functions.
Provide secure device
installations.
Making Driver Design
Decisions
◦ Using the DDK Samples
The Windows DDK includes sample source code for a variety
of drivers. The samples can be useful guides for writing
your own drivers. When you install the DDK, samples are
installed in subdirectories of the \src directory.
If you choose to base your code on one or more of the
samples, keep in mind the following:
Some samples are not complete drivers, but
instead provide guidelines for how such drivers
could be written. For instance, samples might
omit error-handling code in the interest of
brevity and clarity.
Make sure to use a driver sample that was written
for the type of driver that you are writing. For
example, if you are writing a function driver, use
a sample function driver. If you are writing a
storage filter driver, use a sample storage filter
driver.
Making Driver Design
Decisions
◦ Upgrading a Legacy Driver
Although Microsoft Windows 2000 and
later versions of the operating system
continue to support some legacy drivers
written for Windows NT, new drivers
should be WDM drivers.
The system-supplied device drivers have
been modified to support WDM, which
includes Plug and Play and power
management.
Making Driver Design
Decisions
◦ Upgrading a Legacy Driver
If you choose to try to upgrade a
driver, your driver will require the
following types of changes:
Updating or replacing the driver
INF file.
support for Plug and
Supporting power management
Making Driver Design
Decisions
◦ Planning for 64 Bits
Whether you are writing a new driver or
modifying an existing driver, you should
consider making it compatible with 64-bit
Windows. The Windows Driver Kit (WDK)
includes 64-bit build environments that
you can use to create 64-bit drivers.
Many of the driver samples included with
the WDK are designed for 64-bit
compatibility, as noted in the Readme
files for the individual samples.
Building, Debugging, and
Testing Drivers
System
Windows Architecture
System Processes Services Applications Environment
Subsystems
Service
Control Mgr .
Windows
LSASS SvcHost . Exe Task Manager
WinMgt . Exe Explorer
WinLogon
SpoolSv . Exe User OS / 2
User Application
Mode Services . Exe
Session POSIX
Manager
Subsystem DLLs Windows DLLs
Kernel
Mode System Service Dispatcher
Configura -
( registry )
Reference
Processes
Procedure
Play Mgr .
Plug and
Security
tion Mgr
Monitor
Virtual
Threads
Object
Memory
System
Power
Local
Cache
File
Call
Mgr .
Mgr .
Device &
&
File Sys . Graphics
Drivers
Drivers
Kernel
Security
Subsystem
POSIX
Subsystem
OS/2
Subsystem
Win 32
Subsystem
Kernel Level
N’work Drv.s
Device Drv.s
Microkernel (NT Kernel)
MACHINE HARDWARE
Executive
The executive is the main part of the kernel layer and
performs most of the traditional operating system
functions.
It is made up of a group of components, the main ones
being:
◦ The I/O Manager,
◦ Object Manager,
◦ Security Reference Monitor,
◦ Process Manager,
◦ Local Procedure Call Facility and the
◦ Virtual Memory Manager.
◦
The Object Manager
The Object Manager is used to define and manage objects
which represent resources within the computer system.
An example is where the Process Manager uses the object
manager to define an object which tracks all the
processes which are running.
Part of the object management duties include identifying
the objects corresponding to resources and tracking how
many systems are accessing a resource.
When no system is accessing a resource then the object
representing the resource can be deleted.
As most of the native system services are resource related
they almost always invoke the object manager functions.
The object manager can also call other executive
subsystems when necessary.
Object Manager
The Windows kernel-mode object manager component manages objects.
Files, devices, synchronization mechanisms, registry keys, and so on, are
all represented as objects in kernel mode. Each object has a header
(containing information about the object such as its name, type, and
location), and a body (containing data in a format determined by each
type of object).
Windows has more than 25 types of objects. A few of the types are:
◦ Files
◦ Devices
◦ Threads
◦ Processes
◦ Events
◦ Mutexes
◦ Semaphores
◦ Registry keys
◦ Jobs
◦ Sections
◦ Access tokens
◦ Symbolic links
The Process Manager
The Process Manager works with the kernel, which carries
out scheduling, to define the process and thread objects.
It adds the process identifier (PID) to each of the kernel's
process objects.
The Security Reference Monitor
The Security Reference Monitor (SRM) is closely associated
with the object manager and is responsible for the strong
security capabilities in Windows NT.
The object manager calls the SRM to provide a security
check whenever an application wishes to open an object
or perform an operation on an object like a read or write.
The SRM uses the NT security procedures to validate
whether the operation can go ahead and whether it
should be logged.
The SRM uses a security model based on Security
Identifiers (SID) and Discretionary Access Control Lists
(DACL).
Security Reference Monitor
An increasingly important aspect of operating systems
is security.
Before an action can take place, the operating system
must be sure that the action is not a violation of
system policy.
For example, a device may or may not be accessible
to all requests.
When creating a driver, you may want to allow some
requests to succeed or fail, depending on the
permission of the entity making the request.
Windows uses an access control list (ACL) to
determine which objects have what security.
The Windows kernel-mode security reference monitor
provides routines for your driver to work with access
control.
The Virtual Memory Manager
The Virtual Memory Manager creates and manages memory
maps for processes and controls physical memory allocation.
NT can address up to 4GB of memory and this is split between
user and kernel mode memory with the first 2GB going to
user mode applications.
The memory is managed in pages of 4kB in Intel x86 systems,
different page sizes are used in other systems.
The VMM allows the total memory required by an application to
exceed the memory available in the computer.
This is done by using physical memory such as the hard disk,
and memory from a paging file when it is required by an
application.
The VMM allows programs to share individual files and data.
When any one then wishes to write to the shared data it gets
its own individual copy.
The VMM also tunes the memory available to programs by
allocating extra memory where it is needed and ensuring all
Memory Manager
The Windows kernel-mode memory manager
component manages physical memory for the
operating system.
This memory is primarily in the form of RAM
(Random Access Memory).
The memory manager manages memory by
performing the following major tasks:
◦ Managing the allocation and de-allocation of
memory virtually and dynamically.
◦ Supporting the concepts of memory-mapped
files, shared memory, and copy-on-write.
The I/O Manager
The I/O Manager integrates all the add-on devices with NT.
Drivers are dynamically loaded components designed to
provide hardware and network support.
They are designed to run within the kernel and use the extra
functionality that this can provide.
The drivers are usually supplied by the manufacturer of the
hardware and control the specific item by translating
commands from NT and applications to the device and then
manipulating the device to carry them out.
NT uses asynchronous, packet based I/O for hardware
communication. Interrupt Request Packets (IRP) are used to
describes everything the device driver needs to know to
handle an applications requests.
It includes the location of the buffer to read to, a pointer to the
open file object, offsets to where the data resides and the
amount of data the program has to read.
I/O Manager
A computer consists of various devices that provide input and output (I/O)
to and from the outside world.
Typical devices are keyboards, mice, audio controllers, video controllers,
disk drives, networking ports, and so on.
Device drivers provide the software connection between the devices and
the operating system.
For this reason, I/O is very important to the device driver writer.
The Windows kernel-mode I/O manager manages the communication
between applications and the interfaces provided by device drivers.
Because devices operate at speeds that may not match the operating
system, the communication between the operating system and device
drivers is primarily done through I/O request packets (IRPs).
These packets are similar to network packets or Windows message
packets.
They are passed from operating system to specific drivers and from one
driver to another.
The Windows I/O system provides a layered driver model called stacks.
Typically IRPs go from one driver to another in the same stack to facilitate
communication.
For example, a joystick driver would need to communicate to a USB hub,
which in turn would need to communicate to a USB host controller,
The Local Procedure Call
Facility
The Local Procedure Call Facility optimises communications
for applications, including the operating system
environments.
Communication between functions and objects in the
operating system is done via messages which are passed
in different ways depending on their size.
Small messages of less than 256 bytes are copied directly
while larger ones are transferred using shared memory.
This code has been highly optimised to ensure efficiency as
a slow call method would badly affect performance.
From NT 3.51 to NT 4.0 Microsoft moved the GDI (graphics
device interface) out of the user mode and into the kernel
to reduce to number of calls using the LPC.
This led to much improved responsiveness, especially for
graphics operations but at the cost of some stability.
The Kernel
The kernel contains the NT thread scheduler called the
dispatcher.
The dispatcher is a pre-emptive scheduler, time is divided
into slices called quantums and each thread can operate
for a quantum and then is pre-empted to allow another
thread to run.
The kernel operates more closely with hardware than the
executive, and hence contains processor specific code.
If the computer has multiple CPUs the kernel synchronises
activity between them to optimise performance.
Kernel code does not run in threads
The kernel also implements synchronisation and mutual
exclusion.
It has it's own object types so applications can access them
from user mode via the native API.
Kernel Library
Modern operating systems use the term kernel to
describe the core functionality that everything
else in the system depends upon.
The Microsoft Windows kernel provides basic low-
level operations such as scheduling threads or
routing hardware interrupts.
It is the heart of the operating system and all
tasks it performs must be fast and simple.
Routines that provide a direct interface to the
kernel library are usually prefixed with "Ke", for
example, KeGetCurrentThread.
Hardware Abstraction Layer
The HAL provides NT's interface to the CPU.
To make NT portable as much of the processor specific code
as possible was restricted to here.
So the HAL together with the kernel are dynamically
replaceable between processors families.
The HAL exports a common processor model which hides
the differences in processor types. This common
processor used by device drivers.
Processes and Threads
NT is a multithreading operating system.
It runs multiple threads at once and can stop any particular thread
from executing.
Clfs –Common Log File System (CLFS) Library Routines that allow access to
the CLFS library
Cc – Cache Manager
Routines that allow access to the Cache Manager
Cm – Configuration Manager
Routines that allow access to the Configuration Manager
Windows Kernel Prefixes
Ex – Executive Library
Routines that allow access to the system Executive library. This
library provides general policy
decisions not covered by other kernel-mode managers or
libraries.
Io – I/O Manager
Routines that allow access to the I/O Manager
Po – Power Manager
Routines that allow access to the Power Manager
MmAllocateContiguousMemory
MmAllocateContiguousMemorySpecifyCache
MmAllocateContiguousMemorySpecifyCacheNode
MmAllocateMappingAddress
MmAllocateNonCachedMemory
MmAllocatePagesForMdl
MmAllocatePagesForMdlEx
MmBadPointer
MmBuildMdlForNonPagedPool
MmCreateMdl
MmFreeContiguousMemory
MmFreeContiguousMemorySpecifyCache
MmFreeMappingAddress
MmFreeNonCachedMemory
MmFreePagesFromMdl
MmGetMdlByteCount
Object Memory Routines
MmLockPagableCodeSection
MmLockPagableDataSection
MmLockPagableSectionByHandle
MmMapIoSpace
MmMapLockedPages
MmMapLockedPagesSpecifyCache
MmMapLockedPagesWithReservedMapping
MmPageEntireDriver
MmPrepareMdlForReuse
MmProbeAndLockPages
MmProtectMdlSystemAddress
MmQuerySystemSize
MmResetDriverPaging
MmSecureVirtualMemory
MmSizeOfMdl
MmUnlockPagableImageSection
MmUnlockPages
MmUnmapIoSpace
MmUnmapLockedPages
MmUnmapReservedMapping
MmUnsecureVirtualMemory
Mm64BitPhysicalAddress
ADDRESS_AND_SIZE_TO_SPAN_PAGES
ARGUMENT_PRESENT
BYTE_OFFSET
Process and Thread Manager Routines
PsCreateSystemThread
PsGetCurrentProcess
PsGetCurrentProcessId
PsGetCurrentThread
PsGetCurrentThreadId
PsGetProcessCreateTimeQuadPart
PsGetProcessId
PsGetVersion
PsInitialSystemProcess
PsIsSystemThread
PsRemoveCreateThreadNotifyRoutine
PsRemoveLoadImageNotifyRoutine
PsSetCreateProcessNotifyRoutine
PsSetCreateProcessNotifyRoutineEx
PsSetCreateThreadNotifyRoutine
PsSetLoadImageNotifyRoutine
PsTerminateSystemThread
I/O Manager Routines
IoAcquireCancelSpinLock
IoAcquireRemoveLock
IoAcquireRemoveLockEx
IoAdjustPagingPathCount
IoAllocateAdapterChannel
IoAllocateController
IoAllocateDriverObjectExtension
IoAllocateErrorLogEntry
IoAllocateIrp
IoAllocateMdl
IoAllocateWorkItem
IoAssignArcName
IoAssignResources
IoAttachDevice
IoAttachDeviceByPointer
IoAttachDeviceToDeviceStack
IoBuildAsynchronousFsdRequest
IoBuildDeviceIoControlRequest
IoBuildPartialMdl
IoBuildSynchronousFsdRequest
IoCallDriver
IoCancelIrp
IoCheckShareAccess
IoCompleteRequest
IoConnectInterrupt
IoConnectInterruptEx
IoCopyCurrentIrpStackLocationToNext
IoCreateController
IoCreateDevice
I/O Manager Routines
IoCreateDeviceSecure
IoCreateFile
IoCreateNotificationEvent
IoCreateSymbolicLink
IoCreateSynchronizationEvent
IoCreateUnprotectedSymbolicLink
IoCsqInitialize
IoCsqInitializeEx
IoCsqInsertIrp
IoCsqInsertIrpEx
IoCsqRemoveIrp
IoCsqRemoveNextIrp
IoDeassignArcName
IoDeleteController
IoDeleteDevice
IoDeleteSymbolicLink
IoDetachDevice
I/O Manager Routines
IoFreeWorkItem
IoGetAffinityInterrupt
IoGetAttachedDeviceReference
IoGetBootDiskInformation
IoGetConfigurationInformation
IoGetContainerInformation
IoGetCurrentIrpStackLocation
IoGetCurrentProcess
IoGetDeviceInterfaceAlias
IoGetDeviceInterfaces
IoGetDeviceNumaNode
IoGetDeviceObjectPointer
IoGetDeviceProperty
IoGetDevicePropertyData
IoGetDeviceToVerify
IoGetDmaAdapter
IoGetDriverObjectExtension
I/O Manager Routines
IoInitializeRemoveLock
IoInitializeRemoveLockEx
IoInitializeTimer
IoInitializeWorkItem
IoInvalidateDeviceRelations
IoInvalidateDeviceState
IoIs32bitProcess
IoIsErrorUserInduced
IoIsWdmVersionAvailable
IoMakeAssociatedIrp
IoMapTransfer
IoMarkIrpPending
IoOpenDeviceInterfaceRegistryKey
IoOpenDeviceRegistryKey
IoQueryDeviceDescription
IoQueueWorkItem
IoQueueWorkItemEx
I/O Manager Routines
IoReleaseRemoveLockAndWait
IoReleaseRemoveLockAndWaitEx
IoReleaseRemoveLockEx
IoRemoveShareAccess
IoReportDetectedDevice
IoReportResourceForDetection
IoReportResourceUsage
IoReportTargetDeviceChange
IoReportTargetDeviceChangeAsynchronous
IoRequestDeviceEject
IoRequestDpc
IoReuseIrp
IoSetCancelRoutine
IoSetCompletionRoutine
IoSetCompletionRoutineEx
IoSetDeviceInterfaceState
IoSetDevicePropertyData
I/O Manager Routines
IoStartTimer
IoStopTimer
IoUnregisterContainerNotification
IoUninitializeWorkItem
IoUnregisterPlugPlayNotification
IoUnregisterPlugPlayNotificationEx
IoUnregisterShutdownNotification
IoUpdateShareAccess
IoValidateDeviceIoControlAccess
IoVerifyPartitionTable
IoVolumeDeviceToDosName
IoWithinStackLimits
IoWMIAllocateInstanceIds
IoWMIDeviceObjectToProviderId
IoWMIDeviceObjectToInstanceName
IoWMIExecuteMethod
IoWMIHandleToInstanceName
Power Manager Routines
PoCallDriver
PoClearPowerRequest
PoCreatePowerRequest
PoDeletePowerRequest
PoEndDeviceBusy
PoGetSystemWake
PoQueryWatchdogTime
PoRegisterDeviceForIdleDetection
PoRegisterPowerSettingCallback
PoRegisterSystemState
PoRequestPowerIrp
PoSetDeviceBusy
PoSetDeviceBusyEx
PoSetPowerRequest
PoSetPowerState
PoSetSystemState
PoSetSystemWake
PoStartDeviceBusy
PoStartNextPowerIrp
PoUnregisterPowerSettingCallback
PoUnregisterSystemState
Configuration Manager Routines
CmCallbackGetKeyObjectID
CmGetBoundTransaction
CmGetCallbackVersion
CmRegisterCallback
CmRegisterCallbackEx
CmSetCallbackObjectContext
CmUnRegisterCallback
Kernel Transaction Manager (KTM) Routines
Transaction Manager Object
Routines
Transaction Object Routines
Enlistment Object Routines
Resource Manager Object
Routines
KTM Structures
KTM Enumerations
Security Reference Monitor Routines
SeAccessCheck
SeAssignSecurity
SeAssignSecurityEx
SeDeassignSecurity
SeSinglePrivilegeCheck
SeValidSecurityDescriptor
Core Kernel Library Support Routines
KeAcquireSpinLockRaiseToSynch
KeBreakinBreakpoint
KeEnterKernelDebugger
KeFlushWriteBuffer
KeGetBugMessageText
KeRaiseIrqlToSynchLevel
KeRemoveByKeyDeviceQueueIfBusy
KeSetTimeUpdateNotifyRoutine
Executive Library Support Routines
ExAcquireFastMutex
ExAcquireFastMutexUnsafe
ExAcquireResourceExclusive
ExAcquireResourceExclusiveLite
ExAcquireResourceShared
ExAcquireResourceSharedLite
ExAcquireSharedStarveExclusive
ExAcquireSharedWaitForExclusive
ExAllocateFromLookasideListEx
ExAllocateFromNPagedLookasideList
ExAllocateFromPagedLookasideList
ExAllocateFromZone
ExAllocatePool
ExAllocatePoolWithQuota
Windows Kernel-Mode Run-Time Library
Windows provides a set of common utility
routines needed by various kernel-mode
components.
For example, RtlCheckRegistryKey is used to
see if a given key is in the registry.
Most of the run-time library (RTL) routines are
prefixed with the letters "Rtl";
Run-Time Library (RTL) Routines
FirstEntrySList
InitializeListHead
InsertHeadList
InsertTailList
IsListEmpty
PopEntryList
PushEntryList
RemoveEntryList
RemoveHeadList
RemoveTailList
RtlAnsiCharToUnicodeChar
RtlAnsiStringToUnicodeSize
RtlAnsiStringToUnicodeString
RtlAppendUnicodeStringToString
RtlAppendUnicodeToString
Windows Kernel-Mode Safe String Library
One of the major problems in software security is
related to the vulnerability of working with
strings.
To provide greater security, Windows provides a
safe string library.
Safe string library routines are prefixed with the
letters "Rtl"; for a list of all safe string library
routines for the kernel,
Safe String Library Routines
Safe String Functions for Unicode and ANSI
Characters
Safe String Functions for UNICODE_STRING
Structures
Windows Kernel-Mode DMA Library
To enhance performance, a device may need
direct access to memory in a way that bypasses
the central processing unit (CPU).
This technology is called direct memory access
(DMA). Windows provides a DMA library for
device driver developers.
DMA Library Routines
AllocateAdapterChannel
AllocateCommonBuffer
BuildMdlFromScatterGatherList
BuildScatterGatherList
CalculateScatterGatherList
FlushAdapterBuffers
FreeAdapterChannel
FreeCommonBuffer
FreeMapRegisters
GetDmaAlignment
GetScatterGatherList
MapTransfer
PutDmaAdapter
PutScatterGatherList
ReadDmaCounter
Windows Kernel-Mode HAL Library
Windows runs on many different configurations of
the personal computer.
Each configuration requires a layer of software
that interacts between the hardware and the
rest of the operating system.
Because this layer abstracts (hides) the low-level
hardware details from drivers and the operating
system, it is called the hardware abstraction
layer (HAL).
Developers are not encouraged to write their own
HAL.
If you need hardware access, the HAL library
provides routines that can be used for that
purpose.
Routines that interface with the HAL directly are
HAL Library Routines
HalAllocateCommonBuffer
HalAllocateHardwareCounters
HalAssignSlotResources
HalExamineMBR
HalFreeCommonBuffer
HalFreeHardwareCounters
HalGetAdapter
HalGetBusData
HalGetBusDataByOffset
HalGetDmaAlignmentRequirement
HalGetInterruptVector
HalReadDmaCounter
HalReturnToFirmware
HalSetBusData
HalSetBusDataByOffset
HalTranslateBusAddress
READ_PORT_BUFFER_UCHAR
READ_PORT_BUFFER_ULONG
READ_PORT_BUFFER_USHORT
READ_PORT_UCHAR
READ_PORT_ULONG
HAL Library Routines
READ_PORT_BUFFER_USHORT
READ_PORT_UCHAR
READ_PORT_ULONG
READ_PORT_USHORT
READ_REGISTER_BUFFER_UCHAR
READ_REGISTER_BUFFER_ULONG
READ_REGISTER_BUFFER_ULONG64
READ_REGISTER_BUFFER_USHORT
READ_REGISTER_UCHAR
READ_REGISTER_ULONG
READ_REGISTER_ULONG64
READ_REGISTER_USHORT
WRITE_PORT_BUFFER_UCHAR
WRITE_PORT_BUFFER_ULONG
WRITE_PORT_BUFFER_USHORT
WRITE_PORT_UCHAR
WRITE_PORT_ULONG
WRITE_PORT_USHORT
WRITE_REGISTER_BUFFER_UCHAR
WRITE_REGISTER_BUFFER_ULONG
WRITE_REGISTER_BUFFER_ULONG64
WRITE_REGISTER_BUFFER_USHORT
WRITE_REGISTER_UCHAR
WRITE_REGISTER_ULONG
WRITE_REGISTER_ULONG64
WRITE_REGISTER_USHORT
Windows Kernel-Mode CLFS Library
Windows provides a transactional logging system
for system files.
This system is called the Common Log File
System (CLFS).
Routines that provide a direct interface for CLFS
are prefixed with the letters "Clfs";
CLFS Library Routines
ClfsAddLogContainer
ClfsAddLogContainerSet
ClfsAdvanceLogBase
ClfsAlignReservedLog
ClfsAllocReservedLog
ClfsCloseAndResetLogFile
ClfsCloseLogFileObject
ClfsCreateLogFile
ClfsCreateMarshallingArea
ClfsCreateScanContext
ClfsDeleteLogByPointer
ClfsDeleteLogFile
ClfsDeleteMarshallingArea
ClfsFlushBuffers
ClfsFlushToLsn
ClfsGetContainerName
Windows Kernel-Mode WMI Library
Windows provides a general mechanism for
managing components.
This system is called Windows Management
Instrumentation (WMI). To satisify Windows
Driver Model (WDM) requirements, you should
implement WMI for your driver so that your
driver can be managed by the system.
Routines that provide a direct interface to the
WMI library are prefixed with the letters "Wmi";
WMI Library Routines
WmiCompleteRequest
WmiFireEvent
WmiQueryTraceInformation
WmiSystemControl
WmiTraceMessage
WmiTraceMessageVa
WMI Library Callback Routines
The WIN32 API
The Win32 API was developed by Microsoft as their own 32-bit API to
compete with the POSIX and OS/2 APIs and has proved to be extremely
successful.
Win32 provides a set of functions, messages and structures to give
applications access to the features of the operating system in a
standard and consistent fashion.
The Win32 API can be split into five general functional categories.
◦ Windows Management
◦ GDI - Graphics Device Interface
◦ System Services
◦ Multimedia
◦ Remote Procedure Calls
The Windows Management
The Windows Management set of functions allow applications to use the
standard Windows graphic user interface features.
Usually there is one window per application and this can be used for
display output and user input.
The API defines window classes and procedures to be used by the
applications and these give the appearance and behaviour of the
windows.
Input from the mouse and keyboard is passed as messages by message
functions to the correct application in the window and to the appropriate
window procedure.
The functions also provided for dialog boxes, scrolling text, entering text
and all the other features used in the Windows GUI.
The functions also generate the output for the windows.
This is done using the GDI functions to provide the instructions to the
display hardware.
Some of the things involved are: applications shouldn't take all the screen
and when a window is resized the API will request the application to
Operating modes includes things like brush types, background colours etc.
The System Services
The System Services were mentioned before but additional information on
them is given here.
The system services are the set of functions which give applications access
to the resources of a computer, and the features of the underlying
operating system, like memory, files systems and processes.
An application uses the system services to manage and monitor the
resources it needs to complete it's task.
They support file I/O functions and provide methods for applications to
share resources with other applications using Dynamic Link Libraries
(DLLs).
Useful procedures are put in a DLL and applications can access them with
DLL functions.
System information functions allow applications get information about the
computer such as what input devices are present and what size the
screen is.
Multimedia Functions
The range of Multimedia Functions give applications access to audio and
video and provide services for file I/O, media control, joysticks and
timers.
The different types of multimedia functions include audio functions to play
and record audio data.
This is done with a variety of formats including waveform, MIDI, etc.
The audio functions have the capability to use compression and
decompression and sound mixing.
Video functions are used to capture video, compress the clips and control
payback. Playback can be done using the Media Control Interface (MCI)
which is controlled with the video functions.
There also are a range of file I/O functions which are used to store and
retrieve the different types of multimedia files.
Windows API
The functionality provided by the Windows API can be
grouped into eight categories
◦ Base Services
Provide access to the fundamental resources
available to a Windows system. Included are
things like file systems, devices, processes and
threads, and error handling. These functions
reside in kernel.exe, krnl286.exe or krnl386.exe
files on 16-bit Windows, and kernel32.dll on 32-
bit Windows.
◦ Advanced Services
Provide access to functionality that is an addition
on the kernel. Included are things like the
Windows registry, shutdown/restart the system
(or abort), start/stop/create a Windows service,
manage user accounts. These functions reside in
advapi32.dll on 32-bit Windows.
Windows API
Graphics Device Interface
◦ Provides functionality for outputting graphical
content to monitors, printers and other
output devices. It resides in gdi.exe on 16-bit
Windows, and gdi32.dll on 32-bit Windows in
user-mode. Kernel-mode GDI support is provided
by win32k.sys which communicates directly with
the graphics driver.
User Interface
◦ Provides the functionality to create and manage
screen windows and most basic controls, such as
buttons and scrollbars, receive mouse and
keyboard input, and other functionality
associated with the GUI part of Windows. This
functional unit resides in user.exe on 16-bit
Windows, and user32.dll on 32-bit Windows.
Windows API
Common Dialog Box Library
◦ Provides applications the standard dialog boxes for
opening and saving files, choosing color and font,
etc. The library resides in a file called commdlg.dll on
16-bit Windows, and comdlg32.dll on 32-bit Windows.
It is grouped under the User Interface category of the
API.
Common Control Library
◦ Gives applications access to some advanced controls
provided by the operating system. These include
things like status bars, progress bars, toolbars and
tabs. The library resides in a DLL file called
commctrl.dll on 16-bit Windows, and comctl32.dll on
32-bit Windows. It is grouped under the User
Interface category of the API.
Windows API
Windows Shell
◦ Component of the Windows API allows applications to
access the functionality provided by the
operating system shell, as well as change and
enhance it. The component resides in shell.dll on 16-
bit Windows, and shell32.dll on 32-bit Windows. The
Shell Lightweight Utility Functions are in shlwapi.dll.
It is grouped under the User Interface category of the
API.
Network Services
◦ Give access to the various networking capabilities of
the operating system. Its sub-components include
NetBIOS, Winsock, NetDDE, RPC and many others.
Windows API
Web
◦ The Internet Explorer web browser also exposes many API's
that are often used by applications, and as such could be
considered a part of the Windows API. Internet Explorer has
been included with the operating system since
Windows 98 Second Edition, and has provided web related
services to applications since Windows 98. Specifically, it is
used to provide:
An embeddable web browser control, contained in
shdocvw.dll and mshtml.dll.
The URL monitor service, held in urlmon.dll, which
provides COM objects to applications for resolving
URLs. Applications can also provide their own URL
handlers for others to use.
A library for assisting with multi-language and
international text support (mlang.dll).
DirectX Transforms, a set of image filter components.
XML support (the MSXML components, held in
msxml*.dll).
Windows API
Multimedia
◦ Microsoft has provided the DirectX set of APIs as part of every
Windows installation since Windows 95 OSR2. DirectX provides a
loosely related set of multimedia and gaming services, including:
Direct3D for access to 3D hardware accelerated graphics.
DirectDraw for hardware accelerated access to the 2D frame
buffer. As of DirectX 9, this component has been deprecated
in favor of Direct3D, which provides more general high-
performance graphics functionality (as 2D rendering is a
subset of 3D rendering).
DirectSound for low level hardware accelerated sound card
access.
DirectInput for communication with input devices such as
joysticks and gamepads.
DirectPlay as a multiplayer gaming infrastructure. This
component has been deprecated as of DirectX 9 and Microsoft
no longer recommends its use for game development.
DirectShow which builds and runs generic multimedia pipelines.
It is comparable to the GStreamer framework and is often
used to render in-game videos and build media players (
Windows Media Player is based upon it). DirectShow is no
longer recommended for game development.
Windows API
Program interaction
◦ The Windows API mostly concerns itself with the
interaction between the operating system and an
application.
◦ For communication between the different Windows
applications among themselves, Microsoft has
developed a series of technologies alongside the
main Windows API.
◦ This started out with Dynamic Data Exchange (DDE),
which was superseded by
Object Linking and Embedding (OLE) and later by the
Component Object Model (COM), Automation Objects,
ActiveX controls, and the .NET Framework.
◦ There is not always a clear distinction between these
technologies, and there is quite a lot of overlap.
Unit III
Windows
Driver Model
Introduction to WDM
Toallow driver developers to write device
drivers that are source-code compatible
across all Microsoft Windows operating
systems, the Windows Driver Model
(WDM) was introduced.
Kernel-mode drivers that follow WDM rules
are called WDM drivers. All WDM drivers
must:
◦ Include wdm.h, not ntddk.h.
◦ Be designed as a bus driver, a function driver,
or a filter driver, as described in Types of
WDM Drivers.
◦ Create device objects as described in WDM
Device Objects and Device Stacks.
kernel-mode drivers
Highest-level drivers. Highest-level drivers include file
system drivers (FSDs) that support file systems, such as:
NTFS
File allocation table (FAT)
CD-ROM file system (CDFS)
The USB hub bus driver that drives the USB hub. The USB
hub driver is provided with the system by Microsoft.
S in ce th e co n tro lle r exte n sio n is d rive r-sp e cific , its stru ctu re m u st b e
d e fin e d in a d rive r h e a d e r file . A lth o u g h th e exte n sio n 's exa ct
co n te n ts d e p e n d o n w h a t a d rive r d o e s, its g e n e ra l la yo u t lo o ks
so m e th in g like th is:
typ e d e f stru ct _C O N T R O LLE R _E X T E N S IO N
{
// back pointer
PC O N T R O LLE R _O B JE C T C o n tro lle rO b je ct
:
// other driver-specificdeclarations
:
Kernel: Adapter Objects
Just as multiple devices on the same controller need to coordinate
their hardware access, so it is that devices that perform DMA
need an orderly way to share system DMA resources.
The I/O Manager uses adapter objects to prevent arguments over
DMA hardware. There is one adapter object for each DMA data
transfer channel on the system.
Like a controller object, an adapter object can be owned by only
one device at a time.
Before starting a DMA transfer, the Start I/O routine asks for
ownership of the adapter object.
If the hardware is free, ownership is granted.
If not, the device's request is put on hold until the current owner
releases the hardware.
Obviously, if the device supports only programmed I/O, it has no
need for an adapter object.
Kernel: Adapter Objects
The life cycle of the adapter object is described below.
1.The HAL creates Adapter objects for any DMA data channels
detected at boot time.
2.The DriverEntry or AddDevice routine locates the adapter
object for its device and stores that pointer in the device
or controller extension.
3.The Start I/O routine requests ownership of the adapter
object on behalf of a specific device.
4.When ownership is granted, the I/O Manager calls the driver's
Adapter Control routine. This routine then uses the
adapter object to set up a DMA transfer.
5.The driver's DpcForIsr routine may use the adapter object
to perform additional operations in the case of a split
transfer.
6.When a transfer is finished, DpcForIsr releases the adapter
object.
Layout of an Adapter
FigureObject
illustrates the relationship of adapter objects to other
structures. As the diagram shows, the adapter object is
completely opaque and has no externally visible fields. When
working with DMA devices, the pointer to the adapter object, as
well as the number of mapping registers it supports, should be
stored in the device extension or controller extension structure.
Kernel: Interrupt
Objects
Interrupt objects simply give the kernel's interrupt
dispatcher a way to find the right service routine when
an interrupt occurs.
The life cycle of an interrupt object is described below.
1.The DriverEntry or AddDevice routine creates an interrupt
object for each interrupt vector supported by the device or
the controller.
2.When an interrupt occurs, the kernel's interrupt dispatcher
uses the Interrupt object to locate the Interrupt Service
routine.
3.The Unload or RemoveDevice routine deletes the interrupt
object after disabling interrupts from the device.
A driver does not interact with interrupt objects other than
to create and delete them.
A pointer to the interrupt object is typically stored in the
device extension or controller extension.
Layout of an Interrupt
Object
Figure illustrates the structure of an interrupt object. Like adapter objects,
they are completely opaque and have no externally visible fields.
Unit IV
Driver Routines
Initialization and Cleanup
Routines
DriverEntry Routine
What a DriverEntry Routine Does
◦ DriverEntry locates hardware that it will be controlling. That
hardware is allocated—it is marked as under the control of this
driver.
◦ The driver object is initialized by announcing other driver entry
points. The announcements are accomplished by storing function
pointers directly into the driver object.
◦ If the driver manages a multiunit or multifunction controller,
IoCreateController is used to create a controller object. A
controller extension is then initialized.
◦ IoCreateDevice is used to create a device object for each physical
or logical device under the control of this driver. A device
extension is then initialized.
◦ The created device is made visible to the Win32 subsystem by
calling IoCreateSymbolicLink.
◦ The device is connected to an interrupt object. If the ISR requires the
use of a DPC object, it is created and initialized in this step.
◦ Steps 4 to 6 are repeated for each physical or logical device
controlled by this driver.
◦ If successful, DriverEntry should return STATUS_SUCCESS to the I/O
Manager.
DriverEntry Routine
Announcing DriverEntry
Points
The I/O Manager is able to locate the
DriverEntry routine because it has a
well-known name.
Other driver routines don't have fixed
names, so the I/O Manager needs some
other way to locate them.
The linkage mechanism is the driver
object, which contains pointers to other
driver functions.
A DriverEntry routine is responsible for
setting up these function pointers.
Announcing DriverEntry
Points
The following code fragment shows how a
DriverEntry routine initializes both kinds
of function pointers.
pDO->DriverStartIo = StartIo;
pDO->DriverUnload = Unload;
// // Initialize the MajorFunction Dispatch table //
pDO->MajorFunction[ IRP_ MJ_CREATE ] =
DispatchCreate;
pDO->MajorFunction[ IRP_MJ_CLOSE ] = DispatchClose;
Creating Device Objects
Once hardware is identified and allocated,
the next step is to create a device object
for each physical or virtual device that is
to be exposed to the rest of the system.
Most of the work is done by the
IoCreateDevice function, which takes a
description of the device and returns a
device object, complete with an
attached device extension.
Creating Device Objects
IoCreateDevicealso links the new device
object into the list of devices managed
by this driver object. Table contains a
description of this function.
◦ The DeviceType parameter of IoCreateDevice is
simply a 16-bit value describing the class of device
being added.
◦ Microsoft reserves the first half of this range for
predefined device types. Above 32767, private
device types can be defined. Beware, though, that
conflict with another vendor's device is always
possible.
◦ Currently, Microsoft predefines about 30 device types.
◦ The predefined device type values are given symbolic
names of the form FILE_DEVICE_XXX (e.g.,
FILE_DEVICE_DVD).
Creating Device Objects
Code Example: Driver
Initialization
The following example shows how a basic kernel-mode
device driver initializes itself.
This first minimal driver must be manually loaded.
It does not touch any hardware, but instead creates an
internal device name (MINIMAL0) and a symbolic link
name (MIN1).
It consists of a single source module, Driver.cpp.
A header file, Driver.h, declares driver-specific information
about our nonhardware device, such as the
DEVICE_EXTENSION.
DRIVERENTRY
◦ In our first non-WDM driver example, the DriverEntry
routine is small and straightforward. The
responsibilities include
◦ Announcing other DriverEntry points.
◦ For the Minimal driver, the only other routine to
announce is the driver's Unload function.
Code Example:
DriverEntry
//++
// Function: DriverEntry
// Ifthis driver controlled real hardware ,
// code would be placed here to locate it.
Unload
//++
// Function: DriverUnload // a littletrickery...
// Description: // we need to delete the device
// Stops & Deletes devices controlled by this o b je ct, B U T
driver.
// the Device object is pointed to by
// Stops interrupt processing (if any) // Releases
kernel resources consumed by driver p N extO b j
// Arguments: // Ifwe delete the device object
// pDriverObject - Passed from I/O Manager first,
// Return value: // we can't traverse to the next
// None D e vice in th e list
//— // Rather than create another
VOID DriverUnload ( IN PDRIVER_OBJECT p o in te r, w e ca n
pDriverObject ) {
// use the DeviceExtension's back
PDEVICE_OBJECT pNextObj;
p o in te r
// Loop through each device controlled by
Driver // to the device . // So , firstupdate
pNextObj = pDriverObject->DeviceObject; th e n ext p o in te r...
while (pNextObj != NULL) { p N extO b j = p N extO b j-> N extD e vice ;
// Dig out the Device Extension from the
// then delete the device using the
// Device Object
E xte n sio n
PDEVICE_EXTENSION pDevExt =
(PDEVICE_EXTENSION) pNextObj- Io D e le te D e vice ( p D e vE xt-
>DeviceExtension;
> pDevice );
// This will yield the symbolic link name
UNICODE_STRING pLinkName = pDevExt- }
>ustrSymLinkName;
// ... which can now be deleted
// Finally, hardware that was allocated in
IoDeleteSymbolicLink(&pLinkName D rive rE n try
Writing Shutdown
Routines
If a driver has special processing to do before the operating system
disappears, a driver should supply a Shutdown routine.
Execution Context
The I/O Manager calls a Shutdown routine during a system shutdown. As
described in Table the Shutdown routine runs at PASSIVE_LEVEL IRQL,
which means it has access to paged system resources.
What a Shutdown Routine Does
The main purpose of the Shutdown routine is to put the device into a
quiescent state and perhaps store some device information into the
system Registry. Again, saving the current volume settings from a sound
card is a good example of something a Shutdown routine might do.
Unlike the driver's Unload routine, Shutdown routines don't have to worry
about releasing driver resources because the operating system is about to
disappear anyway.
Writing Shutdown
Routines
Enabling Shutdown Notification
There is no direct field in the Driver object for announcing the
Shutdown routine.
Instead, the event of system shutdown is sent as a separate I/O
request to a driver.
It is handled with an entry inside of the driver's MajorFunction
code array.
Additionally, the I/O Manager must be notified that a driver is
interested in receiving shutdown notifications.
This is done by making a call to
IoRegisterShutdownNotification. The following code fragment
shows how to enable shutdown notifications in a driver.
NTSTATUS DriverEntry ( IN PDRIVER_OBJECT pDriverObject, IN
PUNICODE_STRING pRegistryPath ) {
:
pDriverObject->MajorFunction[ IRP_MJ_SHUTDOWN ] = Shutdown;
IoRegisterShutdownNotification( pDriverObject );
:
}
Driver Dispatch
Routines
Announcing Driver Dispatch
Routines
Before a driver can process I/O requests, it must announce what
kinds of operations it supports.
I/O Request Dispatching Mechanism
Defining Private IOCTL
Values
◦ The IOCTL values passed to a driver follow a specific structure. Figure illustrates
the fields of this 32-bit structure. The DDK includes a macro, CTL_CODE, that
offers a convenient mechanism to generate IOCTL values. Table describes
the arguments to this macro.
IOCTL Argument-Passing
Method
◦ The extended functions defined with an IOCTL value within a driver
often require an input or output buffer.
◦ For example, a driver might report performance data using an IOCTL
value.
◦ The data reported would be transferred through a buffer supplied by
the user.
◦ The Win32 DeviceIoControl function defines parameters for two
buffers, one for input, one for output.
◦ The buffer transfer mechanism provided by the I/O Manager is defined
within the IOCTOL value itself.
◦ It can be either buffered or direct I/O.
◦ As described previously, with buffered I/O, the I/O Manager copies the
user buffer (into or out of) nonpaged system memory, where driver
code can then conveniently operate.
◦ With direct I/O, the driver is given direct access to the user buffer.
◦ The buffer transfer mechanism is defined with each IOCTL value
specification and is a field within the IOCTL structure.
◦ This provides maximum flexibility when performing DeviceIoControl
operations.
IOCTL Argument-Passing
Method
The TransferType field of the IOCTL field is two-bits wide and
defines one of the following:
◦ METHOD_BUFFERED.
◦ The I/O Manager copies the user buffer to and from an intermediate nonpaged
pool buffer on behalf of the driver.
◦ METHOD_IN_DIRECT.
◦ The I/O Manager provides a list of pages that encompass the user buffer. The
driver uses this list to provide direct I/O (using DMA or programmed I/O) from
the device into user space (i.e., like a Read operation).
◦ METHOD_OUT_DIRECT.
◦ The I/O Manager provides a list of pages that encompass the user buffer. The
driver uses this list to provide direct I/O from user space into the device (i.e.,
like a Write operation).
◦ METHOD_NEITHER.
◦ The I/O Manager does not assist with the buffer transfer. The user's original
buffer address (presumably from paged memory) is provided to the driver.
For faster, larger transfers, direct I/O is most suitable.
Writing IOCTL Header Files
◦ This header file should also contain any structure definitions that describe the
buffer contents of specific control operations.
◦ The following is an example of an IOCTL header file:
◦
#define IOCTL_MISSLEDEVICE_AIM CTL_CODE(
FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_ACCESS_ANY )
// Structures used by IOCTL_MISSLEDEVICE_AIM
9 .- T h e ke rn e l- m o d e Pn P m a n a g e r
co o rd in a te s w ith th e u se r-m o d e
Pn P m a n a g e r a n d u se r- m o d e
S e tu p co m p o n e n ts to fin d th e
fu n ctio n a n d filte r d rive rs fo r th e
d e vice , if th e re a re a n y.
1 0 .- T h e u se r-m o d e S e tu p
co m p o n e n ts d ire ct th e ke rn e l-
m o d e Pn P m a n a g e r to lo a d th e
fu n ctio n a n d filte r d rive rs.
Adding a PnP Device to a
Running System
1 1 .- Lo w e r- filte r d rive rs
1 2 .- Fu n ctio n d rive r
1 3 .- U p p e r- filte r d rive rs
1 4 .-A ssig n in g re so u rce s a n d sta rtin g
th e d e vice
Postponing PnP IRP Processing Until
Lower Drivers Finish
1. T h e Pn P m a n a g e r ca lls th e I/ O
m a n a g e r to se n d a n IR P to th e
to p d rive r in th e d e vice sta ck .
2. T h e I/ O m a n a g e r ca lls th e
D isp a tch Pn P routine of the top
d rive r.
3. T h e fu n ctio n d rive r d e cla re s a n d
in itia lize s a ke rn e l-m o d e e ve n t,
se ts u p th e sta ck lo ca tio n fo r th e
n ext-lo w e r d rive r, a n d se ts a n
Io C o m p le tio n routine for this IRP.
4. T h e fu n ctio n d rive r p a sse s th e IR P
d o w n th e d e vice sta ck w ith
Io C a llD riv e r before performing
a n y o p e ra tio n s to h a n d le th e IR P.
5. T h e I/ O m a n a g e r se n d s th e IR P to
th e n ext-lo w e r d rive r in th e
d e vice sta ck b y ca llin g th a t
d rive r's D isp a tch Pn P routine .
6. T h e n ext-lo w e r d rive r in th is
exa m p le is th e lo w e st d rive r in
th e d e vice sta ck , th e p a re n t b u s
Postponing PnP IRP Processing Until
Lower Drivers Finish
7.-When the bus driver calls
IoCompleteRequest, the I/O manager examines
the stack locations of the higher drivers and
calls any IoCompletion routines it finds. In
this example, the I/O manager locates and
calls the IoCompletion routine for the next-
higher driver, the function driver.
8.-The function driver's IoCompletion routine
sets the kernel-mode event supplied in the
context parameter and returns
STATUS_MORE_PROCESSING_REQUIRED
9.-The I/O manager stops completing the IRP and
returns control to the routine that called
IoCompleteRequest, which in this example is
the bus driver's DispatchPnP routine .
10.-The bus driver returns from its
DispatchPnp routine with status indicating
the result of its IRP processing: either
STATUS_SUCCESS or an error status.
11 .- IoCallDriver returns control to its
caller, which in this example is the function
driver's DispatchPnP routine.
12.-The function driver's DispatchPnP routine
resumes processing the IRP.
13.-Once lower drivers have successfully
completed the IRP, the function driver
processes the IRP.
Starting a Device
The PnP manager sends an
IRP_MN_START_DEVICE request to drivers
either to start a newly enumerated
device or to restart an existing device
that was stopped for resource
rebalancing.
Function and filter drivers must set an
IoCompletion routine, pass the
IRP_MN_START_DEVICE request down the
device stack, and postpone their start
operations until all lower drivers have
finished with the IRP.
The parent bus driver, the bottom driver in
the device stack, must be the first driver
to perform its start operations on a
device before the device is accessed by
other drivers.
To ensure proper sequencing of start
operations, the PnP manager postpones
exposing device interfaces and blocks
Starting a Device
If a driver for a device fails the
IRP_MN_START_DEVICE request, the
PnP manager sends an
IRP_MN_REMOVE_DEVICE request to
the device stack.
In response to this IRP, the drivers for
the device undo their start
operations (if they succeeded the
start IRP), undo their AddDevice
operations, and detach from the
device stack.
The PnP manager marks such a device
"failed start.“
If a lower driver failed the IRP (
IoCallDriverreturned an error), do
not continue processing the IRP. Do
any necessary cleanup and return
from the DispatchPnP routine .
Starting a Device in a Function
Driver
1. If lower drivers processed the IRP
successfully, start the device.
◦ The exact steps to start a device
vary from device to device.
◦ Such steps might include
mapping I/O space, initializing
hardware registers, setting the
device in the D0 power state,
and connecting the interrupt
with IoConnectInterrupt.
◦ If the driver is restarting a
device after an
IRP_MN_STOP_DEVICE request,
the driver might have device
state to restore.
◦ The device must be powered on
before any drivers can access
it.
Stopping a Device to Rebalance
Resources(999)
1 . T h e Pn P m a n a g e r issu e s a n
IR P _M N _Q U E R Y _S T O P _D E V IC E to ask
w h e th e r th e d rive rs fo r a d e vice ca n sto p
th e d e vice a n d re le a se its h a rd w a re
re so u rce s.
2 . T h e Pn P m a n a g e r issu e s a n
IR P _M N _S T O P _D E V IC E to stop the device .
3 . A fte r su cce ssfu lly re b a la n cin g re so u rce s,
th e Pn P m a n a g e r issu e s
IR P _M N _S TA R T _D E V IC E requests to
re sta rt a n y d e vice s th a t it sto p p e d d u rin g
th e re b a la n ce .
4 . O th e rw ise , th e Pn P m a n a g e r ca n ce ls a
q u e ry -sto p IR P b y se n d in g a n
IR P _M N _C A N C E L_S T O P _D E V IC E .
5 . If a d rive r failsto restart the device after
re b a la n cin g re so u rce s, th e Pn P m a n a g e r
se n d s re m o ve IR Ps to th e d e vice sta ck
Handling an IRP_MN_QUERY_STOP_DEVICE
Request
Determine whether the device can be
[-r SerialNo or 0] - Unplugs devices. Specify 0 to unplug all of
the devices that are enumerated so far.
[-e SerialNo or 0] - Ejects devices. Specify 0 to eject all of
the devices that are enumerated so far.
By design every toaster device will have a globally unique serial number.
filter
◦ Contains six different subdirectories
that each produce one of the
following drivers from a common
source file (Filter.c):
Class upper filter (Clsupper.sys)
Class lower filter (Clslower.sys)
Device upper filter (Devupper.sys)
Device lower filter (Devlower.sys)
Bus FDO upper filter (Bfdoupr.sys)
Bus FDO lower filter (Bfdolwr.sys)
Toaster
Building the Sample
coinstaller
◦ Contains source code of the device-specific coinstaller
(Tostrco1.dll).
◦ The coinstaller demonstrates how to create a FriendlyName for a
device based on its unique instance ID.
◦ In this sample, during enumeration, the bus driver provides the
serial number in the UINumber field of the device capabilities.
◦ The FriendlyName is required to uniquely identify multiple
devices of the same interface class.
◦ The coinstaller also shows how to open an INF file and parse a
custom section.
classinstaller
◦ Contains source code of the class-installer (Tostrcls.dll).
◦ This fake class installer is included to provide a class icon for all
of the TOASTER class devices.
◦ This installer is copied to the system32 directory when the class
is installed for the first time in the system.
Toaster(day)
Building the Sample
inf
◦ Contains three subdirectories (i386, amd64, and
ia64), and each subdirectory contains the
following files:
Bus.inf installs Basenum.sys and sets up the registry.
Simple.inf creates the Toaster class, installs Toaster.sys,
and sets up the registry.
Toaster.inf is functionally similar to Simple.inf but also
installs the class installer. The class installer provides the
custom icon for the class and an advanced property page
to change the FriendlyName of the device in the device
manager.
Toastco.inf is functionally similar to Toaster.inf but also
installs the coinstaller. The coinstaller is used to
dynamically create a unique FriendlyName of the device
based on the serial number.
Busf.inf and Toasterf.inf are functionally similar to the
preceding INF files but also install all of the previously
mentioned filter drivers.
Filter.inf installs a device upper filter for the toaster device.
Toaster
Building the Sample
toastmon
PIO_STACK_LOCATION irpStack;
NTSTATUS status;
PFDO_DEVICE_DATA fdoData;
PCOMMON_DEVICE_DATA commonData;
PAGED_CODE ();
commonData = (PCOMMON_DEVICE_DATA) DeviceObject->DeviceExtension;
//
// We only allow create/close requests for the FDO.
// That is the bus itself.
//
if (!commonData->IsFDO) {
Irp->IoStatus.Status = status = STATUS_INVALID_DEVICE_REQUEST;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
return status;
}
fdoData = (PFDO_DEVICE_DATA) DeviceObject->DeviceExtension;
Bus_IncIoCount (fdoData);
Bus_CreateClose
// Check to see whether the bus is removed
// if (fdoData->DevicePnPState == Deleted) {
Irp->IoStatus.Status = status = STATUS_NO_SUCH_DEVICE;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
return status;
}
irpStack = IoGetCurrentIrpStackLocation (Irp);
switch (irpStack->MajorFunction) {
case IRP_MJ_CREATE:
Bus_KdPrint_Def (BUS_DBG_SS_TRACE, ("Create \n"));
status = STATUS_SUCCESS;
break;
case IRP_MJ_CLOSE:
Bus_KdPrint_Def (BUS_DBG_SS_TRACE, ("Close \n"));
status = STATUS_SUCCESS;
break;
default:
status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = status;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
Bus_DecIoCount (fdoData);
return status;
}
Bus_IoCtl
NTSTATUS Bus_IoCtl(
IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp )
{
PIO_STACK_LOCATION irpStack;
NTSTATUS status;
ULONG inlen;
PFDO_DEVICE_DATA fdoData;
PVOID buffer;
PCOMMON_DEVICE_DATA commonData;
PAGED_CODE ();
commonData = (PCOMMON_DEVICE_DATA) DeviceObject->DeviceExtension;
//
// We only allow create/close requests for the FDO.
// That is the bus itself.
//
if (!commonData->IsFDO) {
Irp->IoStatus.Status = status = STATUS_INVALID_DEVICE_REQUEST;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
return status;
}
fdoData = (PFDO_DEVICE_DATA) DeviceObject->DeviceExtension;
Bus_IncIoCount (fdoData);
Bus_IoCtl
// Check to see whether the bus is removed
//
if (fdoData->DevicePnPState == Deleted) {
status = STATUS_NO_SUCH_DEVICE;
goto END;
}
irpStack = IoGetCurrentIrpStackLocation (Irp);
buffer = Irp->AssociatedIrp.SystemBuffer;
inlen = irpStack->Parameters.DeviceIoControl.InputBufferLength;
status = STATUS_INVALID_PARAMETER;
switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
case IOCTL_BUSENUM_PLUGIN_HARDWARE:
if (
//
// Make sure it has at least two nulls and the size
// field is set to the declared size of the struct
//
((sizeof (BUSENUM_PLUGIN_HARDWARE) + sizeof(UNICODE_NULL) * 2) <=
inlen) &&
//
// The size field should be set to the sizeof the struct as declared
// and *not* the size of the struct plus the multi_sz
//
Bus_IoCtl
(sizeof (BUSENUM_PLUGIN_HARDWARE) ==
((PBUSENUM_PLUGIN_HARDWARE) buffer)->Size)) {
Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("PlugIn called\n"));
status= Bus_PlugInDevice((PBUSENUM_PLUGIN_HARDWARE)buffer,
inlen, fdoData);
}
break;
case IOCTL_BUSENUM_UNPLUG_HARDWARE
if ((sizeof (BUSENUM_UNPLUG_HARDWARE) == inlen) &&
(((PBUSENUM_UNPLUG_HARDWARE)buffer)->Size == inlen)) {
Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("UnPlug called\n"));
status= Bus_UnPlugDevice(
(PBUSENUM_UNPLUG_HARDWARE)buffer, fdoData);
}
break;
case IOCTL_BUSENUM_EJECT_HARDWARE:
if ((sizeof (BUSENUM_EJECT_HARDWARE) == inlen) &&
(((PBUSENUM_EJECT_HARDWARE)buffer)->Size == inlen)) {
Bus_KdPrint(fdoData, BUS_DBG_IOCTL_TRACE, ("Eject called\n"));
status= Bus_EjectDevice((PBUSENUM_EJECT_HARDWARE)buffer,
fdoData);
} Irp->IoStatus.Information = 0;
break; END:
Irp->IoStatus.Status = status;
default: IoCompleteRequest (Irp, IO_NO_INCREMENT);
break; // default status is STATUS_INVALID_PARAMETER Bus_DecIoCount (fdoData);
return status;
} }
Bus_DriverUnload
VOID Bus_DriverUnload( IN PDRIVER_OBJECT DriverObject )
{
PAGED_CODE ();
Bus_KdPrint_Def (BUS_DBG_SS_TRACE, ("Unload\n"));
//
// All the device objects should be gone.
//
ASSERT (NULL == DriverObject->DeviceObject);
//
// Here we free all the resources allocated in the DriverEntry
//
if(Globals.RegistryPath.Buffer)
ExFreePool(Globals.RegistryPath.Buffer);
return;
}
Bus_IncIoCount
VOID Bus_IncIoCount(
IN PFDO_DEVICE_DATA FdoData )
{
LONG result;
result = InterlockedIncrement(&FdoData->OutstandingIO);
ASSERT(result > 0);
//
// Need to clear StopEvent (when OutstandingIO bumps from 1 to 2)
//
if (result == 2) {
//
// We need to clear the event
//
KeClearEvent(&FdoData->StopEvent);
}
return;
}
Bus_DecIoCoun
VOID Bus_DecIoCount(
IN PFDO_DEVICE_DATA FdoData )
{
LONG result;
result = InterlockedDecrement(&FdoData->OutstandingIO);
ASSERT(result >= 0);
if (result == 1) {
// Set the stop event. Note that when this happens
// (i.e. a transition from 2 to 1), the type of requests we
// want to be processed are already held instead of being
// passed away, so that we can't "miss" a request that
// will appear between the decrement and the moment when
// the value is actually used.
KeSetEvent (&FdoData->StopEvent, IO_NO_INCREMENT, FALSE);
}
if (result == 0) {
// The count is 1-biased, so it can be zero only if an
// extra decrement is done when a remove Irp is received
ASSERT(FdoData->DevicePnPState == Deleted);
// Set the remove event, so the device object can be deleted
KeSetEvent (&FdoData->RemoveEvent, IO_NO_INCREMENT, FALSE);
}
return;
}
Buspdo.c Bus_PDO_Pn
NTSTATUS Bus_PDO_PnP(
IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PIO_STACK_LOCATION
IrpStack, IN PPDO_DEVICE_DATA DeviceData )
{
NTSTATUS status;
PAGED_CODE ();
// NB: Because we are a bus enumerator, we have no one to whom we could
// defer these irps. Therefore we do not pass them down but merely
// return them.
switch (IrpStack->MinorFunction) {
case IRP_MN_START_DEVICE:
// Here we do what ever initialization and ``turning on'' that is
SET_NEW_PNP_STATE(DeviceData, Started);
status = STATUS_SUCCESS;
break;
case IRP_MN_STOP_DEVICE:
// Here we shut down the device and give up and unmap any resources
status = STATUS_SUCCESS;
break;
case IRP_MN_QUERY_STOP_DEVICE:
Buspdo.c Bus_PDO_Pn
// No reason here why we can't stop the device.
{
// We did receive a query-stop, so restore.
RESTORE_PREVIOUS_PNP_STATE(DeviceData);
}
status = STATUS_SUCCESS;// We must not fail this IRP.
break;
case IRP_MN_QUERY_REMOVE_DEVICE:
// Check to see whether the device can be removed safely.
break;
}
SET_NEW_PNP_STATE(DeviceData, RemovePending);
status = STATUS_SUCCESS;
break;
case IRP_MN_CANCEL_REMOVE_DEVICE:
{
// We did receive a query-remove, so restore.
RESTORE_PREVIOUS_PNP_STATE(DeviceData);
}
status = STATUS_SUCCESS; // We must not fail this IRP.
break;
case IRP_MN_SURPRISE_REMOVAL:
Buspdo.c Bus_PDO_Pn
// We should stop all access to the device and relinquish all the
PFDO_DEVICE_DATA fdoData;
SET_NEW_PNP_STATE(DeviceData, Deleted);
// Remove the PDO from the list and decrement the count of PDO.
fdoData = FDO_FROM_PDO(DeviceData);
ExAcquireFastMutex (&fdoData->Mutex);
RemoveEntryList (&DeviceData->Link);
fdoData->NumPDOs--;
ExReleaseFastMutex (&fdoData->Mutex);
}
Buspdo.c Bus_PDO_Pn
// Free up resources associated with PDO and delete it.
break;
}
if (DeviceData->Present) {
// When the device is disabled, the PDO transitions from
// RemovePending to NotStarted. We shouldn't delete
// the PDO because a) the device is still present on the bus,
// b) we haven't reported missing to the PnP manager.
SET_NEW_PNP_STATE(DeviceData, NotStarted);
status = STATUS_SUCCESS;
} else {
ASSERT(DeviceData->Present);
status = STATUS_SUCCESS;
}
break;
case IRP_MN_QUERY_CAPABILITIES:
// Return the capabilities of a device, such as whether the device
case IRP_MN_QUERY_BUS_INFORMATION:
break;
case IRP_MN_DEVICE_USAGE_NOTIFICATION:
break;
case IRP_MN_EJECT:
status = STATUS_SUCCESS;
break;
case IRP_MN_QUERY_INTERFACE:
break;
case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
ToasterCleanup
ToasterUnload
ToasterQueueRequest
ToasterProcessQueuedRequests
ToasterCancelQueued
ToasterCanStopDevice
Power.c
ToasterDispatchPower
ToasterDispatchPowerDefault
To a ste rPo w e rB e g in Q u e u in g Irp s
ToasterDispatchSetPowerState
To a ste rC a llb a ckH a n d le D e vice S e tPo w e r
ToasterDispatchQueryPowerState
To a ste rG e tPo w e rPo licie sD e vice S ta te
ToasterDispatchSystemPowerIrp
To a ste rC a n S u sp e n d D e vice
ToasterCompletionSystemPowerUp
D b g Po w e rM in o rFu n ctio n S trin g
ToasterQueueCorrespondingDeviceIrp
D b g S yste m Po w e rS trin g
ToasterCompletionOnFinalizedDeviceIrp D b g D e vice Po w e rS trin g
ToasterDispatchDeviceQueryPower
ToasterDispatchDeviceSetPower
ToasterCompletionDevicePowerUp
ToasterFinalizeDevicePowerIrp
ToasterQueuePassiveLevelPowerCallback
ToasterCallbackHandleDeviceQueryPower
ToasterQueuePassiveLevelPowerCallbackWor
ker
Wake.c
ToasterDispatchWaitWake
ToasterArmForWake
ToasterWaitWakeIoCompletionRoutine
ToasterDisarmWake
ToasterWaitWakePoCompletionRoutine
ToasterQueuePassiveLevelCallback
ToasterPassiveLevelReArmCallbackWorker
ToasterPassiveLevelClearWaitWakeEnableSta
te
ToasterAdjustCapabilities
ToasterSetWaitWakeEnableState
ToasterGetWaitWakeEnableState
Wmi.c
ToasterWmiRegistration
ToasterWmiDeRegistration
ToasterSystemControl
ToasterSetWmiDataItem
ToasterSetWmiDataBlock
ToasterQueryWmiDataBlock
ToasterFunctionControl
ToasterFireArrivalEvent
ToasterQueryWmiRegInfo
GetDeviceFriendlyName
WMIMinorFunctionString