00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
#include "arbp.h"
00027
00028
00029
00030
00031
00032 #define ALLOW_BOOT_ALLOC_CONFLICTS 1
00033 #define PLUG_FEST_HACKS 0
00034
00035
00036
00037
00038
00039 #define ARBITER_ALLOCATION_STATE_TAG 'AbrA'
00040 #define ARBITER_ORDERING_LIST_TAG 'LbrA'
00041 #define ARBITER_MISC_TAG 'MbrA'
00042 #define ARBITER_RANGE_LIST_TAG 'RbrA'
00043 #define ARBITER_CONFLICT_INFO_TAG 'CbrA'
00044
00045
00046
00047
00048
00049 #define PATH_ARBITERS L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Arbiters"
00050 #define KEY_ALLOCATIONORDER L"AllocationOrder"
00051 #define KEY_RESERVEDRESOURCES L"ReservedResources"
00052 #define ARBITER_ORDERING_GROW_SIZE 8
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069 #define FULL_INFO_DATA(k) ((PCHAR)(k) + (k)->DataOffset)
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080 #define DISJOINT(s1,e1,s2,e2) \
00081
( ((s1) < (s2) && (e1) < (s2)) \
00082
||((s2) < (s1) && (e2) < (s1)) )
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092 #define ArbpWstrToUnicodeString(u, p) \
00093
(u)->Length = ((u)->MaximumLength = \
00094
(USHORT) (sizeof((p))) - sizeof(WCHAR)); \
00095
(u)->Buffer = (p)
00096
00097
00098
00099
00100
00101
00102
00103
00104 #define ORDERING_INDEX_FROM_PRIORITY(P) \
00105
( (ULONG) ( (P) > 0 ? (P) - 1 : ((P) * -1) - 1) )
00106
00107
00108
00109
00110
00111
NTSTATUS
00112
ArbpBuildAllocationStack(
00113 IN
PARBITER_INSTANCE Arbiter,
00114 IN PLIST_ENTRY ArbitrationList,
00115 IN ULONG ArbitrationListCount
00116 );
00117
00118
NTSTATUS
00119
ArbpGetRegistryValue(
00120 IN HANDLE KeyHandle,
00121 IN PWSTR ValueName,
00122 OUT PKEY_VALUE_FULL_INFORMATION *Information
00123 );
00124
00125
NTSTATUS
00126
ArbpBuildAlternative(
00127 IN PARBITER_INSTANCE Arbiter,
00128 IN PIO_RESOURCE_DESCRIPTOR Requirement,
00129 OUT
PARBITER_ALTERNATIVE Alternative
00130 );
00131
00132
VOID
00133
ArbpUpdatePriority(
00134 PARBITER_INSTANCE Arbiter,
00135
PARBITER_ALTERNATIVE Alternative
00136 );
00137
00138 BOOLEAN
00139
ArbpQueryConflictCallback(
00140 IN PVOID Context,
00141 IN PRTL_RANGE Range
00142 );
00143
00144
00145
00146
00147
00148
#ifdef ALLOC_PRAGMA
00149
00150
#if ARB_DBG
00151
#pragma alloc_text(PAGE, ArbpDumpArbiterInstance)
00152
#pragma alloc_text(PAGE, ArbpDumpArbiterRange)
00153
#pragma alloc_text(PAGE, ArbpDumpArbitrationList)
00154
#endif
00155
00156
#pragma alloc_text(PAGE, ArbInitializeArbiterInstance)
00157
#pragma alloc_text(PAGE, ArbDeleteArbiterInstance)
00158
#pragma alloc_text(PAGE, ArbArbiterHandler)
00159
#pragma alloc_text(PAGE, ArbStartArbiter)
00160
#pragma alloc_text(PAGE, ArbTestAllocation)
00161
#pragma alloc_text(PAGE, ArbRetestAllocation)
00162
#pragma alloc_text(PAGE, ArbCommitAllocation)
00163
#pragma alloc_text(PAGE, ArbRollbackAllocation)
00164
#pragma alloc_text(PAGE, ArbAddReserved)
00165
#pragma alloc_text(PAGE, ArbPreprocessEntry)
00166
#pragma alloc_text(PAGE, ArbAllocateEntry)
00167
#pragma alloc_text(PAGE, ArbSortArbitrationList)
00168
#pragma alloc_text(PAGE, ArbBacktrackAllocation)
00169
#pragma alloc_text(PAGE, ArbGetNextAllocationRange)
00170
#pragma alloc_text(PAGE, ArbFindSuitableRange)
00171
#pragma alloc_text(PAGE, ArbAddAllocation)
00172
#pragma alloc_text(PAGE, ArbQueryConflict)
00173
#pragma alloc_text(PAGE, ArbInitializeOrderingList)
00174
#pragma alloc_text(PAGE, ArbCopyOrderingList)
00175
#pragma alloc_text(PAGE, ArbPruneOrdering)
00176
#pragma alloc_text(PAGE, ArbAddOrdering)
00177
#pragma alloc_text(PAGE, ArbFreeOrderingList)
00178
#pragma alloc_text(PAGE, ArbBuildAssignmentOrdering)
00179
00180
#pragma alloc_text(PAGE, ArbpGetRegistryValue)
00181
#pragma alloc_text(PAGE, ArbpBuildAllocationStack)
00182
#pragma alloc_text(PAGE, ArbpBuildAlternative)
00183
#pragma alloc_text(PAGE, ArbpQueryConflictCallback)
00184
#endif // ALLOC_PRAGMA
00185
00186
00187
00188
00189
00190
00191
NTSTATUS
00192 ArbInitializeArbiterInstance(
00193 OUT PARBITER_INSTANCE Arbiter,
00194 IN
PDEVICE_OBJECT BusDeviceObject,
00195 IN CM_RESOURCE_TYPE ResourceType,
00196 IN PWSTR Name,
00197 IN PWSTR OrderingName,
00198 IN
PARBITER_TRANSLATE_ALLOCATION_ORDER TranslateOrdering OPTIONAL
00199 )
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239 {
00240
NTSTATUS status;
00241
00242
PAGED_CODE();
00243
00244
ASSERT(Arbiter->UnpackRequirement);
00245
ASSERT(Arbiter->PackResource);
00246
ASSERT(Arbiter->UnpackResource);
00247
00248
ARB_PRINT(2,(
"Initializing %S Arbiter...\n",
Name));
00249
00250
00251
00252
00253
00254
ASSERT(Arbiter->MutexEvent ==
NULL
00255 && Arbiter->Allocation ==
NULL
00256 && Arbiter->PossibleAllocation ==
NULL
00257 && Arbiter->AllocationStack ==
NULL
00258 );
00259
00260
00261
00262
00263
00264 Arbiter->Signature =
ARBITER_INSTANCE_SIGNATURE;
00265
00266
00267
00268
00269
00270 Arbiter->BusDeviceObject = BusDeviceObject;
00271
00272
00273
00274
00275
00276 Arbiter->MutexEvent =
ExAllocatePoolWithTag(
NonPagedPool,
00277
sizeof(
KEVENT),
00278
ARBITER_MISC_TAG
00279 );
00280
00281
if (!Arbiter->MutexEvent) {
00282 status = STATUS_INSUFFICIENT_RESOURCES;
00283
goto cleanup;
00284 }
00285
00286
KeInitializeEvent(Arbiter->MutexEvent, SynchronizationEvent,
TRUE);
00287
00288
00289
00290
00291
00292 Arbiter->AllocationStack =
ExAllocatePoolWithTag(
PagedPool,
00293
INITIAL_ALLOCATION_STATE_SIZE,
00294
ARBITER_ALLOCATION_STATE_TAG
00295 );
00296
00297
if (!Arbiter->AllocationStack) {
00298 status = STATUS_INSUFFICIENT_RESOURCES;
00299
goto cleanup;
00300 }
00301
00302 Arbiter->AllocationStackMaxSize =
INITIAL_ALLOCATION_STATE_SIZE;
00303
00304
00305
00306
00307
00308
00309 Arbiter->Allocation =
ExAllocatePoolWithTag(
PagedPool,
00310
sizeof(RTL_RANGE_LIST),
00311
ARBITER_RANGE_LIST_TAG
00312 );
00313
00314
if (!Arbiter->Allocation) {
00315 status = STATUS_INSUFFICIENT_RESOURCES;
00316
goto cleanup;
00317 }
00318
00319 Arbiter->PossibleAllocation =
ExAllocatePoolWithTag(
PagedPool,
00320
sizeof(RTL_RANGE_LIST),
00321
ARBITER_RANGE_LIST_TAG
00322 );
00323
00324
if (!Arbiter->PossibleAllocation) {
00325 status = STATUS_INSUFFICIENT_RESOURCES;
00326
goto cleanup;
00327 }
00328
00329
00330
00331
00332
00333
RtlInitializeRangeList(Arbiter->Allocation);
00334
RtlInitializeRangeList(Arbiter->PossibleAllocation);
00335
00336
00337
00338
00339 Arbiter->TransactionInProgress =
FALSE;
00340 Arbiter->Name =
Name;
00341 Arbiter->ResourceType = ResourceType;
00342
00343
00344
00345
00346
00347
00348
00349
if (!Arbiter->TestAllocation) {
00350 Arbiter->TestAllocation =
ArbTestAllocation;
00351 }
00352
00353
if (!Arbiter->RetestAllocation) {
00354 Arbiter->RetestAllocation =
ArbRetestAllocation;
00355 }
00356
00357
if (!Arbiter->CommitAllocation) {
00358 Arbiter->CommitAllocation =
ArbCommitAllocation;
00359 }
00360
00361
if (!Arbiter->RollbackAllocation) {
00362 Arbiter->RollbackAllocation =
ArbRollbackAllocation;
00363 }
00364
00365
if (!Arbiter->AddReserved) {
00366 Arbiter->AddReserved =
ArbAddReserved;
00367 }
00368
00369
if (!Arbiter->PreprocessEntry) {
00370 Arbiter->PreprocessEntry =
ArbPreprocessEntry;
00371 }
00372
00373
if (!Arbiter->AllocateEntry) {
00374 Arbiter->AllocateEntry =
ArbAllocateEntry;
00375 }
00376
00377
if (!Arbiter->GetNextAllocationRange) {
00378 Arbiter->GetNextAllocationRange =
ArbGetNextAllocationRange;
00379 }
00380
00381
if (!Arbiter->FindSuitableRange) {
00382 Arbiter->FindSuitableRange =
ArbFindSuitableRange;
00383 }
00384
00385
if (!Arbiter->AddAllocation) {
00386 Arbiter->AddAllocation =
ArbAddAllocation;
00387 }
00388
00389
if (!Arbiter->BacktrackAllocation) {
00390 Arbiter->BacktrackAllocation =
ArbBacktrackAllocation;
00391 }
00392
00393
if (!Arbiter->OverrideConflict) {
00394 Arbiter->OverrideConflict =
ArbOverrideConflict;
00395 }
00396
00397
if (!Arbiter->BootAllocation) {
00398 Arbiter->BootAllocation =
ArbBootAllocation;
00399 }
00400
00401
if (!Arbiter->QueryConflict) {
00402 Arbiter->QueryConflict =
ArbQueryConflict;
00403 }
00404
00405
if (!Arbiter->StartArbiter) {
00406 Arbiter->StartArbiter =
ArbStartArbiter;
00407 }
00408
00409
00410
00411
00412
00413
00414 status =
ArbBuildAssignmentOrdering(Arbiter,
00415 OrderingName,
00416 OrderingName,
00417 TranslateOrdering
00418 );
00419
00420
if (!
NT_SUCCESS(status)) {
00421
goto cleanup;
00422 }
00423
00424
return STATUS_SUCCESS;
00425
00426 cleanup:
00427
00428
if (Arbiter->MutexEvent) {
00429
ExFreePool(Arbiter->MutexEvent);
00430 }
00431
00432
if (Arbiter->Allocation) {
00433
ExFreePool(Arbiter->Allocation);
00434 }
00435
00436
if (Arbiter->PossibleAllocation) {
00437
ExFreePool(Arbiter->PossibleAllocation);
00438 }
00439
00440
if (Arbiter->AllocationStack) {
00441
ExFreePool(Arbiter->AllocationStack);
00442 }
00443
00444
return status;
00445
00446 }
00447
00448
VOID
00449 ArbReferenceArbiterInstance(
00450 IN PARBITER_INSTANCE Arbiter
00451 )
00452 {
00453 InterlockedIncrement(&Arbiter->ReferenceCount);
00454 }
00455
00456
VOID
00457 ArbDereferenceArbiterInstance(
00458 IN PARBITER_INSTANCE Arbiter
00459 )
00460 {
00461 InterlockedDecrement(&Arbiter->ReferenceCount);
00462
00463
if (Arbiter->ReferenceCount == 0) {
00464
ArbDeleteArbiterInstance(Arbiter);
00465 }
00466 }
00467
00468
VOID
00469 ArbDeleteArbiterInstance(
00470 IN PARBITER_INSTANCE Arbiter
00471 )
00472 {
00473
00474
PAGED_CODE();
00475
00476
if (Arbiter->MutexEvent) {
00477
ExFreePool(Arbiter->MutexEvent);
00478 }
00479
00480
if (Arbiter->Allocation) {
00481
RtlFreeRangeList(Arbiter->Allocation);
00482
ExFreePool(Arbiter->Allocation);
00483 }
00484
00485
if (Arbiter->PossibleAllocation) {
00486
RtlFreeRangeList(Arbiter->PossibleAllocation);
00487
ExFreePool(Arbiter->PossibleAllocation);
00488 }
00489
00490
if (Arbiter->AllocationStack) {
00491
ExFreePool(Arbiter->AllocationStack);
00492 }
00493
00494
ArbFreeOrderingList(&Arbiter->OrderingList);
00495
ArbFreeOrderingList(&Arbiter->ReservedList);
00496
00497
#if ARB_DBG
00498
00499 RtlFillMemory(Arbiter,
sizeof(
ARBITER_INSTANCE),
'A');
00500
00501
#endif
00502
00503 }
00504
00505
NTSTATUS
00506 ArbTestAllocation(
00507 IN PARBITER_INSTANCE Arbiter,
00508 IN OUT PLIST_ENTRY ArbitrationList
00509 )
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545 {
00546
00547
NTSTATUS status;
00548
PARBITER_LIST_ENTRY current;
00549 PIO_RESOURCE_DESCRIPTOR alternative;
00550 ULONG count;
00551
PDEVICE_OBJECT previousOwner;
00552
PDEVICE_OBJECT currentOwner;
00553 LONG score;
00554 BOOLEAN performScoring;
00555
00556
PAGED_CODE();
00557
ASSERT(Arbiter);
00558
00559
00560
00561
00562
00563
ARB_PRINT(3, (
"Copy current allocation\n"));
00564 status =
RtlCopyRangeList(Arbiter->PossibleAllocation, Arbiter->Allocation);
00565
00566
if (!
NT_SUCCESS(status)) {
00567
goto cleanup;
00568 }
00569
00570
00571
00572
00573
00574
00575 count = 0;
00576 previousOwner =
NULL;
00577
00578
FOR_ALL_IN_LIST(
ARBITER_LIST_ENTRY, ArbitrationList, current) {
00579
00580 count++;
00581
00582 currentOwner = current->
PhysicalDeviceObject;
00583
00584
if (previousOwner != currentOwner) {
00585
00586 previousOwner = currentOwner;
00587
00588
ARB_PRINT(3,
00589 (
"Delete 0x%08x's resources\n",
00590 currentOwner
00591 ));
00592
00593 status =
RtlDeleteOwnersRanges(Arbiter->PossibleAllocation,
00594 (PVOID)currentOwner
00595 );
00596
00597
if (!
NT_SUCCESS(status)) {
00598
goto cleanup;
00599 }
00600 }
00601
00602
00603
00604
00605
00606
00607
00608 performScoring = Arbiter->ScoreRequirement !=
NULL;
00609
00610
00611 current->
WorkSpace = 0;
00612
00613
if (performScoring) {
00614
00615
FOR_ALL_IN_ARRAY(current->
Alternatives,
00616 current->
AlternativeCount,
00617 alternative) {
00618
00619
ARB_PRINT(3,
00620 (
"Scoring entry %p\n",
00621 currentOwner
00622 ));
00623
00624
00625
00626 score = Arbiter->ScoreRequirement(alternative);
00627
00628
00629
00630
00631
00632
if (score < 0) {
00633 status = STATUS_DEVICE_CONFIGURATION_ERROR;
00634
goto cleanup;
00635 }
00636
00637 current->
WorkSpace += score;
00638 }
00639 }
00640 }
00641
00642 status =
ArbSortArbitrationList(ArbitrationList);
00643
00644
if (!
NT_SUCCESS(status)) {
00645
goto cleanup;
00646 }
00647
00648
00649
00650
00651
00652 status =
ArbpBuildAllocationStack(Arbiter,
00653 ArbitrationList,
00654 count
00655 );
00656
00657
if (!
NT_SUCCESS(status)) {
00658
goto cleanup;
00659 }
00660
00661
00662
00663
00664
00665 status = Arbiter->AllocateEntry(Arbiter, Arbiter->AllocationStack);
00666
00667
if (
NT_SUCCESS(status)) {
00668
00669
00670
00671
00672
00673
return status;
00674 }
00675
00676 cleanup:
00677
00678
00679
00680
00681
00682
RtlFreeRangeList(Arbiter->PossibleAllocation);
00683
00684
return status;
00685 }
00686
00687
00688
NTSTATUS
00689 ArbpBuildAlternative(
00690 IN PARBITER_INSTANCE Arbiter,
00691 IN PIO_RESOURCE_DESCRIPTOR Requirement,
00692 OUT
PARBITER_ALTERNATIVE Alternative
00693 )
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717 {
00718
00719
NTSTATUS status;
00720
00721
PAGED_CODE();
00722
ASSERT(Alternative && Requirement);
00723
00724 Alternative->Descriptor = Requirement;
00725
00726
00727
00728
00729
00730 status = Arbiter->UnpackRequirement(Requirement,
00731 &Alternative->Minimum,
00732 &Alternative->Maximum,
00733 &Alternative->Length,
00734 &Alternative->Alignment
00735 );
00736
00737
if (!
NT_SUCCESS(status)) {
00738
goto cleanup;
00739 }
00740
00741
00742
00743
00744
00745
if (Alternative->Minimum % Alternative->Alignment != 0) {
00746
ALIGN_ADDRESS_UP(Alternative->Minimum,
00747 Alternative->Alignment
00748 );
00749 }
00750
00751 Alternative->Flags = 0;
00752
00753
00754
00755
00756
00757
if(Requirement->ShareDisposition == CmResourceShareShared) {
00758 Alternative->Flags |=
ARBITER_ALTERNATIVE_FLAG_SHARED;
00759 }
00760
00761
00762
00763
00764
00765
if (Alternative->Maximum - Alternative->Minimum + 1 == Alternative->Length) {
00766 Alternative->Flags |=
ARBITER_ALTERNATIVE_FLAG_FIXED;
00767 }
00768
00769
00770
00771
00772
00773
if (Alternative->Maximum < Alternative->Minimum) {
00774 Alternative->Flags |=
ARBITER_ALTERNATIVE_FLAG_INVALID;
00775 }
00776
00777
return STATUS_SUCCESS;
00778
00779 cleanup:
00780
00781
return status;
00782 }
00783
00784
00785
NTSTATUS
00786 ArbpBuildAllocationStack(
00787 IN PARBITER_INSTANCE Arbiter,
00788 IN PLIST_ENTRY ArbitrationList,
00789 IN ULONG ArbitrationListCount
00790 )
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811
00812
00813
00814
00815
00816
00817 {
00818
NTSTATUS status;
00819
PARBITER_LIST_ENTRY currentEntry;
00820
PARBITER_ALLOCATION_STATE currentState;
00821 ULONG stackSize = 0, allocationCount = ArbitrationListCount + 1;
00822
PARBITER_ALTERNATIVE currentAlternative;
00823 PIO_RESOURCE_DESCRIPTOR currentDescriptor;
00824
00825
PAGED_CODE();
00826
00827
00828
00829
00830
00831
FOR_ALL_IN_LIST(
ARBITER_LIST_ENTRY, ArbitrationList, currentEntry) {
00832
00833
if (currentEntry->
AlternativeCount > 0) {
00834 stackSize += currentEntry->
AlternativeCount
00835 *
sizeof(
ARBITER_ALTERNATIVE);
00836 }
else {
00837 allocationCount--;
00838 }
00839 }
00840
00841 stackSize += allocationCount *
sizeof(
ARBITER_ALLOCATION_STATE);
00842
00843
00844
00845
00846
00847
if (Arbiter->AllocationStackMaxSize < stackSize) {
00848
00849
PARBITER_ALLOCATION_STATE temp;
00850
00851
00852
00853
00854
00855 temp =
ExAllocatePoolWithTag(
PagedPool,
00856 stackSize,
00857
ARBITER_ALLOCATION_STATE_TAG
00858 );
00859
if (!temp) {
00860
return STATUS_INSUFFICIENT_RESOURCES;
00861 }
00862
00863
ExFreePool(Arbiter->AllocationStack);
00864 Arbiter->AllocationStack = temp;
00865 }
00866
00867 RtlZeroMemory(Arbiter->AllocationStack, stackSize);
00868
00869
00870
00871
00872
00873 currentState = Arbiter->AllocationStack;
00874 currentAlternative = (
PARBITER_ALTERNATIVE) (Arbiter->AllocationStack
00875 + ArbitrationListCount + 1);
00876
00877
FOR_ALL_IN_LIST(
ARBITER_LIST_ENTRY, ArbitrationList, currentEntry) {
00878
00879
00880
00881
00882
00883
if (currentEntry->
AlternativeCount > 0) {
00884
00885
00886
00887
00888
00889 currentState->
Entry = currentEntry;
00890 currentState->
AlternativeCount = currentEntry->
AlternativeCount;
00891 currentState->
Alternatives = currentAlternative;
00892
00893
00894
00895
00896
00897
00898 currentState->
Start = 1;
00899
ASSERT(currentState->
End == 0);
00900
00901
00902
00903
00904
00905
FOR_ALL_IN_ARRAY(currentEntry->
Alternatives,
00906 currentEntry->
AlternativeCount,
00907 currentDescriptor) {
00908
00909
00910 status =
ArbpBuildAlternative(Arbiter,
00911 currentDescriptor,
00912 currentAlternative
00913 );
00914
00915
if (!
NT_SUCCESS(status)) {
00916
goto cleanup;
00917 }
00918
00919
00920
00921
00922
00923 currentAlternative->
Priority =
ARBITER_PRIORITY_NULL;
00924
00925
00926
00927
00928
00929 currentAlternative++;
00930
00931 }
00932 }
00933 currentState++;
00934 }
00935
00936
00937
00938
00939
00940 currentState->
Entry =
NULL;
00941
00942
return STATUS_SUCCESS;
00943
00944 cleanup:
00945
00946
00947
00948
00949
00950
00951
return status;
00952 }
00953
00954
NTSTATUS
00955 ArbSortArbitrationList(
00956 IN OUT PLIST_ENTRY ArbitrationList
00957 )
00958
00959
00960
00961
00962
00963
00964
00965
00966
00967
00968
00969
00970
00971
00972
00973
00974
00975
00976 {
00977
00978
00979
00980 BOOLEAN sorted =
FALSE;
00981
PARBITER_LIST_ENTRY current, next;
00982
00983
PAGED_CODE();
00984
00985
ARB_PRINT(3, (
"IoSortArbiterList(%p)\n", ArbitrationList));
00986
00987
while (!sorted) {
00988
00989 sorted =
TRUE;
00990
00991
for (current=(
PARBITER_LIST_ENTRY) ArbitrationList->Flink,
00992 next=(
PARBITER_LIST_ENTRY) current->
ListEntry.Flink;
00993
00994 (PLIST_ENTRY) current != ArbitrationList
00995 && (PLIST_ENTRY) next != ArbitrationList;
00996
00997 current = (
PARBITER_LIST_ENTRY) current->
ListEntry.Flink,
00998 next = (
PARBITER_LIST_ENTRY)current->
ListEntry.Flink) {
00999
01000
01001
if (current->
WorkSpace > next->
WorkSpace) {
01002
01003 PLIST_ENTRY before = current->
ListEntry.Blink;
01004 PLIST_ENTRY after = next->
ListEntry.Flink;
01005
01006
01007
01008
01009
01010 before->Flink = (PLIST_ENTRY) next;
01011 after->Blink = (PLIST_ENTRY) current;
01012 current->
ListEntry.Flink = after;
01013 current->
ListEntry.Blink = (PLIST_ENTRY) next;
01014 next->
ListEntry.Flink = (PLIST_ENTRY) current;
01015 next->
ListEntry.Blink = before;
01016
01017 sorted =
FALSE;
01018 }
01019 }
01020 }
01021
01022
return STATUS_SUCCESS;
01023 }
01024
01025
NTSTATUS
01026 ArbCommitAllocation(
01027 PARBITER_INSTANCE Arbiter
01028 )
01029
01030
01031
01032
01033
01034
01035
01036
01037
01038
01039
01040
01041
01042
01043
01044
01045
01046
01047 {
01048 PRTL_RANGE_LIST temp;
01049
01050
PAGED_CODE();
01051
01052
01053
01054
01055
01056
RtlFreeRangeList(Arbiter->Allocation);
01057
01058
01059
01060
01061
01062 temp = Arbiter->Allocation;
01063 Arbiter->Allocation = Arbiter->PossibleAllocation;
01064 Arbiter->PossibleAllocation = temp;
01065
01066
return STATUS_SUCCESS;
01067 }
01068
01069
NTSTATUS
01070 ArbRollbackAllocation(
01071 IN PARBITER_INSTANCE Arbiter
01072 )
01073
01074
01075
01076
01077
01078
01079
01080
01081
01082
01083
01084
01085
01086
01087
01088
01089
01090
01091 {
01092
01093
PAGED_CODE();
01094
01095
01096
01097
01098
01099
RtlFreeRangeList(Arbiter->PossibleAllocation);
01100
01101
return STATUS_SUCCESS;
01102 }
01103
01104
NTSTATUS
01105 ArbRetestAllocation(
01106 IN PARBITER_INSTANCE Arbiter,
01107 IN OUT PLIST_ENTRY ArbitrationList
01108 )
01109
01110
01111
01112
01113
01114
01115
01116
01117
01118
01119
01120
01121
01122
01123
01124
01125
01126
01127
01128
01129
01130
01131
01132
01133 {
01134
NTSTATUS status;
01135
PARBITER_LIST_ENTRY current;
01136
ARBITER_ALLOCATION_STATE state;
01137
ARBITER_ALTERNATIVE alternative;
01138 ULONG length;
01139
01140
PAGED_CODE();
01141
01142
01143
01144
01145
01146 RtlZeroMemory(&state,
sizeof(
ARBITER_ALLOCATION_STATE));
01147 RtlZeroMemory(&alternative,
sizeof(
ARBITER_ALTERNATIVE));
01148 state.
AlternativeCount = 1;
01149 state.
Alternatives = &alternative;
01150 state.
CurrentAlternative = &alternative;
01151 state.
Flags =
ARBITER_STATE_FLAG_RETEST;
01152
01153
01154
01155
01156
01157
ARB_PRINT(2, (
"Retest: Copy current allocation\n"));
01158 status =
RtlCopyRangeList(Arbiter->PossibleAllocation, Arbiter->Allocation);
01159
01160
if (!
NT_SUCCESS(status)) {
01161
goto cleanup;
01162 }
01163
01164
01165
01166
01167
01168
01169
FOR_ALL_IN_LIST(
ARBITER_LIST_ENTRY, ArbitrationList, current) {
01170
01171
ARB_PRINT(3,
01172 (
"Retest: Delete 0x%08x's resources\n",
01173 current->
PhysicalDeviceObject
01174 ));
01175
01176 status =
RtlDeleteOwnersRanges(Arbiter->PossibleAllocation,
01177 (PVOID) current->
PhysicalDeviceObject
01178 );
01179
01180
if (!
NT_SUCCESS(status)) {
01181
goto cleanup;
01182 }
01183 }
01184
01185
01186
01187
01188
01189
01190
FOR_ALL_IN_LIST(
ARBITER_LIST_ENTRY, ArbitrationList, current) {
01191
01192
ASSERT(current->
Assignment && current->
SelectedAlternative);
01193
01194 state.
WorkSpace = 0;
01195 state.
Entry = current;
01196
01197
01198
01199
01200
01201 status =
ArbpBuildAlternative(Arbiter,
01202 current->
SelectedAlternative,
01203 &alternative
01204 );
01205
01206
ASSERT(
NT_SUCCESS(status));
01207
01208
01209
01210
01211
01212 status = Arbiter->UnpackResource(current->
Assignment,
01213 &state.
Start,
01214 &length
01215 );
01216
01217
ASSERT(
NT_SUCCESS(status));
01218
01219 state.
End = state.
Start + length - 1;
01220
01221
01222
01223
01224
01225 status = Arbiter->PreprocessEntry(Arbiter,&state);
01226
01227
if (!
NT_SUCCESS(status)) {
01228
goto cleanup;
01229 }
01230
01231
01232
01233
01234
01235
01236
if (length != 0) {
01237
01238 Arbiter->AddAllocation(Arbiter, &state);
01239
01240 }
01241 }
01242
01243
return status;
01244
01245 cleanup:
01246
01247
RtlFreeRangeList(Arbiter->PossibleAllocation);
01248
return status;
01249 }
01250
01251
NTSTATUS
01252 ArbBootAllocation(
01253 IN PARBITER_INSTANCE Arbiter,
01254 IN OUT PLIST_ENTRY ArbitrationList
01255 )
01256
01257
01258
01259
01260
01261
01262
01263
01264
01265
01266
01267
01268
01269
01270
01271
01272
01273
01274
01275
01276
01277
01278 {
01279
01280
NTSTATUS status;
01281
PARBITER_LIST_ENTRY current;
01282 PRTL_RANGE_LIST temp;
01283
ARBITER_ALLOCATION_STATE state;
01284
ARBITER_ALTERNATIVE alternative;
01285
01286
01287
01288
01289
01290 RtlZeroMemory(&state,
sizeof(
ARBITER_ALLOCATION_STATE));
01291 RtlZeroMemory(&alternative,
sizeof(
ARBITER_ALTERNATIVE));
01292 state.
AlternativeCount = 1;
01293 state.
Alternatives = &alternative;
01294 state.
CurrentAlternative = &alternative;
01295 state.
Flags =
ARBITER_STATE_FLAG_BOOT;
01296 state.
RangeAttributes =
ARBITER_RANGE_BOOT_ALLOCATED;
01297
01298
01299
01300
01301
01302 status =
RtlCopyRangeList(Arbiter->PossibleAllocation, Arbiter->Allocation);
01303
01304
FOR_ALL_IN_LIST(
ARBITER_LIST_ENTRY, ArbitrationList, current) {
01305
01306
ASSERT(current->
AlternativeCount == 1);
01307
ASSERT(current->
PhysicalDeviceObject);
01308
01309
01310
01311
01312
01313
01314 state.
Entry = current;
01315
01316
01317
01318
01319
01320 status =
ArbpBuildAlternative(Arbiter,
01321 ¤t->
Alternatives[0],
01322 &alternative
01323 );
01324
01325
ASSERT(
NT_SUCCESS(status));
01326
ASSERT(alternative.
Flags &
01327 (
ARBITER_ALTERNATIVE_FLAG_FIXED |
ARBITER_ALTERNATIVE_FLAG_INVALID)
01328 );
01329
01330 state.
Start = alternative.
Minimum;
01331 state.
End = alternative.
Maximum;
01332
01333
01334
01335
01336
01337 state.
WorkSpace = 0;
01338 state.
RangeAvailableAttributes = 0;
01339
01340
01341
01342
01343
01344
if (alternative.
Length == 0
01345 || alternative.
Alignment == 0
01346 || state.
End < state.
Start
01347 || state.
Start % alternative.
Alignment != 0
01348 ||
LENGTH_OF(state.
Start, state.
End) != alternative.
Length) {
01349
01350
ARB_PRINT(1,
01351 (
"Skipping invalid boot allocation 0x%I64x-0x%I64x L 0x%x A 0x%x for 0x%08x\n",
01352 state.
Start,
01353 state.
End,
01354 alternative.
Length,
01355 alternative.
Alignment,
01356 current->
PhysicalDeviceObject
01357 ));
01358
01359
continue;
01360 }
01361
01362
#if PLUG_FEST_HACKS
01363
01364
if (alternative.
Flags &
ARBITER_ALTERNATIVE_FLAG_SHARED) {
01365
01366
ARB_PRINT(1,
01367 (
"Skipping shared boot allocation 0x%I64x-0x%I64x L 0x%x A 0x%x for 0x%08x\n",
01368 state.
Start,
01369 state.
End,
01370 alternative.
Length,
01371 alternative.
Alignment,
01372 current->
PhysicalDeviceObject
01373 ));
01374
01375
continue;
01376 }
01377
#endif
01378
01379
01380
01381
01382
01383
01384 status = Arbiter->PreprocessEntry(Arbiter,&state);
01385
01386
if (!
NT_SUCCESS(status)) {
01387
goto cleanup;;
01388 }
01389
01390 Arbiter->AddAllocation(Arbiter, &state);
01391
01392 }
01393
01394
01395
01396
01397
01398
RtlFreeRangeList(Arbiter->Allocation);
01399 temp = Arbiter->Allocation;
01400 Arbiter->Allocation = Arbiter->PossibleAllocation;
01401 Arbiter->PossibleAllocation = temp;
01402
01403
return STATUS_SUCCESS;
01404
01405 cleanup:
01406
01407
RtlFreeRangeList(Arbiter->PossibleAllocation);
01408
return status;
01409
01410 }
01411
01412
01413
NTSTATUS
01414 ArbArbiterHandler(
01415 IN PVOID Context,
01416 IN
ARBITER_ACTION Action,
01417 IN OUT
PARBITER_PARAMETERS Params
01418 )
01419
01420
01421
01422
01423
01424
01425
01426
01427
01428
01429
01430
01431
01432
01433
01434
01435
01436
01437
01438
01439
01440
01441
01442
01443
01444
01445
01446
01447 {
01448
01449
NTSTATUS status;
01450
PARBITER_INSTANCE arbiter = Context;
01451
01452
PAGED_CODE();
01453
ASSERT(Context);
01454
ASSERT(
Action >= 0 &&
Action <=
ArbiterActionBootAllocation);
01455
ASSERT(arbiter->Signature ==
ARBITER_INSTANCE_SIGNATURE);
01456
01457
01458
01459
01460
01461
ArbAcquireArbiterLock(arbiter);
01462
01463
01464
01465
01466
01467
ARB_PRINT(2,
01468 (
"%s %S\n",
01469
ArbpActionStrings[
Action],
01470 arbiter->Name
01471 ));
01472
01473
01474
01475
01476
01477
if (
Action ==
ArbiterActionTestAllocation
01478 ||
Action ==
ArbiterActionRetestAllocation
01479 ||
Action ==
ArbiterActionBootAllocation) {
01480
01481
ASSERT(!arbiter->TransactionInProgress);
01482
01483 }
else if (
Action ==
ArbiterActionCommitAllocation
01484 ||
Action ==
ArbiterActionRollbackAllocation) {
01485
01486
ASSERT(arbiter->TransactionInProgress);
01487 }
01488
01489
#if ARB_DBG
01490
01491 replay:
01492
01493
#endif
01494
01495
01496
01497
01498
01499
switch (
Action) {
01500
01501
case ArbiterActionTestAllocation:
01502
01503
01504
01505
01506
01507
ASSERT(Params->Parameters.TestAllocation.AllocateFromCount == 0);
01508
ASSERT(Params->Parameters.TestAllocation.AllocateFrom ==
NULL);
01509
01510 status = arbiter->TestAllocation(
01511 arbiter,
01512 Params->Parameters.TestAllocation.ArbitrationList
01513 );
01514
break;
01515
01516
case ArbiterActionRetestAllocation:
01517
01518
01519
01520
01521
01522
ASSERT(Params->Parameters.TestAllocation.AllocateFromCount == 0);
01523
ASSERT(Params->Parameters.TestAllocation.AllocateFrom ==
NULL);
01524
01525 status = arbiter->RetestAllocation(
01526 arbiter,
01527 Params->Parameters.TestAllocation.ArbitrationList
01528 );
01529
break;
01530
01531
case ArbiterActionCommitAllocation:
01532
01533 status = arbiter->CommitAllocation(arbiter);
01534
01535
break;
01536
01537
case ArbiterActionRollbackAllocation:
01538
01539 status = arbiter->RollbackAllocation(arbiter);
01540
01541
break;
01542
01543
case ArbiterActionBootAllocation:
01544
01545 status = arbiter->BootAllocation(
01546 arbiter,
01547 Params->Parameters.BootAllocation.ArbitrationList
01548 );
01549
break;
01550
01551
case ArbiterActionQueryConflict:
01552
01553 status = arbiter->QueryConflict(
01554 arbiter,
01555 Params->Parameters.QueryConflict.PhysicalDeviceObject,
01556 Params->Parameters.QueryConflict.ConflictingResource,
01557 Params->Parameters.QueryConflict.ConflictCount,
01558 Params->Parameters.QueryConflict.Conflicts
01559 );
01560
break;
01561
01562
case ArbiterActionQueryArbitrate:
01563
case ArbiterActionQueryAllocatedResources:
01564
case ArbiterActionWriteReservedResources:
01565
case ArbiterActionAddReserved:
01566
01567 status = STATUS_NOT_IMPLEMENTED;
01568
break;
01569
01570
default:
01571 status = STATUS_INVALID_PARAMETER;
01572
break;
01573 }
01574
01575
#if ARB_DBG
01576
01577
01578
01579
01580
01581
if (!
NT_SUCCESS(status)) {
01582
01583
ARB_PRINT(1,
01584 (
"*** %s for %S FAILED status = %08x\n",
01585
ArbpActionStrings[
Action],
01586 arbiter->Name,
01587 status
01588 ));
01589
01590
if (
ArbStopOnError) {
01591 DbgBreakPoint();
01592 }
01593
01594
if (
ArbReplayOnError) {
01595
goto replay;
01596 }
01597 }
01598
01599
#endif // ARB_DBG
01600
01601
if (
NT_SUCCESS(status)) {
01602
01603
if (
Action ==
ArbiterActionTestAllocation
01604 ||
Action ==
ArbiterActionRetestAllocation) {
01605
01606 arbiter->TransactionInProgress =
TRUE;
01607
01608 }
else if (
Action ==
ArbiterActionCommitAllocation
01609 ||
Action ==
ArbiterActionRollbackAllocation) {
01610
01611 arbiter->TransactionInProgress =
FALSE;
01612 }
01613 }
01614
01615
ArbReleaseArbiterLock(arbiter);
01616
01617
return status;
01618
01619 }
01620
01621
NTSTATUS
01622 ArbBuildAssignmentOrdering(
01623 IN OUT PARBITER_INSTANCE Arbiter,
01624 IN PWSTR AllocationOrderName,
01625 IN PWSTR ReservedResourcesName,
01626 IN PARBITER_TRANSLATE_ALLOCATION_ORDER Translate OPTIONAL
01627 )
01628
01629
01630
01631
01632
01633
01634
01635
01636
01637
01638
01639
01640
01641
01642
01643
01644
01645
01646
01647
01648
01649
01650
01651
01652
01653
01654
01655
01656
01657
01658
01659 {
01660
NTSTATUS status;
01661 HANDLE arbitersHandle =
NULL, tempHandle =
NULL;
01662 UNICODE_STRING unicodeString;
01663 PKEY_VALUE_FULL_INFORMATION info =
NULL;
01664 ULONG
dummy;
01665 PIO_RESOURCE_LIST resourceList;
01666 PIO_RESOURCE_DESCRIPTOR current;
01667 ULONGLONG start, end;
01668 OBJECT_ATTRIBUTES attributes;
01669 IO_RESOURCE_DESCRIPTOR translated;
01670
01671
PAGED_CODE();
01672
01673
ArbAcquireArbiterLock(Arbiter);
01674
01675
01676
01677
01678
01679
ArbFreeOrderingList(&Arbiter->OrderingList);
01680
ArbFreeOrderingList(&Arbiter->ReservedList);
01681
01682
01683
01684
01685
01686 status =
ArbInitializeOrderingList(&Arbiter->OrderingList);
01687
01688
if (!
NT_SUCCESS(status)) {
01689
goto cleanup;
01690 }
01691
01692 status =
ArbInitializeOrderingList(&Arbiter->ReservedList);
01693
01694
if (!
NT_SUCCESS(status)) {
01695
goto cleanup;
01696 }
01697
01698
01699
01700
01701
01702
ArbpWstrToUnicodeString(&unicodeString,
PATH_ARBITERS);
01703 InitializeObjectAttributes(&attributes,
01704 &unicodeString,
01705 OBJ_CASE_INSENSITIVE,
01706
NULL,
01707 (PSECURITY_DESCRIPTOR)
NULL
01708 );
01709
01710
01711 status = ZwOpenKey(&arbitersHandle,
01712 KEY_READ,
01713 &attributes
01714 );
01715
01716
if (!
NT_SUCCESS(status)) {
01717
goto cleanup;
01718 }
01719
01720
01721
01722
01723
01724
ArbpWstrToUnicodeString(&unicodeString,
KEY_ALLOCATIONORDER);
01725 InitializeObjectAttributes(&attributes,
01726 &unicodeString,
01727 OBJ_CASE_INSENSITIVE,
01728 arbitersHandle,
01729 (PSECURITY_DESCRIPTOR)
NULL
01730 );
01731
01732
01733 status = ZwOpenKey(&tempHandle,
01734 KEY_READ,
01735 &attributes
01736 );
01737
01738
if (!
NT_SUCCESS(status)) {
01739
goto cleanup;
01740 }
01741
01742
01743
01744
01745
01746 status =
ArbpGetRegistryValue(tempHandle,
01747 AllocationOrderName,
01748 &info
01749 );
01750
01751
if (!
NT_SUCCESS(status)) {
01752
goto cleanup;
01753 }
01754
01755
01756
01757
01758
01759
01760
if (info->Type == REG_SZ) {
01761
01762 PKEY_VALUE_FULL_INFORMATION tempInfo;
01763
01764
01765
01766 status =
ArbpGetRegistryValue(tempHandle,
01767 (PWSTR)
FULL_INFO_DATA(info),
01768 &tempInfo
01769 );
01770
01771
if (!
NT_SUCCESS(status)) {
01772
goto cleanup;
01773 }
01774
01775
ExFreePool(info);
01776 info = tempInfo;
01777
01778 }
01779
01780 ZwClose(tempHandle);
01781
01782
01783
01784
01785
01786
01787
if (info->Type != REG_RESOURCE_REQUIREMENTS_LIST) {
01788 status = STATUS_INVALID_PARAMETER;
01789
goto cleanup;
01790 }
01791
01792
01793
01794
01795
01796
ASSERT(((PIO_RESOURCE_REQUIREMENTS_LIST)
FULL_INFO_DATA(info))
01797 ->AlternativeLists == 1);
01798
01799 resourceList = (PIO_RESOURCE_LIST) &((PIO_RESOURCE_REQUIREMENTS_LIST)
01800
FULL_INFO_DATA(info))->List[0];
01801
01802
01803
01804
01805
01806
FOR_ALL_IN_ARRAY(resourceList->Descriptors,
01807 resourceList->Count,
01808 current) {
01809
01810
01811
01812
01813
01814
if (ARGUMENT_PRESENT(Translate)) {
01815
01816 status = (Translate)(&translated, current);
01817
01818
if (!
NT_SUCCESS(status)) {
01819
goto cleanup;
01820 }
01821 }
else {
01822 translated = *current;
01823 }
01824
01825
if (translated.Type == Arbiter->ResourceType) {
01826
01827 status = Arbiter->UnpackRequirement(&translated,
01828 &start,
01829 &end,
01830 &
dummy,
01831 &
dummy
01832 );
01833
01834
if (!
NT_SUCCESS(status)) {
01835
goto cleanup;
01836 }
01837
01838 status =
ArbAddOrdering(&Arbiter->OrderingList,
01839 start,
01840 end
01841 );
01842
01843
if (!
NT_SUCCESS(status)) {
01844
goto cleanup;
01845 }
01846 }
01847 }
01848
01849
01850
01851
01852
01853
ExFreePool(info);
01854 info =
NULL;
01855
01856
01857
01858
01859
01860
ArbpWstrToUnicodeString(&unicodeString,
KEY_RESERVEDRESOURCES);
01861 InitializeObjectAttributes(&attributes,
01862 &unicodeString,
01863 OBJ_CASE_INSENSITIVE,
01864 arbitersHandle,
01865 (PSECURITY_DESCRIPTOR)
NULL
01866 );
01867
01868
01869 status = ZwCreateKey(&tempHandle,
01870 KEY_READ,
01871 &attributes,
01872 0,
01873 (PUNICODE_STRING)
NULL,
01874 REG_OPTION_NON_VOLATILE,
01875
NULL
01876 );
01877
01878
if (!
NT_SUCCESS(status)) {
01879
goto cleanup;
01880 }
01881
01882
01883
01884
01885
01886 status =
ArbpGetRegistryValue(tempHandle,
01887 ReservedResourcesName,
01888 &info
01889 );
01890
01891
if (!
NT_SUCCESS(status)) {
01892
goto cleanup;
01893 }
01894
01895
01896
01897
01898
01899
01900
if (info->Type == REG_SZ) {
01901
01902 PKEY_VALUE_FULL_INFORMATION tempInfo;
01903
01904
01905
01906 status =
ArbpGetRegistryValue(tempHandle,
01907 (PWSTR)
FULL_INFO_DATA(info),
01908 &tempInfo
01909 );
01910
01911
if (!
NT_SUCCESS(status)) {
01912
goto cleanup;
01913 }
01914
01915
ExFreePool(info);
01916 info = tempInfo;
01917
01918 }
01919
01920 ZwClose(tempHandle);
01921
01922
if (
NT_SUCCESS(status)) {
01923
01924
ASSERT(((PIO_RESOURCE_REQUIREMENTS_LIST)
FULL_INFO_DATA(info))
01925 ->AlternativeLists == 1);
01926
01927 resourceList = (PIO_RESOURCE_LIST) &((PIO_RESOURCE_REQUIREMENTS_LIST)
01928
FULL_INFO_DATA(info))->List[0];
01929
01930
01931
01932
01933
01934
FOR_ALL_IN_ARRAY(resourceList->Descriptors,
01935 resourceList->Count,
01936 current) {
01937
01938
01939
01940
01941
01942
if (ARGUMENT_PRESENT(Translate)) {
01943
01944 status = (Translate)(&translated, current);
01945
01946
if (!
NT_SUCCESS(status)) {
01947
goto cleanup;
01948 }
01949 }
else {
01950 translated = *current;
01951 }
01952
01953
if (translated.Type == Arbiter->ResourceType) {
01954
01955 status = Arbiter->UnpackRequirement(&translated,
01956 &start,
01957 &end,
01958 &
dummy,
01959 &
dummy
01960 );
01961
01962
if (!
NT_SUCCESS(status)) {
01963
goto cleanup;
01964 }
01965
01966
01967
01968
01969
01970 status =
ArbAddOrdering(&Arbiter->ReservedList, start, end);
01971
01972
if (!
NT_SUCCESS(status)) {
01973
goto cleanup;
01974 }
01975
01976
01977
01978
01979
01980 status =
ArbPruneOrdering(&Arbiter->OrderingList, start, end);
01981
01982
if (!
NT_SUCCESS(status)) {
01983
goto cleanup;
01984 }
01985
01986 }
01987 }
01988
01989
ExFreePool(info);
01990 }
01991
01992
01993
01994
01995
01996 ZwClose(arbitersHandle);
01997
01998
#if ARB_DBG
01999
02000 {
02001
PARBITER_ORDERING current;
02002
02003
FOR_ALL_IN_ARRAY(Arbiter->OrderingList.Orderings,
02004 Arbiter->OrderingList.Count,
02005 current) {
02006
ARB_PRINT(2,
02007 (
"Ordering: 0x%I64x-0x%I64x\n",
02008 current->
Start,
02009 current->
End
02010 ));
02011 }
02012
02013
ARB_PRINT(2, (
"\n"));
02014
02015
FOR_ALL_IN_ARRAY(Arbiter->ReservedList.Orderings,
02016 Arbiter->ReservedList.Count,
02017 current) {
02018
ARB_PRINT(2,
02019 (
"Reserved: 0x%I64x-0x%I64x\n",
02020 current->
Start,
02021 current->
End
02022 ));
02023 }
02024
02025 }
02026
02027
#endif
02028
02029
ArbReleaseArbiterLock(Arbiter);
02030
02031
return STATUS_SUCCESS;
02032
02033 cleanup:
02034
02035
if (arbitersHandle) {
02036 ZwClose(arbitersHandle);
02037 }
02038
02039
if (tempHandle) {
02040 ZwClose(tempHandle);
02041 }
02042
02043
if (info) {
02044
ExFreePool(info);
02045 }
02046
02047
if (Arbiter->OrderingList.Orderings) {
02048
ExFreePool(Arbiter->OrderingList.Orderings);
02049 Arbiter->OrderingList.Count = 0;
02050 Arbiter->OrderingList.Maximum = 0;
02051 }
02052
02053
if (Arbiter->ReservedList.Orderings) {
02054
ExFreePool(Arbiter->ReservedList.Orderings);
02055 Arbiter->ReservedList.Count = 0;
02056 Arbiter->ReservedList.Maximum = 0;
02057 }
02058
02059
ArbReleaseArbiterLock(Arbiter);
02060
02061
return status;
02062 }
02063
02064 BOOLEAN
02065 ArbFindSuitableRange(
02066 PARBITER_INSTANCE Arbiter,
02067
PARBITER_ALLOCATION_STATE State
02068 )
02069
02070
02071
02072
02073
02074
02075
02076
02077
02078
02079
02080
02081
02082
02083
02084
02085
02086
02087
02088
02089
02090
02091
02092 {
02093
02094
NTSTATUS status;
02095 ULONG findRangeFlags = 0;
02096
02097
PAGED_CODE();
02098
02099
ASSERT(State->
CurrentAlternative);
02100
02101
02102
02103
02104
02105
if (State->
CurrentMinimum > State->
CurrentMaximum) {
02106
return FALSE;
02107 }
02108
02109
02110
02111
02112
02113
02114
if (State->
CurrentAlternative->
Length == 0) {
02115 State->
End = State->
Start = State->
CurrentMinimum;
02116
return TRUE;
02117 }
02118
02119
02120
02121
02122
02123
02124
02125
02126
02127
02128
if (State->
Entry->
RequestSource ==
ArbiterRequestLegacyReported
02129 || State->
Entry->
RequestSource ==
ArbiterRequestLegacyAssigned) {
02130
02131 State->
RangeAvailableAttributes |=
ARBITER_RANGE_BOOT_ALLOCATED;
02132 }
02133
02134
02135
02136
02137
02138
if (State->
Flags &
ARBITER_STATE_FLAG_NULL_CONFLICT_OK) {
02139 findRangeFlags |= RTL_RANGE_LIST_NULL_CONFLICT_OK;
02140 }
02141
02142
02143
02144
02145
02146
if (State->
CurrentAlternative->
Flags &
ARBITER_ALTERNATIVE_FLAG_SHARED) {
02147 findRangeFlags |= RTL_RANGE_LIST_SHARED_OK;
02148 }
02149
02150
02151
02152
02153
02154 status =
RtlFindRange(
02155 Arbiter->PossibleAllocation,
02156 State->
CurrentMinimum,
02157 State->
CurrentMaximum,
02158 State->
CurrentAlternative->
Length,
02159 State->
CurrentAlternative->
Alignment,
02160 findRangeFlags,
02161 State->
RangeAvailableAttributes,
02162 Arbiter->ConflictCallbackContext,
02163 Arbiter->ConflictCallback,
02164 &State->
Start
02165 );
02166
02167
02168
if (
NT_SUCCESS(status)) {
02169
02170
02171
02172
02173 State->
End = State->
Start + State->
CurrentAlternative->
Length - 1;
02174
02175
return TRUE;
02176
02177 }
else {
02178
02179
02180
02181
02182
02183
02184
return Arbiter->OverrideConflict(Arbiter, State);
02185 }
02186 }
02187
02188
VOID
02189 ArbAddAllocation(
02190 IN PARBITER_INSTANCE Arbiter,
02191 IN
PARBITER_ALLOCATION_STATE State
02192 )
02193
02194
02195
02196
02197
02198
02199
02200
02201
02202
02203
02204
02205
02206
02207
02208
02209
02210
02211
02212
02213
02214 {
02215
02216
NTSTATUS status;
02217
02218
PAGED_CODE();
02219
02220 status =
RtlAddRange(
02221 Arbiter->PossibleAllocation,
02222 State->Start,
02223 State->End,
02224 State->RangeAttributes,
02225 RTL_RANGE_LIST_ADD_IF_CONFLICT +
02226 (State->CurrentAlternative->Flags &
ARBITER_ALTERNATIVE_FLAG_SHARED
02227 ? RTL_RANGE_LIST_ADD_SHARED : 0),
02228
NULL,
02229 State->Entry->PhysicalDeviceObject
02230 );
02231
02232
ASSERT(
NT_SUCCESS(status));
02233
02234 }
02235
02236
02237
VOID
02238 ArbBacktrackAllocation(
02239 IN PARBITER_INSTANCE Arbiter,
02240 IN
PARBITER_ALLOCATION_STATE State
02241 )
02242
02243
02244
02245
02246
02247
02248
02249
02250
02251
02252
02253
02254
02255
02256
02257
02258
02259
02260
02261
02262
02263
02264
02265 {
02266
NTSTATUS status;
02267
02268
PAGED_CODE();
02269
02270
02271
02272
02273
02274
02275 status =
RtlDeleteRange(
02276 Arbiter->PossibleAllocation,
02277 State->Start,
02278 State->End,
02279 State->Entry->PhysicalDeviceObject
02280 );
02281
02282
ASSERT(
NT_SUCCESS(status));
02283
02284
ARB_PRINT(2,
02285 (
"\t\tBacktracking on 0x%I64x-0x%I64x for %p\n",
02286 State->Start,
02287 State->End,
02288 State->Entry->PhysicalDeviceObject
02289 ));
02290
02291 }
02292
02293
02294
NTSTATUS
02295 ArbPreprocessEntry(
02296 IN PARBITER_INSTANCE Arbiter,
02297 IN
PARBITER_ALLOCATION_STATE State
02298 )
02299
02300
02301
02302
02303
02304
02305
02306
02307
02308
02309
02310
02311
02312
02313
02314
02315
02316
02317 {
02318
02319
PAGED_CODE();
02320
02321
return STATUS_SUCCESS;
02322 }
02323
02324
NTSTATUS
02325 ArbAllocateEntry(
02326 IN PARBITER_INSTANCE Arbiter,
02327 IN
PARBITER_ALLOCATION_STATE State
02328 )
02329
02330
02331
02332
02333
02334
02335
02336
02337
02338
02339
02340
02341
02342
02343
02344
02345
02346
02347
02348
02349
02350
02351
02352 {
02353
02354
NTSTATUS status;
02355
PARBITER_ALLOCATION_STATE currentState = State;
02356 BOOLEAN backtracking =
FALSE;
02357
02358
PAGED_CODE();
02359
02360
02361
02362
02363
02364
02365 tryAllocation:
02366
02367
while(currentState >= State && currentState->
Entry !=
NULL) {
02368
02369
02370
02371
02372
02373 status = Arbiter->PreprocessEntry(Arbiter,currentState);
02374
02375
if (!
NT_SUCCESS(status)) {
02376
return status;
02377 }
02378
02379
02380
02381
02382
02383
if (backtracking) {
02384
02385 ULONGLONG possibleCurrentMinimum;
02386
02387 backtracking =
FALSE;
02388
02389
02390
02391
02392
02393
02394
02395
02396
02397
02398 (currentState + 1)->CurrentAlternative =
NULL;
02399
02400
02401
02402
02403
02404
02405
if (currentState->
CurrentAlternative->
Length == 0) {
02406
goto failAllocation;
02407 }
02408
02409
02410
02411
02412
02413 Arbiter->BacktrackAllocation(Arbiter, currentState);
02414
02415
02416
02417
02418
02419
02420 possibleCurrentMinimum = currentState->
Start - 1;
02421
02422
if (possibleCurrentMinimum > currentState->
CurrentMinimum
02423 || possibleCurrentMinimum < currentState->
CurrentAlternative->
Minimum) {
02424
02425
02426
02427
02428
02429
goto continueWithNextAllocationRange;
02430
02431 }
else {
02432
02433 currentState->
CurrentMaximum = possibleCurrentMinimum;
02434
02435
02436
02437
02438
02439
goto continueWithNextSuitableRange;
02440 }
02441 }
02442
02443
02444
02445
02446
02447 continueWithNextAllocationRange:
02448
02449
while (Arbiter->GetNextAllocationRange(Arbiter, currentState)) {
02450
02451
ARB_INDENT(2, (ULONG)(currentState - State));
02452
02453
ARB_PRINT(2,
02454 (
"Testing 0x%I64x-0x%I64x %s\n",
02455 currentState->
CurrentMinimum,
02456 currentState->
CurrentMaximum,
02457 currentState->
CurrentAlternative->
Flags &
ARBITER_ALTERNATIVE_FLAG_SHARED ?
02458
"shared" :
"non-shared"
02459 ));
02460
02461 continueWithNextSuitableRange:
02462
02463
while (Arbiter->FindSuitableRange(Arbiter, currentState)) {
02464
02465
02466
02467
02468
02469
ARB_INDENT(2, (ULONG)(currentState - State));
02470
02471
if (currentState->
CurrentAlternative->
Length != 0) {
02472
02473
ARB_PRINT(2,
02474 (
"Possible solution for %p = 0x%I64x-0x%I64x, %s\n",
02475 currentState->
Entry->
PhysicalDeviceObject,
02476 currentState->
Start,
02477 currentState->
End,
02478 currentState->
CurrentAlternative->
Flags &
ARBITER_ALTERNATIVE_FLAG_SHARED ?
02479
"shared" :
"non-shared"
02480 ));
02481
02482
02483
02484
02485
02486 Arbiter->AddAllocation(Arbiter, currentState);
02487
02488 }
else {
02489
02490
ARB_PRINT(2,
02491 (
"Zero length solution solution for %p = 0x%I64x-0x%I64x, %s\n",
02492 currentState->
Entry->
PhysicalDeviceObject,
02493 currentState->
Start,
02494 currentState->
End,
02495 currentState->
CurrentAlternative->
Flags &
ARBITER_ALTERNATIVE_FLAG_SHARED ?
02496
"shared" :
"non-shared"
02497 ));
02498
02499
02500
02501
02502
02503
02504 currentState->
Entry->
Result =
ArbiterResultNullRequest;
02505 }
02506
02507
02508
02509
02510
02511 currentState++;
02512
goto tryAllocation;
02513 }
02514 }
02515
02516 failAllocation:
02517
02518
02519
02520
02521
02522
if (currentState == State) {
02523
02524
02525
02526
02527
02528
02529
return STATUS_UNSUCCESSFUL;
02530
02531 }
else {
02532
02533
02534
02535
02536
02537
ARB_INDENT(2, (ULONG)(currentState - State));
02538
02539
ARB_PRINT(2,
02540 (
"Allocation failed for %p - backtracking\n",
02541 currentState->
Entry->
PhysicalDeviceObject
02542 ));
02543
02544 backtracking =
TRUE;
02545
02546
02547
02548
02549
02550 currentState--;
02551
goto tryAllocation;
02552 }
02553 }
02554
02555
02556
02557
02558
02559 currentState = State;
02560
02561
while (currentState->
Entry !=
NULL) {
02562
02563 status = Arbiter->PackResource(
02564 currentState->
CurrentAlternative->
Descriptor,
02565 currentState->
Start,
02566 currentState->
Entry->
Assignment
02567 );
02568
02569
ASSERT(
NT_SUCCESS(status));
02570
02571
02572
02573
02574
02575 currentState->
Entry->
SelectedAlternative
02576 = currentState->
CurrentAlternative->
Descriptor;
02577
02578
ARB_PRINT(2,
02579 (
"Assigned - 0x%I64x-0x%I64x\n",
02580 currentState->
Start,
02581 currentState->
End
02582 ));
02583
02584 currentState++;
02585 }
02586
02587
return STATUS_SUCCESS;
02588
02589 }
02590
02591 BOOLEAN
02592 ArbGetNextAllocationRange(
02593 IN PARBITER_INSTANCE Arbiter,
02594 IN OUT
PARBITER_ALLOCATION_STATE State
02595 )
02596
02597
02598
02599
02600
02601
02602
02603
02604
02605
02606
02607
02608
02609
02610
02611
02612
02613
02614
02615
02616
02617 {
02618
02619
PARBITER_ALTERNATIVE current, lowestAlternative;
02620 ULONGLONG
min,
max;
02621
PARBITER_ORDERING ordering;
02622
02623
02624
for (;;) {
02625
02626
if (State->CurrentAlternative) {
02627
02628
02629
02630
02631
02632
ArbpUpdatePriority(Arbiter, State->CurrentAlternative);
02633
02634 }
else {
02635
02636
02637
02638
02639
02640
02641
FOR_ALL_IN_ARRAY(State->Alternatives,
02642 State->AlternativeCount,
02643 current) {
02644
02645 current->
Priority =
ARBITER_PRIORITY_NULL;
02646
ArbpUpdatePriority(Arbiter, current);
02647
02648 }
02649 }
02650
02651
02652
02653
02654
02655 lowestAlternative = State->Alternatives;
02656
02657
FOR_ALL_IN_ARRAY(State->Alternatives + 1,
02658 State->AlternativeCount - 1,
02659 current) {
02660
02661
if (current->
Priority < lowestAlternative->
Priority) {
02662 lowestAlternative = current;
02663 }
02664 }
02665
02666
ARB_INDENT(2, (ULONG)(State - Arbiter->AllocationStack));
02667
02668
02669
02670
02671
02672
if (lowestAlternative->
Priority ==
ARBITER_PRIORITY_EXHAUSTED) {
02673
02674
if (lowestAlternative->
Flags &
ARBITER_ALTERNATIVE_FLAG_FIXED) {
02675
02676
ARB_PRINT(2,(
"Fixed alternative exhausted\n"));
02677
02678 }
else {
02679
02680
ARB_PRINT(2,(
"Alternative exhausted\n"));
02681 }
02682
02683
return FALSE;
02684
02685 }
else {
02686
02687
ARB_PRINT(2,(
02688
"LowestAlternative: [%i] 0x%I64x-0x%I64x L=0x%08x A=0x%08x\n",
02689 lowestAlternative->
Priority,
02690 lowestAlternative->
Minimum,
02691 lowestAlternative->
Maximum,
02692 lowestAlternative->
Length,
02693 lowestAlternative->
Alignment
02694 ));
02695
02696 }
02697
02698
02699
02700
02701
02702
if (lowestAlternative->
Priority ==
ARBITER_PRIORITY_RESERVED
02703 || lowestAlternative->
Priority ==
ARBITER_PRIORITY_PREFERRED_RESERVED) {
02704
02705
02706
02707
02708
02709
02710
02711
min = lowestAlternative->
Minimum;
02712
max = lowestAlternative->
Maximum;
02713
02714
ARB_INDENT(2, (ULONG)(State - Arbiter->AllocationStack));
02715
02716
ARB_PRINT(2,(
"Allowing reserved ranges\n"));
02717
02718 }
else {
02719
02720
ASSERT(
ORDERING_INDEX_FROM_PRIORITY(lowestAlternative->
Priority) >= 0 &&
02721
ORDERING_INDEX_FROM_PRIORITY(lowestAlternative->
Priority) <
02722 Arbiter->OrderingList.Count);
02723
02724
02725
02726
02727
02728 ordering = &Arbiter->OrderingList.Orderings
02729 [
ORDERING_INDEX_FROM_PRIORITY(lowestAlternative->
Priority)];
02730
02731
02732
02733
02734
02735
ASSERT(
INTERSECT(lowestAlternative->
Minimum,
02736 lowestAlternative->
Maximum,
02737 ordering->
Start,
02738 ordering->
End)
02739 &&
INTERSECT_SIZE(lowestAlternative->
Minimum,
02740 lowestAlternative->
Maximum,
02741 ordering->
Start,
02742 ordering->
End) >= lowestAlternative->
Length);
02743
02744
02745
02746
02747
02748
min =
__max(lowestAlternative->
Minimum, ordering->
Start);
02749
02750
max =
__min(lowestAlternative->
Maximum, ordering->
End);
02751
02752 }
02753
02754
02755
02756
02757
02758
02759
if (lowestAlternative->
Length == 0) {
02760
02761
min = lowestAlternative->
Minimum;
02762
max = lowestAlternative->
Maximum;
02763
02764 }
else {
02765
02766
02767
02768
02769
02770
min += lowestAlternative->
Alignment - 1;
02771
min -=
min % lowestAlternative->
Alignment;
02772
02773
if ((lowestAlternative->
Length - 1) > (
max -
min)) {
02774
02775
ARB_INDENT(3, (ULONG)(State - Arbiter->AllocationStack));
02776
ARB_PRINT(3, (
"Range cannot be aligned ... Skipping\n"));
02777
02778
02779
02780
02781
02782
02783 State->CurrentAlternative = lowestAlternative;
02784
continue;
02785 }
02786
02787
max -= lowestAlternative->
Length - 1;
02788
max -=
max % lowestAlternative->
Alignment;
02789
max += lowestAlternative->
Length - 1;
02790
02791 }
02792
02793
02794
02795
02796
02797
02798
if (
min == State->CurrentMinimum
02799 &&
max == State->CurrentMaximum
02800 && State->CurrentAlternative == lowestAlternative) {
02801
02802
ARB_INDENT(2, (ULONG)(State - Arbiter->AllocationStack));
02803
02804
ARB_PRINT(2,
02805 (
"Skipping identical allocation range\n"
02806 ));
02807
02808
continue;
02809 }
02810
02811 State->CurrentMinimum =
min;
02812 State->CurrentMaximum =
max;
02813 State->CurrentAlternative = lowestAlternative;
02814
02815
ARB_INDENT(2, (ULONG)(State - Arbiter->AllocationStack));
02816
ARB_PRINT(1, (
"AllocationRange: 0x%I64x-0x%I64x\n",
min,
max));
02817
02818
return TRUE;
02819
02820 }
02821 }
02822
02823
NTSTATUS
02824 ArbpGetRegistryValue(
02825 IN HANDLE KeyHandle,
02826 IN PWSTR ValueName,
02827 OUT PKEY_VALUE_FULL_INFORMATION *Information
02828 )
02829
02830
02831
02832
02833
02834
02835
02836
02837
02838
02839
02840
02841
02842
02843
02844
02845
02846
02847
02848
02849
02850
02851
02852
02853
02854
02855
02856
02857
02858
02859
02860 {
02861 UNICODE_STRING unicodeString;
02862
NTSTATUS status;
02863 PKEY_VALUE_FULL_INFORMATION infoBuffer;
02864 ULONG keyValueLength;
02865
02866
PAGED_CODE();
02867
02868
RtlInitUnicodeString( &unicodeString,
ValueName );
02869
02870
02871
02872
02873
02874
02875 status = ZwQueryValueKey( KeyHandle,
02876 &unicodeString,
02877 KeyValueFullInformationAlign64,
02878 (PVOID)
NULL,
02879 0,
02880 &keyValueLength );
02881
if (status != STATUS_BUFFER_OVERFLOW &&
02882 status != STATUS_BUFFER_TOO_SMALL) {
02883
return status;
02884 }
02885
02886
02887
02888
02889
02890 infoBuffer =
ExAllocatePoolWithTag(
PagedPool,
02891 keyValueLength,
02892
ARBITER_MISC_TAG
02893 );
02894
02895
if (!infoBuffer) {
02896
return STATUS_INSUFFICIENT_RESOURCES;
02897 }
02898
02899
02900
02901
02902
02903 status = ZwQueryValueKey( KeyHandle,
02904 &unicodeString,
02905 KeyValueFullInformationAlign64,
02906 infoBuffer,
02907 keyValueLength,
02908 &keyValueLength );
02909
if (!
NT_SUCCESS( status )) {
02910
ExFreePool( infoBuffer );
02911
return status;
02912 }
02913
02914
02915
02916
02917
02918
02919 *Information = infoBuffer;
02920
return STATUS_SUCCESS;
02921 }
02922
02923
02924 #define ARBITER_ORDERING_LIST_INITIAL_SIZE 16
02925
02926
NTSTATUS
02927 ArbInitializeOrderingList(
02928 IN OUT
PARBITER_ORDERING_LIST List
02929 )
02930
02931
02932
02933
02934
02935
02936
02937
02938
02939
02940
02941
02942
02943
02944
02945
02946
02947 {
02948
PAGED_CODE();
02949
02950
ASSERT(
List);
02951
02952
List->Orderings =
ExAllocatePoolWithTag(
PagedPool,
02953
ARBITER_ORDERING_LIST_INITIAL_SIZE *
02954
sizeof(
ARBITER_ORDERING),
02955
ARBITER_ORDERING_LIST_TAG
02956 );
02957
02958
if (!
List->Orderings) {
02959
List->Maximum = 0;
02960
List->Count = 0;
02961
return STATUS_INSUFFICIENT_RESOURCES;
02962 }
02963
02964
List->Count = 0;
02965
List->Maximum =
ARBITER_ORDERING_LIST_INITIAL_SIZE;
02966
02967
return STATUS_SUCCESS;
02968 }
02969
02970
NTSTATUS
02971 ArbCopyOrderingList(
02972 OUT
PARBITER_ORDERING_LIST Destination,
02973 IN
PARBITER_ORDERING_LIST Source
02974 )
02975
02976
02977
02978
02979
02980
02981
02982
02983
02984
02985
02986
02987
02988
02989
02990
02991
02992
02993
02994
02995 {
02996
02997
PAGED_CODE()
02998
02999
ASSERT(Source->Count <= Source->Maximum);
03000
ASSERT(Source->Maximum > 0);
03001
03002 Destination->Orderings =
03003
ExAllocatePoolWithTag(
PagedPool,
03004 Source->Maximum *
sizeof(
ARBITER_ORDERING),
03005
ARBITER_ORDERING_LIST_TAG
03006 );
03007
03008
if (Destination->Orderings ==
NULL) {
03009
return STATUS_INSUFFICIENT_RESOURCES;
03010 }
03011
03012 Destination->Count = Source->Count;
03013 Destination->Maximum = Source->Maximum;
03014
03015
if (Source->Count > 0) {
03016
03017 RtlCopyMemory(Destination->Orderings,
03018 Source->Orderings,
03019 Source->Count *
sizeof(
ARBITER_ORDERING)
03020 );
03021 }
03022
03023
return STATUS_SUCCESS;
03024 }
03025
03026
03027
NTSTATUS
03028 ArbAddOrdering(
03029 OUT
PARBITER_ORDERING_LIST List,
03030 IN ULONGLONG Start,
03031 IN ULONGLONG End
03032 )
03033
03034
03035
03036
03037
03038
03039
03040
03041
03042
03043
03044
03045
03046
03047
03048
03049
03050
03051
03052
03053
03054
03055 {
03056
03057
03058
03059
03060
03061
if (
End <
Start) {
03062
return STATUS_INVALID_PARAMETER;
03063 }
03064
03065
03066
03067
03068
03069
if (
List->Count ==
List->Maximum) {
03070
03071
PARBITER_ORDERING temp;
03072
03073
03074
03075
03076
03077 temp =
ExAllocatePoolWithTag(
PagedPool,
03078 (
List->Count +
ARBITER_ORDERING_GROW_SIZE) *
03079
sizeof(
ARBITER_ORDERING),
03080
ARBITER_ORDERING_LIST_TAG
03081 );
03082
03083
if (!temp) {
03084
return STATUS_INSUFFICIENT_RESOURCES;
03085 }
03086
03087
03088
03089
03090
03091
if (
List->Orderings) {
03092
03093 RtlCopyMemory(temp,
03094
List->Orderings,
03095
List->Count *
sizeof(
ARBITER_ORDERING)
03096 );
03097
03098
ExFreePool(
List->Orderings);
03099 }
03100
03101
List->Maximum +=
ARBITER_ORDERING_GROW_SIZE;
03102
List->Orderings = temp;
03103
03104 }
03105
03106
03107
03108
03109
03110
List->Orderings[
List->Count].Start =
Start;
03111
List->Orderings[
List->Count].End =
End;
03112
List->Count++;
03113
03114
ASSERT(
List->Count <=
List->Maximum);
03115
03116
return STATUS_SUCCESS;
03117 }
03118
03119
NTSTATUS
03120 ArbPruneOrdering(
03121 IN OUT
PARBITER_ORDERING_LIST OrderingList,
03122 IN ULONGLONG Start,
03123 IN ULONGLONG End
03124 )
03125
03126
03127
03128
03129
03130
03131
03132
03133
03134
03135
03136
03137
03138
03139
03140
03141
03142
03143
03144
03145
03146
03147
03148
03149
03150
03151
03152 {
03153
03154
NTSTATUS status;
03155
PARBITER_ORDERING current, currentInsert, newOrdering =
NULL, temp =
NULL;
03156
USHORT count;
03157
03158
ASSERT(OrderingList);
03159
ASSERT(OrderingList->Orderings);
03160
03161
03162
03163
03164
03165
if (
End <
Start) {
03166 status = STATUS_INVALID_PARAMETER;
03167
goto cleanup;
03168 }
03169
03170
03171
03172
03173
03174 newOrdering =
ExAllocatePoolWithTag(
PagedPool,
03175 (OrderingList->Count * 2 + 1) *
03176
sizeof(
ARBITER_ORDERING),
03177
ARBITER_ORDERING_LIST_TAG
03178 );
03179
03180
if (!newOrdering) {
03181 status = STATUS_INSUFFICIENT_RESOURCES;
03182
goto cleanup;
03183 }
03184
03185 currentInsert = newOrdering;
03186
03187
03188
03189
03190
03191
if (OrderingList->Count > 0) {
03192
03193
03194
03195
03196
03197
FOR_ALL_IN_ARRAY(OrderingList->Orderings, OrderingList->Count, current) {
03198
03199
if (
End < current->
Start ||
Start > current->
End) {
03200
03201
03202
03203
03204
03205
03206
03207
03208 *currentInsert++ = *current;
03209
03210 }
else if (
Start > current->
Start) {
03211
03212
if (
End < current->
End) {
03213
03214
03215
03216
03217
03218
03219
03220
03221 currentInsert->
Start =
End + 1;
03222 currentInsert->
End = current->
End;
03223 currentInsert++;
03224
03225 currentInsert->
Start = current->
Start;
03226 currentInsert->
End =
Start - 1;
03227 currentInsert++;
03228
03229
03230 }
else {
03231
03232
03233
03234
03235
03236
03237
03238
03239
ASSERT(
End >= current->
End);
03240
03241 currentInsert->
Start = current->
Start;
03242 currentInsert->
End =
Start - 1;
03243 currentInsert++;
03244 }
03245 }
else {
03246
03247
ASSERT(Start <= current->
Start);
03248
03249
if (
End < current->
End) {
03250
03251
03252
03253
03254
03255
03256
03257
03258 currentInsert->
Start =
End + 1;
03259 currentInsert->
End = current->
End;
03260 currentInsert++;
03261
03262 }
else {
03263
03264
ASSERT(
End >= current->
End);
03265
03266
03267
03268
03269
03270
03271
03272
03273 }
03274 }
03275 }
03276 }
03277
03278
03279
ASSERT(currentInsert - newOrdering >= 0);
03280
03281 count = (
USHORT)(currentInsert - newOrdering);
03282
03283
03284
03285
03286
03287
if (count > 0) {
03288
03289
if (count > OrderingList->Maximum) {
03290
03291
03292
03293
03294
03295 temp =
03296
ExAllocatePoolWithTag(
PagedPool,
03297 count *
sizeof(
ARBITER_ORDERING),
03298
ARBITER_ORDERING_LIST_TAG
03299 );
03300
03301
if (!temp) {
03302 status = STATUS_INSUFFICIENT_RESOURCES;
03303
goto cleanup;
03304 }
03305
03306
if (OrderingList->Orderings) {
03307
ExFreePool(OrderingList->Orderings);
03308 }
03309
03310 OrderingList->Orderings = temp;
03311 OrderingList->Maximum = count;
03312
03313 }
03314
03315
03316
03317
03318
03319
03320 RtlCopyMemory(OrderingList->Orderings,
03321 newOrdering,
03322 count *
sizeof(
ARBITER_ORDERING)
03323 );
03324 }
03325
03326
03327
03328
03329
03330
ExFreePool(newOrdering);
03331
03332 OrderingList->Count = count;
03333
03334
return STATUS_SUCCESS;
03335
03336 cleanup:
03337
03338
if (newOrdering) {
03339
ExFreePool(newOrdering);
03340 }
03341
03342
if (temp) {
03343
ExFreePool(temp);
03344 }
03345
03346
return status;
03347
03348 }
03349
VOID
03350 ArbFreeOrderingList(
03351 IN
PARBITER_ORDERING_LIST List
03352 )
03353
03354
03355
03356
03357
03358
03359
03360
03361
03362
03363
03364
03365
03366
03367
03368
03369 {
03370
if (
List->Orderings) {
03371
ASSERT(
List->Maximum);
03372
ExFreePool(
List->Orderings);
03373 }
03374
03375
List->Count = 0;
03376
List->Maximum = 0;
03377
List->Orderings =
NULL;
03378 }
03379
03380
03381
03382 BOOLEAN
03383 ArbOverrideConflict(
03384 IN PARBITER_INSTANCE Arbiter,
03385 IN
PARBITER_ALLOCATION_STATE State
03386 )
03387
03388
03389
03390
03391
03392
03393
03394
03395
03396
03397
03398
03399
03400
03401
03402
03403
03404
03405
03406 {
03407
03408 PRTL_RANGE current;
03409 RTL_RANGE_LIST_ITERATOR iterator;
03410 BOOLEAN ok =
FALSE;
03411
03412
PAGED_CODE();
03413
03414
if (!(State->CurrentAlternative->Flags &
ARBITER_ALTERNATIVE_FLAG_FIXED)) {
03415
return FALSE;
03416 }
03417
03418 FOR_ALL_RANGES(Arbiter->PossibleAllocation, &iterator, current) {
03419
03420
03421
03422
03423
03424
if (
INTERSECT(current->Start, current->End, State->CurrentMinimum, State->CurrentMaximum)) {
03425
03426
03427
03428
03429
03430
03431
if (current->Attributes & State->RangeAvailableAttributes) {
03432
03433
03434
03435
03436
03437
03438
03439
continue;
03440 }
03441
03442
03443
03444
03445
03446
03447
if (current->Owner == State->Entry->PhysicalDeviceObject
03448 && State->CurrentAlternative->Flags &
ARBITER_ALTERNATIVE_FLAG_FIXED) {
03449
03450 State->Start=State->CurrentMinimum;
03451 State->End=State->CurrentMaximum;
03452
03453 ok =
TRUE;
03454
continue;
03455 }
03456
03457
03458
03459
03460
03461
return FALSE;
03462 }
03463 }
03464
return ok;
03465 }
03466
03467
VOID
03468 ArbpUpdatePriority(
03469 PARBITER_INSTANCE Arbiter,
03470
PARBITER_ALTERNATIVE Alternative
03471 )
03472
03473
03474
03475
03476
03477
03478
03479
03480
03481
03482
03483
03484
03485
03486
03487
03488
03489
03490
03491
03492
03493
03494
03495
03496
03497
03498
03499
03500
03501
03502
03503
03504
03505
03506
03507
03508
03509
03510
03511
03512
03513
03514
03515
03516
03517
03518
03519
03520 {
03521
03522
PARBITER_ORDERING ordering;
03523 BOOLEAN preferred;
03524 LONG priority;
03525
03526
PAGED_CODE();
03527
03528 priority = Alternative->
Priority;
03529
03530
03531
03532
03533
03534
if (priority ==
ARBITER_PRIORITY_RESERVED
03535 || priority ==
ARBITER_PRIORITY_PREFERRED_RESERVED) {
03536
03537 Alternative->
Priority =
ARBITER_PRIORITY_EXHAUSTED;
03538
return;
03539 }
03540
03541
03542
03543
03544
03545 preferred = Alternative->
Descriptor->Option & IO_RESOURCE_PREFERRED;
03546
03547
03548
03549
03550
03551
03552
if (priority ==
ARBITER_PRIORITY_NULL) {
03553
03554 ordering = Arbiter->OrderingList.Orderings;
03555
03556 }
else {
03557
03558
03559
03560
03561
03562
03563
03564
03565
if (Alternative->
Flags &
ARBITER_ALTERNATIVE_FLAG_FIXED) {
03566
03567 Alternative->
Priority =
ARBITER_PRIORITY_EXHAUSTED;
03568
03569
return;
03570 }
03571
03572
ASSERT(
ORDERING_INDEX_FROM_PRIORITY(Alternative->
Priority) >= 0 &&
03573
ORDERING_INDEX_FROM_PRIORITY(Alternative->
Priority) <
03574 Arbiter->OrderingList.Count);
03575
03576 ordering = &Arbiter->OrderingList.Orderings
03577 [
ORDERING_INDEX_FROM_PRIORITY(Alternative->
Priority) + 1];
03578
03579 }
03580
03581
03582
03583
03584
03585
03586
FOR_REST_IN_ARRAY(Arbiter->OrderingList.Orderings,
03587 Arbiter->OrderingList.Count,
03588 ordering) {
03589
03590
03591
03592
03593
03594
if (
INTERSECT(Alternative->
Minimum, Alternative->
Maximum,
03595 ordering->
Start, ordering->
End)
03596 &&
INTERSECT_SIZE(Alternative->
Minimum, Alternative->
Maximum,
03597 ordering->
Start,ordering->
End) >= Alternative->
Length) {
03598
03599
03600
03601
03602
03603 Alternative->
Priority = (LONG)(ordering - Arbiter->OrderingList.Orderings + 1);
03604
03605
03606
03607
03608
03609
if (preferred) {
03610 Alternative->
Priority *= -1;
03611 }
03612
03613
return;
03614 }
03615 }
03616
03617
03618
03619
03620
03621
if (preferred) {
03622 Alternative->
Priority =
ARBITER_PRIORITY_PREFERRED_RESERVED;
03623 }
else {
03624 Alternative->
Priority =
ARBITER_PRIORITY_RESERVED;
03625 }
03626
03627 }
03628
03629
NTSTATUS
03630 ArbAddReserved(
03631 IN PARBITER_INSTANCE Arbiter,
03632 IN PIO_RESOURCE_DESCRIPTOR Requirement OPTIONAL,
03633 IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Resource OPTIONAL
03634 )
03635 {
03636
PAGED_CODE();
03637
03638
return STATUS_NOT_SUPPORTED;
03639 }
03640
03641 BOOLEAN
03642 ArbpQueryConflictCallback(
03643 IN PVOID Context,
03644 IN PRTL_RANGE Range
03645 )
03646
03647
03648
03649
03650
03651
03652
03653
03654
03655
03656
03657
03658
03659
03660
03661
03662
03663
03664
03665
03666
03667 {
03668 PRTL_RANGE *conflictingRange = (PRTL_RANGE*)Context;
03669
03670
PAGED_CODE();
03671
03672
ARB_PRINT(2,(
"Possible conflict: (%p) 0x%I64x-0x%I64x Owner: %p",
03673 Range,
03674 Range->Start,
03675 Range->End,
03676 Range->Owner
03677 ));
03678
03679
03680
03681
03682
03683 *conflictingRange = Range;
03684
03685
03686
03687
03688
03689
03690
return FALSE;
03691 }
03692
03693
03694
NTSTATUS
03695 ArbQueryConflict(
03696 IN PARBITER_INSTANCE Arbiter,
03697 IN
PDEVICE_OBJECT PhysicalDeviceObject,
03698 IN PIO_RESOURCE_DESCRIPTOR ConflictingResource,
03699 OUT PULONG ConflictCount,
03700 OUT
PARBITER_CONFLICT_INFO *Conflicts
03701 )
03702
03703
03704
03705
03706
03707
03708
03709
03710
03711
03712
03713
03714
03715
03716
03717
03718
03719
03720
03721
03722
03723
03724
03725
03726 {
03727
NTSTATUS status;
03728 RTL_RANGE_LIST backupAllocation;
03729 BOOLEAN backedUp =
FALSE;
03730
ARBITER_LIST_ENTRY entry;
03731
ARBITER_ALLOCATION_STATE state;
03732
ARBITER_ALTERNATIVE alternative;
03733 ULONG count = 0, size = 10;
03734 PRTL_RANGE conflictingRange;
03735
PARBITER_CONFLICT_INFO conflictInfo =
NULL;
03736 PVOID savedContext;
03737 PRTL_CONFLICT_RANGE_CALLBACK savedCallback;
03738 ULONG sz;
03739
03740
PAGED_CODE();
03741
03742
ASSERT(PhysicalDeviceObject);
03743
ASSERT(ConflictingResource);
03744
ASSERT(ConflictCount);
03745
ASSERT(Conflicts);
03746
03747
03748
03749 savedCallback = Arbiter->ConflictCallback;
03750 savedContext = Arbiter->ConflictCallbackContext;
03751 Arbiter->ConflictCallback =
ArbpQueryConflictCallback;
03752 Arbiter->ConflictCallbackContext = &conflictingRange;
03753
03754
03755
03756
03757
03758
03759
if (Arbiter->TransactionInProgress) {
03760
03761
RtlInitializeRangeList(&backupAllocation);
03762
03763 status =
RtlCopyRangeList(&backupAllocation, Arbiter->PossibleAllocation);
03764
03765
if (!
NT_SUCCESS(status)) {
03766
goto cleanup;
03767 }
03768
03769
RtlFreeRangeList(Arbiter->PossibleAllocation);
03770
03771 backedUp =
TRUE;
03772 }
03773
03774
03775
03776
03777
03778
03779 status =
RtlCopyRangeList(Arbiter->PossibleAllocation, Arbiter->Allocation);
03780
03781
if (!
NT_SUCCESS(status)) {
03782
goto cleanup;
03783 }
03784
03785 status =
ArbpBuildAlternative(Arbiter, ConflictingResource, &alternative);
03786
03787
if (!
NT_SUCCESS(status)) {
03788
goto cleanup;
03789 }
03790
03791 RtlZeroMemory(&state,
sizeof(
ARBITER_ALLOCATION_STATE));
03792
03793 state.
Start = alternative.
Minimum;
03794 state.
End = alternative.
Maximum;
03795 state.
CurrentMinimum = state.
Start;
03796 state.
CurrentMaximum = state.
End;
03797 state.
CurrentAlternative = &alternative;
03798 state.
AlternativeCount = 1;
03799 state.
Alternatives = &alternative;
03800 state.
Flags =
ARBITER_STATE_FLAG_CONFLICT;
03801 state.
Entry = &entry;
03802
03803
03804
03805
03806 RtlZeroMemory(&entry,
sizeof(
ARBITER_LIST_ENTRY));
03807 entry.
RequestSource =
ArbiterRequestPnpEnumerated;
03808 entry.
PhysicalDeviceObject = PhysicalDeviceObject;
03809
03810
03811
03812
03813
03814
03815
03816
03817
if (!
NT_SUCCESS(
IoGetDeviceProperty(PhysicalDeviceObject,
DevicePropertyLegacyBusType,
sizeof(entry.
InterfaceType),&entry.
InterfaceType,&sz))) {
03818 entry.
InterfaceType = Isa;
03819 }
03820
if (!
NT_SUCCESS(
IoGetDeviceProperty(PhysicalDeviceObject,
DevicePropertyBusNumber,
sizeof(entry.
InterfaceType),&entry.
BusNumber,&sz))) {
03821 entry.
BusNumber = 0;
03822 }
03823
03824
03825
03826
03827
03828 conflictInfo =
ExAllocatePoolWithTag(
PagedPool,
03829 size *
sizeof(
ARBITER_CONFLICT_INFO),
03830
ARBITER_CONFLICT_INFO_TAG
03831 );
03832
03833
if (!conflictInfo) {
03834 status = STATUS_INSUFFICIENT_RESOURCES;
03835
goto cleanup;
03836 }
03837
03838
03839
03840
03841
03842 status = Arbiter->PreprocessEntry(Arbiter, &state);
03843
03844
if (!
NT_SUCCESS(status)) {
03845
goto cleanup;
03846 }
03847
03848
03849
03850
03851
03852
03853
03854
03855
03856
03857 status =
RtlDeleteOwnersRanges(Arbiter->PossibleAllocation,
03858 state.
Entry->
PhysicalDeviceObject
03859 );
03860
03861
03862
03863
03864 conflictingRange =
NULL;
03865 state.
CurrentMinimum = state.
Start;
03866 state.
CurrentMaximum = state.
End;
03867
03868
while (!Arbiter->FindSuitableRange(Arbiter, &state)) {
03869
03870
if (count == size) {
03871
03872
03873
03874
03875
03876
PARBITER_CONFLICT_INFO temp = conflictInfo;
03877
03878 size += 5;
03879
03880 conflictInfo =
03881
ExAllocatePoolWithTag(
PagedPool,
03882 size *
sizeof(
ARBITER_CONFLICT_INFO),
03883
ARBITER_CONFLICT_INFO_TAG
03884 );
03885
03886
if (!conflictInfo) {
03887 status = STATUS_INSUFFICIENT_RESOURCES;
03888 conflictInfo = temp;
03889
goto cleanup;
03890 }
03891
03892 RtlCopyMemory(conflictInfo,
03893 temp,
03894 count *
sizeof(
ARBITER_CONFLICT_INFO)
03895 );
03896
03897
ExFreePool(temp);
03898
03899 }
03900
03901
if (conflictingRange !=
NULL) {
03902 conflictInfo[count].
OwningObject = conflictingRange->Owner;
03903 conflictInfo[count].
Start = conflictingRange->Start;
03904 conflictInfo[count].
End = conflictingRange->End;
03905
03906 count++;
03907
03908
03909
03910
03911
#if 0
03912
status =
RtlDeleteRange(Arbiter->PossibleAllocation,
03913 conflictingRange->Start,
03914 conflictingRange->End,
03915 conflictingRange->Owner
03916 );
03917
#endif
03918
status =
RtlDeleteOwnersRanges(Arbiter->PossibleAllocation,
03919 conflictingRange->Owner
03920 );
03921
03922
if (!
NT_SUCCESS(status)) {
03923
goto cleanup;
03924 }
03925
03926 }
else {
03927
03928
03929
03930
ARB_PRINT(0,(
"Conflict detected - but someone hasn't set conflicting info\n"));
03931
03932 conflictInfo[count].
OwningObject =
NULL;
03933 conflictInfo[count].
Start = (ULONGLONG)0;
03934 conflictInfo[count].
End = (ULONGLONG)(-1);
03935
03936 count++;
03937
03938
03939
03940
03941
break;
03942 }
03943
03944
03945
03946
03947 conflictingRange =
NULL;
03948 state.
CurrentMinimum = state.
Start;
03949 state.
CurrentMaximum = state.
End;
03950 }
03951
03952
RtlFreeRangeList(Arbiter->PossibleAllocation);
03953
03954
if (Arbiter->TransactionInProgress) {
03955
03956 status =
RtlCopyRangeList(Arbiter->PossibleAllocation, &backupAllocation);
03957
03958
if (!
NT_SUCCESS(status)) {
03959
goto cleanup;
03960 }
03961
03962
RtlFreeRangeList(&backupAllocation);
03963 }
03964
03965 Arbiter->ConflictCallback = savedCallback;
03966 Arbiter->ConflictCallbackContext = savedContext;
03967
03968 *Conflicts = conflictInfo;
03969 *ConflictCount = count;
03970
03971
return STATUS_SUCCESS;
03972
03973 cleanup:
03974
03975
if (conflictInfo) {
03976
ExFreePool(conflictInfo);
03977 }
03978
03979
RtlFreeRangeList(Arbiter->PossibleAllocation);
03980
03981
if (Arbiter->TransactionInProgress && backedUp) {
03982 status =
RtlCopyRangeList(Arbiter->PossibleAllocation, &backupAllocation);
03983
RtlFreeRangeList(&backupAllocation);
03984 }
03985
03986 Arbiter->ConflictCallback = savedCallback;
03987 Arbiter->ConflictCallbackContext = savedContext;
03988
03989 *Conflicts =
NULL;
03990
03991
return status;
03992 }
03993
03994
03995
NTSTATUS
03996 ArbStartArbiter(
03997 IN PARBITER_INSTANCE Arbiter,
03998 IN PCM_RESOURCE_LIST StartResources
03999 )
04000
04001
04002
04003
04004
04005
04006
04007
04008
04009
04010
04011
04012
04013
04014
04015
04016
04017
04018
04019
04020
04021
04022
04023 {
04024
PAGED_CODE();
04025
04026
return STATUS_SUCCESS;
04027 }
04028
04029
04030
04031
04032
VOID
04033 ArbpIndent(
04034 IN ULONG Count
04035 )
04036 {
04037 UCHAR spaces[80];
04038
04039
ASSERT(
Count <= 80);
04040
04041 RtlFillMemory(spaces,
Count,
'*');
04042
04043 spaces[
Count] = 0;
04044
04045
DbgPrint(
"%s", spaces);
04046
04047 }