windows-nt/Source/XPSP1/NT/base/ntos/inc/arbiter.h

865 lines
20 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
arbiter.h
Abstract:
This module contains support routines for the Pnp resource arbiters.
Author:
Andrew Thornton (andrewth) 1-April-1997
Environment:
Kernel mode
--*/
#ifndef _ARBITER_
#define _ARBITER_
#if !defined(MAXULONGLONG)
#define MAXULONGLONG ((ULONGLONG)-1)
#endif
#if ARB_DBG
//
// Debug print level:
// -1 = no messages
// 0 = vital messages only
// 1 = call trace
// 2 = verbose messages
//
extern LONG ArbDebugLevel;
#define ARB_PRINT(Level, Message) \
if (Level <= ArbDebugLevel) DbgPrint Message
#define ARB_INDENT(Level, Count) \
if (Level < ArbDebugLevel) ArbpIndent(Count)
#else
#define ARB_PRINT(Level, Message)
#define ARB_INDENT(Level, Count)
#endif // ARB_DBG
//
// The ARBITER_ORDRING_LIST abstract data type
//
typedef struct _ARBITER_ORDERING {
ULONGLONG Start;
ULONGLONG End;
} ARBITER_ORDERING, *PARBITER_ORDERING;
typedef struct _ARBITER_ORDERING_LIST {
//
// The number of valid entries in the array
//
USHORT Count;
//
// The maximum number of entries that can fit in the Ordering buffer
//
USHORT Maximum;
//
// Array of orderings
//
PARBITER_ORDERING Orderings;
} ARBITER_ORDERING_LIST, *PARBITER_ORDERING_LIST;
NTSTATUS
ArbInitializeOrderingList(
IN OUT PARBITER_ORDERING_LIST List
);
VOID
ArbFreeOrderingList(
IN OUT PARBITER_ORDERING_LIST List
);
NTSTATUS
ArbCopyOrderingList(
OUT PARBITER_ORDERING_LIST Destination,
IN PARBITER_ORDERING_LIST Source
);
NTSTATUS
ArbAddOrdering(
OUT PARBITER_ORDERING_LIST List,
IN ULONGLONG Start,
IN ULONGLONG End
);
NTSTATUS
ArbPruneOrdering(
IN OUT PARBITER_ORDERING_LIST OrderingList,
IN ULONGLONG Start,
IN ULONGLONG End
);
//
// ULONGLONG
// ALIGN_ADDRESS_DOWN(
// ULONGLONG address,
// ULONG alignment
// );
//
// This aligns address to the previously correctly aligned value
//
#define ALIGN_ADDRESS_DOWN(address, alignment) \
((address) & ~((ULONGLONG)alignment - 1))
//
// ULONGLONG
// ALIGN_ADDRESS_UP(
// ULONGLONG address,
// ULONG alignment
// );
//
// This aligns address to the next correctly aligned value
//
#define ALIGN_ADDRESS_UP(address, alignment) \
(ALIGN_ADDRESS_DOWN( (address + alignment - 1), alignment))
#define LENGTH_OF(_start, _end) \
((_end) - (_start) + 1)
//
// This indicates that the alternative can coexist with shared resources and
// should be added to the range lists shared
//
#define ARBITER_ALTERNATIVE_FLAG_SHARED 0x00000001
//
// This indicates that the request if for a specific range with no alternatives.
// ie (End - Start + 1 == Length) eg port 60-60 L1 A1
//
#define ARBITER_ALTERNATIVE_FLAG_FIXED 0x00000002
//
// This indicates that request is invalid
//
#define ARBITER_ALTERNATIVE_FLAG_INVALID 0x00000004
typedef struct _ARBITER_ALTERNATIVE {
//
// The minimum acceptable start value from the requirement descriptor
//
ULONGLONG Minimum;
//
// The maximum acceptable end value from the requirement descriptor
//
ULONGLONG Maximum;
//
// The length from the requirement descriptor
//
ULONG Length;
//
// The alignment from the requirement descriptor
//
ULONG Alignment;
//
// Priority index - see comments below
//
LONG Priority;
//
// Flags - ARBITER_ALTERNATIVE_FLAG_SHARED - indicates the current
// requirement was for a shared resource.
// ARBITER_ALTERNATIVE_FLAG_FIXED - indicates the current
// requirement is for a specific resource (eg ports 220-230 and
// nothing else)
//
ULONG Flags;
//
// Descriptor - the descriptor describing this alternative
//
PIO_RESOURCE_DESCRIPTOR Descriptor;
//
// Packing...
//
ULONG Reserved[3];
} ARBITER_ALTERNATIVE, *PARBITER_ALTERNATIVE;
/*
The priorities are a LONG values organised as:
<------Preferred priorities-----> <-----Ordinary Priorities----->
MINLONG--------------------------0-----------------------------MAXLONG
^ ^ ^ ^
| | | |
NULL PREFERRED_RESERVED | |
RESERVED |
EXHAUSTED
An ordinary priority is calculated the (index + 1) of the next ordering it
intersects with (and has enough space for an allocation).
A preferred priority is the ordinary priority * - 1
In this way by examining each of the alternatives in priority order (lowest
first) we achieve the desired allocation order of:
(1) Preferred alternative with non-reserved resources
(2) Alternatives with non-reserved resources
(3) Preferred reserved resources
(4) Reserved Resources
MAXLONG the worst priority indicates that there are no more allocation range
left.
*/
//
// The least significant 16 bits are reserved for the base arbitration code
// the most significant are arbiter specific
//
#define ARBITER_STATE_FLAG_RETEST 0x0001
#define ARBITER_STATE_FLAG_BOOT 0x0002
#define ARBITER_STATE_FLAG_CONFLICT 0x0004
#define ARBITER_STATE_FLAG_NULL_CONFLICT_OK 0x0008
typedef struct _ARBITER_ALLOCATION_STATE {
//
// The current value being considered as a possible start value
//
ULONGLONG Start;
//
// The current value being considered as a possible end value
//
ULONGLONG End;
//
// The values currently being considered as the Minimum and Maximum (this is
// different because the prefered orderings can restrict the ranges where
// we can allocate)
//
ULONGLONG CurrentMinimum;
ULONGLONG CurrentMaximum;
//
// The entry in the arbitration list containing this request.
//
PARBITER_LIST_ENTRY Entry;
//
// The alternative currently being considered
//
PARBITER_ALTERNATIVE CurrentAlternative;
//
// The number of alternatives in the Alternatives array
//
ULONG AlternativeCount;
//
// The arbiters representation of the alternatives being considered
//
PARBITER_ALTERNATIVE Alternatives;
//
// Flags - ARBITER_STATE_FLAG_RETEST - indicates that we are in a retest
// operation not a test.
// ARBITER_STATE_FLAG_BOOT - indicates we are in a boot allocation
// operation not a test.
//
USHORT Flags;
//
// RangeAttributes - these are logically ORed in to the attributes for all
// ranges added to the range list.
//
UCHAR RangeAttributes;
//
// Ranges that are to be considered available
//
UCHAR RangeAvailableAttributes;
//
// Space for the arbiter to use as it wishes
//
ULONG_PTR WorkSpace;
} ARBITER_ALLOCATION_STATE, *PARBITER_ALLOCATION_STATE;
typedef struct _ARBITER_INSTANCE ARBITER_INSTANCE, *PARBITER_INSTANCE;
typedef
NTSTATUS
(*PARBITER_UNPACK_REQUIREMENT) (
IN PIO_RESOURCE_DESCRIPTOR Descriptor,
OUT PULONGLONG Minimum,
OUT PULONGLONG Maximum,
OUT PULONG Length,
OUT PULONG Alignment
);
typedef
NTSTATUS
(*PARBITER_PACK_RESOURCE) (
IN PIO_RESOURCE_DESCRIPTOR Requirement,
IN ULONGLONG Start,
OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor
);
typedef
NTSTATUS
(*PARBITER_UNPACK_RESOURCE) (
IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor,
OUT PULONGLONG Start,
OUT PULONG Length
);
typedef
LONG
(*PARBITER_SCORE_REQUIREMENT) (
IN PIO_RESOURCE_DESCRIPTOR Descriptor
);
typedef
NTSTATUS
(*PARBITER_PREPROCESS_ENTRY)(
IN PARBITER_INSTANCE Arbiter,
IN PARBITER_ALLOCATION_STATE Entry
);
typedef
NTSTATUS
(*PARBITER_ALLOCATE_ENTRY)(
IN PARBITER_INSTANCE Arbiter,
IN PARBITER_ALLOCATION_STATE Entry
);
typedef
NTSTATUS
(*PARBITER_TEST_ALLOCATION)(
IN PARBITER_INSTANCE Arbiter,
IN OUT PLIST_ENTRY ArbitrationList
);
typedef
NTSTATUS
(*PARBITER_COMMIT_ALLOCATION)(
IN PARBITER_INSTANCE Arbiter
);
typedef
NTSTATUS
(*PARBITER_ROLLBACK_ALLOCATION)(
IN PARBITER_INSTANCE Arbiter
);
typedef
NTSTATUS
(*PARBITER_RETEST_ALLOCATION)(
IN PARBITER_INSTANCE Arbiter,
IN OUT PLIST_ENTRY ArbitrationList
);
typedef
NTSTATUS
(*PARBITER_BOOT_ALLOCATION)(
IN PARBITER_INSTANCE Arbiter,
IN OUT PLIST_ENTRY ArbitrationList
);
typedef
NTSTATUS
(*PARBITER_ADD_RESERVED)(
IN PARBITER_INSTANCE Arbiter,
IN PIO_RESOURCE_DESCRIPTOR Requirement OPTIONAL,
IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Resource OPTIONAL
);
typedef
BOOLEAN
(*PARBITER_GET_NEXT_ALLOCATION_RANGE)(
PARBITER_INSTANCE Arbiter,
PARBITER_ALLOCATION_STATE State
);
typedef
BOOLEAN
(*PARBITER_FIND_SUITABLE_RANGE)(
IN PARBITER_INSTANCE Arbiter,
IN PARBITER_ALLOCATION_STATE State
);
typedef
VOID
(*PARBITER_ADD_ALLOCATION)(
IN PARBITER_INSTANCE Arbiter,
IN PARBITER_ALLOCATION_STATE State
);
typedef
VOID
(*PARBITER_BACKTRACK_ALLOCATION)(
IN PARBITER_INSTANCE Arbiter,
IN PARBITER_ALLOCATION_STATE State
);
typedef
BOOLEAN
(*PARBITER_OVERRIDE_CONFLICT)(
IN PARBITER_INSTANCE Arbiter,
IN PARBITER_ALLOCATION_STATE State
);
typedef
NTSTATUS
(*PARBITER_QUERY_ARBITRATE)(
IN PARBITER_INSTANCE Arbiter,
IN PLIST_ENTRY ArbitrationList
);
typedef
NTSTATUS
(*PARBITER_QUERY_CONFLICT)(
IN PARBITER_INSTANCE Arbiter,
IN PDEVICE_OBJECT PhysicalDeviceObject,
IN PIO_RESOURCE_DESCRIPTOR ConflictingResource,
OUT PULONG ConflictCount,
OUT PARBITER_CONFLICT_INFO *Conflicts
);
typedef
NTSTATUS
(*PARBITER_START_ARBITER)(
IN PARBITER_INSTANCE Arbiter,
IN PCM_RESOURCE_LIST StartResources
);
//
// Attributes for the ranges
//
#define ARBITER_RANGE_BOOT_ALLOCATED 0x01
#define ARBITER_RANGE_SHARE_DRIVER_EXCLUSIVE 0x02
#define ARBITER_RANGE_ALIAS 0x10
#define ARBITER_RANGE_POSITIVE_DECODE 0x20
#define INITIAL_ALLOCATION_STATE_SIZE PAGE_SIZE
#define ARBITER_INSTANCE_SIGNATURE 'sbrA'
typedef struct _ARBITER_INSTANCE {
//
// Signature - must be ARBITER_INSTANCE_SIGNATURE
//
ULONG Signature;
//
// Synchronisation lock
//
PKEVENT MutexEvent;
//
// The name of this arbiter - used for debugging and registry storage
//
PWSTR Name;
//
// The resource type this arbiter arbitrates.
//
CM_RESOURCE_TYPE ResourceType;
//
// Pointer to a pool allocated range list which contains the current
// allocation
//
PRTL_RANGE_LIST Allocation;
//
// Pointer to a pool allocated range list which contains the allocation
// under considetation. This is set by test allocation.
//
PRTL_RANGE_LIST PossibleAllocation;
//
// The order in which these resources should be allocated. Taken from the
// HKLM\System\CurrentControlSet\Control\SystemResources\AssignmentOrdering
// key and modified based on the reserved resources.
//
ARBITER_ORDERING_LIST OrderingList;
//
// The resources that should be reserved (not allocated until absolutley
// necessary)
//
ARBITER_ORDERING_LIST ReservedList;
//
// The reference count of the number of entities that are using the
// ARBITER_INTERFACE associated with this instance.
//
LONG ReferenceCount;
//
// The ARBITER_INTERFACE associated with this instance.
//
PARBITER_INTERFACE Interface;
//
// The size in bytes of the currently allocated AllocationStack
//
ULONG AllocationStackMaxSize;
//
// A pointer to an array of ARBITER_ALLOCATION_STATE entries encapsulating
// the state of the current arbitration
//
PARBITER_ALLOCATION_STATE AllocationStack;
//
// Required helper function dispatches - these functions must always be
// provided
//
PARBITER_UNPACK_REQUIREMENT UnpackRequirement;
PARBITER_PACK_RESOURCE PackResource;
PARBITER_UNPACK_RESOURCE UnpackResource;
PARBITER_SCORE_REQUIREMENT ScoreRequirement;
//
// Main arbiter action dispatches
//
PARBITER_TEST_ALLOCATION TestAllocation; OPTIONAL
PARBITER_RETEST_ALLOCATION RetestAllocation; OPTIONAL
PARBITER_COMMIT_ALLOCATION CommitAllocation; OPTIONAL
PARBITER_ROLLBACK_ALLOCATION RollbackAllocation; OPTIONAL
PARBITER_BOOT_ALLOCATION BootAllocation; OPTIONAL
PARBITER_QUERY_ARBITRATE QueryArbitrate; OPTIONAL
PARBITER_QUERY_CONFLICT QueryConflict; OPTIONAL
PARBITER_ADD_RESERVED AddReserved; OPTIONAL
PARBITER_START_ARBITER StartArbiter; OPTIONAL
//
// Optional helper functions
//
PARBITER_PREPROCESS_ENTRY PreprocessEntry; OPTIONAL
PARBITER_ALLOCATE_ENTRY AllocateEntry; OPTIONAL
PARBITER_GET_NEXT_ALLOCATION_RANGE GetNextAllocationRange; OPTIONAL
PARBITER_FIND_SUITABLE_RANGE FindSuitableRange; OPTIONAL
PARBITER_ADD_ALLOCATION AddAllocation; OPTIONAL
PARBITER_BACKTRACK_ALLOCATION BacktrackAllocation; OPTIONAL
PARBITER_OVERRIDE_CONFLICT OverrideConflict; OPTIONAL
//
// Debugging support
//
BOOLEAN TransactionInProgress;
//
// Arbiter specific extension - can be used to store extra arbiter specific
// information
//
PVOID Extension;
//
// The bus device we arbitrate for
//
PDEVICE_OBJECT BusDeviceObject;
//
// Callback and context for RtlFindRange/RtlIsRangeAvailable to allow
// complex conflicts
//
PVOID ConflictCallbackContext;
PRTL_CONFLICT_RANGE_CALLBACK ConflictCallback;
} ARBITER_INSTANCE, *PARBITER_INSTANCE;
//
// Lock primitives that leave us at PASSIVE_LEVEL after acquiring the lock.
// (A FAST_MUTEX or CriticalRegion leave us at APC level and some people (ACPI)
// need to be at passive level in their arbiter)
//
#define ArbAcquireArbiterLock(_Arbiter) \
KeWaitForSingleObject( (_Arbiter)->MutexEvent, Executive, KernelMode, FALSE, NULL )
#define ArbReleaseArbiterLock(_Arbiter) \
KeSetEvent( (_Arbiter)->MutexEvent, 0, FALSE )
//
// Iteration macros
//
//
// Control macro (used like a for loop) which iterates over all entries in
// a standard doubly linked list. Head is the list head and the entries are of
// type Type. A member called ListEntry is assumed to be the LIST_ENTRY
// structure linking the entries together. Current contains a pointer to each
// entry in turn.
//
#define FOR_ALL_IN_LIST(Type, Head, Current) \
for((Current) = CONTAINING_RECORD((Head)->Flink, Type, ListEntry); \
(Head) != &(Current)->ListEntry; \
(Current) = CONTAINING_RECORD((Current)->ListEntry.Flink, \
Type, \
ListEntry) \
)
//
// Similar to the above only iteration is over an array of length _Size.
//
#define FOR_ALL_IN_ARRAY(_Array, _Size, _Current) \
for ( (_Current) = (_Array); \
(_Current) < (_Array) + (_Size); \
(_Current)++ )
//
// As above only iteration begins with the entry _Current
//
#define FOR_REST_IN_ARRAY(_Array, _Size, _Current) \
for ( ; \
(_Current) < (_Array) + (_Size); \
(_Current)++ )
//
// BOOLEAN
// INTERSECT(
// ULONGLONG s1,
// ULONGLONG e1,
// ULONGLONG s2,
// ULONGLONG e2
// );
//
// Determines if the ranges s1-e1 and s2-e2 intersect
//
#define INTERSECT(s1,e1,s2,e2) \
!( ((s1) < (s2) && (e1) < (s2)) \
||((s2) < (s1) && (e2) < (s1)) )
//
// ULONGLONG
// INTERSECT_SIZE(
// ULONGLONG s1,
// ULONGLONG e1,
// ULONGLONG s2,
// ULONGLONG e2
// );
//
// Returns the size of the intersection of s1-e1 and s2-e2, undefined if they
// don't intersect
//
#define INTERSECT_SIZE(s1,e1,s2,e2) \
( __min((e1),(e2)) - __max((s1),(s2)) + 1)
#define LEGACY_REQUEST(_Entry) \
((_Entry)->RequestSource == ArbiterRequestLegacyReported || \
(_Entry)->RequestSource == ArbiterRequestLegacyAssigned)
#define PNP_REQUEST(_Entry) \
((_Entry)->RequestSource == ArbiterRequestPnpDetected || \
(_Entry)->RequestSource == ArbiterRequestPnpEnumerated)
//
// Priorities used in ArbGetNextAllocationRange
//
#define ARBITER_PRIORITY_NULL 0
#define ARBITER_PRIORITY_PREFERRED_RESERVED (MAXLONG-2)
#define ARBITER_PRIORITY_RESERVED (MAXLONG-1)
#define ARBITER_PRIORITY_EXHAUSTED (MAXLONG)
typedef
NTSTATUS
(*PARBITER_TRANSLATE_ALLOCATION_ORDER)(
OUT PIO_RESOURCE_DESCRIPTOR TranslatedDescriptor,
IN PIO_RESOURCE_DESCRIPTOR RawDescriptor
);
//
// Common arbiter routines
//
NTSTATUS
ArbInitializeArbiterInstance(
OUT PARBITER_INSTANCE Arbiter,
IN PDEVICE_OBJECT BusDevice,
IN CM_RESOURCE_TYPE ResourceType,
IN PWSTR Name,
IN PWSTR OrderingName,
IN PARBITER_TRANSLATE_ALLOCATION_ORDER TranslateOrdering
);
VOID
ArbDeleteArbiterInstance(
IN PARBITER_INSTANCE Arbiter
);
NTSTATUS
ArbArbiterHandler(
IN PVOID Context,
IN ARBITER_ACTION Action,
IN OUT PARBITER_PARAMETERS Params
);
NTSTATUS
ArbTestAllocation(
IN PARBITER_INSTANCE Arbiter,
IN OUT PLIST_ENTRY ArbitrationList
);
NTSTATUS
ArbRetestAllocation(
IN PARBITER_INSTANCE Arbiter,
IN OUT PLIST_ENTRY ArbitrationList
);
NTSTATUS
ArbCommitAllocation(
PARBITER_INSTANCE Arbiter
);
NTSTATUS
ArbRollbackAllocation(
PARBITER_INSTANCE Arbiter
);
NTSTATUS
ArbAddReserved(
IN PARBITER_INSTANCE Arbiter,
IN PIO_RESOURCE_DESCRIPTOR Requirement OPTIONAL,
IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Resource OPTIONAL
);
NTSTATUS
ArbPreprocessEntry(
IN PARBITER_INSTANCE Arbiter,
IN PARBITER_ALLOCATION_STATE State
);
NTSTATUS
ArbAllocateEntry(
IN PARBITER_INSTANCE Arbiter,
IN PARBITER_ALLOCATION_STATE State
);
NTSTATUS
ArbSortArbitrationList(
IN OUT PLIST_ENTRY ArbitrationList
);
VOID
ArbConfirmAllocation(
IN PARBITER_INSTANCE Arbiter,
IN PARBITER_ALLOCATION_STATE State
);
BOOLEAN
ArbOverrideConflict(
IN PARBITER_INSTANCE Arbiter,
IN PARBITER_ALLOCATION_STATE State
);
NTSTATUS
ArbQueryConflict(
IN PARBITER_INSTANCE Arbiter,
IN PDEVICE_OBJECT PhysicalDeviceObject,
IN PIO_RESOURCE_DESCRIPTOR ConflictingResource,
OUT PULONG ConflictCount,
OUT PARBITER_CONFLICT_INFO *Conflicts
);
VOID
ArbBacktrackAllocation(
IN PARBITER_INSTANCE Arbiter,
IN PARBITER_ALLOCATION_STATE State
);
BOOLEAN
ArbGetNextAllocationRange(
PARBITER_INSTANCE Arbiter,
PARBITER_ALLOCATION_STATE State
);
BOOLEAN
ArbFindSuitableRange(
PARBITER_INSTANCE Arbiter,
PARBITER_ALLOCATION_STATE State
);
VOID
ArbAddAllocation(
IN PARBITER_INSTANCE Arbiter,
IN PARBITER_ALLOCATION_STATE State
);
NTSTATUS
ArbBootAllocation(
IN PARBITER_INSTANCE Arbiter,
IN OUT PLIST_ENTRY ArbitrationList
);
NTSTATUS
ArbStartArbiter(
IN PARBITER_INSTANCE Arbiter,
IN PCM_RESOURCE_LIST StartResources
);
NTSTATUS
ArbBuildAssignmentOrdering(
IN OUT PARBITER_INSTANCE Arbiter,
IN PWSTR AllocationOrderName,
IN PWSTR ReservedResourcesName,
IN PARBITER_TRANSLATE_ALLOCATION_ORDER Translate OPTIONAL
);
#if ARB_DBG
VOID
ArbpIndent(
ULONG Count
);
#endif // DBG
#endif