/*++

    Copyright (c) Microsoft Corporation.  All rights reserved.

Rule Name:

    WdfSpinlock

Domain:

    wdf

Rule ID:

    Not Applicable

Description:

    This rule verifies that calls to WdfSpinLockAcquire is used in
    strict alternation with WdfSpinLockRelease. Moreover, at the end of any KMDF callback
    routine the driver should not hold the WdfSpinLock.

Help Link:

    https://go.microsoft.com/fwlink/?LinkId=507154

--*/



#include "slic_base.h"

state
{
   enum {initial,locked} s = initial;
}
watch WdfSpinLockCreate.exit.(*$2);

WdfSpinLockCreate.exit[guard *$2]
{  
        if($return!=STATUS_SUCCESS)
        {
            halt;
        }
}

WdfSpinLockAcquire.exit[guard $1]
{  
        if (s == locked) 
        {
            abort "The driver is calling $fname after already acquiring the WdfSpinLock.";
        }
        else
        {
            s=locked;
        } 
}

WdfSpinLockRelease.entry[guard $1]
{
        if (s != locked) 
        {
            abort "The driver is calling $fname without first acquiring the WdfSpinLock.";
        } 
        else 
        {
            halt;
        }
}

[fun_WDF_DEVICE_CONTEXT_CLEANUP
,fun_WDF_DEVICE_CONTEXT_DESTROY
,fun_WDF_IO_QUEUE_CONTEXT_CLEANUP_CALLBACK
,fun_WDF_IO_QUEUE_CONTEXT_DESTROY_CALLBACK
,fun_WDF_FILE_CONTEXT_CLEANUP_CALLBACK
,fun_WDF_FILE_CONTEXT_DESTROY_CALLBACK
,fun_WDF_CHILD_LIST_CREATE_DEVICE
,fun_WDF_CHILD_LIST_SCAN_FOR_CHILDREN
,fun_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_COPY
,fun_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_DUPLICATE
,fun_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_COMPARE
,fun_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_CLEANUP
,fun_WDF_CHILD_LIST_ADDRESS_DESCRIPTION_COPY
,fun_WDF_CHILD_LIST_ADDRESS_DESCRIPTION_DUPLICATE
,fun_WDF_CHILD_LIST_ADDRESS_DESCRIPTION_CLEANUP
,fun_WDF_CHILD_LIST_DEVICE_REENUMERATED
,fun_WDF_DEVICE_SHUTDOWN_NOTIFICATION
,fun_WDF_DEVICE_FILE_CREATE
,fun_WDF_FILE_CLOSE
,fun_WDF_FILE_CLEANUP
,fun_WDF_DEVICE_PNP_STATE_CHANGE_NOTIFICATION
,fun_WDF_DEVICE_POWER_STATE_CHANGE_NOTIFICATION
,fun_WDF_DEVICE_POWER_POLICY_STATE_CHANGE_NOTIFICATION
,fun_WDF_DEVICE_D0_ENTRY
,fun_WDF_DEVICE_D0_ENTRY_POST_INTERRUPTS_ENABLED
,fun_WDF_DEVICE_D0_EXIT
,fun_WDF_DEVICE_D0_EXIT_PRE_INTERRUPTS_DISABLED
,fun_WDF_DEVICE_PREPARE_HARDWARE
,fun_WDF_DEVICE_RELEASE_HARDWARE
,fun_WDF_DEVICE_SELF_MANAGED_IO_CLEANUP
,fun_WDF_DEVICE_SELF_MANAGED_IO_FLUSH
,fun_WDF_DEVICE_SELF_MANAGED_IO_INIT
,fun_WDF_DEVICE_SELF_MANAGED_IO_SUSPEND
,fun_WDF_DEVICE_SELF_MANAGED_IO_RESTART
,fun_WDF_DEVICE_QUERY_STOP
,fun_WDF_DEVICE_QUERY_REMOVE
,fun_WDF_DEVICE_SURPRISE_REMOVAL
,fun_WDF_DEVICE_USAGE_NOTIFICATION
,fun_WDF_DEVICE_RELATIONS_QUERY
,fun_WDF_DEVICE_ARM_WAKE_FROM_S0
,fun_WDF_DEVICE_ARM_WAKE_FROM_SX
,fun_WDF_DEVICE_DISARM_WAKE_FROM_S0
,fun_WDF_DEVICE_DISARM_WAKE_FROM_SX
,fun_WDF_DEVICE_WAKE_FROM_S0_TRIGGERED
,fun_WDF_DEVICE_WAKE_FROM_SX_TRIGGERED
,fun_WDFDEVICE_WDM_IRP_PREPROCESS_1
,fun_WDFDEVICE_WDM_IRP_PREPROCESS_2
,fun_WDFDEVICE_WDM_IRP_PREPROCESS_3
,fun_WDFDEVICE_WDM_IRP_PREPROCESS_4
,fun_WDFDEVICE_WDM_IRP_PREPROCESS_5
,fun_WDFDEVICE_WDM_IRP_PREPROCESS_6
,fun_WDF_IO_IN_CALLER_CONTEXT
,fun_WDF_DMA_ENABLER_FILL
,fun_WDF_DMA_ENABLER_FLUSH
,fun_WDF_DMA_ENABLER_ENABLE
,fun_WDF_DMA_ENABLER_DISABLE
,fun_WDF_DMA_ENABLER_SELFMANAGED_IO_START
,fun_WDF_DMA_ENABLER_SELFMANAGED_IO_STOP
,fun_WDF_PROGRAM_DMA_1
,fun_WDF_PROGRAM_DMA_2
,fun_WDF_PROGRAM_DMA_3
,fun_WDF_PROGRAM_DMA_4
,fun_WDF_PROGRAM_DMA_5
,fun_WDF_PROGRAM_DMA_6
,fun_WDF_PROGRAM_DMA_7
,fun_WDF_PROGRAM_DMA_8
,fun_WDF_PROGRAM_DMA_9
,fun_WDF_PROGRAM_DMA_10
,fun_WDF_DPC_1
,fun_WDF_DPC_2
,fun_WDF_DPC_3
,fun_WDF_DPC_4
,fun_WDF_DPC_5
,fun_WDF_DPC_6
,fun_WDF_DPC_7
,fun_WDF_DRIVER_DEVICE_ADD
,fun_WDF_DRIVER_UNLOAD
,fun_WDF_DEVICE_FILTER_RESOURCE_REQUIREMENTS
,fun_WDF_DEVICE_REMOVE_ADDED_RESOURCES
,fun_WDF_INTERRUPT_ISR
,fun_WDF_INTERRUPT_DPC
,fun_WDF_IO_QUEUE_IO_DEFAULT
,fun_WDF_IO_QUEUE_IO_STOP
,fun_WDF_IO_QUEUE_IO_RESUME
,fun_WDF_IO_QUEUE_IO_READ
,fun_WDF_IO_QUEUE_IO_WRITE
,fun_WDF_IO_QUEUE_IO_DEVICE_CONTROL
,fun_WDF_IO_QUEUE_IO_INTERNAL_DEVICE_CONTROL
,fun_WDF_IO_QUEUE_IO_CANCELED_ON_QUEUE
,fun_SDV_WDF_IO_QUEUE_STATE
,fun_WDF_IO_TARGET_QUERY_REMOVE
,fun_WDF_IO_TARGET_REMOVE_CANCELED
,fun_WDF_IO_TARGET_REMOVE_COMPLETE
,fun_WDF_OBJECT_CONTEXT_CLEANUP
,fun_WDF_OBJECT_CONTEXT_DESTROY
,fun_WDF_DEVICE_RESOURCES_QUERY
,fun_WDF_DEVICE_RESOURCE_REQUIREMENTS_QUERY
,fun_WDF_DEVICE_EJECT
,fun_WDF_DEVICE_SET_LOCK
,fun_WDF_DEVICE_ENABLE_WAKE_AT_BUS
,fun_WDF_DEVICE_DISABLE_WAKE_AT_BUS
,fun_WDF_DEVICE_PROCESS_QUERY_INTERFACE_REQUEST
,fun_WDF_REQUEST_CANCEL_1
,fun_WDF_REQUEST_CANCEL_2
,fun_WDF_REQUEST_CANCEL_3
,fun_WDF_REQUEST_CANCEL_4
,fun_WDF_REQUEST_CANCEL_5
,fun_WDF_REQUEST_CANCEL_6
,fun_WDF_REQUEST_COMPLETION_ROUTINE_1
,fun_WDF_REQUEST_COMPLETION_ROUTINE_2
,fun_WDF_REQUEST_COMPLETION_ROUTINE_3
,fun_WDF_REQUEST_COMPLETION_ROUTINE_4
,fun_WDF_REQUEST_COMPLETION_ROUTINE_5
,fun_WDF_REQUEST_COMPLETION_ROUTINE_6
,fun_WDF_TIMER_1
,fun_WDF_TIMER_2
,fun_WDF_TIMER_3
,fun_WDF_TIMER_4
,fun_WDF_TIMER_5
,fun_WDF_TIMER_6
,fun_WDF_WMI_INSTANCE_QUERY_INSTANCE_1
,fun_WDF_WMI_INSTANCE_QUERY_INSTANCE_2
,fun_WDF_WMI_INSTANCE_QUERY_INSTANCE_3
,fun_WDF_WMI_INSTANCE_QUERY_INSTANCE_4
,fun_WDF_WMI_INSTANCE_QUERY_INSTANCE_5
,fun_WDF_WMI_INSTANCE_QUERY_INSTANCE_6
,fun_WDF_WMI_INSTANCE_QUERY_INSTANCE_7
,fun_WDF_WMI_INSTANCE_QUERY_INSTANCE_8
,fun_WDF_WMI_INSTANCE_QUERY_INSTANCE_9
,fun_WDF_WMI_INSTANCE_QUERY_INSTANCE_10
,fun_WDF_WMI_INSTANCE_SET_INSTANCE_1
,fun_WDF_WMI_INSTANCE_SET_INSTANCE_2
,fun_WDF_WMI_INSTANCE_SET_INSTANCE_3
,fun_WDF_WMI_INSTANCE_SET_INSTANCE_4
,fun_WDF_WMI_INSTANCE_SET_INSTANCE_5
,fun_WDF_WMI_INSTANCE_SET_ITEM_1
,fun_WDF_WMI_INSTANCE_SET_ITEM_2
,fun_WDF_WMI_INSTANCE_SET_ITEM_3
,fun_WDF_WMI_INSTANCE_SET_ITEM_4
,fun_WDF_WMI_INSTANCE_SET_ITEM_5
,fun_WDF_WMI_INSTANCE_EXECUTE_METHOD_1
,fun_WDF_WMI_INSTANCE_EXECUTE_METHOD_2
,fun_WDF_WMI_INSTANCE_EXECUTE_METHOD_3
,fun_WDF_WMI_INSTANCE_EXECUTE_METHOD_4
,fun_WDF_WMI_INSTANCE_EXECUTE_METHOD_5
,fun_WDF_WMI_PROVIDER_FUNCTION_CONTROL
,fun_WDF_WORKITEM_1
,fun_WDF_WORKITEM_2
,fun_WDF_WORKITEM_3
,fun_WDF_WORKITEM_4
,fun_WDF_WORKITEM_5
,fun_WDF_WORKITEM_6
,fun_WDF_USB_READERS_FAILED_1
,fun_WDF_USB_READERS_FAILED_2
,fun_WDF_USB_READERS_FAILED_3
,fun_WDF_USB_READER_COMPLETION_ROUTINE_1
,fun_WDF_USB_READER_COMPLETION_ROUTINE_2
,fun_WDF_USB_READER_COMPLETION_ROUTINE_3
,fun_WDF_DEVICE_ARM_WAKE_FROM_SX_WITH_REASON].exit
{
        if (s == locked) 
        {
            abort "The KMDF callback routine has returned without releasing a WdfSpinLock.";
        }
}

[SDV_PO_RUNTIME_CALLBACKS].exit
{
        if (s == locked) {
            abort "The KMDF callback has returned without releasing a spinlock.";
        }
}
