ReactOS 0.4.17-dev-806-gffa4164
range.c File Reference
#include <ntifs.h>
#include <ndk/rtlfuncs.h>
#include "arbiter.h"
#include <debug.h>
Include dependency graph for range.c:

Go to the source code of this file.

Macros

#define NDEBUG
 
#define ARBITER_RESERVED_PASS_DONE   0xFFFFFFFF
 

Functions

BOOLEAN NTAPI ArbiterLibOverrideConflict (_In_ PARBITER_INSTANCE Arbiter, _Inout_ PARBITER_ALLOCATION_STATE ArbState)
 The OverrideConflict default, the last of the conflict escapes: grants a FIXED requirement whose window conflicts only with ranges the requesting device itself already owns.
 
static VOID ArbpWritePriority (_In_ PARBITER_INSTANCE Arbiter, _Inout_ PARBITER_ALTERNATIVE Alternative)
 Writes an alternative's priority to the next ordering-list range it can be satisfied from.
 
static BOOLEAN ArbpIsRootEnumerated (_In_ PDEVICE_OBJECT DeviceObject)
 Determines whether a device is enumerated by the root enumerator.
 
static BOOLEAN ArbpSharesDriverStack (_In_ PDEVICE_OBJECT DeviceA, _In_ PDEVICE_OBJECT DeviceB)
 Determines whether a common driver is loaded on both device stacks, above the physical device objects.
 
static BOOLEAN ArbpShareDriverExclusive (_In_ PARBITER_INSTANCE Arbiter, _Inout_ PARBITER_ALLOCATION_STATE ArbState)
 Attempts last-chance sharing for a CmResourceShareDriverExclusive requirement whose window RtlFindRange found occupied.
 
static BOOLEAN ArbpReuseOwnedInterrupt (_In_ PARBITER_INSTANCE Arbiter, _Inout_ PARBITER_ALLOCATION_STATE ArbState)
 Hands a device back its own already routed IRQ instead of searching for a fresh one, on legacy-PIC / no-ACPI interrupt routing setups.
 
static BOOLEAN ArbpTakeReservedWindow (_In_ PARBITER_INSTANCE Arbiter, _Inout_ PARBITER_ALTERNATIVE Alternative, _Out_ PUINT64 Minimum, _Out_ PUINT64 Maximum)
 Takes the next window of the reserved (last-resort) pass for an alternative: each ReservedList range intersecting the requirement in turn, then one final try over the whole requirement window.
 
BOOLEAN NTAPI ArbiterLibGetNextAllocationRange (_In_ PARBITER_INSTANCE Arbiter, _Inout_ PARBITER_ALLOCATION_STATE ArbState)
 Moves the working window to the next candidate range, walking the entry's alternatives in priority order across the arbiter's ordering list.
 
BOOLEAN NTAPI ArbiterLibFindSuitableRange (_In_ PARBITER_INSTANCE Arbiter, _Inout_ PARBITER_ALLOCATION_STATE ArbState)
 Finds a free range of the current candidate window in the arbiter's tentative allocation list.
 
VOID NTAPI ArbiterLibAddAllocation (_In_ PARBITER_INSTANCE Arbiter, _Inout_ PARBITER_ALLOCATION_STATE ArbState)
 Records the chosen placement in the arbiter's tentative allocation list, owned by the requesting device.
 
VOID NTAPI ArbiterLibBacktrackAllocation (_In_ PARBITER_INSTANCE Arbiter, _Inout_ PARBITER_ALLOCATION_STATE ArbState)
 Undoes the last AddAllocation performed for this entry.
 

Macro Definition Documentation

◆ ARBITER_RESERVED_PASS_DONE

#define ARBITER_RESERVED_PASS_DONE   0xFFFFFFFF

Definition at line 19 of file range.c.

◆ NDEBUG

#define NDEBUG

Definition at line 14 of file range.c.

Function Documentation

◆ ArbiterLibAddAllocation()

VOID NTAPI ArbiterLibAddAllocation ( _In_ PARBITER_INSTANCE  Arbiter,
_Inout_ PARBITER_ALLOCATION_STATE  ArbState 
)

Records the chosen placement in the arbiter's tentative allocation list, owned by the requesting device.

Parameters
[in]ArbiterThe arbiter instance whose PossibleAllocation list receives the range.
[in,out]ArbStateThe allocation state whose Start, End and RangeAttributes describe the placement. The range is owned by the entry's physical device object.
Remarks
ADD_IF_CONFLICT is required because override solutions intentionally overlap existing ranges.

Definition at line 828 of file range.c.

831{
833
834 PAGED_CODE();
835
836 if (ArbState->CurrentAlternative != NULL &&
837 (ArbState->CurrentAlternative->Flags & ARBITER_ALTERNATIVE_FLAG_SHARED))
838 {
840 }
841
842 RtlAddRange(Arbiter->PossibleAllocation,
843 ArbState->Start,
844 ArbState->End,
845 ArbState->RangeAttributes,
846 Flags,
847 NULL,
848 ArbState->Entry ? ArbState->Entry->PhysicalDeviceObject : NULL);
849}
#define PAGED_CODE()
#define ARBITER_ALTERNATIVE_FLAG_SHARED
Definition: arbiter.h:31
_In_ D3DDDI_VIDEO_PRESENT_TARGET_ID _In_ ULONG _In_ ULONG Flags
Definition: dispmprt.h:245
#define NULL
Definition: types.h:112
NTSYSAPI NTSTATUS NTAPI RtlAddRange(_Inout_ PRTL_RANGE_LIST RangeList, _In_ ULONGLONG Start, _In_ ULONGLONG End, _In_ UCHAR Attributes, _In_ ULONG Flags, _In_opt_ PVOID UserData, _In_opt_ PVOID Owner)
#define RTL_RANGE_LIST_ADD_IF_CONFLICT
Definition: rtltypes.h:81
#define RTL_RANGE_LIST_ADD_SHARED
Definition: rtltypes.h:82
uint32_t ULONG
Definition: typedefs.h:59

Referenced by ArbiterLibInitializeInstance().

◆ ArbiterLibBacktrackAllocation()

VOID NTAPI ArbiterLibBacktrackAllocation ( _In_ PARBITER_INSTANCE  Arbiter,
_Inout_ PARBITER_ALLOCATION_STATE  ArbState 
)

Undoes the last AddAllocation performed for this entry.

Parameters
[in]ArbiterThe arbiter instance whose PossibleAllocation list the tentative range is deleted from.
[in,out]ArbStateThe allocation state whose Start and End describe the placement being removed sanity checked by the entry's physical device object.

Definition at line 866 of file range.c.

869{
870 PAGED_CODE();
871
872 RtlDeleteRange(Arbiter->PossibleAllocation,
873 ArbState->Start,
874 ArbState->End,
875 ArbState->Entry ? ArbState->Entry->PhysicalDeviceObject : NULL);
876}
NTSYSAPI NTSTATUS NTAPI RtlDeleteRange(_Inout_ PRTL_RANGE_LIST RangeList, _In_ ULONGLONG Start, _In_ ULONGLONG End, _In_ PVOID Owner)

Referenced by ArbiterLibInitializeInstance().

◆ ArbiterLibFindSuitableRange()

BOOLEAN NTAPI ArbiterLibFindSuitableRange ( _In_ PARBITER_INSTANCE  Arbiter,
_Inout_ PARBITER_ALLOCATION_STATE  ArbState 
)

Finds a free range of the current candidate window in the arbiter's tentative allocation list.

Parameters
[in]ArbiterThe arbiter instance whose PossibleAllocation list is searched.
[in,out]ArbStateThe allocation state of the entry being placed. On success, Start and End receive the chosen window.
Returns
Returns TRUE if a placement was found,FALSE if the window cannot satisfy the requirement.
Remarks
Legacy requests treat boot-allocated ranges as available. When RtlFindRange reports a conflict, a driver-exclusive requirement may still share the range (ArbpShareDriverExclusive), and failing that the arbiter's OverrideConflict callback gets a last-chance override. this is how a device is re-assigned its own boot configuration.

Definition at line 717 of file range.c.

720{
721 PARBITER_ALTERNATIVE Alternative = ArbState->CurrentAlternative;
722 ULONG Flags = 0;
724
725 PAGED_CODE();
726
727 if (Alternative == NULL)
728 return FALSE;
729
730 if (ArbState->CurrentMinimum > ArbState->CurrentMaximum)
731 return FALSE;
732
733 if (Alternative->Length == 0)
734 {
735 ArbState->Start = ArbState->CurrentMinimum;
736 ArbState->End = ArbState->CurrentMinimum;
737 return TRUE;
738 }
739
740 /*
741 * Interrupt retention: give the device back its firmware-routed vector rather
742 * than letting the top-down search pick an untranslatable one
743 */
744 if (ArbpReuseOwnedInterrupt(Arbiter, ArbState))
745 return TRUE;
746
747 /* Legacy requests consider preallocated (boot) ranges available. */
748 if (ArbState->Entry != NULL &&
749 (ArbState->Entry->RequestSource == ArbiterRequestLegacyReported ||
750 ArbState->Entry->RequestSource == ArbiterRequestLegacyAssigned))
751 {
752 ArbState->RangeAvailableAttributes |= ARBITER_RANGE_BOOT_ALLOCATED;
753 }
754
755 if (ArbState->Flags & ARBITER_STATE_FLAG_NULL_CONFLICT_OK)
757 if (Alternative->Flags & ARBITER_ALTERNATIVE_FLAG_SHARED)
760 ArbState->RangeAvailableAttributes |= ARBITER_RANGE_INACCESSIBLE;
761
762 Status = RtlFindRange(Arbiter->PossibleAllocation,
763 ArbState->CurrentMinimum,
764 ArbState->CurrentMaximum,
765 Alternative->Length,
766 max(Alternative->Alignment, 1),
767 Flags,
768 ArbState->RangeAvailableAttributes,
769 Arbiter->ConflictCallbackContext,
770 Arbiter->ConflictCallback,
771 &ArbState->Start);
772 if (!NT_SUCCESS(Status))
773 {
774 /*
775 * The window is occupied. A CmResourceShareDriverExclusive requirement
776 * can still succeed by sharing the conflicting range with the same driver
777 * or another root-enumerated device
778 *
779 * This matters a lot because HAL reverses quite a bit and marks it this.
780 * This mechanism is how Windows "internally allows this".
781 */
782 if (ArbpShareDriverExclusive(Arbiter, ArbState))
783 return TRUE;
784 if (Arbiter->OverrideConflict != NULL &&
785 Arbiter->OverrideConflict(Arbiter, ArbState))
786 {
787 return TRUE;
788 }
789
790 /*
791 * A window that only fails because it runs into the MMCONFIG region
792 * points at the firmware's MCFG table rather than at any device.
793 */
794 if (ArbiterLibIsConflictWithMmConfigRange(ArbState->CurrentMinimum,
795 ArbState->CurrentMaximum))
796 {
797 ArbState->Flags |= ARBITER_STATE_FLAG_MCFG_CONFLICT;
798 }
799
800 return FALSE;
801 }
802
803 ArbState->End = ArbState->Start + Alternative->Length - 1;
804 return TRUE;
805}
#define ARBITER_STATE_FLAG_NULL_CONFLICT_OK
Definition: arbiter.h:60
#define ARBITER_STATE_FLAG_MCFG_CONFLICT
Definition: arbiter.h:62
#define ARBITER_RANGE_INACCESSIBLE
Definition: arbiter.h:56
#define ARBITER_ALTERNATIVE_FLAG_INACCESSIBLE_OK
Definition: arbiter.h:34
BOOLEAN NTAPI ArbiterLibIsConflictWithMmConfigRange(_In_ ULONGLONG Start, _In_ ULONGLONG End)
Determines whether a range overlaps the recorded MMCONFIG window.
Definition: ordering.c:689
#define ARBITER_RANGE_BOOT_ALLOCATED
Definition: arbiter.h:53
LONG NTSTATUS
Definition: precomp.h:26
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
Status
Definition: gdiplustypes.h:24
NTSYSAPI NTSTATUS NTAPI RtlFindRange(_In_ PRTL_RANGE_LIST RangeList, _In_ ULONGLONG Minimum, _In_ ULONGLONG Maximum, _In_ ULONGLONG Length, _In_ ULONGLONG Alignment, _In_ ULONG Flags, _In_ UCHAR AttributeAvailableMask, _In_opt_ PVOID Context, _In_opt_ PRTL_CONFLICT_RANGE_CALLBACK Callback, _Out_ PULONGLONG Start)
#define RTL_RANGE_LIST_NULL_CONFLICT_OK
Definition: rtltypes.h:90
#define RTL_RANGE_LIST_SHARED_OK
Definition: rtltypes.h:89
static BOOLEAN ArbpShareDriverExclusive(_In_ PARBITER_INSTANCE Arbiter, _Inout_ PARBITER_ALLOCATION_STATE ArbState)
Attempts last-chance sharing for a CmResourceShareDriverExclusive requirement whose window RtlFindRan...
Definition: range.c:300
static BOOLEAN ArbpReuseOwnedInterrupt(_In_ PARBITER_INSTANCE Arbiter, _Inout_ PARBITER_ALLOCATION_STATE ArbState)
Hands a device back its own already routed IRQ instead of searching for a fresh one,...
Definition: range.c:401
#define max(a, b)
Definition: svc.c:63
@ ArbiterRequestLegacyAssigned
Definition: iotypes.h:4619
@ ArbiterRequestLegacyReported
Definition: iotypes.h:4617

Referenced by ArbiterLibInitializeInstance(), IopArbMemFindSuitableRange(), and IopArbPortFindSuitableRange().

◆ ArbiterLibGetNextAllocationRange()

BOOLEAN NTAPI ArbiterLibGetNextAllocationRange ( _In_ PARBITER_INSTANCE  Arbiter,
_Inout_ PARBITER_ALLOCATION_STATE  ArbState 
)

Moves the working window to the next candidate range, walking the entry's alternatives in priority order across the arbiter's ordering list.

Parameters
[in]ArbiterThe arbiter instance whose ordering list supplies the candidate windows.
[in,out]ArbStateThe allocation state of the entry being placed. On success, CurrentMinimum, CurrentMaximum and CurrentAlternative describe the next window to search; the window is pre-trimmed so an aligned allocation of the required length fits inside it.
Returns
Returns TRUE if a new candidate window was produced, FALSE once every alternative is exhausted.

Definition at line 562 of file range.c.

565{
566 PARBITER_ALTERNATIVE Alternative;
568 UINT64 Minimum, Maximum;
569
570 PAGED_CODE();
571
572 if (ArbState->AlternativeCount == 0)
573 return FALSE;
574
575 for (;;)
576 {
577 /* Advance the alternative we last worked on, or seed all on first entry. */
578 if (ArbState->CurrentAlternative != NULL)
579 {
580 ArbpWritePriority(Arbiter, ArbState->CurrentAlternative);
581 }
582 else
583 {
584 for (Alternative = ArbState->Alternatives;
585 Alternative < &ArbState->Alternatives[ArbState->AlternativeCount];
586 ++Alternative)
587 {
588 Alternative->Priority = ARBITER_PRIORITY_NULL;
589 ArbpWritePriority(Arbiter, Alternative);
590 }
591 }
592
593 /* Pick the best (lowest-priority) alternative. */
594 Lowest = ArbState->Alternatives;
595 for (Alternative = ArbState->Alternatives + 1;
596 Alternative < &ArbState->Alternatives[ArbState->AlternativeCount];
597 ++Alternative)
598 {
599 if (Alternative->Priority < Lowest->Priority)
600 Lowest = Alternative;
601 }
602
604 return FALSE;
605
606 if (Lowest->Priority == ARBITER_PRIORITY_RESERVED ||
608 {
609 /*
610 * Last-resort pass: the reserved windows in turn, then the whole
611 * requirement window (see ArbpTakeReservedWindow).
612 */
613 if (!ArbpTakeReservedWindow(Arbiter, Lowest, &Minimum, &Maximum))
614 {
615 /*
616 * CurrentAlternative must be set before looping. While it is
617 * still NULL, the top of the loop re-seeds every alternative's
618 * priority back to ARBITER_PRIORITY_NULL, which would discard
619 * the EXHAUSTED just recorded and spin forever.
620 */
622 ArbState->CurrentAlternative = Lowest;
623 continue;
624 }
625 }
626 else
627 {
628 PARBITER_ORDERING Ordering;
629 ULONG Index = (Lowest->Priority < 0) ? (ULONG)(-(Lowest->Priority + 1))
630 : (ULONG)(Lowest->Priority - 1);
631 if (Index >= Arbiter->OrderingList.Count)
632 {
634 ArbState->CurrentAlternative = Lowest;
635 continue;
636 }
637 Ordering = &Arbiter->OrderingList.Orderings[Index];
638 Minimum = max(Lowest->Minimum, Ordering->Start);
639 Maximum = min(Lowest->Maximum, Ordering->End);
640 }
641
642 /*
643 * Trim the window so an aligned allocation of the required length is
644 * possible; skip the window entirely if it cannot hold one.
645 */
646 if (Lowest->Length != 0)
647 {
648 UINT64 Alignment = Lowest->Alignment ? Lowest->Alignment : 1;
649 UINT64 LengthMinusOne = Lowest->Length - 1;
650 UINT64 AlignedMax;
651
652 Minimum += Alignment - 1;
653 Minimum -= Minimum % Alignment;
654
655 if (Minimum > Maximum || LengthMinusOne > Maximum - Minimum)
656 {
657 ArbState->CurrentAlternative = Lowest; /* consume this priority */
658 continue;
659 }
660
661 AlignedMax = Maximum - LengthMinusOne;
662 AlignedMax -= AlignedMax % Alignment;
663 if (AlignedMax < Minimum)
664 {
665 ArbState->CurrentAlternative = Lowest; /* no aligned start fits */
666 continue;
667 }
668 Maximum = AlignedMax + LengthMinusOne;
669 }
670 else
671 {
672 Minimum = Lowest->Minimum;
673 Maximum = Lowest->Maximum;
674 }
675
676 if (Minimum != ArbState->CurrentMinimum ||
677 Maximum != ArbState->CurrentMaximum ||
678 ArbState->CurrentAlternative != Lowest)
679 {
680 ArbState->CurrentMinimum = Minimum;
681 ArbState->CurrentMaximum = Maximum;
682 ArbState->CurrentAlternative = Lowest;
683 return TRUE;
684 }
685
686 ArbState->CurrentAlternative = Lowest;
687 }
688}
COMPILER_DEPENDENT_UINT64 UINT64
Definition: actypes.h:131
#define ARBITER_PRIORITY_NULL
Definition: arbiter.h:25
#define ARBITER_PRIORITY_RESERVED
Definition: arbiter.h:27
#define ARBITER_PRIORITY_EXHAUSTED
Definition: arbiter.h:28
#define ARBITER_PRIORITY_PREFERRED_RESERVED
Definition: arbiter.h:26
union Alignment_ Alignment
#define min(a, b)
Definition: monoChain.cc:55
static BOOLEAN ArbpTakeReservedWindow(_In_ PARBITER_INSTANCE Arbiter, _Inout_ PARBITER_ALTERNATIVE Alternative, _Out_ PUINT64 Minimum, _Out_ PUINT64 Maximum)
Takes the next window of the reserved (last-resort) pass for an alternative: each ReservedList range ...
Definition: range.c:472
static VOID ArbpWritePriority(_In_ PARBITER_INSTANCE Arbiter, _Inout_ PARBITER_ALTERNATIVE Alternative)
Writes an alternative's priority to the next ordering-list range it can be satisfied from.
Definition: range.c:116
UINT64 Start
Definition: arbiter.h:99
_In_ WDFCOLLECTION _In_ ULONG Index

Referenced by ArbiterLibInitializeInstance().

◆ ArbiterLibOverrideConflict()

BOOLEAN NTAPI ArbiterLibOverrideConflict ( _In_ PARBITER_INSTANCE  Arbiter,
_Inout_ PARBITER_ALLOCATION_STATE  ArbState 
)

The OverrideConflict default, the last of the conflict escapes: grants a FIXED requirement whose window conflicts only with ranges the requesting device itself already owns.

Parameters
[in]ArbiterThe arbiter instance whose tentative allocation list is walked.
[in,out]ArbStateThe allocation state of the requirement. On a grant, Start and End receive the requested window.
Returns
Returns TRUE if at least one conflicting range was found and every one of them is owned by the requesting device, FALSE if any conflict belongs to someone else (or to no one).
Remarks
A fixed requirement has one possible placement, so when re-arbitration finds that window occupied by the device's own earlier reservation, there is nowhere else to move it and the self-conflict has to be allowed.

Definition at line 48 of file range.c.

51{
53 PRTL_RANGE Range;
54 BOOLEAN SelfConflictOnly = FALSE;
55
56 PAGED_CODE();
57
58 /*
59 * Only a fixed requirement may reclaim its window. Anything else still
60 * has other placements to try, and letting it overlap would hide
61 * real conflicts.
62 */
63 if (ArbState->CurrentAlternative == NULL ||
64 !(ArbState->CurrentAlternative->Flags & ARBITER_ALTERNATIVE_FLAG_FIXED))
65 {
66 return FALSE;
67 }
68
69 if (ArbState->Entry == NULL || ArbState->Entry->PhysicalDeviceObject == NULL)
70 return FALSE;
71
72 if (!NT_SUCCESS(RtlGetFirstRange(Arbiter->PossibleAllocation, &Iterator, &Range)))
73 return FALSE;
74
75 while (Range != NULL)
76 {
77 /* A range that overlaps the window and is not made available. */
78 if (Range->Start <= ArbState->CurrentMaximum &&
79 Range->End >= ArbState->CurrentMinimum &&
80 !(Range->Attributes & ArbState->RangeAvailableAttributes))
81 {
82 if ((PDEVICE_OBJECT)Range->Owner != ArbState->Entry->PhysicalDeviceObject)
83 return FALSE;
84
85 SelfConflictOnly = TRUE;
86 ArbState->Start = ArbState->CurrentMinimum;
87 ArbState->End = ArbState->CurrentMaximum;
88 }
89
90 if (!NT_SUCCESS(RtlGetNextRange(&Iterator, &Range, TRUE)))
91 break;
92 }
93
94 return SelfConflictOnly;
95}
unsigned char BOOLEAN
Definition: actypes.h:127
#define ARBITER_ALTERNATIVE_FLAG_FIXED
Definition: arbiter.h:32
NTSYSAPI NTSTATUS NTAPI RtlGetNextRange(_Inout_ PRTL_RANGE_LIST_ITERATOR Iterator, _Outptr_ PRTL_RANGE *Range, _In_ BOOLEAN MoveForwards)
NTSYSAPI NTSTATUS NTAPI RtlGetFirstRange(_In_ PRTL_RANGE_LIST RangeList, _Out_ PRTL_RANGE_LIST_ITERATOR Iterator, _Outptr_ PRTL_RANGE *Range)
ULONGLONG End
Definition: rtltypes.h:1497
ULONGLONG Start
Definition: rtltypes.h:1496
UCHAR Attributes
Definition: rtltypes.h:1500
PVOID Owner
Definition: rtltypes.h:1499
_In_ WDFCHILDLIST _In_ PWDF_CHILD_LIST_ITERATOR Iterator
Definition: wdfchildlist.h:656

Referenced by ArbiterLibInitializeInstance().

◆ ArbpIsRootEnumerated()

static BOOLEAN ArbpIsRootEnumerated ( _In_ PDEVICE_OBJECT  DeviceObject)
static

Determines whether a device is enumerated by the root enumerator.

Parameters
[in]DeviceObjectThe physical device object to examine. May be NULL, in which case the device is not considered root-enumerated.
Returns
Returns TRUE if the device's enumerator name is "ROOT", FALSE otherwise or if the property cannot be read.

Definition at line 208 of file range.c.

210{
211 WCHAR Buffer[16];
214 ULONG Length = 0;
215
216 PAGED_CODE();
217
218 if (DeviceObject == NULL)
219 return FALSE;
220
222 sizeof(Buffer), Buffer, &Length)))
223 {
224 return FALSE;
225 }
226
229}
Definition: bufpool.h:45
LPWSTR Name
Definition: desk.c:124
#define RTL_CONSTANT_STRING(s)
Definition: combase.c:35
#define L(x)
Definition: resources.c:13
@ Root
Definition: cmtypes.h:261
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
NTSYSAPI BOOLEAN NTAPI RtlEqualUnicodeString(PUNICODE_STRING String1, PUNICODE_STRING String2, BOOLEAN CaseInSensitive)
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
short WCHAR
Definition: pedump.c:58
NTSTATUS NTAPI IoGetDeviceProperty(IN PDEVICE_OBJECT DeviceObject, IN DEVICE_REGISTRY_PROPERTY DeviceProperty, IN ULONG BufferLength, OUT PVOID PropertyBuffer, OUT PULONG ResultLength)
Definition: pnpmgr.c:1382
_In_ PDEVICE_OBJECT DeviceObject
Definition: wdfdevice.h:2061
@ DevicePropertyEnumeratorName
Definition: iotypes.h:1210

Referenced by ArbpShareDriverExclusive().

◆ ArbpReuseOwnedInterrupt()

static BOOLEAN ArbpReuseOwnedInterrupt ( _In_ PARBITER_INSTANCE  Arbiter,
_Inout_ PARBITER_ALLOCATION_STATE  ArbState 
)
static

Hands a device back its own already routed IRQ instead of searching for a fresh one, on legacy-PIC / no-ACPI interrupt routing setups.

Parameters
[in]ArbiterThe arbiter instance. The routine is a no-op for every resource type other than CmResourceTypeInterrupt.
[in,out]ArbStateThe allocation state of the requirement. On success, Start and End receive the vector this device already owns in the committed allocation list.
Returns
Returns TRUE if an owned vector inside the requested window was found and reused, FALSE otherwise.
Remarks
pci.sys emits line-based interrupt requirement of (MinimumVector 0, MaximumVector 0xFFFFFFFF) which expects an upstream ACPI _PRT arbiter to clamp it to the routed GSIV. With no ACPI the root IRQ arbiter is the only one in the tree, and RtlFindRange searches top-down so a loose window resolves to 0xFFFFFFFF. But the BIOS already handled each device's IRQ which pci.sys reports as the device's boot config; the boot reservation recorded it as a [Vector, Vector] range owned by this PDO in the committed list, and every later commit re-records the assigned vector the same way. Reusing that vector keeps the device on the interrupt the firmware wired it to.

Definition at line 401 of file range.c.

404{
405 PARBITER_LIST_ENTRY Entry = ArbState->Entry;
406 PARBITER_ALTERNATIVE Alternative = ArbState->CurrentAlternative;
408 PRTL_RANGE Range;
409
410 PAGED_CODE();
411
412 if (Arbiter->ResourceType != CmResourceTypeInterrupt)
413 return FALSE;
414
415 if (Entry == NULL || Entry->PhysicalDeviceObject == NULL || Alternative == NULL)
416 return FALSE;
417
418 if (!NT_SUCCESS(RtlGetFirstRange(Arbiter->Allocation, &Iterator, &Range)))
419 return FALSE;
420
421 while (Range != NULL)
422 {
423 if ((PDEVICE_OBJECT)Range->Owner == Entry->PhysicalDeviceObject &&
424 Range->Start >= ArbState->CurrentMinimum &&
425 Range->Start <= ArbState->CurrentMaximum &&
426 Range->End <= ArbState->CurrentMaximum &&
427 (Range->End - Range->Start + 1) >= Alternative->Length)
428 {
429 ArbState->Start = Range->Start;
430 ArbState->End = Range->Start + Alternative->Length - 1;
431 return TRUE;
432 }
433
434 if (!NT_SUCCESS(RtlGetNextRange(&Iterator, &Range, TRUE)))
435 break;
436 }
437
438 return FALSE;
439}
#define CmResourceTypeInterrupt
Definition: restypes.h:105
Entry
Definition: section.c:5216
Definition: iotypes.h:4633

Referenced by ArbiterLibFindSuitableRange().

◆ ArbpShareDriverExclusive()

static BOOLEAN ArbpShareDriverExclusive ( _In_ PARBITER_INSTANCE  Arbiter,
_Inout_ PARBITER_ALLOCATION_STATE  ArbState 
)
static

Attempts last-chance sharing for a CmResourceShareDriverExclusive requirement whose window RtlFindRange found occupied.

Parameters
[in]ArbiterThe arbiter instance whose tentative allocation list is walked for an overlapping, owned, not-already-available range that the request is allowed to share.
[in,out]ArbStateThe allocation state of the requirement. On success, Start and End receive the requested window and the range attributes are tagged ARBITER_RANGE_SHARED_DRIVER for a driver-exclusive requirement.
Returns
Returns TRUE if the conflicting range may be shared with the requester, FALSE if the conflict is real.
Remarks
"DriverExclusive" excludes only OTHER drivers: the SAME driver may share the resource across its devices, and two root-enumerated ("ROOT") devices may share it. This is how a device claims a resource the HAL/firmware reports for the same hardware Example: the ports the kernel debugger reserves, which the HAL marks DriverExclusive.

Definition at line 300 of file range.c.

303{
304 PARBITER_LIST_ENTRY Entry = ArbState->Entry;
305 PDEVICE_OBJECT Requester;
307 PRTL_RANGE Range;
308 BOOLEAN RequesterIsRoot;
309
310 PAGED_CODE();
311
312 if (Entry == NULL || Entry->PhysicalDeviceObject == NULL ||
313 ArbState->CurrentAlternative == NULL)
314 {
315 return FALSE;
316 }
317
318 Requester = Entry->PhysicalDeviceObject;
319 RequesterIsRoot = ArbpIsRootEnumerated(Requester);
320
321 if (!NT_SUCCESS(RtlGetFirstRange(Arbiter->PossibleAllocation, &Iterator, &Range)))
322 return FALSE;
323
324 while (Range != NULL)
325 {
326 /*
327 * Candidate: overlaps the requested window, is not already made available
328 * by attribute, and either the request or the range is driver-exclusive.
329 */
330 if (Range->Start <= ArbState->CurrentMaximum &&
331 Range->End >= ArbState->CurrentMinimum &&
332 !(Range->Attributes & ArbState->RangeAvailableAttributes) &&
333 (ArbState->CurrentAlternative->Descriptor->ShareDisposition == CmResourceShareDriverExclusive ||
335 Range->Owner != NULL)
336 {
338 BOOLEAN Share = FALSE;
339
340 /* Two root-enumerated devices may share; else only a shared driver. */
341 if (RequesterIsRoot && ArbpIsRootEnumerated(Owner))
342 Share = TRUE;
343 else if (ArbpSharesDriverStack(Requester, Owner))
344 Share = TRUE;
345
346 if (Share)
347 {
348 ArbState->Start = ArbState->CurrentMinimum;
349 ArbState->End = ArbState->CurrentMaximum;
350 if (ArbState->CurrentAlternative->Descriptor->ShareDisposition ==
352 {
353 ArbState->RangeAttributes |= ARBITER_RANGE_SHARED_DRIVER;
354 }
355 return TRUE;
356 }
357 }
358
359 if (!NT_SUCCESS(RtlGetNextRange(&Iterator, &Range, TRUE)))
360 break;
361 }
362
363 return FALSE;
364}
#define ARBITER_RANGE_SHARED_DRIVER
Definition: arbiter.h:54
struct _DEVICE_OBJECT * PDEVICE_OBJECT
if(dx< 0)
Definition: linetemp.h:194
_Out_writes_bytes_to_opt_ AbsoluteSecurityDescriptorSize PSECURITY_DESCRIPTOR _Inout_ PULONG _Out_writes_bytes_to_opt_ DaclSize PACL _Inout_ PULONG _Out_writes_bytes_to_opt_ SaclSize PACL _Inout_ PULONG _Out_writes_bytes_to_opt_ OwnerSize PSID Owner
Definition: rtlfuncs.h:1629
static BOOLEAN ArbpSharesDriverStack(_In_ PDEVICE_OBJECT DeviceA, _In_ PDEVICE_OBJECT DeviceB)
Determines whether a common driver is loaded on both device stacks, above the physical device objects...
Definition: range.c:249
static BOOLEAN ArbpIsRootEnumerated(_In_ PDEVICE_OBJECT DeviceObject)
Determines whether a device is enumerated by the root enumerator.
Definition: range.c:208
@ CmResourceShareDriverExclusive
Definition: cmtypes.h:242

Referenced by ArbiterLibFindSuitableRange().

◆ ArbpSharesDriverStack()

static BOOLEAN ArbpSharesDriverStack ( _In_ PDEVICE_OBJECT  DeviceA,
_In_ PDEVICE_OBJECT  DeviceB 
)
static

Determines whether a common driver is loaded on both device stacks, above the physical device objects.

Parameters
[in]DeviceAThe first physical device object whose attached stack is walked.
[in]DeviceBThe second physical device object whose attached stack is walked.
Returns
Returns TRUE if any driver attached above DeviceA also appears above DeviceB, FALSE otherwise.

Definition at line 249 of file range.c.

252{
254
255 PAGED_CODE();
256
257 for (A = DeviceA->AttachedDevice; A != NULL; A = A->AttachedDevice)
258 {
259 for (B = DeviceB->AttachedDevice; B != NULL; B = B->AttachedDevice)
260 {
261 if (A->DriverObject == B->DriverObject)
262 return TRUE;
263 }
264 }
265
266 return FALSE;
267}
Definition: ehthrow.cxx:93
Definition: ehthrow.cxx:54
#define A(row, col)
#define B(row, col)

Referenced by ArbpShareDriverExclusive().

◆ ArbpTakeReservedWindow()

static BOOLEAN ArbpTakeReservedWindow ( _In_ PARBITER_INSTANCE  Arbiter,
_Inout_ PARBITER_ALTERNATIVE  Alternative,
_Out_ PUINT64  Minimum,
_Out_ PUINT64  Maximum 
)
static

Takes the next window of the reserved (last-resort) pass for an alternative: each ReservedList range intersecting the requirement in turn, then one final try over the whole requirement window.

Parameters
[in]ArbiterThe arbiter instance whose ReservedList supplies the windows.
[in,out]AlternativeThe alternative in its reserved pass. Reserved[0] holds the pass cursor: the next ReservedList index to consider, or ARBITER_RESERVED_PASS_DONE once the whole-window try is spent.
[out]MinimumReceives the start of the produced window.
[out]MaximumReceives the end of the produced window.
Returns
Returns TRUE with a window to try, FALSE when the pass is spent.
Remarks
Once ReservedResources data populates the ReservedList, its windows are only ever offered here.

Definition at line 472 of file range.c.

477{
478 ULONG Index;
479
480 PAGED_CODE();
481
482 if (Alternative->Reserved[0] == ARBITER_RESERVED_PASS_DONE)
483 return FALSE;
484
485 for (Index = Alternative->Reserved[0];
486 Index < Arbiter->ReservedList.Count;
487 ++Index)
488 {
489 PARBITER_ORDERING Window = &Arbiter->ReservedList.Orderings[Index];
490 UINT64 Lo, Hi;
491
492 if (Window->Start > Alternative->Maximum ||
493 Alternative->Minimum > Window->End)
494 {
495 continue; /* No intersection with this alternative's window */
496 }
497
498 Lo = max(Alternative->Minimum, Window->Start);
499 Hi = min(Alternative->Maximum, Window->End);
500 if ((Hi - Lo + 1) < Alternative->Length)
501 continue;
502
503 Alternative->Reserved[0] = Index + 1;
504 *Minimum = Lo;
505 *Maximum = Hi;
506 return TRUE;
507 }
508
509 /*
510 * Reserved windows exhausted. A final whole-window pass follows
511 * turns on FIXED, and either answer is wrong for the other case.
512 *
513 * A flexible alternative must not get one: [Minimum, Maximum] ignores both
514 * the ordering and the reserved list, re-granting the ranges the reserved
515 * pass had just punched out. A bridge's [0, 0xFFFFFFFF] memory window
516 * searched against an empty pool resolves to 0, placing the window on top
517 * of RAM.
518 *
519 * A fixed alternative must get one: it has a single possible placement, so
520 * the whole window is that candidate. Withholding it goes straight to
521 * EXHAUSTED without ever calling FindSuitableRange, so neither the
522 * boot-allocated availability mask nor OverrideConflict can grant the
523 * device its own firmware configuration. That is fatal whenever no
524 * ordering window spans the requirement, as the root port list's does not
525 * below 0x100.
526 */
527 Alternative->Reserved[0] = ARBITER_RESERVED_PASS_DONE;
528
529 if (Alternative->Flags & ARBITER_ALTERNATIVE_FLAG_FIXED)
530 {
531 *Minimum = Alternative->Minimum;
532 *Maximum = Alternative->Maximum;
533 return TRUE;
534 }
535
536 return FALSE;
537}
#define ARBITER_RESERVED_PASS_DONE
Definition: range.c:19
Definition: window.c:29

Referenced by ArbiterLibGetNextAllocationRange().

◆ ArbpWritePriority()

static VOID ArbpWritePriority ( _In_ PARBITER_INSTANCE  Arbiter,
_Inout_ PARBITER_ALTERNATIVE  Alternative 
)
static

Writes an alternative's priority to the next ordering-list range it can be satisfied from.

Parameters
[in]ArbiterThe arbiter instance whose ordering list is walked.
[in,out]AlternativeThe alternative whose priority is written. Ordinary priorities are ordering-list indices biased by one, negated for IO_RESOURCE_PREFERRED alternatives so they sort first. Once the orderings are exhausted the alternative is given one final full-range pass at (PREFERRED_)RESERVED priority, after which it goes EXHAUSTED.

Definition at line 116 of file range.c.

119{
120 PARBITER_ORDERING Ordering;
122 INT32 Priority = Alternative->Priority;
123 BOOLEAN Preferred;
124 ULONG Index;
125
126 PAGED_CODE();
127
129 return;
130
133 {
134 /* Stay in the reserved pass until its final whole-window try is spent. */
135 if (Alternative->Reserved[0] == ARBITER_RESERVED_PASS_DONE)
136 Alternative->Priority = ARBITER_PRIORITY_EXHAUSTED;
137 return;
138 }
139
140 Preferred = (Alternative->Descriptor->Option & IO_RESOURCE_PREFERRED) != 0;
141
143 {
144 Ordering = Arbiter->OrderingList.Orderings;
145 }
146 else
147 {
148 /* A fixed alternative fits in exactly one place; it gets a single shot. */
149 if (Alternative->Flags & ARBITER_ALTERNATIVE_FLAG_FIXED)
150 {
151 Alternative->Priority = ARBITER_PRIORITY_EXHAUSTED;
152 return;
153 }
154
155 Index = (Priority < 0) ? (ULONG)(-(Priority + 1)) : (ULONG)(Priority - 1);
156 if (Index >= Arbiter->OrderingList.Count)
157 {
158 Alternative->Reserved[0] = 0;
159 Alternative->Priority = Preferred ? ARBITER_PRIORITY_PREFERRED_RESERVED
161 return;
162 }
163 Ordering = &Arbiter->OrderingList.Orderings[Index + 1];
164 }
165
166 End = &Arbiter->OrderingList.Orderings[Arbiter->OrderingList.Count];
167 for (; Ordering < End; ++Ordering)
168 {
169 UINT64 Start, RangeEnd;
170
171 if (Ordering->Start > Alternative->Maximum ||
172 Alternative->Minimum > Ordering->End)
173 {
174 continue; /* No intersection with this alternative's window */
175 }
176
177 Start = max(Alternative->Minimum, Ordering->Start);
178 RangeEnd = min(Alternative->Maximum, Ordering->End);
179
180 if ((RangeEnd - Start + 1) >= Alternative->Length)
181 {
182 INT32 NewPriority = (INT32)(Ordering - Arbiter->OrderingList.Orderings) + 1;
183 Alternative->Priority = Preferred ? -NewPriority : NewPriority;
184 return;
185 }
186 }
187
188 Alternative->Reserved[0] = 0;
189 Alternative->Priority = Preferred ? ARBITER_PRIORITY_PREFERRED_RESERVED
191}
static _Out_opt_ PULONGLONG Start
int32_t INT32
Definition: typedefs.h:58
_In_ WDFINTERRUPT _In_ WDF_INTERRUPT_POLICY _In_ WDF_INTERRUPT_PRIORITY Priority
Definition: wdfinterrupt.h:655
#define IO_RESOURCE_PREFERRED

Referenced by ArbiterLibGetNextAllocationRange().