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

pnpmemio.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1997 Microsoft Corporation 00004 00005 Module Name: 00006 00007 pnpmemio.c 00008 00009 Abstract: 00010 00011 Root IO Port and Memory arbiter 00012 00013 Author: 00014 00015 Andy Thornton (andrewth) 04/17/97 00016 00017 Revision History: 00018 00019 --*/ 00020 00021 #include "iop.h" 00022 #pragma hdrstop 00023 00024 #define BUGFEST_HACKS 00025 00026 // 00027 // Constants 00028 // 00029 00030 #define MAX_ULONGLONG ((ULONGLONG) -1) 00031 #define MAX_ALIAS_PORT 0x0000FFFF 00032 00033 typedef struct _PORT_ARBITER_EXTENSION { 00034 00035 PRTL_RANGE_LIST Aliases; 00036 PRTL_RANGE_LIST PossibleAliases; 00037 RTL_RANGE_LIST RangeLists[2]; 00038 00039 } PORT_ARBITER_EXTENSION, *PPORT_ARBITER_EXTENSION; 00040 00041 // 00042 // Prototypes 00043 // 00044 00045 VOID 00046 IopPortBacktrackAllocation( 00047 IN PARBITER_INSTANCE Arbiter, 00048 IN PARBITER_ALLOCATION_STATE State 00049 ); 00050 00051 BOOLEAN 00052 IopPortGetNextAlias( 00053 ULONG IoDescriptorFlags, 00054 ULONGLONG LastAlias, 00055 PULONGLONG NextAlias 00056 ); 00057 00058 BOOLEAN 00059 IopPortFindSuitableRange( 00060 PARBITER_INSTANCE Arbiter, 00061 PARBITER_ALLOCATION_STATE State 00062 ); 00063 00064 BOOLEAN 00065 IopMemFindSuitableRange( 00066 PARBITER_INSTANCE Arbiter, 00067 PARBITER_ALLOCATION_STATE State 00068 ); 00069 00070 00071 NTSTATUS 00072 IopGenericUnpackRequirement( 00073 IN PIO_RESOURCE_DESCRIPTOR Descriptor, 00074 OUT PULONGLONG Minimum, 00075 OUT PULONGLONG Maximum, 00076 OUT PULONG Length, 00077 OUT PULONG Alignment 00078 ); 00079 00080 NTSTATUS 00081 IopGenericPackResource( 00082 IN PIO_RESOURCE_DESCRIPTOR Requirement, 00083 IN ULONGLONG Start, 00084 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor 00085 ); 00086 00087 LONG 00088 IopGenericScoreRequirement( 00089 IN PIO_RESOURCE_DESCRIPTOR Descriptor 00090 ); 00091 00092 NTSTATUS 00093 IopGenericUnpackResource( 00094 IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor, 00095 OUT PULONGLONG Start, 00096 OUT PULONG Length 00097 ); 00098 00099 BOOLEAN 00100 IopPortIsAliasedRangeAvailable( 00101 IN PARBITER_INSTANCE Arbiter, 00102 IN PARBITER_ALLOCATION_STATE State 00103 ); 00104 00105 NTSTATUS 00106 IopMemInitialize( 00107 VOID 00108 ); 00109 00110 VOID 00111 IopPortAddAllocation( 00112 IN PARBITER_INSTANCE Arbiter, 00113 IN PARBITER_ALLOCATION_STATE State 00114 ); 00115 00116 NTSTATUS 00117 IopTranslateBusAddress( 00118 IN PHYSICAL_ADDRESS SourceAddress, 00119 IN UCHAR SourceResourceType, 00120 OUT PPHYSICAL_ADDRESS TargetAddress, 00121 OUT PUCHAR TargetResourceType 00122 ); 00123 00124 00125 // 00126 // Make everything pageable 00127 // 00128 00129 #ifdef ALLOC_PRAGMA 00130 00131 #pragma alloc_text(PAGE, IopPortInitialize) 00132 #pragma alloc_text(PAGE, IopMemInitialize) 00133 #pragma alloc_text(PAGE, IopGenericUnpackRequirement) 00134 #pragma alloc_text(PAGE, IopGenericPackResource) 00135 #pragma alloc_text(PAGE, IopGenericScoreRequirement) 00136 #pragma alloc_text(PAGE, IopGenericUnpackResource) 00137 #pragma alloc_text(PAGE, IopPortBacktrackAllocation) 00138 #pragma alloc_text(PAGE, IopPortFindSuitableRange) 00139 #pragma alloc_text(PAGE, IopMemFindSuitableRange) 00140 #pragma alloc_text(PAGE, IopPortGetNextAlias) 00141 #pragma alloc_text(PAGE, IopPortAddAllocation) 00142 #pragma alloc_text(PAGE, IopPortIsAliasedRangeAvailable) 00143 #pragma alloc_text(PAGE, IopTranslateBusAddress) 00144 #endif // ALLOC_PRAGMA 00145 00146 00147 #define ADDRESS_SPACE_MEMORY 0x0 00148 #define ADDRESS_SPACE_PORT 0x1 00149 #define ADDRESS_SPACE_USER_MEMORY 0x2 00150 #define ADDRESS_SPACE_USER_PORT 0x3 00151 #define ADDRESS_SPACE_DENSE_MEMORY 0x4 00152 #define ADDRESS_SPACE_USER_DENSE_MEMORY 0x6 00153 00154 NTSTATUS 00155 IopTranslateBusAddress( 00156 IN PHYSICAL_ADDRESS SourceAddress, 00157 IN UCHAR SourceResourceType, 00158 OUT PPHYSICAL_ADDRESS TargetAddress, 00159 OUT PUCHAR TargetResourceType 00160 ) 00161 /*++ 00162 00163 Routine Description: 00164 00165 This routine translates addresses. 00166 00167 Parameters: 00168 00169 SourceAddress - The address to translate 00170 00171 ResourceType - The resource type (IO or Memory) we are translaing. If the 00172 address space changes from IO->Memory this will be updated. 00173 00174 TargetAddress - Pointer to where the target should be translated to. 00175 00176 Return Value: 00177 00178 STATUS_SUCCESS or an error status 00179 00180 --*/ 00181 00182 { 00183 NTSTATUS status = STATUS_UNSUCCESSFUL; 00184 ULONG sourceAddressSpace, targetAddressSpace; 00185 BOOLEAN translated; 00186 00187 PAGED_CODE(); 00188 00189 // 00190 // Select the appropriate address space 00191 // 00192 00193 if (SourceResourceType == CmResourceTypeMemory) { 00194 sourceAddressSpace = ADDRESS_SPACE_MEMORY; 00195 } else if (SourceResourceType == CmResourceTypePort) { 00196 sourceAddressSpace = ADDRESS_SPACE_PORT; 00197 } else { 00198 return STATUS_INVALID_PARAMETER; 00199 } 00200 00201 ARB_PRINT( 00202 2, 00203 ("Translating %s address 0x%I64x => ", 00204 SourceResourceType == CmResourceTypeMemory ? "Memory" : "I/O", 00205 SourceAddress.QuadPart 00206 )); 00207 00208 // 00209 // HACKHACK Ask the HAL to translate on ISA bus - if we can't then just 00210 // don't translate because this must be a PCI system so the root arbiters 00211 // don't do much (Yes it's a steaming hack but it'll work for beta 1) 00212 // 00213 00214 targetAddressSpace = sourceAddressSpace; 00215 translated = HalTranslateBusAddress( 00216 Isa, 00217 0, 00218 SourceAddress, 00219 &targetAddressSpace, 00220 TargetAddress 00221 ); 00222 00223 if (!translated) { 00224 ARB_PRINT(2,("Translation failed!\n")); 00225 return STATUS_UNSUCCESSFUL; 00226 } 00227 00228 // 00229 // Update the resource type in the target if we have gone from Io to Memory 00230 // 00231 00232 00233 // 00234 // BUBBUG - update the length for IO -> Memory (Dense vs Sparse) 00235 // I think the answer is dense -> spares is multiply length by 32 00236 // 00237 00238 if (targetAddressSpace == ADDRESS_SPACE_MEMORY 00239 || targetAddressSpace == ADDRESS_SPACE_USER_MEMORY 00240 || targetAddressSpace == ADDRESS_SPACE_DENSE_MEMORY 00241 || targetAddressSpace == ADDRESS_SPACE_USER_DENSE_MEMORY) { 00242 *TargetResourceType = CmResourceTypeMemory; 00243 } else if (targetAddressSpace == ADDRESS_SPACE_PORT 00244 || targetAddressSpace == ADDRESS_SPACE_USER_PORT) { 00245 *TargetResourceType = CmResourceTypePort; 00246 } else { 00247 ASSERT(0 && "Translation has returned an unknown address space"); 00248 } 00249 00250 ARB_PRINT( 00251 2, 00252 ("%s address 0x%I64x\n", 00253 *TargetResourceType == CmResourceTypeMemory ? "Memory" : "I/O", 00254 TargetAddress->QuadPart 00255 )); 00256 00257 return STATUS_SUCCESS; 00258 00259 } 00260 00261 00262 NTSTATUS 00263 IopGenericTranslateOrdering( 00264 OUT PIO_RESOURCE_DESCRIPTOR Target, 00265 IN PIO_RESOURCE_DESCRIPTOR Source 00266 ) 00267 00268 /* 00269 00270 Routine Description: 00271 00272 This routine is called during arbiter initialization to translate the 00273 orderings. 00274 00275 Parameters: 00276 00277 Target - Place to put the translated descriptor 00278 00279 Source - Descriptor to translate 00280 00281 Return Value: 00282 00283 STATUS_SUCCESS 00284 00285 00286 00287 */ 00288 00289 { 00290 NTSTATUS status; 00291 UCHAR initialResourceType, minResourceType, maxResourceType; 00292 PAGED_CODE(); 00293 00294 00295 *Target = *Source; 00296 00297 if (Source->Type != CmResourceTypeMemory 00298 && Source->Type != CmResourceTypePort) { 00299 return STATUS_SUCCESS; 00300 } 00301 00302 initialResourceType = Source->Type; 00303 00304 // 00305 // Translate the minimum 00306 // 00307 00308 status = IopTranslateBusAddress(Source->u.Generic.MinimumAddress, 00309 initialResourceType, 00310 &Target->u.Generic.MinimumAddress, 00311 &minResourceType 00312 ); 00313 00314 if (NT_SUCCESS(status)) { 00315 00316 // 00317 // Translate the maximum iff we could translate the minimum 00318 // 00319 00320 status = IopTranslateBusAddress(Source->u.Generic.MaximumAddress, 00321 initialResourceType, 00322 &Target->u.Generic.MaximumAddress, 00323 &maxResourceType 00324 ); 00325 00326 } 00327 00328 // 00329 // If we couldn't translate both ends of the range then we want to skip this 00330 // range - set it's type to CmResourceTypeNull 00331 // 00332 00333 if (!NT_SUCCESS(status)) { 00334 Target->Type = CmResourceTypeNull; 00335 } else { 00336 ASSERT(minResourceType == maxResourceType); 00337 Target->Type = minResourceType; 00338 } 00339 00340 return STATUS_SUCCESS; 00341 00342 } 00343 00344 // 00345 // Implementation 00346 // 00347 00348 NTSTATUS 00349 IopPortInitialize( 00350 VOID 00351 ) 00352 00353 /*++ 00354 00355 Routine Description: 00356 00357 This routine initializes the arbiter 00358 00359 Parameters: 00360 00361 None 00362 00363 Return Value: 00364 00365 None 00366 00367 --*/ 00368 00369 { 00370 PAGED_CODE(); 00371 00372 // 00373 // Fill in the non-default action handlers 00374 // 00375 00376 IopRootPortArbiter.FindSuitableRange = IopPortFindSuitableRange; 00377 IopRootPortArbiter.AddAllocation = IopPortAddAllocation; 00378 IopRootPortArbiter.BacktrackAllocation = IopPortBacktrackAllocation; 00379 00380 IopRootPortArbiter.UnpackRequirement = IopGenericUnpackRequirement; 00381 IopRootPortArbiter.PackResource = IopGenericPackResource; 00382 IopRootPortArbiter.UnpackResource = IopGenericUnpackResource; 00383 IopRootPortArbiter.ScoreRequirement = IopGenericScoreRequirement; 00384 00385 return ArbInitializeArbiterInstance(&IopRootPortArbiter, 00386 NULL, // Indicates ROOT arbiter 00387 CmResourceTypePort, 00388 L"RootPort", 00389 L"Root", 00390 IopGenericTranslateOrdering 00391 ); 00392 00393 } 00394 00395 NTSTATUS 00396 IopMemInitialize( 00397 VOID 00398 ) 00399 00400 /*++ 00401 00402 Routine Description: 00403 00404 This routine initializes the arbiter 00405 00406 Parameters: 00407 00408 None 00409 00410 Return Value: 00411 00412 None 00413 00414 --*/ 00415 00416 { 00417 NTSTATUS status; 00418 00419 PAGED_CODE(); 00420 00421 IopRootMemArbiter.UnpackRequirement = IopGenericUnpackRequirement; 00422 IopRootMemArbiter.PackResource = IopGenericPackResource; 00423 IopRootMemArbiter.UnpackResource = IopGenericUnpackResource; 00424 IopRootMemArbiter.ScoreRequirement = IopGenericScoreRequirement; 00425 00426 IopRootMemArbiter.FindSuitableRange = IopMemFindSuitableRange; 00427 00428 status = ArbInitializeArbiterInstance(&IopRootMemArbiter, 00429 NULL, // Indicates ROOT arbiter 00430 CmResourceTypeMemory, 00431 L"RootMemory", 00432 L"Root", 00433 IopGenericTranslateOrdering 00434 ); 00435 00436 if (!NT_SUCCESS(status)) { 00437 return status; 00438 } 00439 00440 // 00441 // Allocate the first page of physical memory as the firmware uses it and 00442 // doesn't report it as so Mm doesn't reuse it. 00443 // 00444 00445 status = RtlAddRange(IopRootMemArbiter.Allocation, 00446 0, 00447 PAGE_SIZE, 00448 0, // RangeAttributes 00449 0, // Flags 00450 NULL, 00451 NULL 00452 ); 00453 return status; 00454 00455 } 00456 00457 00458 // 00459 // Arbiter callbacks 00460 // 00461 00462 NTSTATUS 00463 IopGenericUnpackRequirement( 00464 IN PIO_RESOURCE_DESCRIPTOR Descriptor, 00465 OUT PULONGLONG Minimum, 00466 OUT PULONGLONG Maximum, 00467 OUT PULONG Length, 00468 OUT PULONG Alignment 00469 ) 00470 00471 /*++ 00472 00473 Routine Description: 00474 00475 This routine unpacks an resource requirement descriptor. 00476 00477 Arguments: 00478 00479 Descriptor - The descriptor describing the requirement to unpack. 00480 00481 Minimum - Pointer to where the minimum acceptable start value should be 00482 unpacked to. 00483 00484 Maximum - Pointer to where the maximum acceptable end value should be 00485 unpacked to. 00486 00487 Length - Pointer to where the required length should be unpacked to. 00488 00489 Minimum - Pointer to where the required alignment should be unpacked to. 00490 00491 Return Value: 00492 00493 Returns the status of this operation. 00494 00495 --*/ 00496 00497 { 00498 PAGED_CODE(); 00499 ASSERT(Descriptor); 00500 ASSERT(Descriptor->Type == CmResourceTypePort 00501 || Descriptor->Type == CmResourceTypeMemory); 00502 00503 00504 *Minimum = (ULONGLONG) Descriptor->u.Generic.MinimumAddress.QuadPart; 00505 *Maximum = (ULONGLONG) Descriptor->u.Generic.MaximumAddress.QuadPart; 00506 *Length = Descriptor->u.Generic.Length; 00507 *Alignment = Descriptor->u.Generic.Alignment; 00508 00509 // 00510 // Fix the broken hardware that reports 0 alignment 00511 // 00512 00513 if (*Alignment == 0) { 00514 *Alignment = 1; 00515 } 00516 00517 // 00518 // Fix broken INF's that report they support 24bit memory > 0xFFFFFF 00519 // 00520 00521 if (Descriptor->Type == CmResourceTypeMemory 00522 && Descriptor->Flags & CM_RESOURCE_MEMORY_24 00523 && Descriptor->u.Memory.MaximumAddress.QuadPart > 0xFFFFFF) { 00524 *Maximum = 0xFFFFFF; 00525 } 00526 00527 ARB_PRINT(2, 00528 ("Unpacking %s requirement %p => 0x%I64x-0x%I64x length 0x%x alignment 0x%x\n", 00529 Descriptor->Type == CmResourceTypePort ? "port" : "memory", 00530 Descriptor, 00531 *Minimum, 00532 *Maximum, 00533 *Length, 00534 *Alignment 00535 )); 00536 00537 return STATUS_SUCCESS; 00538 00539 } 00540 00541 LONG 00542 IopGenericScoreRequirement( 00543 IN PIO_RESOURCE_DESCRIPTOR Descriptor 00544 ) 00545 00546 /*++ 00547 00548 Routine Description: 00549 00550 This routine scores a requirement based on how flexible it is. The least 00551 flexible devices are scored the least and so when the arbitration list is 00552 sorted we try to allocate their resources first. 00553 00554 Arguments: 00555 00556 Descriptor - The descriptor describing the requirement to score. 00557 00558 00559 Return Value: 00560 00561 The score. 00562 00563 --*/ 00564 00565 { 00566 LONG score; 00567 ULONGLONG start, end; 00568 LONGLONG bigscore; 00569 ULONG alignment; 00570 00571 PAGED_CODE(); 00572 00573 #define MAX_SCORE MAXLONG 00574 00575 ASSERT(Descriptor); 00576 ASSERT((Descriptor->Type == CmResourceTypePort) || 00577 (Descriptor->Type == CmResourceTypeMemory)); 00578 00579 alignment = Descriptor->u.Generic.Alignment; 00580 00581 // 00582 // Fix the broken hardware that reports 0 alignment 00583 // Since this is not a PCI device, set the alignment to 1. 00584 // 00585 // 00586 00587 if (alignment == 0 && 00588 ((Descriptor->Type == CmResourceTypePort) || 00589 (Descriptor->Type == CmResourceTypeMemory))) { 00590 alignment = 1; 00591 } 00592 00593 00594 00595 start = ALIGN_ADDRESS_UP( 00596 Descriptor->u.Generic.MinimumAddress.QuadPart, 00597 alignment 00598 ); 00599 00600 end = Descriptor->u.Generic.MaximumAddress.QuadPart; 00601 00602 // 00603 // The score is the number of possible allocations that could be made 00604 // given the alignment and length constraints 00605 // 00606 00607 bigscore = (((end - Descriptor->u.Generic.Length + 1) - start) 00608 / alignment) + 1; 00609 00610 score = (LONG)bigscore; 00611 if (bigscore < 0) { 00612 score = -1; 00613 } else if (bigscore > MAX_SCORE) { 00614 score = MAX_SCORE; 00615 } 00616 00617 ARB_PRINT(2, 00618 ("Scoring port resource %p(0x%I64x-0x%I64x) => %i\n", 00619 Descriptor->Type == CmResourceTypePort ? "port" : "memory", 00620 Descriptor, 00621 Descriptor->u.Generic.MinimumAddress.QuadPart, 00622 end, 00623 score 00624 )); 00625 00626 return score; 00627 } 00628 00629 NTSTATUS 00630 IopGenericPackResource( 00631 IN PIO_RESOURCE_DESCRIPTOR Requirement, 00632 IN ULONGLONG Start, 00633 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor 00634 ) 00635 00636 /*++ 00637 00638 Routine Description: 00639 00640 This routine packs an resource descriptor. 00641 00642 Arguments: 00643 00644 Requirement - The requirement from which this resource was chosen. 00645 00646 Start - The start value of the resource. 00647 00648 Descriptor - Pointer to the descriptor to pack into. 00649 00650 Return Value: 00651 00652 Returns the status of this operation. 00653 00654 --*/ 00655 00656 { 00657 00658 PAGED_CODE(); 00659 ASSERT(Descriptor); 00660 ASSERT(Requirement); 00661 ASSERT(Requirement->Type == CmResourceTypePort 00662 || Requirement->Type == CmResourceTypeMemory); 00663 00664 Descriptor->Type = Requirement->Type; 00665 Descriptor->Flags = Requirement->Flags; 00666 Descriptor->ShareDisposition = Requirement->ShareDisposition; 00667 Descriptor->u.Generic.Start.QuadPart = Start; 00668 Descriptor->u.Generic.Length = Requirement->u.Generic.Length; 00669 00670 ARB_PRINT(2, 00671 ("Packing %s resource %p => 0x%I64x length 0x%x\n", 00672 Descriptor->Type == CmResourceTypePort ? "port" : "memory", 00673 Descriptor, 00674 Descriptor->u.Port.Start.QuadPart, 00675 Descriptor->u.Port.Length 00676 )); 00677 00678 return STATUS_SUCCESS; 00679 } 00680 00681 NTSTATUS 00682 IopGenericUnpackResource( 00683 IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor, 00684 OUT PULONGLONG Start, 00685 OUT PULONG Length 00686 ) 00687 00688 /*++ 00689 00690 Routine Description: 00691 00692 This routine unpacks an resource descriptor. 00693 00694 Arguments: 00695 00696 Descriptor - The descriptor describing the resource to unpack. 00697 00698 Start - Pointer to where the start value should be unpacked to. 00699 00700 Length - Pointer to where the length value should be unpacked to. 00701 00702 Return Value: 00703 00704 Returns the status of this operation. 00705 00706 --*/ 00707 00708 { 00709 00710 PAGED_CODE(); 00711 ASSERT(Descriptor); 00712 ASSERT(Descriptor->Type == CmResourceTypePort 00713 || Descriptor->Type == CmResourceTypeMemory); 00714 00715 *Start = Descriptor->u.Generic.Start.QuadPart; 00716 *Length = Descriptor->u.Generic.Length; 00717 00718 ARB_PRINT(2, 00719 ("Unpacking %s resource %p => 0x%I64x Length 0x%x\n", 00720 Descriptor->Type == CmResourceTypePort ? "port" : "memory", 00721 Descriptor, 00722 *Start, 00723 *Length 00724 )); 00725 00726 return STATUS_SUCCESS; 00727 00728 } 00729 #if 0 00730 NTSTATUS 00731 IopPortRetestAllocation( 00732 IN PARBITER_INSTANCE Arbiter, 00733 IN OUT PLIST_ENTRY ArbitrationList 00734 ) 00735 00736 /*++ 00737 00738 Routine Description: 00739 00740 This providesa port specific implementation of the RetestAllocation action 00741 which takes into account ISA aliases and adds them where appropriate. 00742 It walks the arbitration list and updates the possible allocation to reflect 00743 the allocation entries of the list. For these entries to be valid 00744 TestAllocation must have been performed on this arbitration list. 00745 00746 Parameters: 00747 00748 Arbiter - The arbiter instance data for the arbiter being called. 00749 00750 ArbitrationList - A list of ARBITER_LIST_ENTRY entries which contain the 00751 requirements and associated devices. TestAllocation for this arbiter 00752 should have been called on this list. 00753 00754 Return Value: 00755 00756 Status code that indicates whether or not the function was successful. 00757 00758 --*/ 00759 00760 { 00761 NTSTATUS status; 00762 PARBITER_LIST_ENTRY current; 00763 PIO_RESOURCE_DESCRIPTOR alternative; 00764 ULONGLONG start; 00765 ULONG length; 00766 00767 PAGED_CODE(); 00768 00769 // 00770 // Copy the current allocation and reserved 00771 // 00772 00773 ARB_PRINT(3, ("Retest: Copy current allocation\n")); 00774 status = RtlCopyRangeList(Arbiter->PossibleAllocation, Arbiter->Allocation); 00775 00776 if (!NT_SUCCESS(status)) { 00777 goto cleanup; 00778 } 00779 00780 // 00781 // Free all the resources currently allocated to all the devices we 00782 // are arbitrating for 00783 // 00784 00785 FOR_ALL_IN_LIST(ARBITER_LIST_ENTRY, ArbitrationList, current) { 00786 00787 ARB_PRINT(2, ("Retest: Delete 0x%08x's resources\n", current->PhysicalDeviceObject)); 00788 00789 status = RtlDeleteOwnersRanges(Arbiter->PossibleAllocation, 00790 (PVOID) current->PhysicalDeviceObject 00791 ); 00792 00793 if (!NT_SUCCESS(status)) { 00794 goto cleanup; 00795 } 00796 } 00797 00798 // 00799 // Copy the previous allocation into the range list 00800 // 00801 00802 FOR_ALL_IN_LIST(ARBITER_LIST_ENTRY, ArbitrationList, current) { 00803 00804 ASSERT(current->Assignment); 00805 00806 status = Arbiter->UnpackResource(current->Assignment, 00807 &start, 00808 &length 00809 ); 00810 00811 ASSERT(NT_SUCCESS(status)); 00812 00813 // 00814 // If we had a requirement for length 0 then that will be seen as 00815 // end == start - 1 here so don't attempt to add the range - it will 00816 // fail! 00817 // 00818 00819 if (length != 0) { 00820 00821 status = RtlAddRange( 00822 Arbiter->PossibleAllocation, 00823 start, 00824 start + length - 1, 00825 0, 00826 RTL_RANGE_LIST_ADD_IF_CONFLICT + 00827 (current->Assignment->ShareDisposition == CmResourceShareShared ? 00828 RTL_RANGE_LIST_ADD_SHARED : 0), 00829 NULL, 00830 current->PhysicalDeviceObject 00831 ); 00832 00833 ASSERT(NT_SUCCESS(status)); 00834 00835 // 00836 // Retireve the alternative from which the assignment was chosen from 00837 // then 00838 // 00839 00840 alternative = current->SelectedAlternative; 00841 00842 // 00843 // Add the aliases 00844 // 00845 00846 if (alternative->Flags & CM_RESOURCE_PORT_10_BIT_DECODE 00847 || alternative->Flags & CM_RESOURCE_PORT_12_BIT_DECODE) { 00848 00849 ULONGLONG alias = start; 00850 BOOLEAN shared = current->Assignment->ShareDisposition == 00851 CmResourceShareShared; 00852 00853 ARB_PRINT(3, ("Adding aliases\n")); 00854 00855 while (IopPortGetNextAlias(alternative->Flags, 00856 alias, 00857 &alias)) { 00858 00859 status = RtlAddRange( 00860 Arbiter->PossibleAllocation, 00861 alias, 00862 alias + length - 1, 00863 ARBITER_RANGE_ALIAS, 00864 RTL_RANGE_LIST_ADD_IF_CONFLICT + 00865 (shared ? RTL_RANGE_LIST_SHARED_OK : 0), 00866 NULL, 00867 current->PhysicalDeviceObject 00868 ); 00869 00870 // 00871 // We have already checked if these ranges are available 00872 // so we should not fail... 00873 // 00874 00875 ASSERT(NT_SUCCESS(status)); 00876 } 00877 } 00878 } 00879 } 00880 00881 return status; 00882 00883 cleanup: 00884 00885 RtlFreeRangeList(Arbiter->PossibleAllocation); 00886 return status; 00887 } 00888 #endif 00889 VOID 00890 IopPortBacktrackAllocation( 00891 IN PARBITER_INSTANCE Arbiter, 00892 IN PARBITER_ALLOCATION_STATE State 00893 ) 00894 00895 /*++ 00896 00897 Routine Description: 00898 00899 This routine is called from AllocateEntry if the possible solution 00900 (State->Start - State->End) does not allow us to allocate resources to 00901 the rest of the devices being considered. It deletes the ranges that were 00902 added to Arbiter->PossibleAllocation by AddAllocation including those 00903 associated with ISA aliases. 00904 00905 Arguments: 00906 00907 Arbiter - The instance data of the arbiter who was called. 00908 00909 State - The state of the current arbitration. 00910 00911 Return Value: 00912 00913 None. 00914 00915 --*/ 00916 00917 00918 { 00919 00920 NTSTATUS status; 00921 ULONGLONG alias = State->Start; 00922 00923 PAGED_CODE(); 00924 00925 // 00926 // Delete the aliases 00927 // 00928 00929 ARB_PRINT(2, ("\t\tDeleting aliases\n")); 00930 00931 while (IopPortGetNextAlias(State->CurrentAlternative->Flags, 00932 alias, 00933 &alias)) { 00934 00935 status = RtlDeleteRange( 00936 Arbiter->PossibleAllocation, 00937 alias, 00938 alias + State->CurrentAlternative->Length - 1, 00939 State->Entry->PhysicalDeviceObject 00940 ); 00941 00942 // 00943 // We should not fail... 00944 // 00945 00946 ASSERT(NT_SUCCESS(status)); 00947 } 00948 00949 // 00950 // Now call the original function to delete the base range 00951 // 00952 00953 ArbBacktrackAllocation(Arbiter, State); 00954 00955 } 00956 00957 00958 BOOLEAN 00959 IopPortFindSuitableRange( 00960 PARBITER_INSTANCE Arbiter, 00961 PARBITER_ALLOCATION_STATE State 00962 ) 00963 /*++ 00964 00965 Routine Description: 00966 00967 This routine is called from AllocateEntry once we have decided where we want 00968 to allocate from. It tries to find a free range that matches the 00969 requirements in State while restricting its possible solutions to the range 00970 State->Start to State->CurrentMaximum. On success State->Start and 00971 State->End represent this range. Conflicts with ISA aliases are considered. 00972 00973 Arguments: 00974 00975 Arbiter - The instance data of the arbiter who was called. 00976 00977 State - The state of the current arbitration. 00978 00979 Return Value: 00980 00981 TRUE if we found a range, FALSE otherwise. 00982 00983 --*/ 00984 { 00985 NTSTATUS status; 00986 UCHAR userFlagsMask = 0; 00987 00988 PAGED_CODE(); 00989 00990 // 00991 // If we are asking for zero ports then trivially succeed with the minimum 00992 // value 00993 // 00994 00995 if (State->CurrentAlternative->Length == 0) { 00996 State->End = State->Start; 00997 return TRUE; 00998 } 00999 01000 // 01001 // For legacy requests from IoAssignResources (directly or by way of 01002 // HalAssignSlotResources) or IoReportResourceUsage we consider preallocated 01003 // resources to be available for backward compatibility reasons. 01004 // 01005 // If we are allocating a devices boot config then we consider all other 01006 // boot configs to be available. 01007 // 01008 01009 if (State->Entry->RequestSource == ArbiterRequestLegacyReported 01010 || State->Entry->RequestSource == ArbiterRequestLegacyAssigned 01011 || State->Entry->Flags & ARBITER_FLAG_BOOT_CONFIG) { 01012 01013 userFlagsMask = ARBITER_RANGE_BOOT_ALLOCATED; 01014 } 01015 01016 // 01017 // Try to satisfy the request 01018 // 01019 01020 while (State->CurrentMinimum <= State->CurrentMaximum) { 01021 01022 // 01023 // Select the first free alternative from the current alternative 01024 // 01025 01026 status = RtlFindRange( 01027 Arbiter->PossibleAllocation, 01028 State->CurrentMinimum, 01029 State->CurrentMaximum, 01030 State->CurrentAlternative->Length, 01031 State->CurrentAlternative->Alignment, 01032 State->CurrentAlternative->Flags & 01033 ARBITER_ALTERNATIVE_FLAG_SHARED ? 01034 RTL_RANGE_LIST_SHARED_OK : 0, 01035 userFlagsMask, 01036 Arbiter->ConflictCallbackContext, 01037 Arbiter->ConflictCallback, 01038 &State->Start 01039 ); 01040 01041 01042 // 01043 // Did we find a range and if not can we override any conflict 01044 // 01045 if (NT_SUCCESS(status) 01046 || Arbiter->OverrideConflict(Arbiter, State)) { 01047 01048 State->End = State->Start + State->CurrentAlternative->Length - 1; 01049 01050 // 01051 // Check if the aliases are available 01052 // 01053 if (IopPortIsAliasedRangeAvailable(Arbiter, State)) { 01054 01055 // 01056 // We found a suitable range so return 01057 // 01058 01059 return TRUE; 01060 01061 } else { 01062 01063 // 01064 // This range's aliases arn't available so try the next range 01065 // 01066 01067 State->Start += State->CurrentAlternative->Length; 01068 01069 continue; 01070 } 01071 } else { 01072 01073 // 01074 // We couldn't find a base range 01075 // 01076 01077 break; 01078 } 01079 } 01080 01081 return FALSE; 01082 } 01083 01084 01085 01086 BOOLEAN 01087 IopPortGetNextAlias( 01088 ULONG IoDescriptorFlags, 01089 ULONGLONG LastAlias, 01090 PULONGLONG NextAlias 01091 ) 01092 /*++ 01093 01094 Routine Description: 01095 01096 This routine calculates the next alias of an IO port up to MAX_ALIAS_PORT. 01097 01098 Arguments: 01099 01100 IoDescriptorFlags - The flags from the requirement descriptor indicating the 01101 type of alias if any. 01102 01103 LastAlias - The alias previous to this one. 01104 01105 NextAlias - Point to where the next alias should be returned 01106 01107 Return Value: 01108 01109 TRUE if we found an alias, FALSE otherwise. 01110 01111 --*/ 01112 01113 { 01114 ULONGLONG next; 01115 01116 PAGED_CODE(); 01117 01118 if (IoDescriptorFlags & CM_RESOURCE_PORT_10_BIT_DECODE) { 01119 next = LastAlias + (1 << 10); 01120 } else if (IoDescriptorFlags & CM_RESOURCE_PORT_12_BIT_DECODE) { 01121 next = LastAlias + (1 << 12); 01122 } else { 01123 01124 // BUGBUG - should CM_RESOURCE_PORT_16_BIT_DECODE be set? 01125 // 01126 // There are no aliases 01127 // 01128 01129 return FALSE; 01130 } 01131 01132 // 01133 // Check that we are below the maximum aliased port 01134 // 01135 01136 if (next > MAX_ALIAS_PORT) { 01137 return FALSE; 01138 } else { 01139 *NextAlias = next; 01140 return TRUE; 01141 } 01142 } 01143 01144 01145 VOID 01146 IopPortAddAllocation( 01147 IN PARBITER_INSTANCE Arbiter, 01148 IN PARBITER_ALLOCATION_STATE State 01149 ) 01150 01151 /*++ 01152 01153 Routine Description: 01154 01155 This routine is called from AllocateEntry once we have found a possible 01156 solution (State->Start - State->End). It adds the ranges that will not be 01157 available if we commit to this solution to Arbiter->PossibleAllocation. 01158 01159 Arguments: 01160 01161 Arbiter - The instance data of the arbiter who was called. 01162 01163 State - The state of the current arbitration. 01164 01165 Return Value: 01166 01167 None. 01168 01169 --*/ 01170 01171 { 01172 NTSTATUS status; 01173 ULONGLONG alias; 01174 BOOLEAN isAlias; 01175 01176 PAGED_CODE(); 01177 01178 ASSERT(Arbiter); 01179 ASSERT(State); 01180 01181 status = RtlAddRange(Arbiter->PossibleAllocation, 01182 State->Start, 01183 State->End, 01184 State->RangeAttributes, 01185 RTL_RANGE_LIST_ADD_IF_CONFLICT + 01186 (State->CurrentAlternative->Flags & ARBITER_ALTERNATIVE_FLAG_SHARED 01187 ? RTL_RANGE_LIST_ADD_SHARED : 0), 01188 NULL, 01189 State->Entry->PhysicalDeviceObject 01190 ); 01191 01192 ASSERT(NT_SUCCESS(status)); 01193 01194 // 01195 // Add any aliases 01196 // 01197 01198 alias = State->Start; 01199 ARB_PRINT(2, ("Adding aliases\n")); 01200 01201 while (IopPortGetNextAlias(State->CurrentAlternative->Descriptor->Flags, 01202 alias, 01203 &alias)) { 01204 01205 status = RtlAddRange(Arbiter->PossibleAllocation, 01206 alias, 01207 alias + State->CurrentAlternative->Length - 1, 01208 (UCHAR) (State->RangeAttributes | ARBITER_RANGE_ALIAS), 01209 RTL_RANGE_LIST_ADD_IF_CONFLICT + 01210 (State->CurrentAlternative->Flags & ARBITER_ALTERNATIVE_FLAG_SHARED 01211 ? RTL_RANGE_LIST_ADD_SHARED : 0), 01212 NULL, 01213 State->Entry->PhysicalDeviceObject 01214 ); 01215 01216 // 01217 // We have already checked if these ranges are available 01218 // so we should not fail... 01219 // 01220 01221 ASSERT(NT_SUCCESS(status)); 01222 } 01223 } 01224 01225 01226 BOOLEAN 01227 IopPortIsAliasedRangeAvailable( 01228 PARBITER_INSTANCE Arbiter, 01229 PARBITER_ALLOCATION_STATE State 01230 ) 01231 01232 /*++ 01233 01234 Routine Description: 01235 01236 This routine determines if the range (Start-(Length-1)) is available taking 01237 into account any aliases. 01238 01239 Arguments: 01240 01241 Arbiter - The instance data of the arbiter who was called. 01242 01243 State - The state of the current arbitration. 01244 01245 Return Value: 01246 01247 TRUE if the range is available, FALSE otherwise. 01248 01249 --*/ 01250 01251 { 01252 NTSTATUS status; 01253 ULONGLONG alias = State->Start; 01254 BOOLEAN aliasAvailable; 01255 UCHAR userFlagsMask = 0; 01256 01257 PAGED_CODE(); 01258 01259 #if defined(BUGFEST_HACKS) 01260 // 01261 // For the purposes of the Bug^H^H^HPlugFest don't mind is aliases conflict 01262 // with any devices but still add them... 01263 // 01264 return TRUE; 01265 #endif 01266 01267 // 01268 // For legacy requests from IoAssignResources (directly or by way of 01269 // HalAssignSlotResources) or IoReportResourceUsage we consider preallocated 01270 // resources to be available for backward compatibility reasons. 01271 // 01272 if (State->Entry->RequestSource == ArbiterRequestLegacyReported 01273 || State->Entry->RequestSource == ArbiterRequestLegacyAssigned) { 01274 01275 userFlagsMask |= ARBITER_RANGE_BOOT_ALLOCATED; 01276 } 01277 01278 while (IopPortGetNextAlias(State->CurrentAlternative->Descriptor->Flags, 01279 alias, 01280 &alias)) { 01281 01282 status = RtlIsRangeAvailable( 01283 Arbiter->PossibleAllocation, 01284 alias, 01285 alias + State->CurrentAlternative->Length - 1, 01286 State->CurrentAlternative->Flags & ARBITER_ALTERNATIVE_FLAG_SHARED ? 01287 RTL_RANGE_LIST_SHARED_OK : 0, 01288 userFlagsMask, 01289 Arbiter->ConflictCallbackContext, 01290 Arbiter->ConflictCallback, 01291 &aliasAvailable 01292 ); 01293 01294 ASSERT(NT_SUCCESS(status)); 01295 01296 if (!aliasAvailable) { 01297 01298 ARBITER_ALLOCATION_STATE tempState; 01299 01300 // 01301 // Check if we allow this conflict by calling OverrideConflict - 01302 // we will need to falsify ourselves an allocation state first 01303 // 01304 // BUGBUG - this works but relies on knowing what OverrideConflict 01305 // looks at. A better fix invloves storing the aliases in another 01306 // list but this it too much of a change for Win2k 01307 // 01308 01309 RtlCopyMemory(&tempState, State, sizeof(ARBITER_ALLOCATION_STATE)); 01310 01311 tempState.CurrentMinimum = alias; 01312 tempState.CurrentMaximum = alias + State->CurrentAlternative->Length - 1; 01313 01314 if (Arbiter->OverrideConflict(Arbiter, &tempState)) { 01315 // 01316 // We decided this conflict was ok so contine checking the rest 01317 // of the aliases 01318 // 01319 01320 continue; 01321 01322 } 01323 01324 // 01325 // An alias isn't available - get another possibility 01326 // 01327 01328 ARB_PRINT(2, 01329 ("\t\tAlias 0x%x-0x%x not available\n", 01330 alias, 01331 alias + State->CurrentAlternative->Length - 1 01332 )); 01333 01334 return FALSE; 01335 } 01336 } 01337 01338 return TRUE; 01339 } 01340 01341 BOOLEAN 01342 IopMemFindSuitableRange( 01343 PARBITER_INSTANCE Arbiter, 01344 PARBITER_ALLOCATION_STATE State 01345 ) 01346 /*++ 01347 01348 Routine Description: 01349 01350 This routine is called from AllocateEntry once we have decided where we want 01351 to allocate from. It tries to find a free range that matches the 01352 requirements in State while restricting its possible solutions to the range 01353 State->Start to State->CurrentMaximum. On success State->Start and 01354 State->End represent this range. Conflicts between boot configs are allowed 01355 01356 Arguments: 01357 01358 Arbiter - The instance data of the arbiter who was called. 01359 01360 State - The state of the current arbitration. 01361 01362 Return Value: 01363 01364 TRUE if we found a range, FALSE otherwise. 01365 01366 --*/ 01367 { 01368 // 01369 // If this was a boot config then consider other boot configs to be 01370 // available 01371 // 01372 01373 if (State->Entry->Flags & ARBITER_FLAG_BOOT_CONFIG) { 01374 State->RangeAvailableAttributes |= ARBITER_RANGE_BOOT_ALLOCATED; 01375 } 01376 01377 // 01378 // Do the default thing 01379 // 01380 01381 return ArbFindSuitableRange(Arbiter, State); 01382 } 01383

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