/*++ Copyright (c) 2000 Microsoft Corporation Module Name: vfdevobj.c Abstract: This module verifies drivers properly manage device objects. Author: Adrian J. Oney (adriao) 09-May-1998 Environment: Kernel mode Revision History: AdriaO 05/02/2000 - Seperated out from ntos\io\trackirp.c --*/ // // Disable W4 level warnings generated by public headers. // #include "vfpragma.h" #include "..\io\iop.h" // Includes vfdef.h #if (( defined(_X86_) ) && ( FPO )) #pragma optimize( "y", off ) // disable FPO for consistent stack traces #endif #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGEVRFY, VerifierIoAttachDeviceToDeviceStack) #pragma alloc_text(PAGEVRFY, VerifierIoDetachDevice) #pragma alloc_text(PAGEVRFY, VerifierIoDeleteDevice) #pragma alloc_text(PAGEVRFY, VfDevObjPreAddDevice) #pragma alloc_text(PAGEVRFY, VfDevObjPostAddDevice) #pragma alloc_text(PAGEVRFY, VfDevObjAdjustFdoForVerifierFilters) #endif VOID VerifierIoAttachDeviceToDeviceStack( IN PDEVICE_OBJECT NewDevice, IN PDEVICE_OBJECT ExistingDevice ) { UNREFERENCED_PARAMETER (NewDevice); IovUtilFlushStackCache(ExistingDevice, DATABASELOCKSTATE_HELD); } VOID VerifierIoDetachDevice( IN PDEVICE_OBJECT LowerDevice ) { PVOID callerAddress; ULONG stackHash; if (LowerDevice->AttachedDevice == NULL) { if (RtlCaptureStackBackTrace(2, 1, &callerAddress, &stackHash) != 1) { callerAddress = NULL; } WDM_FAIL_ROUTINE(( DCERROR_DETACH_NOT_ATTACHED, DCPARAM_ROUTINE + DCPARAM_DEVOBJ, callerAddress, LowerDevice )); } IovUtilFlushStackCache(LowerDevice, DATABASELOCKSTATE_HELD); } VOID VerifierIoDeleteDevice( IN PDEVICE_OBJECT DeviceObject ) { PDEVICE_OBJECT deviceBelow; PVOID callerAddress; ULONG stackHash; if (RtlCaptureStackBackTrace(2, 1, &callerAddress, &stackHash) != 1) { callerAddress = NULL; } // // ADRIAO N.B. 06/16/2000 - A good thing to do here would be to send a // second remove IRP to every deleted device object that was a member // of a WDM device stack. Just to check. // if (IovUtilIsDeviceObjectMarked(DeviceObject, MARKTYPE_DELETED)) { WDM_FAIL_ROUTINE(( DCERROR_DOUBLE_DELETION, DCPARAM_ROUTINE, callerAddress )); } IovUtilMarkDeviceObject(DeviceObject, MARKTYPE_DELETED); IovUtilGetLowerDeviceObject(DeviceObject, &deviceBelow); if (deviceBelow) { WDM_FAIL_ROUTINE(( DCERROR_DELETE_WHILE_ATTACHED, DCPARAM_ROUTINE, callerAddress )); ObDereferenceObject(deviceBelow); } VfIrpLogDeleteDeviceLogs(DeviceObject); } VOID VfDevObjPreAddDevice( IN PDEVICE_OBJECT PhysicalDeviceObject, IN PDRIVER_OBJECT DriverObject, IN PDRIVER_ADD_DEVICE AddDeviceFunction, IN VF_DEVOBJ_TYPE DevObjType ) /*++ Description: This routine is called before the specified driver's AddDevice has been invoked. Arguments: PhysicalDeviceObject - Device object at the bottom of the PnP stack. DriverObject - Driver object of the driver who's AddDevice has been invoked. AddDeviceFunction - Address of the AddDevice routine. DevObjType - Type of device object (lower device filter, FDO, etc.) Return Value: None. --*/ { VF_DEVOBJ_TYPE objType; UNREFERENCED_PARAMETER(AddDeviceFunction); if (!MmIsDriverVerifying(DriverObject)) { return; } if (VfSettingsIsOptionEnabled(NULL, VERIFIER_OPTION_INSERT_WDM_FILTERS)) { if (DevObjType == VF_DEVOBJ_FDO) { // // If we are calling AddDevice for the FDO, first attempt to attach // a lower class filter. // objType = VF_DEVOBJ_LOWER_CLASS_FILTER; } else { objType = DevObjType; } // // Attach a filter, cause pain. // VfFilterAttach(PhysicalDeviceObject, objType); } } VOID VfDevObjPostAddDevice( IN PDEVICE_OBJECT PhysicalDeviceObject, IN PDRIVER_OBJECT DriverObject, IN PDRIVER_ADD_DEVICE AddDeviceFunction, IN VF_DEVOBJ_TYPE DevObjType, IN NTSTATUS Result ) /*++ Description: This routine is called after the specified driver's AddDevice has been invoked. Arguments: PhysicalDeviceObject - Device object at the bottom of the PnP stack. DriverObject - Driver object of the driver who's AddDevice has been invoked. AddDeviceFunction - Address of the AddDevice routine. DevObjType - Type of device object (lower device filter, FDO, etc.) Result - Result returned by the AddDevice Routine Return Value: None. --*/ { PDEVICE_OBJECT deviceAbove, deviceBelow; BOOLEAN powerFailure; VF_DEVOBJ_TYPE objType; UNREFERENCED_PARAMETER(DriverObject); if (NT_SUCCESS(Result) && VfSettingsIsOptionEnabled(NULL, VERIFIER_OPTION_INSERT_WDM_FILTERS) && MmIsDriverVerifying(DriverObject)) { if (DevObjType == VF_DEVOBJ_FDO) { // // If we've just attached an FDO, try to add a upper device filter // on top of it. // objType = VF_DEVOBJ_UPPER_DEVICE_FILTER; } else { objType = DevObjType; } // // Attach filter, cause pain. // VfFilterAttach(PhysicalDeviceObject, objType); } if (!VfSettingsIsOptionEnabled(NULL, VERIFIER_OPTION_VERIFY_DO_FLAGS)) { return; } // // Take this opportunity to check the PDO. // if (!IovUtilIsDeviceObjectMarked(PhysicalDeviceObject, MARKTYPE_DEVICE_CHECKED)) { if ((PhysicalDeviceObject->Flags & (DO_BUFFERED_IO | DO_DIRECT_IO)) == (DO_BUFFERED_IO | DO_DIRECT_IO)) { // // Both direct I/O and buffered I/O are set. These are mutually // exclusive. // WDM_FAIL_ROUTINE(( DCERROR_INCONSISTANT_DO_FLAGS, DCPARAM_ROUTINE + DCPARAM_DEVOBJ, PhysicalDeviceObject->DriverObject->DriverExtension->AddDevice, PhysicalDeviceObject )); } // // No need to check DO_DEVICE_INITIALIZING as PDO's get them cleared // automagically. // IovUtilMarkDeviceObject(PhysicalDeviceObject, MARKTYPE_DEVICE_CHECKED); } powerFailure = FALSE; deviceBelow = PhysicalDeviceObject; ObReferenceObject(deviceBelow); while(1) { IovUtilGetUpperDeviceObject(deviceBelow, &deviceAbove); if (deviceAbove == NULL) { ObDereferenceObject(deviceBelow); break; } if (!IovUtilIsDeviceObjectMarked(deviceAbove, MARKTYPE_DEVICE_CHECKED)) { if ((deviceAbove->Flags & (DO_BUFFERED_IO | DO_DIRECT_IO)) == (DO_BUFFERED_IO | DO_DIRECT_IO)) { // // Both direct I/O and buffered I/O are set. These are mutually // exclusive. // WDM_FAIL_ROUTINE(( DCERROR_INCONSISTANT_DO_FLAGS, DCPARAM_ROUTINE + DCPARAM_DEVOBJ, AddDeviceFunction, deviceAbove )); } if (deviceAbove->Flags & DO_DEVICE_INITIALIZING) { // // A device didn't clear the DO_DEVICE_INITIALIZING flag during // AddDevice. Fail it now. // WDM_FAIL_ROUTINE(( DCERROR_DO_INITIALIZING_NOT_CLEARED, DCPARAM_ROUTINE + DCPARAM_DEVOBJ, AddDeviceFunction, deviceAbove )); // // Clean up the mess. // deviceAbove->Flags &= ~DO_DEVICE_INITIALIZING; } if ((deviceBelow->Flags & DO_POWER_PAGABLE) && (!(deviceAbove->Flags & DO_POWER_PAGABLE))) { if (!powerFailure) { // // We have caught a driver bug. deviceAbove didn't inherit the // DO_POWER_PAGABLE flag. // WDM_FAIL_ROUTINE(( DCERROR_POWER_PAGABLE_NOT_INHERITED, DCPARAM_ROUTINE + DCPARAM_DEVOBJ, AddDeviceFunction, deviceAbove )); // // Don't blame anyone else. // powerFailure = TRUE; } deviceAbove->Flags |= DO_POWER_PAGABLE; } if ((deviceBelow->Flags & DO_BUFFERED_IO) && (!(deviceAbove->Flags & DO_BUFFERED_IO))) { // // Buffered I/O flag not copied. Broken filter! // WDM_FAIL_ROUTINE(( DCERROR_DO_FLAG_NOT_COPIED, DCPARAM_ROUTINE + DCPARAM_DEVOBJ, AddDeviceFunction, deviceAbove )); } if ((deviceBelow->Flags & DO_DIRECT_IO) && (!(deviceAbove->Flags & DO_DIRECT_IO))) { // // Direct I/O flag not copied. Broken filter! // WDM_FAIL_ROUTINE(( DCERROR_DO_FLAG_NOT_COPIED, DCPARAM_ROUTINE + DCPARAM_DEVOBJ, AddDeviceFunction, deviceAbove )); } if ((deviceBelow->DeviceType != FILE_DEVICE_UNKNOWN) && (deviceAbove->DeviceType == FILE_DEVICE_UNKNOWN)) { // // The device type wasn't copied by a filter! // WDM_FAIL_ROUTINE(( DCERROR_DEVICE_TYPE_NOT_COPIED, DCPARAM_ROUTINE + DCPARAM_DEVOBJ, AddDeviceFunction, deviceAbove )); } // // Characteristics don't have to be checked because PnP takes care // of propogating them appropriately. // } IovUtilMarkDeviceObject(deviceAbove, MARKTYPE_DEVICE_CHECKED); ObDereferenceObject(deviceBelow); deviceBelow = deviceAbove; } } VOID VfDevObjAdjustFdoForVerifierFilters( IN OUT PDEVICE_OBJECT *FunctionalDeviceObject ) /*++ Description: This routine adjusts the designated FDO to take into account any verifier filter DO's added by this file. Arguments: FunctionalDeviceObject - On input, contains FDO. Adjusted to point to the correct FDO if verifier added a filter. Return Value: None. --*/ { PDEVICE_OBJECT fdo; fdo = *FunctionalDeviceObject; if (VfFilterIsVerifierFilterObject(fdo)) { fdo = fdo->AttachedDevice; ASSERT(fdo); *FunctionalDeviceObject = fdo; } }