Drivers can register callback routines that the system executes when it issues a bug check.
On all NT-based operating systems, drivers can use the KeRegisterBugCheckCallback routine to register a BugCheckCallback routine, and KeDeregisterBugCheckCallback to remove the routine. Drivers can use a BugCheckCallback routine to reset their device to a known state.
Prior to Windows XP Service Pack 1 (SP1) and Windows Server 2003, drivers could also use BugCheckCallback to store data in the crash dump file: the system called each BugCheckCallback routine before writing the crash dump file, so any data written to the buffer that was passed to BugCheckCallback was stored in the crash dump file.
In Windows XP SP1 and Windows Server 2003 and later, the system calls BugCheckCallbackafter the crash dump file is written. Instead, the system supports two additional types of bug check callback routines. A BugCheckSecondaryDumpDataCallback routine can be used to write secondary data to the crash dump file. A BugCheckDumpIoCallback routine can be used to copy the crash dump file to a device.
In Windows Server 2008 and later versions of Windows, a driver can implement a BugCheckAddPagesCallback routine to add pages of driver-specific data to the crash dump file. Unlike a BugCheckSecondaryDumpDataCallback routine, which appends data to the secondary crash dump region, a BugCheckAddPagesCallback routine adds pages of data to the crash dump region. During debugging, crash dump data is easier to access than secondary crash dump data.
A bug check callback routine executes at IRQL = HIGH_LEVEL, which imposes strong restrictions on what it can do.
A bug check callback routine cannot:
Access pageable memory
Use any synchronization mechanisms
Call any routine that must execute at IRQL = DISPATCH_LEVEL or below
Bug check callback routines are guaranteed to run without interruption, so no synchronization is required. (If the bug check routine does use any synchronization mechanisms, the system will deadlock.)
A driver's bug check callback routine can safely use the READ_PORT_*XXX, **READ_REGISTER_XXX, *WRITE_PORT_*XXX, and **WRITE_REGISTER_XXX*** routines to communicate with the driver's device. (For information about these routines, see Hardware Abstraction Layer Routines.)