ReactOS 0.4.17-dev-804-g023d8af
arbport.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: MIT (https://spdx.org/licenses/MIT)
4 * PURPOSE: PnP manager Root Port Arbiter
5 * COPYRIGHT: Copyright 2025-2026 Justin Miller <justin.miller@reactos.org>
6 */
7
8/* INCLUDES *****************************************************************/
9
10#include <ntoskrnl.h>
11#define NDEBUG
12#include <debug.h>
13
14/* GLOBALS *******************************************************************/
15
17
25
31
32/*
33 * A card that decodes only the low 10 or 12 address lines answers not just on
34 * its own range but on every "alias" a multiple of 0x400 / 0x1000 above it, up
35 * to the top of the 64 KB port space.
36 */
37#define PORT_ALIAS_STRIDE_10_BIT 0x400
38#define PORT_ALIAS_STRIDE_12_BIT 0x1000
39#define PORT_MAX_ADDRESS 0xFFFF
40
41/* FUNCTIONS *****************************************************************/
42
70static
73 _In_ UCHAR SourceType,
76 _Out_ PUCHAR TranslatedType)
77{
79
80 PAGED_CODE();
81
82 if (SourceType == CmResourceTypePort)
83 AddressSpace = 1; /* I/O port space */
84 else if (SourceType == CmResourceTypeMemory || SourceType == CmResourceTypeMemoryLarge)
85 AddressSpace = 0; /* System memory */
86 else
88
91
92 /* The HAL reports back the space it landed in; only these two are expected. */
93 if (AddressSpace == 1)
94 {
95 *TranslatedType = CmResourceTypePort;
96 }
97 else if (AddressSpace == 0)
98 {
99 *TranslatedType = (SourceType == CmResourceTypeMemoryLarge)
102 }
103 else
104 {
106 }
107
108 return STATUS_SUCCESS;
109}
110
132static
135 _In_ USHORT DescriptorFlags,
136 _In_ UINT64 LastAlias,
137 _Out_ PUINT64 NextAlias)
138{
139 UINT64 Next;
140
141 PAGED_CODE();
142
143 if (DescriptorFlags & CM_RESOURCE_PORT_10_BIT_DECODE)
144 Next = LastAlias + PORT_ALIAS_STRIDE_10_BIT;
145 else if (DescriptorFlags & CM_RESOURCE_PORT_12_BIT_DECODE)
146 Next = LastAlias + PORT_ALIAS_STRIDE_12_BIT;
147 else
148 return FALSE;
149
151 return FALSE;
152
153 *NextAlias = Next;
154 return TRUE;
155}
156
182static
184NTAPI
186 _In_ PIO_RESOURCE_DESCRIPTOR IoDescriptor,
187 _Out_ PUINT64 OutMinimumAddress,
188 _Out_ PUINT64 OutMaximumAddress,
189 _Out_ PUINT64 OutLength,
190 _Out_ PUINT64 OutAlignment)
191{
192 PAGED_CODE();
193
194 *OutLength = RtlIoDecodeMemIoResource(IoDescriptor,
195 OutAlignment,
196 OutMinimumAddress,
197 OutMaximumAddress);
198
199 if (*OutAlignment == 0)
200 *OutAlignment = 1;
201
202 return STATUS_SUCCESS;
203}
204
224static
226NTAPI
228 _In_ PIO_RESOURCE_DESCRIPTOR IoDescriptor,
231{
232 PAGED_CODE();
233
234 CmDescriptor->Type = IoDescriptor->Type;
235 CmDescriptor->Flags = IoDescriptor->Flags;
236 CmDescriptor->ShareDisposition = IoDescriptor->ShareDisposition;
237
238 CmDescriptor->u.Generic.Start.QuadPart = Start;
239 CmDescriptor->u.Generic.Length = IoDescriptor->u.Generic.Length;
240
241 return STATUS_SUCCESS;
242}
243
263static
265NTAPI
269 _Out_ PUINT64 OutLength)
270{
271 PAGED_CODE();
272
273 *OutLength = RtlCmDecodeMemIoResource(CmDescriptor, Start);
274
275 return STATUS_SUCCESS;
276}
277
299static
300INT32
301NTAPI
303 _In_ PIO_RESOURCE_DESCRIPTOR IoDescriptor)
304{
306 UINT64 Minimum, Maximum, AlignedMinimum;
307 UINT64 Span, Placements;
308
309 PAGED_CODE();
310
311 Length = RtlIoDecodeMemIoResource(IoDescriptor, &Alignment, &Minimum, &Maximum);
312
313 if (Alignment == 0)
314 Alignment = 1;
315
316 /* Round the window's base up to the first address the device can sit at. */
317 AlignedMinimum = (Minimum + Alignment - 1) & ~(Alignment - 1);
318 if (AlignedMinimum < Minimum || AlignedMinimum > Maximum)
319 return -1;
320
321 /* Count in addresses above the base, so a full-width window cannot overflow. */
322 Span = Maximum - AlignedMinimum;
323
324 if (Length != 0)
325 {
326 if (Length - 1 > Span)
327 return -1;
328
329 Span -= Length - 1;
330 }
331
332 Placements = Span / Alignment + 1;
333 return (INT32)min(Placements, MAXLONG);
334}
335
355static
357NTAPI
359 _Out_ PIO_RESOURCE_DESCRIPTOR OutIoDescriptor,
360 _In_ PIO_RESOURCE_DESCRIPTOR IoDescriptor)
361{
362 UCHAR SourceType;
363 UCHAR MinimumType;
365
366 PAGED_CODE();
367
368 *OutIoDescriptor = *IoDescriptor;
369
370 SourceType = IoDescriptor->Type;
371 if (SourceType != CmResourceTypePort &&
372 SourceType != CmResourceTypeMemory &&
373 SourceType != CmResourceTypeMemoryLarge)
374 {
375 return STATUS_SUCCESS;
376 }
377
378 MinimumType = SourceType;
379 MaximumType = SourceType;
380
382 IoDescriptor->u.Generic.MinimumAddress,
383 &OutIoDescriptor->u.Generic.MinimumAddress,
384 &MinimumType)) ||
386 IoDescriptor->u.Generic.MaximumAddress,
387 &OutIoDescriptor->u.Generic.MaximumAddress,
388 &MaximumType)))
389 {
390 OutIoDescriptor->Type = CmResourceTypeNull;
391 }
392 else
393 {
394 OutIoDescriptor->Type = MaximumType;
395 }
396
397 return STATUS_SUCCESS;
398}
399
423static
425NTAPI
427 _In_ PARBITER_INSTANCE Arbiter,
429{
430 PAGED_CODE();
431
432 if (ArbState->Entry != NULL && (ArbState->Entry->Flags & ARBITER_FLAG_BOOT_CONFIG))
433 ArbState->RangeAvailableAttributes |= ARBITER_RANGE_BOOT_ALLOCATED;
434
435 return ArbiterLibFindSuitableRange(Arbiter, ArbState);
436}
437
452static
453VOID
454NTAPI
456 _In_ PARBITER_INSTANCE Arbiter,
458{
459 PARBITER_ALTERNATIVE Alternative = ArbState->CurrentAlternative;
460 PVOID Owner = ArbState->Entry ? ArbState->Entry->PhysicalDeviceObject : NULL;
462 UINT64 Alias;
463 UINT64 Span;
464
465 PAGED_CODE();
466
467 if (Alternative != NULL && (Alternative->Flags & ARBITER_ALTERNATIVE_FLAG_SHARED))
469
470 RtlAddRange(Arbiter->PossibleAllocation,
471 ArbState->Start,
472 ArbState->End,
473 ArbState->RangeAttributes,
474 Flags,
475 NULL,
476 Owner);
477
478 if (Alternative == NULL)
479 return;
480
481 /* Alias the width actually granted, not the width asked for. */
482 Span = ArbState->End - ArbState->Start;
483
484 Alias = ArbState->Start;
485 while (IopArbPortGetNextAlias(Alternative->Descriptor->Flags, Alias, &Alias))
486 {
487 RtlAddRange(Arbiter->PossibleAllocation,
488 Alias,
489 Alias + Span,
490 ArbState->RangeAttributes | ARBITER_RANGE_PORT_ALIAS,
491 Flags,
492 NULL,
493 Owner);
494 }
495}
496
513static
514VOID
515NTAPI
517 _In_ PARBITER_INSTANCE Arbiter,
519{
520 PARBITER_ALTERNATIVE Alternative = ArbState->CurrentAlternative;
521 PVOID Owner = ArbState->Entry ? ArbState->Entry->PhysicalDeviceObject : NULL;
522 UINT64 Alias;
523 UINT64 Span;
524
525 PAGED_CODE();
526
527 if (Alternative != NULL)
528 {
529 Span = ArbState->End - ArbState->Start;
530
531 Alias = ArbState->Start;
532 while (IopArbPortGetNextAlias(Alternative->Descriptor->Flags, Alias, &Alias))
533 {
534 RtlDeleteRange(Arbiter->PossibleAllocation, Alias, Alias + Span, Owner);
535 }
536 }
537
538 RtlDeleteRange(Arbiter->PossibleAllocation, ArbState->Start, ArbState->End, Owner);
539}
540
556NTAPI
558{
560
561 PAGED_CODE();
562
563 IopRootPortArbiter.Name = L"RootPort";
568
569 /* Port-specific placement: boot-config leniency and ISA decode aliasing. */
573
575 NULL,
578 L"Root",
580 if (!NT_SUCCESS(Status))
581 {
582 DPRINT1("IopArbPortInitialize: Failed with %X\n", Status);
583 }
584
585 return Status;
586}
#define PAGED_CODE()
static _Out_opt_ PULONGLONG _Out_opt_ PULONGLONG MinimumAddress
static _Out_opt_ PULONGLONG Start
static _Out_opt_ PULONGLONG _Out_opt_ PULONGLONG _Out_opt_ PULONGLONG MaximumAddress
unsigned char BOOLEAN
Definition: actypes.h:127
COMPILER_DEPENDENT_UINT64 UINT64
Definition: actypes.h:131
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:237
#define ARBITER_ALTERNATIVE_FLAG_SHARED
Definition: arbiter.h:29
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:520
#define ARBITER_RANGE_PORT_ALIAS
Definition: arbiter.h:47
#define ARBITER_RANGE_BOOT_ALLOCATED
Definition: arbiter.h:46
static VOID NTAPI IopArbPortAddAllocation(_In_ PARBITER_INSTANCE Arbiter, _Inout_ PARBITER_ALLOCATION_STATE ArbState)
The Root Port arbiter's AddAllocation: records the granted range in the tentative allocation,...
Definition: arbport.c:455
static VOID NTAPI IopArbPortBacktrackAllocation(_In_ PARBITER_INSTANCE Arbiter, _Inout_ PARBITER_ALLOCATION_STATE ArbState)
The Root Port arbiter's BacktrackAllocation: the exact inverse of IopArbPortAddAllocation.
Definition: arbport.c:516
static NTSTATUS NTAPI IopArbPortPackResource(_In_ PIO_RESOURCE_DESCRIPTOR IoDescriptor, _In_ UINT64 Start, _Out_ PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor)
Materialises the arbiter's chosen placement as an assigned CM descriptor. The PackResource callback o...
Definition: arbport.c:227
static NTSTATUS NTAPI IopArbPortUnpackResource(_In_ PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor, _Out_ PUINT64 Start, _Out_ PUINT64 OutLength)
Reads the placement back out of an already-assigned descriptor (a firmware boot configuration,...
Definition: arbport.c:266
#define PORT_MAX_ADDRESS
Definition: arbport.c:39
static NTSTATUS NTAPI IopArbPortTranslateOrdering(_Out_ PIO_RESOURCE_DESCRIPTOR OutIoDescriptor, _In_ PIO_RESOURCE_DESCRIPTOR IoDescriptor)
Translates one registry allocation-ordering window from the bus-relative addresses it is written in i...
Definition: arbport.c:358
ULONGLONG NTAPI RtlIoDecodeMemIoResource(_In_ PIO_RESOURCE_DESCRIPTOR Descriptor, _Out_opt_ PULONGLONG Alignment, _Out_opt_ PULONGLONG MinimumAddress, _Out_opt_ PULONGLONG MaximumAddress)
Definition: memres.c:79
#define PORT_ALIAS_STRIDE_10_BIT
Definition: arbport.c:37
static BOOLEAN IopArbPortGetNextAlias(_In_ USHORT DescriptorFlags, _In_ UINT64 LastAlias, _Out_ PUINT64 NextAlias)
Walks the decode-alias chain of a port range: given the previous alias, or the granted range's start ...
Definition: arbport.c:134
ARBITER_INSTANCE IopRootPortArbiter
Definition: pnpinit.c:27
NTSTATUS NTAPI IopArbPortInitialize(VOID)
Initialize the RootPortArbiter.
Definition: arbport.c:557
ULONGLONG NTAPI RtlCmDecodeMemIoResource(_In_ PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor, _Out_opt_ PULONGLONG Start)
Definition: memres.c:58
#define PORT_ALIAS_STRIDE_12_BIT
Definition: arbport.c:38
static NTSTATUS NTAPI IopArbPortUnpackRequirements(_In_ PIO_RESOURCE_DESCRIPTOR IoDescriptor, _Out_ PUINT64 OutMinimumAddress, _Out_ PUINT64 OutMaximumAddress, _Out_ PUINT64 OutLength, _Out_ PUINT64 OutAlignment)
Extracts the placement window from one I/O port requirement. The UnpackRequirement callback of the Ro...
Definition: arbport.c:185
static INT32 NTAPI IopArbPortScoreRequirement(_In_ PIO_RESOURCE_DESCRIPTOR IoDescriptor)
Scores how constrained a requirement is: the number of distinct aligned addresses it could be placed ...
Definition: arbport.c:302
static NTSTATUS IopArbPortTranslateAddress(_In_ UCHAR SourceType, _In_ PHYSICAL_ADDRESS SourceAddress, _Out_ PPHYSICAL_ADDRESS TranslatedAddress, _Out_ PUCHAR TranslatedType)
Translates one bus-relative address to a system-physical one on the ISA bus, and reports the space it...
Definition: arbport.c:72
static BOOLEAN NTAPI IopArbPortFindSuitableRange(_In_ PARBITER_INSTANCE Arbiter, _Inout_ PARBITER_ALLOCATION_STATE ArbState)
The Root Port arbiter's FindSuitableRange: the engine search, incremented for a device asking to keep...
Definition: arbport.c:426
LONG NTSTATUS
Definition: precomp.h:26
#define DPRINT1
Definition: precomp.h:8
unsigned __int64 * PUINT64
Definition: basetsd.h:181
_In_ D3DDDI_VIDEO_PRESENT_TARGET_ID _In_ ULONG _In_ ULONG Flags
Definition: dispmprt.h:245
#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 L(x)
Definition: resources.c:13
union Alignment_ Alignment
Status
Definition: gdiplustypes.h:24
BOOLEAN NTAPI HalTranslateBusAddress(IN INTERFACE_TYPE InterfaceType, IN ULONG BusNumber, IN PHYSICAL_ADDRESS BusAddress, IN OUT PULONG AddressSpace, OUT PPHYSICAL_ADDRESS TranslatedAddress)
Definition: bus.c:140
#define min(a, b)
Definition: monoChain.cc:55
#define CM_RESOURCE_PORT_12_BIT_DECODE
Definition: cmtypes.h:111
#define CM_RESOURCE_PORT_10_BIT_DECODE
Definition: cmtypes.h:110
_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
NTSYSAPI NTSTATUS NTAPI RtlDeleteRange(_Inout_ PRTL_RANGE_LIST RangeList, _In_ ULONGLONG Start, _In_ ULONGLONG End, _In_ PVOID Owner)
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
#define _Out_opt_
Definition: no_sal2.h:214
#define _Inout_
Definition: no_sal2.h:162
#define _Out_
Definition: no_sal2.h:160
#define _In_
Definition: no_sal2.h:158
__GNU_EXTENSION typedef unsigned __int64 * PULONGLONG
Definition: ntbasedef.h:395
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
unsigned short USHORT
Definition: pedump.c:61
#define CmResourceTypeNull
Definition: restypes.h:103
#define CmResourceTypeMemory
Definition: restypes.h:106
@ Isa
Definition: restypes.h:122
#define CmResourceTypePort
Definition: restypes.h:104
@ MaximumType
Definition: arc.h:154
#define STATUS_SUCCESS
Definition: shellext.h:65
STDMETHOD() Next(THIS_ ULONG celt, IAssociationElement *pElement, ULONG *pceltFetched) PURE
PIO_RESOURCE_DESCRIPTOR Descriptor
Definition: arbiter.h:67
PARB_UNPACK_RESOURCE UnpackResource
Definition: arbiter.h:302
PARB_SCORE_REQUIREMENT ScoreRequirement
Definition: arbiter.h:303
PARB_UNPACK_REQUIREMENT UnpackRequirement
Definition: arbiter.h:300
PARB_FIND_SUITABLE_RANGE FindSuitableRange
Definition: arbiter.h:316
PARB_ADD_ALLOCATION AddAllocation
Definition: arbiter.h:317
PARB_PACK_RESOURCE PackResource
Definition: arbiter.h:301
PARB_BACKTRACK_ALLOCATION BacktrackAllocation
Definition: arbiter.h:318
int32_t INT32
Definition: typedefs.h:58
unsigned char UCHAR
Definition: typedefs.h:53
#define NTAPI
Definition: typedefs.h:36
uint64_t ULONGLONG
Definition: typedefs.h:67
unsigned char * PUCHAR
Definition: typedefs.h:53
uint32_t ULONG
Definition: typedefs.h:59
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
#define MAXLONG
Definition: umtypes.h:116
_Must_inspect_result_ _In_ WDFIORESLIST _In_ PIO_RESOURCE_DESCRIPTOR Descriptor
Definition: wdfresource.h:342
#define CmResourceTypeMemoryLarge
Definition: cmtypes.h:231
_In_ ULONG _In_ PHYSICAL_ADDRESS _Inout_ PULONG _Out_ PPHYSICAL_ADDRESS TranslatedAddress
Definition: iofuncs.h:2275
_In_ ULONG _In_ PHYSICAL_ADDRESS _Inout_ PULONG AddressSpace
Definition: iofuncs.h:2274
#define ARBITER_FLAG_BOOT_CONFIG
Definition: iotypes.h:4631
_Must_inspect_result_ typedef _In_ PHYSICAL_ADDRESS SourceAddress
Definition: iotypes.h:1127