/*++

Copyright (c) Microsoft Corporation

Module Name:

    FxGlobals.h

Abstract:

    This module contains globals definitions for the frameworks.

Author:




Environment:

    Both kernel and user mode

Revision History:

        Made it mode agnostic
        Moved km specific portions to FxGlobalsKm.h









        New failure paths:
            AllocatedTagTrackersLock initialization -
                If this fails we free debug extensions structure and not use it
            ThreadTableLock initialization -
                If this fails we turn off lock verification
            FxDriverGlobalsListLock initialization -
                If this fails we fail FxLibraryGlobalsCommission

--*/

#ifndef _FXGLOBALS_H
#define _FXGLOBALS_H

#include "wdfglobals.h"
#include <debug.h>

// REACTOS
#define ROSWDFNOTIMPLEMENTED (DbgPrint("(%s:%d) ReactOS KMDF: %s not implemented\n", __RELFILE__, __LINE__, __FUNCTION__))
// REACTOS

#ifdef __cplusplus
extern "C" {
#endif

struct FxLibraryGlobalsType;

class CWudfDriverGlobals; //UMDF driver globals

//
// NOTE: any time you add a value to this enum, you must add a field to the
// union in FxObjectDebugInfo.
//
enum FxObjectDebugInfoFlags {
    FxObjectDebugTrackReferences = 0x0001,
};

typedef enum FxTrackPowerOption : UCHAR {
    FxTrackPowerNone = 0,
    FxTrackPowerRefs,
    FxTrackPowerRefsAndStack,
    FxTrackPowerMaxValue
} FxTrackPowerOption;

typedef enum FxVerifierDownlevelOption {
    NotOkForDownLevel = 0,
    OkForDownLevel = 1,
} FxVerifierDownLevelOption;

typedef enum WaitSignalFlags {
    WaitSignalBreakUnderVerifier      = 0x01,
    WaitSignalBreakUnderDebugger      = 0x02,
    WaitSignalAlwaysBreak             = 0x04
} WaitSignalFlags;


struct FxObjectDebugInfo {
    //
    // FX_OBJECT_TYPES enum value
    //
    USHORT ObjectType;

    union {
        //
        // Combo of values from FxObjectDebugInfoFlags
        //
        USHORT DebugFlags;

        //
        // Break out of DebugFlags as individual fields.  This is used by the
        // debugger extension to reference the values w/out knowing the actual
        // enum values.
        //
        struct {
            USHORT TrackReferences : 1;
        } Bits;
    } u;
};

struct FxDriverGlobalsDebugExtension {
    //
    // Debug information per object.  List is sorted by
    // FxObjectDebugInfo::ObjectType, length is the same as FxObjectsInfo.
    //
    FxObjectDebugInfo* ObjectDebugInfo;

    //
    // Track allocated Mdls only in kernel mode version
    //
#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE)
    FxAllocatedMdls AllocatedMdls;

    KSPIN_LOCK AllocatedMdlsLock;
#endif

    //
    // List of all allocated tag trackers for this driver.  This is used to keep
    // track of orphaned objects due to leaked reference counts in the debugger
    // extension.
    //
    LIST_ENTRY AllocatedTagTrackersListHead;

    //
    // Synchronizes access to AllocatedTagTrackersListHead
    //
    MxLock AllocatedTagTrackersLock;

    //
    // Whether we track power references for WDFDEVICE objects
    // and optionally capture stack frames.
    //
    FxTrackPowerOption TrackPower;
};

//
// A telemetry context that is allocated if the telemetry provider is enabled.
//
typedef struct _FX_TELEMETRY_CONTEXT{
    //
    // A GUID representing the driver session
    //
    GUID DriverSessionGUID;

    //
    // A general purpose bitmap that can be used
    // by various telemetry events that may want to
    // fire once per driver session.
    //
    volatile LONG DoOnceFlagsBitmap;
}  FX_TELEMETRY_CONTEXT, *PFX_TELEMETRY_CONTEXT;

typedef struct _FX_DRIVER_GLOBALS {
public:
    ULONG
    __inline
    AddRef(
        __in_opt   PVOID Tag = NULL,
        __in       LONG Line = 0,
        __in_opt   PSTR File = NULL
        )
    {
        ULONG c;

        UNREFERENCED_PARAMETER(Tag);
        UNREFERENCED_PARAMETER(Line);
        UNREFERENCED_PARAMETER(File);

        c = InterlockedIncrement(&Refcnt);

        //
        // Catch the transition from 0 to 1.  Since the RefCount starts off at 1,
        // we should never have to increment to get to this value.
        //
        ASSERT(c > 1);
        return c;
    }

    ULONG
    __inline
    Release(
        __in_opt    PVOID Tag = NULL,
        __in        LONG Line = 0,
        __in_opt    PSTR File = NULL
        )
    {
        ULONG c;

        UNREFERENCED_PARAMETER(Tag);
        UNREFERENCED_PARAMETER(Line);
        UNREFERENCED_PARAMETER(File);

        c = InterlockedDecrement(&Refcnt);
        ASSERT((LONG)c >= 0);
        if (c == 0) {
            DestroyEvent.Set();
        }

        return c;
    }

    BOOLEAN
    IsPoolTrackingOn(
        VOID
        )
    {
        return (FxPoolTrackingOn) ? TRUE : FALSE;
    }

    BOOLEAN
    IsObjectDebugOn(
        VOID
        )
    {
        if (FxVerifierHandle) {
            return TRUE;
        }
        else {
            return FALSE;
        }
    }

    VOID
    SetVerifierState(
        __in BOOLEAN State
        )
    {
        //
        // Master switch
        //
        FxVerifierOn                = State;

        FxVerifierHandle            = State;
        FxVerifierIO                = State;
        FxVerifierLock              = State;
        FxPoolTrackingOn            = State;

        //
        // Following two can be overridden by the registry settings
        // WDFVERIFY matches the state of the verifier.
        //
        FxVerifyOn                  = State;
        FxVerifierDbgBreakOnError   = State;
        FxVerifierDbgBreakOnDeviceStateError = FALSE;

        //
        // Set the public flags for consumption by client drivers.
        //
        if (State) {
            Public.DriverFlags |= (WdfVerifyOn | WdfVerifierOn);
        }
    }

    _Must_inspect_result_
    BOOLEAN
    IsVersionGreaterThanOrEqualTo(
        __in ULONG  Major,
        __in ULONG  Minor
        );

    _Must_inspect_result_
    BOOLEAN
    IsCorrectVersionRegistered(
        _In_ PCUNICODE_STRING ServiceKeyName
        );

    VOID
    RegisterClientVersion(
        _In_ PCUNICODE_STRING ServiceKeyName
        );

    _Must_inspect_result_
    BOOLEAN
    IsVerificationEnabled(
        __in ULONG  Major,
        __in ULONG  Minor,
        __in FxVerifierDownlevelOption DownLevel
        )
    {
        //
        // those verifier checks that are restricted to specific version can be
        // applied to previous version drivers if driver opts-in by setting a
        // reg key (whose value is stored in FxVerifyDownlevel)
        //
        if (FxVerifierOn &&
            (IsVersionGreaterThanOrEqualTo(Major, Minor) ||
             (DownLevel ? FxVerifyDownlevel : FALSE))) {
            return TRUE;
        }
        else {
            return FALSE;
        }
    }

    //
    // To be used in code path where it is already determined that the driver
    // is down-level, otherwise use IsVerificationEnabled.
    //
    __inline
    _Must_inspect_result_
    BOOLEAN
    IsDownlevelVerificationEnabled(
        )
    {
        return FxVerifyDownlevel;
    }

    VOID
    WaitForSignal(
        __in MxEvent* Event,
        __in PCSTR ReasonForWaiting,
        __in PVOID Handle,
        __in ULONG WarningTimeoutInSec,
        __in ULONG WaitSignalFlags
        );

    _Must_inspect_result_
    BOOLEAN
    IsDebuggerAttached(
        VOID
        );

public:
    //
    // Link list of driver FxDriverGlobals on this WDF Version.
    //
    LIST_ENTRY Linkage;

    //
    // Reference count is operated on with interlocked operations
    //
    LONG Refcnt;

    //
    // This event is signaled when globals can be freed. Unload thread waits
    // on this event to make sure driver's threads are done and driver unload
    // can proceed.
    //
    MxEvent DestroyEvent;

    //
    // Mask to XOR all outgoing handles against
    //
    ULONG_PTR WdfHandleMask;

    //
    // If verifier is on, this is the count of allocations
    // to fail at
    //
    LONG    WdfVerifierAllocateFailCount;

    //
    // Tag to be used for allocations on behalf of the driver writer.  This is
    // based off of the service name (which might be different than the binary
    // name).
    //
    ULONG Tag;

    //
    // Backpointer to Fx driver object
    //
    FxDriver* Driver;

    FxDriverGlobalsDebugExtension* DebugExtension;

    FxLibraryGlobalsType* LibraryGlobals;

    //
    // WDF internal In-Flight Recorder (IFR) log
    //
    PVOID  WdfLogHeader;

    //
    // The driver's memory pool header
    //
    FX_POOL FxPoolFrameworks;

    //
    // Framworks Pool Tracking
    //
    BOOLEAN FxPoolTrackingOn;

    //
    // FxVerifierLock per driver state
    //
    MxLock ThreadTableLock;

    PLIST_ENTRY ThreadTable;

    //
    // Embedded pointer to driver's WDF_BIND_INFO structure (in stub)
    //
    PWDF_BIND_INFO WdfBindInfo;

    //
    // The base address of the image.
    //
    PVOID ImageAddress;

    //
    // The size of the image.
    //
    ULONG ImageSize;

    //
    // Top level verifier flag.
    //
    BOOLEAN FxVerifierOn;

    //
    // Apply latest-version-restricted verifier checks to downlevel drivers.
    // Drivers set this value in registry.
    //
    BOOLEAN FxVerifyDownlevel;

    //
    // Breakpoint on errors.
    //
    BOOLEAN FxVerifierDbgBreakOnError;

    //
    // Breakpoint on device state errors.
    //
    BOOLEAN FxVerifierDbgBreakOnDeviceStateError;

    //
    // Handle verifier.
    //
    BOOLEAN FxVerifierHandle;

    //
    // I/O verifier.
    //
    BOOLEAN FxVerifierIO;

    //
    // Lock verifier.
    //
    BOOLEAN FxVerifierLock;

    //
    // Not a verifier option.  Rather, controls whether WDFVERIFY macros are
    // live.
    //
    BOOLEAN FxVerifyOn;

    //
    // Capture IFR Verbose messages.
    //
    BOOLEAN FxVerboseOn;

    //
    // Parent queue presented requests (to device).
    //
    BOOLEAN FxRequestParentOptimizationOn;

    //
    // Enable/Disable support for device simulation framework (DSF).
    //
    BOOLEAN FxDsfOn;

    //
    // Force copy of IFR data to mini-dump when a bugcheck happens.
    //
    BOOLEAN FxForceLogsInMiniDump;

    //
    // TRUE to enable run-time driver tracking. The dump callback logic
    // uses this info for finding the right log to write in the minidump.
    //
    BOOLEAN FxTrackDriverForMiniDumpLog;

    //
    // TRUE if compiled for user-mode
    //
    BOOLEAN IsUserModeDriver;

    //
    // Remove lock options, these are also specified through
    // WdfDeviceInitSetRemoveLockOptions.
    //
    ULONG RemoveLockOptionFlags;

    //
    // Bug check callback data for kernel mode only



    //
#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE)
    //
    // 0-based index into the BugCheckDriverInfo holding this driver info.
    //
    ULONG BugCheckDriverInfoIndex;

    //
    // Bug check callback record for processing bugchecks.
    //
    KBUGCHECK_REASON_CALLBACK_RECORD BugCheckCallbackRecord;

#endif

    //
    // Enhanced Verifier Options.
    //
    ULONG FxEnhancedVerifierOptions;

    //
    // If FxVerifierDbgBreakOnError is true, WaitForSignal interrupts the
    // execution of the system after waiting for the specified number
    // of seconds. Developer will have an opportunity to validate the state
    // of the driver when breakpoint is hit. Developer can continue to wait
    // by entering 'g' in the debugger.
    //
    ULONG FxVerifierDbgWaitForSignalTimeoutInSec;

    //
    // Timeout used by the wake interrupt ISR in WaitForSignal to catch
    // scenarios where the interrupt ISR is blocked because the device stack
    // is taking too long to power up
    //
    ULONG DbgWaitForWakeInterruptIsrTimeoutInSec;

#if (FX_CORE_MODE==FX_CORE_USER_MODE)
    CWudfDriverGlobals * UfxDriverGlobals;
#endif

    PFX_TELEMETRY_CONTEXT TelemetryContext;

    //
    // The public version of WDF_DRIVER_GLOBALS
    //
    DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) WDF_DRIVER_GLOBALS  Public;

} FX_DRIVER_GLOBALS, *PFX_DRIVER_GLOBALS;

__bcount(Size)
PVOID
FORCEINLINE
FxPoolAllocate(
    __in PFX_DRIVER_GLOBALS Globals,
    __in POOL_TYPE Type,
    __in size_t Size
    )
{
    //
    // Always pass in the return address, regardless of the value of
    // Globals->WdfPoolTrackingOn.
    //
    return FxPoolAllocator(
        Globals,
        &Globals->FxPoolFrameworks,
        Type,
        Size,
        Globals->Tag,
        _ReturnAddress()
        );
}

__bcount(Size)
PVOID
FORCEINLINE
FxPoolAllocateWithTag(
    __in PFX_DRIVER_GLOBALS Globals,
    __in POOL_TYPE Type,
    __in size_t Size,
    __in ULONG Tag
    )
{
    return FxPoolAllocator(
        Globals,
        &Globals->FxPoolFrameworks,
        Type,
        Size,
        Tag,
        Globals->FxPoolTrackingOn ? _ReturnAddress() : NULL
        );
}

//
// Get FxDriverGlobals from api's DriverGlobals
//
__inline
PFX_DRIVER_GLOBALS
GetFxDriverGlobals(
    __in PWDF_DRIVER_GLOBALS DriverGlobals
    )
{
    return CONTAINING_RECORD( DriverGlobals, FX_DRIVER_GLOBALS, Public );
}

typedef struct _WDF_DRIVER_CONFIG *PWDF_DRIVER_CONFIG;

#if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE))
VOID
LockVerifierSection(
    _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
    _In_ PCUNICODE_STRING RegistryPath
    );

VOID
UnlockVerifierSection(
    _In_ PFX_DRIVER_GLOBALS FxDriverGlobals
    );
#endif

BOOLEAN
IsWindowsVerifierOn(
    _In_ MdDriverObject DriverObject
    );

_Must_inspect_result_
NTSTATUS
FxInitialize(
    __inout     PFX_DRIVER_GLOBALS FxDriverGlobals,
    __in        MdDriverObject DriverObject,
    __in        PCUNICODE_STRING RegistryPath,
    __in_opt    PWDF_DRIVER_CONFIG DriverConfig //optional in user mode
    );

VOID
FxDestroy(
    __in PFX_DRIVER_GLOBALS FxDriverGlobals
    );

_Must_inspect_result_
NTSTATUS
FxLibraryGlobalsCommission(
    VOID
    );

VOID
FxLibraryGlobalsDecommission(
    VOID
    );

VOID
FxCheckAssumptions(
    VOID
    );

void
FxVerifierLockInitialize(
    __in PFX_DRIVER_GLOBALS FxDriverGlobals
    );

void
FxVerifierLockDestroy(
    __in PFX_DRIVER_GLOBALS FxDriverGlobals
    );

_Must_inspect_result_
BOOLEAN
FxVerifierGetTrackReferences(
    __in FxObjectDebugInfo* DebugInfo,
    __in WDFTYPE ObjectType
    );

PCSTR
FxObjectTypeToHandleName(
    __in WDFTYPE ObjectType
    );

typedef
NTSTATUS
(*PFN_WMI_QUERY_TRACE_INFORMATION)(
    __in      TRACE_INFORMATION_CLASS TraceInformationClass,
    __out     PVOID TraceInformation,
    __in      ULONG TraceInformationLength,
    __out_opt PULONG RequiredLength,
    __in_opt  PVOID Buffer
    );

typedef
NTSTATUS
(*PFN_WMI_TRACE_MESSAGE_VA)(
    __in TRACEHANDLE  LoggerHandle,
    __in ULONG        MessageFlags,
    __in LPGUID       MessageGuid,
    __in USHORT       MessageNumber,
    __in va_list      MessageArgList
    );

enum FxMachineSleepStates {
    FxMachineS1Index = 0,
    FxMachineS2Index,
    FxMachineS3Index,
    FxMachineSleepStatesMax,
};

//
// Private Globals for the entire DLL

//
struct FxLibraryGlobalsType {

#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE)

    //
    // The driver object for the library.





    //
    PDRIVER_OBJECT DriverObject;

    //
    // As long as this device object is around, the library cannot be unloaded.
    // This prevents the following scenario from unloading the service
    // 1  wdfldr.sys loads the library
    // 2  user tries to run "net stop <service>" while there are outstanding clients
    //    through wdfldr
    //
    PDEVICE_OBJECT LibraryDeviceObject;

    PFN_IO_CONNECT_INTERRUPT_EX IoConnectInterruptEx;

    PFN_IO_DISCONNECT_INTERRUPT_EX IoDisconnectInterruptEx;

    PFN_KE_QUERY_ACTIVE_PROCESSORS KeQueryActiveProcessors;

    PFN_KE_SET_TARGET_PROCESSOR_DPC KeSetTargetProcessorDpc;

    PFN_KE_SET_COALESCABLE_TIMER KeSetCoalescableTimer;

    PFN_IO_UNREGISTER_PLUGPLAY_NOTIFICATION_EX IoUnregisterPlugPlayNotificationEx;

    PFN_POX_REGISTER_DEVICE PoxRegisterDevice;

    PFN_POX_START_DEVICE_POWER_MANAGEMENT PoxStartDevicePowerManagement;

    PFN_POX_UNREGISTER_DEVICE PoxUnregisterDevice;

    PFN_POX_ACTIVATE_COMPONENT PoxActivateComponent;

    PFN_POX_IDLE_COMPONENT PoxIdleComponent;

    PFN_POX_REPORT_DEVICE_POWERED_ON PoxReportDevicePoweredOn;

    PFN_POX_COMPLETE_IDLE_STATE PoxCompleteIdleState;

    PFN_POX_COMPLETE_IDLE_CONDITION PoxCompleteIdleCondition;

    PFN_POX_COMPLETE_DEVICE_POWER_NOT_REQUIRED PoxCompleteDevicePowerNotRequired;

    PFN_POX_SET_DEVICE_IDLE_TIMEOUT PoxSetDeviceIdleTimeout;

    PFN_IO_REPORT_INTERRUPT_ACTIVE IoReportInterruptActive;

    PFN_IO_REPORT_INTERRUPT_INACTIVE IoReportInterruptInactive;

    PFN_VF_CHECK_NX_POOL_TYPE VfCheckNxPoolType;

#endif

    RTL_OSVERSIONINFOEXW OsVersionInfo;

    MxLockNoDynam FxDriverGlobalsListLock;

    LIST_ENTRY   FxDriverGlobalsList;

#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE)
    //
    // Index to first free entry in BugCheckDriverInfo array.
    //
    ULONG BugCheckDriverInfoIndex;

    //
    // # of entries in BugCheckDriverInfo array.
    //
    ULONG BugCheckDriverInfoCount;

    //
    // Array of info about loaded driver. The library bugcheck callback
    // writes this data into the minidump.
    //
    PFX_DUMP_DRIVER_INFO_ENTRY   BugCheckDriverInfo;

    //
    // Library bug-check callback record for processing bugchecks.
    //
    KBUGCHECK_REASON_CALLBACK_RECORD  BugCheckCallbackRecord;

    BOOLEAN ProcessorGroupSupport;

#endif
    //
    // WPP tracing.
    //
    BOOLEAN InternalTracingInitialized;

#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE)
    //
    // The following field is used by the debug dump callback routine for
    // finding which driver's dump log file to write in the minidump if an
    // exact match is not found.
    //
    FX_DRIVER_TRACKER_CACHE_AWARE DriverTracker;

    //
    // Best driver match for the mini-dump log.
    //
    PFX_DRIVER_GLOBALS BestDriverForDumpLog;
#endif

    BOOLEAN PassiveLevelInterruptSupport;

    //
    // TRUE if compiled for user-mode
    //
    BOOLEAN IsUserModeFramework;

    //






    //

    BOOLEAN MachineSleepStates[FxMachineSleepStatesMax];

#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE)
    //
    // used for locking/unlocking Enhanced-verifier image section
    //
    PVOID VerifierSectionHandle;

    //
    // This keeps track of the # of times we pinned the paged memory down.
    // This is only used to aid debugging.
    //
    volatile LONG VerifierSectionHandleRefCount;

    //
    // Routines provided by the kernel SystemTraceProvider for perf
    // tracing of WDF operations. The size member of this structure
    // allows versioning across multiple OS versions.
    //
    //PWMI_WDF_NOTIFY_ROUTINES PerfTraceRoutines; __REACTOS__
    PVOID PerfTraceRoutines;

    //
    //  PerfTraceRoutines points here if the SystemTraceProvider failed
    //  to provide trace routines.
    //
    //WMI_WDF_NOTIFY_ROUTINES DummyPerfTraceRoutines; __REACTOS__
    PVOID DummyPerfTraceRoutines;

#endif

    //
    // Registry setting to disable IFR on low-memory systems.
    //
    BOOLEAN IfrDisabled;
};

extern FxLibraryGlobalsType FxLibraryGlobals;


typedef struct _FX_OBJECT_INFO {
    //
    // The name of the object, ie "FxObject"
    //
    const CHAR* Name;

    //
    // The name of the external WDF handle that represents the object, ie
    // WDFDEVICE.  If the object does not have an external handle, this field
    // may be NULL.
    //
    const CHAR* HandleName;

    //
    // The minimum size of the object, ie sizeof(FxObject).  There are objects
    // which allocate more than their sizeof() length.
    //
    USHORT Size;

    //
    // FX_OBJECT_TYPES value
    //
    USHORT ObjectType;

} FX_OBJECT_INFO, *PFX_OBJECT_INFO;

//
// Define to declare an internal entry.  An internal entry has no external WDF
// handle.
//
#define FX_INTERNAL_OBJECT_INFO_ENTRY(_obj, _type)  \
    { #_obj, NULL, sizeof(_obj), _type, }

//
// Define to declare an external entry.  An external entry has an external WDF
// handle.
//
// By casting #_handletype to a (_handletype), we make sure that _handletype is
// actually a valid WDF handle name.  The cast forces the parameter to be
// evaluated as true handle type vs a string (ie the # preprocesor operator).
// For instance, this would catch the following error:
//
//    FX_EXTERNAL_OBJECT_INFO_ENTRY(FxDevice, FX_TYPE_DEVICE, WDFDEVICES),
//
// because the statement would evaluate to (const CHAR*) (WDFDEVICES) "WDFDEVICES"
// and WDFDEVICES is not a valid type (WDFDEVICE is though).
//
#define FX_EXTERNAL_OBJECT_INFO_ENTRY(_obj, _type, _handletype) \
    { #_obj,                                                    \
      (const CHAR*) (_handletype) #_handletype,                 \
      sizeof(_obj),                                             \
      _type,                                                    \
    }

_Must_inspect_result_
BOOLEAN
FxVerifyObjectTypeInTable(
    __in USHORT ObjectType
    );

VOID
FxFlushQueuedDpcs(
    VOID
    );

VOID
FxFreeAllocatedMdlsDebugInfo(
    __in FxDriverGlobalsDebugExtension* DebugExtension
    );

//













//

_Must_inspect_result_
__inline
BOOLEAN
FxIsClassExtension(
    __in PFX_DRIVER_GLOBALS FxDriverGlobals,
    __in PFX_DRIVER_GLOBALS ExtDriverGlobals
    )
{
    return (FxDriverGlobals == ExtDriverGlobals) ? FALSE : TRUE;
}


_Must_inspect_result_
BOOLEAN
__inline
FxIsEqualGuid(
    __in CONST GUID* Lhs,
    __in CONST GUID* Rhs
    )
{
    return RtlCompareMemory(Lhs, Rhs, sizeof(GUID)) == sizeof(GUID);
}

__inline
size_t
FxSizeTMax(
    __in size_t A,
    __in size_t B
    )
{
    return A > B ? A : B;
}

__inline
size_t
FxSizeTMin(
    __in size_t A,
    __in size_t B
    )
{
    return A < B ? A : B;
}

__inline
LONG
FxInterlockedIncrementFloor(
    __inout LONG  volatile *Target,
    __in LONG Floor
    )
{
    LONG startVal;
    LONG currentVal;

    currentVal = *Target;

    do {
        if (currentVal <= Floor) {
            return currentVal;
        }

        startVal = currentVal;

        //
        // currentVal will be the value that used to be Target if the exchange was made
        // or its current value if the exchange was not made.
        //
        currentVal = InterlockedCompareExchange(Target, startVal+1, startVal);

        //
        // If startVal == currentVal, then no one updated Target in between the deref at the top
        // and the InterlockedCompareExchange afterward.
        //
    } while (startVal != currentVal);

    //
    // startVal is the old value of Target. Since InterlockedIncrement returns the new
    // incremented value of Target, we should do the same here.
    //
    return startVal+1;
}

__inline
LONG
FxInterlockedIncrementGTZero(
    __inout LONG  volatile *Target
    )
{
    return FxInterlockedIncrementFloor(Target, 0);
}

__inline
ULONG
FxRandom(
    __inout PULONG RandomSeed
    )
/*++

Routine Description:

    Simple threadsafe random number generator to use at DISPATCH_LEVEL
    (in kernel mode) because the system provided function RtlRandomEx
    can be called at only passive-level.

    This function requires the user to provide a variable used to seed
    the generator, and it must be valid and initialized to some number.

Return Value:

   ULONG

--*/
{
    *RandomSeed = *RandomSeed * 1103515245 + 12345;
    return (ULONG)(*RandomSeed / 65536) % 32768;
}

_Must_inspect_result_
__inline
BOOLEAN
FxIsPassiveLevelInterruptSupported(
    VOID
    )
{
    //
    // Passive-level interrupt handling is supported in Win 8 and forward.
    //
    return FxLibraryGlobals.PassiveLevelInterruptSupport;
}

__inline
_Must_inspect_result_
BOOLEAN
IsOsVersionGreaterThanOrEqualTo(
    __in ULONG Major,
    __in ULONG Minor
    )
{
    return ((FxLibraryGlobals.OsVersionInfo.dwMajorVersion > Major) ||
            ((FxLibraryGlobals.OsVersionInfo.dwMajorVersion == Major) &&
             (FxLibraryGlobals.OsVersionInfo.dwMinorVersion >= Minor)));
}

#ifdef __cplusplus
}
#endif
#endif // _FXGLOBALS_H