ReactOS 0.4.17-dev-806-gffa4164
arbiter.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS Arbitration Library
3 * LICENSE: MIT (https://spdx.org/licenses/MIT)
4 * PURPOSE: Generic Arbiter Library
5 * COPYRIGHT: Copyright 2026 Justin Miller <justin.miller@reactos.org>
6 */
7
8/* INCLUDES *******************************************************************/
9
10#include <ntifs.h>
11#include <ndk/rtlfuncs.h>
12#include "arbiter.h"
13
14#define NDEBUG
15#include <debug.h>
16
17#define ARBITER_SIG 'sbrA'
18
19CODE_SEG("PAGE")
20VOID
23 _In_ PARBITER_INSTANCE Arbiter)
24{
25 PAGED_CODE();
26
27 if (Arbiter->PossibleAllocation)
28 {
29 RtlFreeRangeList(Arbiter->PossibleAllocation);
30 ExFreePoolWithTag(Arbiter->PossibleAllocation, TAG_ARBITER);
31 Arbiter->PossibleAllocation = NULL;
32 }
33
34 if (Arbiter->Allocation)
35 {
36 RtlFreeRangeList(Arbiter->Allocation);
37 ExFreePoolWithTag(Arbiter->Allocation, TAG_ARBITER);
38 Arbiter->Allocation = NULL;
39 }
40
41 if (Arbiter->AllocationStack)
42 {
43 ExFreePoolWithTag(Arbiter->AllocationStack, TAG_ARBITER);
44 Arbiter->AllocationStack = NULL;
45 Arbiter->AllocationStackMaxSize = 0;
46 }
47
48 ArbiterLibFreeOrderingList(&Arbiter->OrderingList);
49 ArbiterLibFreeOrderingList(&Arbiter->ReservedList);
50
51#if (NTDDI_VERSION >= NTDDI_VISTA)
52 if (Arbiter->TransactionEvent)
53 {
54 ExFreePoolWithTag(Arbiter->TransactionEvent, TAG_ARBITER);
55 Arbiter->TransactionEvent = NULL;
56 }
57#endif
58
59 if (Arbiter->MutexEvent)
60 {
61 ExFreePoolWithTag(Arbiter->MutexEvent, TAG_ARBITER);
62 Arbiter->MutexEvent = NULL;
63 }
64}
65
66CODE_SEG("PAGE")
71 _In_ PDEVICE_OBJECT BusDeviceObject,
72 _In_ CM_RESOURCE_TYPE ResourceType,
73 _In_ PCWSTR ArbiterName,
74 _In_ PCWSTR OrderName,
75 _In_ PARB_TRANSLATE_ORDERING TranslateOrderingFunction)
76{
78
79 PAGED_CODE();
80
81 DPRINT("ArbiterLibInitializeInstance: '%S'\n", ArbiterName);
82
83 ASSERT(Arbiter->UnpackRequirement != NULL);
84 ASSERT(Arbiter->PackResource != NULL);
85 ASSERT(Arbiter->UnpackResource != NULL);
86 ASSERT(Arbiter->MutexEvent == NULL);
87 ASSERT(Arbiter->Allocation == NULL);
88 ASSERT(Arbiter->PossibleAllocation == NULL);
89 ASSERT(Arbiter->AllocationStack == NULL);
90
91 Arbiter->Signature = ARBITER_SIG;
92 Arbiter->BusDeviceObject = BusDeviceObject;
93 Arbiter->Name = ArbiterName;
94 Arbiter->ResourceType = ResourceType;
95 Arbiter->TransactionInProgress = FALSE;
96#if (NTDDI_VERSION >= NTDDI_VISTA)
97 Arbiter->OrderingName = OrderName;
98#endif
99
100 /* The per-instance lock: a signaled synchronization event used as a mutex. */
101 Arbiter->MutexEvent = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_ARBITER);
102 if (!Arbiter->MutexEvent)
103 {
105 goto Failure;
106 }
107 KeInitializeEvent(Arbiter->MutexEvent, SynchronizationEvent, TRUE);
108
109#if (NTDDI_VERSION >= NTDDI_VISTA)
110 /* Vista+: a notification event exposing whether a Test is outstanding. */
111 Arbiter->TransactionEvent = ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_ARBITER);
112 if (!Arbiter->TransactionEvent)
113 {
115 goto Failure;
116 }
117 KeInitializeEvent(Arbiter->TransactionEvent, NotificationEvent, TRUE);
118#endif
119
120 Arbiter->AllocationStack = ExAllocatePoolWithTag(PagedPool, PAGE_SIZE, TAG_ARBITER);
121 if (!Arbiter->AllocationStack)
122 {
124 goto Failure;
125 }
126 Arbiter->AllocationStackMaxSize = PAGE_SIZE;
127 Arbiter->Allocation = ExAllocatePoolWithTag(PagedPool, sizeof(RTL_RANGE_LIST), TAG_ARBITER);
128 if (!Arbiter->Allocation)
129 {
131 goto Failure;
132 }
133 RtlInitializeRangeList(Arbiter->Allocation);
134
135 Arbiter->PossibleAllocation = ExAllocatePoolWithTag(PagedPool, sizeof(RTL_RANGE_LIST), TAG_ARBITER);
136 if (!Arbiter->PossibleAllocation)
137 {
139 goto Failure;
140 }
141 RtlInitializeRangeList(Arbiter->PossibleAllocation);
142
143 if (!Arbiter->TestAllocation)
144 Arbiter->TestAllocation = ArbiterLibTestAllocation;
145 if (!Arbiter->RetestAllocation)
146 Arbiter->RetestAllocation = ArbiterLibRetestAllocation;
147 if (!Arbiter->CommitAllocation)
148 Arbiter->CommitAllocation = ArbiterLibCommitAllocation;
149 if (!Arbiter->RollbackAllocation)
150 Arbiter->RollbackAllocation = ArbiterLibRollbackAllocation;
151 if (!Arbiter->BootAllocation)
152 Arbiter->BootAllocation = ArbiterLibBootAllocation;
153 if (!Arbiter->AddReserved)
154 Arbiter->AddReserved = ArbiterLibAddReserved;
155 if (!Arbiter->QueryConflict)
156 Arbiter->QueryConflict = ArbiterLibQueryConflict;
157 if (!Arbiter->QueryArbitrate)
158 Arbiter->QueryArbitrate = ArbiterLibQueryArbitrate;
159 if (!Arbiter->StartArbiter)
160 Arbiter->StartArbiter = ArbiterLibStartArbiter;
161 if (!Arbiter->PreprocessEntry)
162 Arbiter->PreprocessEntry = ArbiterLibPreprocessEntry;
163 if (!Arbiter->AllocateEntry)
164 Arbiter->AllocateEntry = ArbiterLibAllocateEntry;
165 if (!Arbiter->GetNextAllocationRange)
166 Arbiter->GetNextAllocationRange = ArbiterLibGetNextAllocationRange;
167 if (!Arbiter->FindSuitableRange)
168 Arbiter->FindSuitableRange = ArbiterLibFindSuitableRange;
169 if (!Arbiter->AddAllocation)
170 Arbiter->AddAllocation = ArbiterLibAddAllocation;
171 if (!Arbiter->BacktrackAllocation)
172 Arbiter->BacktrackAllocation = ArbiterLibBacktrackAllocation;
173 if (!Arbiter->OverrideConflict)
174 Arbiter->OverrideConflict = ArbiterLibOverrideConflict;
175#if (NTDDI_VERSION >= NTDDI_VISTA)
176 if (!Arbiter->InitializeRangeList)
177 Arbiter->InitializeRangeList = ArbiterLibInitializeRangeList;
178#endif
179
180 Status = ArbiterLibDefaultAssignmentOrdering(Arbiter, OrderName, OrderName, TranslateOrderingFunction);
181 if (!NT_SUCCESS(Status))
182 {
183 DPRINT1("ArbiterLibInitializeInstance: ArbiterLibDefaultAssignmentOrdering failed, Status %X\n", Status);
184 goto Failure;
185 }
186
187 return STATUS_SUCCESS;
188
189Failure:
190 DPRINT1("ArbiterLibInitializeInstance: '%S' failed, Status %X\n", ArbiterName, Status);
192 return Status;
193}
#define PAGED_CODE()
#define CODE_SEG(...)
VOID NTAPI ArbiterLibDeleteInstance(_In_ PARBITER_INSTANCE Arbiter)
Definition: arbiter.c:22
#define ARBITER_SIG
Definition: arbiter.c:17
NTSTATUS NTAPI ArbiterLibInitializeInstance(_Inout_ PARBITER_INSTANCE Arbiter, _In_ PDEVICE_OBJECT BusDeviceObject, _In_ CM_RESOURCE_TYPE ResourceType, _In_ PCWSTR ArbiterName, _In_ PCWSTR OrderName, _In_ PARB_TRANSLATE_ORDERING TranslateOrderingFunction)
Definition: arbiter.c:69
NTSTATUS NTAPI ArbiterLibBootAllocation(_In_ PARBITER_INSTANCE Arbiter, _Inout_ PARBITER_BOOT_ALLOCATION_PARAMETERS Parameters)
The BootAllocation action: records every entry's firmware boot configuration in the committed allocat...
Definition: transaction.c:684
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 or...
Definition: range.c:562
NTSTATUS NTAPI ArbiterLibInitializeRangeList(_In_ PARBITER_INSTANCE Arbiter, _In_ ULONG ResourceCount, _In_ PCM_PARTIAL_RESOURCE_DESCRIPTOR Resources, _Inout_ PRTL_RANGE_LIST RangeList)
The InitializeRangeList callback default.
Definition: handler.c:440
NTSTATUS NTAPI ArbiterLibAllocateEntry(_In_ PARBITER_INSTANCE Arbiter, _Inout_ PARBITER_ALLOCATION_STATE ArbState)
Places the whole stack of entries with backtracking: when an entry cannot be placed,...
Definition: entry.c:223
NTSTATUS NTAPI ArbiterLibRetestAllocation(_In_ PARBITER_INSTANCE Arbiter, _Inout_ PARBITER_RETEST_ALLOCATION_PARAMETERS Parameters)
The RetestAllocation action: deterministically re-establishes the placements a previous test chose,...
Definition: transaction.c:483
NTSTATUS(NTAPI * PARB_TRANSLATE_ORDERING)(_Out_ PIO_RESOURCE_DESCRIPTOR OutIoDescriptor, _In_ PIO_RESOURCE_DESCRIPTOR IoDescriptor)
Definition: arbiter.h:278
NTSTATUS NTAPI ArbiterLibTestAllocation(_In_ PARBITER_INSTANCE Arbiter, _Inout_ PARBITER_TEST_ALLOCATION_PARAMETERS Parameters)
The TestAllocation action: tentatively places every entry of the arbitration list,...
Definition: transaction.c:447
NTSTATUS NTAPI ArbiterLibAddReserved(_In_ PARBITER_INSTANCE Arbiter, _Inout_ PARBITER_ADD_RESERVED_PARAMETERS Parameters)
The AddReserved action default: nothing to reserve.
Definition: handler.c:112
VOID NTAPI ArbiterLibBacktrackAllocation(_In_ PARBITER_INSTANCE Arbiter, _Inout_ PARBITER_ALLOCATION_STATE ArbState)
Undoes the last AddAllocation performed for this entry.
Definition: range.c:866
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.
Definition: range.c:717
NTSTATUS NTAPI ArbiterLibQueryArbitrate(_In_ PARBITER_INSTANCE Arbiter, _Inout_ PARBITER_QUERY_ARBITRATE_PARAMETERS Parameters)
The QueryArbitrate action default: reports that this arbiter is willing to arbitrate the given list.
Definition: handler.c:73
#define TAG_ARBITER
Definition: arbiter.h:10
NTSTATUS NTAPI ArbiterLibCommitAllocation(_In_ PARBITER_INSTANCE Arbiter)
The CommitAllocation action: the tentative PossibleAllocation becomes the committed Allocation,...
Definition: transaction.c:515
NTSTATUS NTAPI ArbiterLibRollbackAllocation(_In_ PARBITER_INSTANCE Arbiter)
The RollbackAllocation action: discards the tentative allocation; the committed one is untouched.
Definition: transaction.c:543
NTSTATUS NTAPI ArbiterLibPreprocessEntry(_In_ PARBITER_INSTANCE Arbiter, _Inout_ PARBITER_ALLOCATION_STATE ArbState)
Per-entry hook invoked before each placement attempt. The library default does nothing and succeeds.
Definition: entry.c:38
NTSTATUS NTAPI ArbiterLibStartArbiter(_In_ PARBITER_INSTANCE Arbiter, _In_ PCM_RESOURCE_LIST StartResources)
The StartArbiter action default: seeds the committed allocation with the windows the bus decodes,...
Definition: handler.c:470
NTSTATUS NTAPI ArbiterLibDefaultAssignmentOrdering(_Inout_ PARBITER_INSTANCE Arbiter, _In_ PCWSTR AllocationOrderName, _In_ PCWSTR ReservedResourcesName, _In_opt_ PARB_TRANSLATE_ORDERING TranslateOrderingFunction)
Builds the arbiter's allocation ordering from the registry policy, most-preferred window first.
Definition: ordering.c:571
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 wind...
Definition: range.c:48
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 devi...
Definition: range.c:828
VOID NTAPI ArbiterLibFreeOrderingList(_Inout_ PARBITER_ORDERING_LIST OrderingList)
Definition: ordering.c:60
NTSTATUS NTAPI ArbiterLibQueryConflict(_In_ PARBITER_INSTANCE Arbiter, _Inout_ PARBITER_QUERY_CONFLICT_PARAMETERS Parameters)
The QueryConflict action: reports which devices' committed ranges collide with a candidate resource.
Definition: transaction.c:937
LONG NTSTATUS
Definition: precomp.h:26
#define DPRINT1
Definition: precomp.h:8
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
#define KeInitializeEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:477
#define PAGE_SIZE
Definition: env_spec_w32.h:49
#define NonPagedPool
Definition: env_spec_w32.h:307
#define PagedPool
Definition: env_spec_w32.h:308
Status
Definition: gdiplustypes.h:24
#define ASSERT(a)
Definition: mode.c:44
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1109
NTSYSAPI VOID NTAPI RtlInitializeRangeList(_Out_ PRTL_RANGE_LIST RangeList)
NTSYSAPI VOID NTAPI RtlFreeRangeList(_In_ PRTL_RANGE_LIST RangeList)
#define _Inout_
Definition: no_sal2.h:162
#define _In_
Definition: no_sal2.h:158
@ NotificationEvent
@ SynchronizationEvent
#define STATUS_SUCCESS
Definition: shellext.h:65
#define DPRINT
Definition: sndvol32.h:73
const uint16_t * PCWSTR
Definition: typedefs.h:57
#define NTAPI
Definition: typedefs.h:36
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158