Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

arbiter.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1997 Microsoft Corporation 00004 00005 Module Name: 00006 00007 arbiter.c 00008 00009 Abstract: 00010 00011 This module contains support routines for the Pnp resource arbiters. 00012 00013 Author: 00014 00015 Andrew Thornton (andrewth) 1-April-1997 00016 00017 00018 Environment: 00019 00020 Kernel mode 00021 00022 Revision History: 00023 00024 --*/ 00025 00026 #include "arbp.h" 00027 00028 // 00029 // Conditional compilation constants 00030 // 00031 00032 #define ALLOW_BOOT_ALLOC_CONFLICTS 1 00033 #define PLUG_FEST_HACKS 0 00034 00035 // 00036 // Pool Tags 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 // Constants 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 // Macros 00057 // 00058 00059 // 00060 // PVOID 00061 // FULL_INFO_DATA( 00062 // IN PKEY_VALUE_FULL_INFORMATION k 00063 // ); 00064 // 00065 // This macro returns the pointer to the beginning of the data area of a 00066 // KEY_VALUE_FULL_INFORMATION structure. 00067 // 00068 00069 #define FULL_INFO_DATA(k) ((PCHAR)(k) + (k)->DataOffset) 00070 00071 // 00072 // BOOLEAN 00073 // DISJOINT( 00074 // IN ULONGLONG s1, 00075 // IN ULONGLONG e1, 00076 // IN ULONGLONG s2, 00077 // IN ULONGLONG e2 00078 // ); 00079 // 00080 #define DISJOINT(s1,e1,s2,e2) \ 00081 ( ((s1) < (s2) && (e1) < (s2)) \ 00082 ||((s2) < (s1) && (e2) < (s1)) ) 00083 00084 // 00085 // VOID 00086 // ArbpWstrToUnicodeString( 00087 // IN PUNICODE_STRING u, 00088 // IN PWSTR p 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 // ULONG 00099 // INDEX_FROM_PRIORITY( 00100 // LONG Priority 00101 // ); 00102 // 00103 00104 #define ORDERING_INDEX_FROM_PRIORITY(P) \ 00105 ( (ULONG) ( (P) > 0 ? (P) - 1 : ((P) * -1) - 1) ) 00106 00107 // 00108 // Prototypes 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 // Make everything pageable 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 // Implementation 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 Routine Description: 00204 00205 This routine initializes an arbiter instance and fills in any optional NULL 00206 dispatch table entries with system default functions. 00207 00208 Parameters: 00209 00210 Arbiter - A caller allocated arbiter instance structure. 00211 The UnpackRequirement, PackResource, UnpackResource and ScoreRequirement 00212 entries should be initialized with the appropriate routines as should 00213 any other entries if the default system routines are not sufficient. 00214 00215 BusDeviceObject - The device object that exposes this arbiter - normally an 00216 FDO. 00217 00218 ResourceType - The resource type this arbiter arbitrates. 00219 00220 Name - A string used to identify the arbiter, used in debug messages and 00221 for registry storage 00222 00223 OrderingName - The name of the preferred assignment ordering list under 00224 HKLM\System\CurrentControlSet\Control\SystemResources\AssignmentOrdering 00225 00226 00227 TranslateOrdering - Function that, if present, will be called to translate 00228 each descriptor from the ordering list 00229 00230 Return Value: 00231 00232 Status code that indicates whether or not the function was successful. 00233 00234 Notes: 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 // Initialize all pool allocation pointers to NULL so we can cleanup 00252 // 00253 00254 ASSERT(Arbiter->MutexEvent == NULL 00255 && Arbiter->Allocation == NULL 00256 && Arbiter->PossibleAllocation == NULL 00257 && Arbiter->AllocationStack == NULL 00258 ); 00259 00260 // 00261 // We are an arbiter 00262 // 00263 00264 Arbiter->Signature = ARBITER_INSTANCE_SIGNATURE; 00265 00266 // 00267 // Remember the bus that produced us 00268 // 00269 00270 Arbiter->BusDeviceObject = BusDeviceObject; 00271 00272 // 00273 // Initialize state lock (KEVENT must be non-paged) 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 // Initialize the allocation stack to a reasonable size 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 // Allocate buffers to hold the range lists 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 // Initialize the range lists 00331 // 00332 00333 RtlInitializeRangeList(Arbiter->Allocation); 00334 RtlInitializeRangeList(Arbiter->PossibleAllocation); 00335 00336 // 00337 // Initialize the data fields 00338 // 00339 Arbiter->TransactionInProgress = FALSE; 00340 Arbiter->Name = Name; 00341 Arbiter->ResourceType = ResourceType; 00342 00343 // 00344 // If the caller has not supplied the optional functions set them to the 00345 // defaults (If this were C++ we'd just inherit this loit but seeing as its 00346 // not we'll do it the old fashioned way...) 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 // Build the prefered assignment ordering - we assume that the reserved 00411 // ranges have the same name as the assignment ordering 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 Routine Description: 00514 00515 This is the default implementation of the arbiter Test Allocation action. 00516 It takes a list of requests for resources for particular devices and attempts 00517 to satisfy them. 00518 00519 Parameters: 00520 00521 Arbiter - The instance of the arbiter being called. 00522 00523 ArbitrationList - A list of ARBITER_LIST_ENTRY entries which contain the 00524 requirements and associated devices. 00525 00526 Return Value: 00527 00528 Status code that indicates whether or not the function was successful. 00529 These include: 00530 00531 STATUS_SUCCESSFUL - Arbitration suceeded and an allocation has been made for 00532 all the entries in the arbitration list. 00533 00534 STATUS_UNSUCCESSFUL - Arbitration failed to find an allocation for all 00535 entries. 00536 00537 STATUS_ARBITRATION_UNHANDLED - If returning this error the arbiter is 00538 partial (and therefore must have set the ARBITER_PARTIAL flag in its 00539 interface.) This status indicates that this arbiter doesn't handle the 00540 resources requested and the next arbiter towards the root of the device 00541 tree should be asked instead. 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 // Copy the current allocation 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 // Free all the resources currently allocated to all the devices we 00572 // are arbitrating for 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 // Score the entries in the arbitration list if a scoring function was 00604 // provided and this is not a legacy request (which is guaranteed to be 00605 // made of all fixed requests so sorting is pointless) 00606 // 00607 00608 performScoring = Arbiter->ScoreRequirement != NULL; 00609 // BUGBUG - fix for rebalance being broken and not passing in flags... 00610 // && !LEGACY_REQUEST(current); 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 // Ensure the score is valid 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 // Build the arbitration stack 00650 // 00651 00652 status = ArbpBuildAllocationStack(Arbiter, 00653 ArbitrationList, 00654 count 00655 ); 00656 00657 if (!NT_SUCCESS(status)) { 00658 goto cleanup; 00659 } 00660 00661 // 00662 // Attempt allocation 00663 // 00664 00665 status = Arbiter->AllocateEntry(Arbiter, Arbiter->AllocationStack); 00666 00667 if (NT_SUCCESS(status)) { 00668 00669 // 00670 // Success. 00671 // 00672 00673 return status; 00674 } 00675 00676 cleanup: 00677 00678 // 00679 // We didn't succeed so empty the possible allocation list... 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 Routine Description: 00698 00699 This routine initializes a arbiter alternative from a given resource 00700 requirement descriptor 00701 00702 Parameters: 00703 00704 Arbiter - The arbiter instance data where the allocation stack should be 00705 placed. 00706 00707 Requirement - The requirement descriptor describing this requirement 00708 00709 Alternative - The alternative to be initialized 00710 00711 Return Value: 00712 00713 Status code that indicates whether or not the function was successful. 00714 00715 --*/ 00716 00717 { 00718 00719 NTSTATUS status; 00720 00721 PAGED_CODE(); 00722 ASSERT(Alternative && Requirement); 00723 00724 Alternative->Descriptor = Requirement; 00725 00726 // 00727 // Unpack the requirement into the alternatives table 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 // Align the minimum if necessary 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 // Check if this alternative is shared 00755 // 00756 00757 if(Requirement->ShareDisposition == CmResourceShareShared) { 00758 Alternative->Flags |= ARBITER_ALTERNATIVE_FLAG_SHARED; 00759 } 00760 00761 // 00762 // Check if this alternative is fixed 00763 // 00764 00765 if (Alternative->Maximum - Alternative->Minimum + 1 == Alternative->Length) { 00766 Alternative->Flags |= ARBITER_ALTERNATIVE_FLAG_FIXED; 00767 } 00768 00769 // 00770 // Check for validity 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 Routine Description: 00795 00796 This routine initializes the allocation stack for the requests in 00797 ArbitrationList. It overwrites any previous allocation stack and allocates 00798 additional memory if more is required. Arbiter->AllocationStack contains 00799 the initialized stack on success. 00800 00801 Parameters: 00802 00803 Arbiter - The arbiter instance data where the allocation stack should be 00804 placed. 00805 00806 ArbitrationList - A list of ARBITER_LIST_ENTRY entries which contain the 00807 requirements and associated devices. 00808 00809 ArbitrationListCount - The number of entries in the ArbitrationList 00810 00811 Return Value: 00812 00813 Status code that indicates whether or not the function was successful. 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 // Calculate the size the stack needs to be and the 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 // Make sure the allocation stack is large enough 00845 // 00846 00847 if (Arbiter->AllocationStackMaxSize < stackSize) { 00848 00849 PARBITER_ALLOCATION_STATE temp; 00850 00851 // 00852 // Enlarge the allocation stack 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 // Fill in the locations 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 // Do we need to allocate anything for this entry? 00881 // 00882 00883 if (currentEntry->AlternativeCount > 0) { 00884 00885 // 00886 // Initialize the stack location 00887 // 00888 00889 currentState->Entry = currentEntry; 00890 currentState->AlternativeCount = currentEntry->AlternativeCount; 00891 currentState->Alternatives = currentAlternative; 00892 00893 // 00894 // Initialize the start and end values to an invalid range so 00895 // that we don't skip the range 0-0 every time... 00896 // 00897 00898 currentState->Start = 1; 00899 ASSERT(currentState->End == 0); // From RtlZeroMemory 00900 00901 // 00902 // Initialize the alternatives table 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 // Initialize the priority 00921 // 00922 00923 currentAlternative->Priority = ARBITER_PRIORITY_NULL; 00924 00925 // 00926 // Advance to the next alternative 00927 // 00928 00929 currentAlternative++; 00930 00931 } 00932 } 00933 currentState++; 00934 } 00935 00936 // 00937 // Terminate the stack with NULL entry 00938 // 00939 00940 currentState->Entry = NULL; 00941 00942 return STATUS_SUCCESS; 00943 00944 cleanup: 00945 00946 // 00947 // We don't need to free the buffer as it is attached to the arbiter and 00948 // will be used next time 00949 // 00950 00951 return status; 00952 } 00953 00954 NTSTATUS 00955 ArbSortArbitrationList( 00956 IN OUT PLIST_ENTRY ArbitrationList 00957 ) 00958 00959 /*++ 00960 00961 Routine Description: 00962 00963 This routine sorts the arbitration list in order of each entry's 00964 WorkSpace value. 00965 00966 Parameters: 00967 00968 ArbitrationList - The list to be sorted. 00969 00970 Return Value: 00971 00972 Status code that indicates whether or not the function was successful. 00973 00974 --*/ 00975 00976 { 00977 // 00978 // BUGBUG - maybe should use a get next type thing or a better sort! 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 // Swap the locations of current and next 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 Routine Description: 01033 01034 This provides the default implementation of the CommitAllocation action. 01035 It frees the old allocation and replaces it with the new allocation. 01036 01037 Parameters: 01038 01039 Arbiter - The arbiter instance data for the arbiter being called. 01040 01041 Return Value: 01042 01043 Status code that indicates whether or not the function was successful. 01044 01045 --*/ 01046 01047 { 01048 PRTL_RANGE_LIST temp; 01049 01050 PAGED_CODE(); 01051 01052 // 01053 // Free up the current allocation 01054 // 01055 01056 RtlFreeRangeList(Arbiter->Allocation); 01057 01058 // 01059 // Swap the allocated and duplicate lists 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 Routine Description: 01077 01078 This provides the default implementation of the RollbackAllocation action. 01079 It frees the possible allocation the last TestAllocation provided. 01080 01081 Parameters: 01082 01083 Arbiter - The arbiter instance data for the arbiter being called. 01084 01085 Return Value: 01086 01087 Status code that indicates whether or not the function was successful. 01088 01089 --*/ 01090 01091 { 01092 01093 PAGED_CODE(); 01094 01095 // 01096 // Free up the possible allocation 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 Routine Description: 01113 01114 This provides the default implementation of the RetestAllocation action. 01115 It walks the arbitration list and updates the possible allocation to reflect 01116 the allocation entries of the list. For these entries to be valid 01117 TestAllocation must have been performed on this arbitration list. 01118 01119 Parameters: 01120 01121 Arbiter - The arbiter instance data for the arbiter being called. 01122 01123 ArbitrationList - A list of ARBITER_LIST_ENTRY entries which contain the 01124 requirements and associated devices. TestAllocation for this arbiter 01125 should have been called on this list. 01126 01127 Return Value: 01128 01129 Status code that indicates whether or not the function was successful. 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 // Initialize the state 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 // Copy the current allocation and reserved 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 // Free all the resources currently allocated to all the devices we 01166 // are arbitrating for 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 // Build an allocation state for the allocation and call AddAllocation to 01187 // update the range lists accordingly 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 // Initialize the alternative 01199 // 01200 01201 status = ArbpBuildAlternative(Arbiter, 01202 current->SelectedAlternative, 01203 &alternative 01204 ); 01205 01206 ASSERT(NT_SUCCESS(status)); 01207 01208 // 01209 // Update it with our allocation 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 // Do any preprocessing that is required 01223 // 01224 01225 status = Arbiter->PreprocessEntry(Arbiter,&state); 01226 01227 if (!NT_SUCCESS(status)) { 01228 goto cleanup; 01229 } 01230 01231 // 01232 // If we had a requirement for length 0 then don't attemp to add the 01233 // range - it will fail! 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 Routine Description: 01259 01260 This provides the default implementation of the BootAllocation action. 01261 It walks the arbitration list and updates the allocation to reflect the fact 01262 that the allocation entries in the list are in use. 01263 01264 Parameters: 01265 01266 Arbiter - The arbiter instance data for the arbiter being called. 01267 01268 ArbitrationList - A list of ARBITER_LIST_ENTRY entries which contain the 01269 requirements and associated devices. Each device should have one and 01270 only one requirement reflecting the resources it is currently consuming. 01271 01272 Return Value: 01273 01274 Status code that indicates whether or not the function was successful. 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 // Initialize the state 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 // Work on the possible allocation list 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 // Build an alternative and state structure for this allocation and 01311 // add it to the range list 01312 // 01313 01314 state.Entry = current; 01315 01316 // 01317 // Initialize the alternative 01318 // 01319 01320 status = ArbpBuildAlternative(Arbiter, 01321 &current->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 // Blow away the old workspace and masks 01335 // 01336 01337 state.WorkSpace = 0; 01338 state.RangeAvailableAttributes = 0; 01339 01340 // 01341 // Validate the requirement 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 // Do any preprocessing that is required 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 // Everything went OK so make this our allocated range 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 Routine Description: 01423 01424 This provides the default entry point to an arbiter. 01425 01426 Parameters: 01427 01428 Context - The context provided in the interface where this function was 01429 called from. This is converted to an ARBITER_INSTANCE using the 01430 ARBITER_CONTEXT_TO_INSTANCE macro which should be defined. 01431 01432 Action - The action the arbiter should perform. 01433 01434 Params - The parameters for the action. 01435 01436 Return Value: 01437 01438 Status code that indicates whether or not the function was successful. 01439 01440 Note: 01441 01442 The routines which implement each action are determined from the dispatch 01443 table in the arbiter instance. 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 // Acquire the state lock 01459 // 01460 01461 ArbAcquireArbiterLock(arbiter); 01462 01463 // 01464 // Announce ourselves 01465 // 01466 01467 ARB_PRINT(2, 01468 ("%s %S\n", 01469 ArbpActionStrings[Action], 01470 arbiter->Name 01471 )); 01472 01473 // 01474 // Check the transaction flag 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 // Do the appropriate thing 01497 // 01498 01499 switch (Action) { 01500 01501 case ArbiterActionTestAllocation: 01502 01503 // 01504 // Suballocation can not occur for a root arbiter 01505 // BUGBUG - this should be generalised 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 // Suballocation can not occur for a root arbiter 01520 // BUGBUG - this should be generalised 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 // Check if we failed and want to stop or replay on errors 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 Routine Description: 01632 01633 This is called as part of arbiter initialization and extracts the allocation 01634 ordering and reserved information from the registry and combines them into 01635 an ordering list. The reserved ranges are put in Arbiter->ReservedList 01636 and the initial ordering in Arbiter->OrderingList. 01637 01638 Parameters: 01639 01640 Arbiter - The instance data of the arbiter to be initialized. 01641 01642 AllocationOrderName - The name of the key under HKLM\System\ 01643 CurrentControlSet\Control\Arbiters\AllocationOrder the ordering 01644 information should be taken from. 01645 01646 ReservedResourcesName - The name of the key under HKLM\System\ 01647 CurrentControlSet\Control\Arbiters\ReservedResources the reserved ranges 01648 information should be taken from. 01649 01650 Translate - A function to be called for each range that will perform system 01651 dependant translations required for this system. 01652 01653 Return Value: 01654 01655 Status code that indicates whether or not the function was successful. 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 // If we are reinitializing the orderings free the old ones 01677 // 01678 01679 ArbFreeOrderingList(&Arbiter->OrderingList); 01680 ArbFreeOrderingList(&Arbiter->ReservedList); 01681 01682 // 01683 // Initialize the orderings 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 // Open HKLM\System\CurrentControlSet\Control\Arbiters 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 // Open AllocationOrder 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 // Extract the value the user asked for 01744 // 01745 01746 status = ArbpGetRegistryValue(tempHandle, 01747 AllocationOrderName, 01748 &info 01749 ); 01750 01751 if (!NT_SUCCESS(status)) { 01752 goto cleanup; 01753 } 01754 01755 // 01756 // Check if the value we retrieved was a string and if so then it was a 01757 // short cut to a value of that name - open it. 01758 // 01759 01760 if (info->Type == REG_SZ) { 01761 01762 PKEY_VALUE_FULL_INFORMATION tempInfo; 01763 01764 // BUGBUG - check this is a valid string... 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 // We only support one level of short cuts so this should be a 01784 // REG_RESOURCE_REQUIREMENTS_LIST 01785 // 01786 01787 if (info->Type != REG_RESOURCE_REQUIREMENTS_LIST) { 01788 status = STATUS_INVALID_PARAMETER; 01789 goto cleanup; 01790 } 01791 01792 // 01793 // Extract the resource list 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 // Convert the resource list into an ordering list 01804 // 01805 01806 FOR_ALL_IN_ARRAY(resourceList->Descriptors, 01807 resourceList->Count, 01808 current) { 01809 01810 // 01811 // Perform any translation that is necessary on the resources 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, //length 01831 &dummy //alignment 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 // We're finished with info... 01851 // 01852 01853 ExFreePool(info); 01854 info = NULL; 01855 01856 // 01857 // Open ReservedResources 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 // Extract the arbiter's reserved resources 01884 // 01885 01886 status = ArbpGetRegistryValue(tempHandle, 01887 ReservedResourcesName, 01888 &info 01889 ); 01890 01891 if (!NT_SUCCESS(status)) { 01892 goto cleanup; 01893 } 01894 01895 // 01896 // Check if the value we retrieved was a string and if so then it was a 01897 // short cut to a value of that name - open it. 01898 // 01899 01900 if (info->Type == REG_SZ) { 01901 01902 PKEY_VALUE_FULL_INFORMATION tempInfo; 01903 01904 // BUGBUG - check this is a valid string... 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 // Apply the reserved ranges to the ordering 01932 // 01933 01934 FOR_ALL_IN_ARRAY(resourceList->Descriptors, 01935 resourceList->Count, 01936 current) { 01937 01938 // 01939 // Perform any translation that is necessary on the resources 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, //length 01959 &dummy //alignment 01960 ); 01961 01962 if (!NT_SUCCESS(status)) { 01963 goto cleanup; 01964 } 01965 01966 // 01967 // Add the reserved range to the reserved ordering 01968 // 01969 01970 status = ArbAddOrdering(&Arbiter->ReservedList, start, end); 01971 01972 if (!NT_SUCCESS(status)) { 01973 goto cleanup; 01974 } 01975 01976 // 01977 // Prune the reserved range from the current ordering 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 // All done! 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 Routine Description: 02073 02074 This routine is called from AllocateEntry once we have decided where we want 02075 to allocate from. It tries to find a free range that matches the 02076 requirements in State while restricting its possible solutions to the range 02077 State->CurrentMinimum to State->CurrentMaximum. On success State->Start and 02078 State->End represent this range. 02079 02080 Arguments: 02081 02082 Arbiter - The instance data of the arbiter who was called. 02083 02084 State - The state of the current arbitration. 02085 02086 Return Value: 02087 02088 TRUE if we found a range, FALSE otherwise. 02089 02090 --*/ 02091 02092 { 02093 02094 NTSTATUS status; 02095 ULONG findRangeFlags = 0; 02096 02097 PAGED_CODE(); 02098 02099 ASSERT(State->CurrentAlternative); 02100 02101 // 02102 // Catch the case where we backtrack and advance past the maximum 02103 // 02104 02105 if (State->CurrentMinimum > State->CurrentMaximum) { 02106 return FALSE; 02107 } 02108 02109 // 02110 // If we are asking for zero ports then trivially succeed with the minimum 02111 // value and remember that backtracking this is a recipe for infinite loops 02112 // 02113 02114 if (State->CurrentAlternative->Length == 0) { 02115 State->End = State->Start = State->CurrentMinimum; 02116 return TRUE; 02117 } 02118 02119 // 02120 // For legacy requests from IoAssignResources (directly or by way of 02121 // HalAssignSlotResources) or IoReportResourceUsage we consider preallocated 02122 // resources to be available for backward compatibility reasons. 02123 // 02124 // If we are allocating a devices boot config then we consider all other 02125 // boot configs to be available. BUGBUG(andrewth) - this behavior is bad! 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 // Check if null conflicts are OK... 02136 // 02137 02138 if (State->Flags & ARBITER_STATE_FLAG_NULL_CONFLICT_OK) { 02139 findRangeFlags |= RTL_RANGE_LIST_NULL_CONFLICT_OK; 02140 } 02141 02142 // 02143 // ...or we are shareable... 02144 // 02145 02146 if (State->CurrentAlternative->Flags & ARBITER_ALTERNATIVE_FLAG_SHARED) { 02147 findRangeFlags |= RTL_RANGE_LIST_SHARED_OK; 02148 } 02149 02150 // 02151 // Select the first free alternative from the current alternative 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 // We found a suitable range 02172 // 02173 State->End = State->Start + State->CurrentAlternative->Length - 1; 02174 02175 return TRUE; 02176 02177 } else { 02178 02179 // 02180 // We couldn't find any range so check if we will allow this conflict 02181 // - if so don'd fail! 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 Routine Description: 02197 02198 This routine is called from AllocateEntry once we have found a possible 02199 solution (State->Start - State->End). It adds the ranges that will not be 02200 available if we commit to this solution to Arbiter->PossibleAllocation. 02201 02202 Arguments: 02203 02204 Arbiter - The instance data of the arbiter who was called. 02205 02206 State - The state of the current arbitration. 02207 02208 Return Value: 02209 02210 None. 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 Routine Description: 02246 02247 This routine is called from AllocateEntry if the possible solution 02248 (State->Start - State->End) does not allow us to allocate resources to 02249 the rest of the devices being considered. It deletes the ranges that were 02250 added to Arbiter->PossibleAllocation by AddAllocation. 02251 02252 Arguments: 02253 02254 Arbiter - The instance data of the arbiter who was called. 02255 02256 State - The state of the current arbitration. 02257 02258 Return Value: 02259 02260 None. 02261 02262 --*/ 02263 02264 02265 { 02266 NTSTATUS status; 02267 02268 PAGED_CODE(); 02269 02270 // 02271 // We couldn't allocate for the rest of the ranges then 02272 // backtrack 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 Routine Description: 02302 02303 This routine is called from AllocateEntry to allow preprocessing of 02304 entries 02305 02306 Arguments: 02307 02308 Arbiter - The instance data of the arbiter who was called. 02309 02310 State - The state of the current arbitration. 02311 02312 Return Value: 02313 02314 None. 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 Routine Description: 02332 02333 This is the core arbitration routine and is called from TestAllocation 02334 to allocate resources for all of the entries in the allocation stack. 02335 It calls off to various helper routines (described above) to perform this 02336 task. 02337 02338 Arguments: 02339 02340 Arbiter - The instance data of the arbiter who was called. 02341 02342 State - The state of the current arbitration. 02343 02344 Return Value: 02345 02346 None. 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 // Have we reached the end of the list? If so then we have a working 02362 // allocation. 02363 // 02364 02365 tryAllocation: 02366 02367 while(currentState >= State && currentState->Entry != NULL) { 02368 02369 // 02370 // Do any preprocessing that is required 02371 // 02372 02373 status = Arbiter->PreprocessEntry(Arbiter,currentState); 02374 02375 if (!NT_SUCCESS(status)) { 02376 return status; 02377 } 02378 02379 // 02380 // If we need to backtrack do so! 02381 // 02382 02383 if (backtracking) { 02384 02385 ULONGLONG possibleCurrentMinimum; 02386 02387 backtracking = FALSE; 02388 02389 // 02390 // Clear the CurrentAlternative of the *next* alternative - this will 02391 // cause the priorities to be recalculated next time through so we 02392 // will attempt to explore the search space again 02393 // 02394 // The currentState+1 is guaranteed to be safe because the only way 02395 // we can get here is from where we currentState-- below. 02396 // 02397 02398 (currentState + 1)->CurrentAlternative = NULL; 02399 02400 // 02401 // We can't backtrack length 0 requests because there is nothing to 02402 // backtrack so we would get stuck in an inifinite loop... 02403 // 02404 02405 if (currentState->CurrentAlternative->Length == 0) { 02406 goto failAllocation; 02407 } 02408 02409 // 02410 // Backtrack 02411 // 02412 02413 Arbiter->BacktrackAllocation(Arbiter, currentState); 02414 02415 // 02416 // Reduce allocation window to not include the range we backtracked 02417 // and check that that doesn't underflow the minimum or wrap 02418 // 02419 02420 possibleCurrentMinimum = currentState->Start - 1; 02421 02422 if (possibleCurrentMinimum > currentState->CurrentMinimum // wrapped 02423 || possibleCurrentMinimum < currentState->CurrentAlternative->Minimum) { 02424 02425 // 02426 // We have run out space in this alternative move on to the next 02427 // 02428 02429 goto continueWithNextAllocationRange; 02430 02431 } else { 02432 02433 currentState->CurrentMaximum = possibleCurrentMinimum; 02434 02435 // 02436 // Get back into arbitrating at the right point 02437 // 02438 02439 goto continueWithNextSuitableRange; 02440 } 02441 } 02442 02443 // 02444 // Try to allocate for this entry 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 // We found a possible solution 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 // Update the arbiter with the possible allocation 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 // Set the result in the arbiter appropriatley so that we 02501 // don't try and translate this zero requirement - it won't! 02502 // 02503 02504 currentState->Entry->Result = ArbiterResultNullRequest; 02505 } 02506 02507 // 02508 // Move on to the next entry 02509 // 02510 02511 currentState++; 02512 goto tryAllocation; 02513 } 02514 } 02515 02516 failAllocation: 02517 02518 // 02519 // We couldn't allocate for this device 02520 // 02521 02522 if (currentState == State) { 02523 02524 // 02525 // We are at the top of the allocation stack to we can't backtrack - 02526 // *** GAME OVER *** 02527 // 02528 02529 return STATUS_UNSUCCESSFUL; 02530 02531 } else { 02532 02533 // 02534 // Backtrack and try again 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 // Pop the last state off the stack and try a different path 02548 // 02549 02550 currentState--; 02551 goto tryAllocation; 02552 } 02553 } 02554 02555 // 02556 // We have successfully allocated for all ranges so fill in the allocation 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 // Remember the alternative we chose from so we can retrieve it during retest 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 Routine Description: 02600 02601 This routine attempts to find the next range where allocation should be 02602 tried. It updates State->CurrentMinimum, State->CurrentMaximum and 02603 State->CurrentAlternative to indicate this range. 02604 02605 Arguments: 02606 02607 Arbiter - The instance data of the arbiter 02608 02609 State - The state of the current arbitration 02610 02611 Return Value: 02612 02613 TRUE if a range to attemp allocation in is found, FALSE otherwise 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 // Update the priority of the alternative we selected last time 02630 // 02631 02632 ArbpUpdatePriority(Arbiter, State->CurrentAlternative); 02633 02634 } else { 02635 02636 // 02637 // This is the first time we are looking at this alternative or a 02638 // backtrack - either way we need to update all the priorities 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 // Find the lowest priority of the alternatives 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 // Check if we have run out of allocation ranges 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 // Check if we are now allowing reserved ranges 02700 // 02701 02702 if (lowestAlternative->Priority == ARBITER_PRIORITY_RESERVED 02703 || lowestAlternative->Priority == ARBITER_PRIORITY_PREFERRED_RESERVED) { 02704 02705 // 02706 // Set min and max to be the Minimum and Maximum that the descriptor 02707 // specified ignoring any reservations or orderings - this is our 02708 // last chance 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 // Locate the ordering we match 02726 // 02727 02728 ordering = &Arbiter->OrderingList.Orderings 02729 [ORDERING_INDEX_FROM_PRIORITY(lowestAlternative->Priority)]; 02730 02731 // 02732 // Make sure they overlap and are big enough - this is just paranoia 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 // Calculate the allocation range 02746 // 02747 02748 min = __max(lowestAlternative->Minimum, ordering->Start); 02749 02750 max = __min(lowestAlternative->Maximum, ordering->End); 02751 02752 } 02753 02754 // 02755 // If this is a length 0 requirement then succeed now and avoid much 02756 // trauma later 02757 // 02758 02759 if (lowestAlternative->Length == 0) { 02760 02761 min = lowestAlternative->Minimum; 02762 max = lowestAlternative->Maximum; 02763 02764 } else { 02765 02766 // 02767 // Trim range to match alignment. 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 // Set CurrentAlternative so we will update the priority of this 02780 // alternative 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 // Check if we handed back the same range last time, for the same 02795 // alternative, if so try to find another range 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 Routine Description: 02833 02834 This routine is invoked to retrieve the data for a registry key's value. 02835 This is done by querying the value of the key with a zero-length buffer 02836 to determine the size of the value, and then allocating a buffer and 02837 actually querying the value into the buffer. 02838 02839 It is the responsibility of the caller to free the buffer. 02840 02841 Arguments: 02842 02843 KeyHandle - Supplies the key handle whose value is to be queried 02844 02845 ValueName - Supplies the null-terminated Unicode name of the value. 02846 02847 Information - Returns a pointer to the allocated data buffer. 02848 02849 Return Value: 02850 02851 The function value is the final status of the query operation. 02852 02853 Note: 02854 02855 The same as IopGetRegistryValue - it allows us to share the arbiter 02856 code with pci.sys 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 // Figure out how big the data value is so that a buffer of the 02872 // appropriate size can be allocated. 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 // Allocate a buffer large enough to contain the entire key data value. 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 // Query the data for the key value. 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 // Everything worked, so simply return the address of the allocated 02916 // buffer to the caller, who is now responsible for freeing it. 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 Routine Description: 02934 02935 This routine inititialize an arbiter ordering list. 02936 02937 Arguments: 02938 02939 List - The list to be initialized 02940 02941 Return Value: 02942 02943 Status code that indicates whether or not the function was successful. 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 Routine Description: 02979 02980 This routine copies an arbiter ordering list. 02981 02982 Arguments: 02983 02984 Destination - An uninitialized arbiter ordering list where the data 02985 should be copied from 02986 02987 Source - Arbiter ordering list to be copied 02988 Return Value: 02989 02990 Status code that indicates whether or not the function was successful. 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 Routine Description: 03037 03038 This routine adds the range Start-End to the end of the ordering list. No 03039 checking for overlaps or pruning is done (see ArbpPruneOrdering) 03040 03041 Arguments: 03042 03043 OrderingList - The list where the range should be added. 03044 03045 Start - The start of the range to be added. 03046 03047 End - The end of the range to be added. 03048 03049 Return Value: 03050 03051 Status code that indicates whether or not the function was successful. 03052 03053 --*/ 03054 03055 { 03056 03057 // 03058 // Validate parameters 03059 // 03060 03061 if (End < Start) { 03062 return STATUS_INVALID_PARAMETER; 03063 } 03064 03065 // 03066 // Check if the buffer is full 03067 // 03068 03069 if (List->Count == List->Maximum) { 03070 03071 PARBITER_ORDERING temp; 03072 03073 // 03074 // Out of space - grow the buffer 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 // If we had any orderings copy them 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 // Add the entry to the list 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 Routine Description: 03129 03130 This routine removes the range Start-End from all entries in the ordering 03131 list, splitting ranges into two or deleting them as necessary. 03132 03133 Arguments: 03134 03135 OrderingList - The list to be pruned. 03136 03137 Start - The start of the range to be deleted. 03138 03139 End - The end of the range to be deleted. 03140 03141 Return Value: 03142 03143 Status code that indicates whether or not the function was successful. 03144 03145 Note: 03146 03147 In the comments below *** represents the range Start - End and --- the range 03148 current->Start - current->End. 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 // Validate parameters 03163 // 03164 03165 if (End < Start) { 03166 status = STATUS_INVALID_PARAMETER; 03167 goto cleanup; 03168 } 03169 03170 // 03171 // Allocate a buffer big enough for all eventualities 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 // Do we have a current ordering? 03189 // 03190 03191 if (OrderingList->Count > 0) { 03192 03193 // 03194 // Iterate through the current ordering and prune accordingly 03195 // 03196 03197 FOR_ALL_IN_ARRAY(OrderingList->Orderings, OrderingList->Count, current) { 03198 03199 if (End < current->Start || Start > current->End) { 03200 03201 // 03202 // **** or **** 03203 // ---- ---- 03204 // 03205 // We don't overlap so copy the range unchanged 03206 // 03207 03208 *currentInsert++ = *current; 03209 03210 } else if (Start > current->Start) { 03211 03212 if (End < current->End) { 03213 03214 // 03215 // **** 03216 // -------- 03217 // 03218 // Split the range into two 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 // **** or **** 03234 // -------- -------- 03235 // 03236 // Prune the end of the range 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 // **** or **** 03253 // -------- -------- 03254 // 03255 // Prune the start of the range 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 // ******** or ******** 03268 // ---- -------- 03269 // 03270 // Don't copy the range (ie. Delete it) 03271 // 03272 03273 } 03274 } 03275 } 03276 } 03277 03278 03279 ASSERT(currentInsert - newOrdering >= 0); 03280 03281 count = (USHORT)(currentInsert - newOrdering); 03282 03283 // 03284 // Check if we have any orderings left 03285 // 03286 03287 if (count > 0) { 03288 03289 if (count > OrderingList->Maximum) { 03290 03291 // 03292 // There isn't enough space so allocate a new buffer 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 // Copy the new ordering 03318 // 03319 03320 RtlCopyMemory(OrderingList->Orderings, 03321 newOrdering, 03322 count * sizeof(ARBITER_ORDERING) 03323 ); 03324 } 03325 03326 // 03327 // Free our temporary buffer 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 Routine Description: 03356 03357 Frees storage associated with an ordering list. 03358 Reverses ArbInitializeOrderingList. 03359 03360 Arguments: 03361 03362 List - The list to be fred 03363 03364 Return Value: 03365 03366 None 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 Routine Description: 03391 03392 This is the default implementation of override conflict which 03393 03394 Arguments: 03395 03396 Arbiter - The instance data of the arbiter who was called. 03397 03398 State - The state of the current arbitration. 03399 03400 Return Value: 03401 03402 TRUE if the conflict is allowable, false otherwise 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 // Only test the overlapping ones 03422 // 03423 03424 if (INTERSECT(current->Start, current->End, State->CurrentMinimum, State->CurrentMaximum)) { 03425 03426 03427 // 03428 // Check if we should ignore the range because of its attributes 03429 // 03430 03431 if (current->Attributes & State->RangeAvailableAttributes) { 03432 03433 // 03434 // We DON'T set ok to true because we are just ignoring the range, 03435 // as RtlFindRange would have and thus it can't be the cause of 03436 // RtlFindRange failing, so ignoring it can't fix the conflict. 03437 // 03438 03439 continue; 03440 } 03441 03442 // 03443 // Check if we are conflicting with ourselves AND the conflicting range 03444 // is a fixed requirement 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 // The conflict is still valid 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 Routine Description: 03476 03477 This routine updates the priority of an arbiter alternative. 03478 03479 Arguments: 03480 03481 Arbiter - The arbiter we are operating on 03482 03483 Alternative - The alternative currently being considered 03484 03485 Return Value: 03486 03487 Status code that indicates whether or not the function was successful. 03488 03489 Note: 03490 03491 The priorities are a LONG values organised as: 03492 03493 <------Preferred priorities-----> <-----Ordinary Priorities-----> 03494 03495 MINLONG--------------------------0-----------------------------MAXLONG 03496 ^ ^ ^ ^ 03497 | | | | 03498 NULL PREFERRED_RESERVED | | 03499 RESERVED | 03500 EXHAUSTED 03501 03502 An ordinary priority is calculated the (index + 1) of the next ordering it 03503 intersects with (and has enough space for an allocation). 03504 03505 A preferred priority is the ordinary priority * - 1 03506 03507 In this way by examining each of the alternatives in priority order (lowest 03508 first) we achieve the desired allocation order of: 03509 03510 (1) Preferred alternative with non-reserved resources 03511 (2) Alternatives with non-reserved resources 03512 (3) Preferred reserved resources 03513 (4) Reserved Resources 03514 03515 MAXLONG the worst priority indicates that there are no more allocation ranges 03516 left. 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 // If we have already tried the reserved resources then we are out of luck! 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 // Check if this is a preferred value - we treat them specially 03543 // 03544 03545 preferred = Alternative->Descriptor->Option & IO_RESOURCE_PREFERRED; 03546 03547 // 03548 // If priority is NULL then we haven't started calculating one so we 03549 // should start the search from the initial ordering 03550 // 03551 03552 if (priority == ARBITER_PRIORITY_NULL) { 03553 03554 ordering = Arbiter->OrderingList.Orderings; 03555 03556 } else { 03557 03558 // 03559 // If we are a fixed resource then there is no point 03560 // in trying to find another range - it will be the 03561 // same and thus still conflict. Mark this alternative as 03562 // exhausted 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 // Now find the first member of the assignent ordering for this arbiter 03583 // where we have an overlap big enough 03584 // 03585 03586 FOR_REST_IN_ARRAY(Arbiter->OrderingList.Orderings, 03587 Arbiter->OrderingList.Count, 03588 ordering) { 03589 03590 // 03591 // Is the ordering applicable? 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 // This is out guy, calculate his priority 03601 // 03602 03603 Alternative->Priority = (LONG)(ordering - Arbiter->OrderingList.Orderings + 1); 03604 03605 // 03606 // Preferred priorities are -ve 03607 // 03608 03609 if (preferred) { 03610 Alternative->Priority *= -1; 03611 } 03612 03613 return; 03614 } 03615 } 03616 03617 // 03618 // We have runout of non-reserved resources so try the reserved ones 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 Routine Description: 03650 03651 This call back is called from FindSuitableRange (via RtlFindRange) when we 03652 encounter an conflicting range. 03653 03654 Arguments: 03655 03656 Context - Actually a PRTL_RANGE * where we store the range we conflicted 03657 with. 03658 03659 Range - The range we conflict with. 03660 03661 Return Value: 03662 03663 FALSE 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 // Remember the conflicting range 03681 // 03682 03683 *conflictingRange = Range; 03684 03685 // 03686 // We want to allow the rest of FindSuitableRange to determine if this really 03687 // is a conflict. 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 Routine Description: 03706 03707 This routine examines the arbiter state and returns a list of devices that 03708 conflict with ConflictingResource 03709 03710 Arguments: 03711 03712 Arbiter - The arbiter to examine conflicts in 03713 03714 ConflictingResource - The resource we want to know the conflicts with 03715 03716 ConflictCount - On success contains the number of conflicts detected 03717 03718 ConflictList - On success contains a pointer to an array of conflicting 03719 devices 03720 03721 Return Value: 03722 03723 Status code that indicates whether or not the function was successful. 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 // Set up our conflict callback 03748 // 03749 savedCallback = Arbiter->ConflictCallback; 03750 savedContext = Arbiter->ConflictCallbackContext; 03751 Arbiter->ConflictCallback = ArbpQueryConflictCallback; 03752 Arbiter->ConflictCallbackContext = &conflictingRange; 03753 03754 // 03755 // If there is a transaction in progress then we need to backup the 03756 // the possible allocation so we can restore it when we are done. 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 // Fake up the allocation state 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 // BUGBUG(andrewth) - need to fill in more of this false entry 03805 // 03806 RtlZeroMemory(&entry, sizeof(ARBITER_LIST_ENTRY)); 03807 entry.RequestSource = ArbiterRequestPnpEnumerated; 03808 entry.PhysicalDeviceObject = PhysicalDeviceObject; 03809 // 03810 // BUGBUG(jamiehun) - we didn't allow for passing interface type 03811 // now we have to live with the decision 03812 // this really only comes into being for PCI Translator AFAIK 03813 // upshot of not doing this is we get false conflicts when PCI Boot alloc 03814 // maps over top of ISA alias 03815 // IoGetDeviceProperty generally does the right thing for the times we have to use this info 03816 // 03817 if (!NT_SUCCESS(IoGetDeviceProperty(PhysicalDeviceObject,DevicePropertyLegacyBusType,sizeof(entry.InterfaceType),&entry.InterfaceType,&sz))) { 03818 entry.InterfaceType = Isa; // not what I want to do! However this has the right effect - good enough for conflict detection 03819 } 03820 if (!NT_SUCCESS(IoGetDeviceProperty(PhysicalDeviceObject,DevicePropertyBusNumber,sizeof(entry.InterfaceType),&entry.BusNumber,&sz))) { 03821 entry.BusNumber = 0; // not what I want to do! However this has the right effect - good enough for conflict detection 03822 } 03823 03824 // 03825 // Initialize the return buffers 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 // Perform any necessary preprocessing 03840 // 03841 03842 status = Arbiter->PreprocessEntry(Arbiter, &state); 03843 03844 if (!NT_SUCCESS(status)) { 03845 goto cleanup; 03846 } 03847 03848 // 03849 // Remove self from list of possible allocations 03850 // status may be set, but can be ignored 03851 // we take ourself out of test completely, so that a user can 03852 // pick new values in context of rest of the world 03853 // if we decide to use RtlDeleteRange instead 03854 // make sure we do it for every alias formed in PreprocessEntry 03855 // 03856 03857 status = RtlDeleteOwnersRanges(Arbiter->PossibleAllocation, 03858 state.Entry->PhysicalDeviceObject 03859 ); 03860 03861 // 03862 // Keep trying to find a suitable range and each time we fail remember why. 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 // We need to resize the return buffer 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 // BUGBUG - maybe need some more info... 03906 count++; 03907 03908 // 03909 // Delete the range we conflicted with so we don't loop forever 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 // someone isn't playing by the rules (such as ACPI!) 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 // BUGBUG - maybe need some more info... 03936 count++; 03937 03938 // 03939 // we daren't continue at risk of looping forever 03940 // 03941 break; 03942 } 03943 03944 // 03945 // reset for next round 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 Routine Description: 04004 04005 This function is called by the driver that implements the arbiter once 04006 it has been started and knowns what resources it can allocate to its 04007 children. 04008 04009 BUGBUG - It will eventually initialize the range lists correctly but for 04010 now it is just an overloadable place holder as that work is done elsewhere. 04011 04012 Parameters: 04013 04014 Arbiter - The instance of the arbiter being called. 04015 04016 04017 Return Value: 04018 04019 Status code that indicates whether or not the function was successful. 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 }

Generated on Sat May 15 19:39:16 2004 for test by doxygen 1.3.7