Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4238 lines
107 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. arbiter.c
  5. Abstract:
  6. This module contains support routines for the Pnp resource arbiters.
  7. Author:
  8. Andrew Thornton (andrewth) 1-April-1997
  9. Environment:
  10. Kernel mode
  11. Revision History:
  12. --*/
  13. #include "arbp.h"
  14. #define REGSTR_KEY_ROOTENUM L"ROOT"
  15. //
  16. // Conditional compilation constants
  17. //
  18. #define ALLOW_BOOT_ALLOC_CONFLICTS 1
  19. #define PLUG_FEST_HACKS 0
  20. //
  21. // Pool Tags
  22. //
  23. #define ARBITER_ALLOCATION_STATE_TAG 'AbrA'
  24. #define ARBITER_ORDERING_LIST_TAG 'LbrA'
  25. #define ARBITER_MISC_TAG 'MbrA'
  26. #define ARBITER_RANGE_LIST_TAG 'RbrA'
  27. #define ARBITER_CONFLICT_INFO_TAG 'CbrA'
  28. //
  29. // Constants
  30. //
  31. #define PATH_ARBITERS L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Arbiters"
  32. #define KEY_ALLOCATIONORDER L"AllocationOrder"
  33. #define KEY_RESERVEDRESOURCES L"ReservedResources"
  34. #define ARBITER_ORDERING_GROW_SIZE 8
  35. //
  36. // Macros
  37. //
  38. //
  39. // PVOID
  40. // FULL_INFO_DATA(
  41. // IN PKEY_VALUE_FULL_INFORMATION k
  42. // );
  43. //
  44. // This macro returns the pointer to the beginning of the data area of a
  45. // KEY_VALUE_FULL_INFORMATION structure.
  46. //
  47. #define FULL_INFO_DATA(k) ((PCHAR)(k) + (k)->DataOffset)
  48. //
  49. // BOOLEAN
  50. // DISJOINT(
  51. // IN ULONGLONG s1,
  52. // IN ULONGLONG e1,
  53. // IN ULONGLONG s2,
  54. // IN ULONGLONG e2
  55. // );
  56. //
  57. #define DISJOINT(s1,e1,s2,e2) \
  58. ( ((s1) < (s2) && (e1) < (s2)) \
  59. ||((s2) < (s1) && (e2) < (s1)) )
  60. //
  61. // VOID
  62. // ArbpWstrToUnicodeString(
  63. // IN PUNICODE_STRING u,
  64. // IN PWSTR p
  65. // );
  66. //
  67. #define ArbpWstrToUnicodeString(u, p) \
  68. (u)->Length = ((u)->MaximumLength = \
  69. (USHORT) (sizeof((p))) - sizeof(WCHAR)); \
  70. (u)->Buffer = (p)
  71. //
  72. // ULONG
  73. // INDEX_FROM_PRIORITY(
  74. // LONG Priority
  75. // );
  76. //
  77. #define ORDERING_INDEX_FROM_PRIORITY(P) \
  78. ( (ULONG) ( (P) > 0 ? (P) - 1 : ((P) * -1) - 1) )
  79. //
  80. // Prototypes
  81. //
  82. NTSTATUS
  83. ArbpBuildAllocationStack(
  84. IN PARBITER_INSTANCE Arbiter,
  85. IN PLIST_ENTRY ArbitrationList,
  86. IN ULONG ArbitrationListCount
  87. );
  88. NTSTATUS
  89. ArbpGetRegistryValue(
  90. IN HANDLE KeyHandle,
  91. IN PWSTR ValueName,
  92. OUT PKEY_VALUE_FULL_INFORMATION *Information
  93. );
  94. NTSTATUS
  95. ArbpBuildAlternative(
  96. IN PARBITER_INSTANCE Arbiter,
  97. IN PIO_RESOURCE_DESCRIPTOR Requirement,
  98. OUT PARBITER_ALTERNATIVE Alternative
  99. );
  100. VOID
  101. ArbpUpdatePriority(
  102. PARBITER_INSTANCE Arbiter,
  103. PARBITER_ALTERNATIVE Alternative
  104. );
  105. BOOLEAN
  106. ArbpQueryConflictCallback(
  107. IN PVOID Context,
  108. IN PRTL_RANGE Range
  109. );
  110. BOOLEAN
  111. ArbShareDriverExclusive(
  112. IN PARBITER_INSTANCE Arbiter,
  113. IN PARBITER_ALLOCATION_STATE State
  114. );
  115. //
  116. // Make everything pageable
  117. //
  118. #ifdef ALLOC_PRAGMA
  119. VOID
  120. ArbDereferenceArbiterInstance(
  121. IN PARBITER_INSTANCE Arbiter
  122. );
  123. #pragma alloc_text(PAGE, ArbInitializeArbiterInstance)
  124. #pragma alloc_text(PAGE, ArbDereferenceArbiterInstance)
  125. #pragma alloc_text(PAGE, ArbDeleteArbiterInstance)
  126. #pragma alloc_text(PAGE, ArbTestAllocation)
  127. #pragma alloc_text(PAGE, ArbpBuildAlternative)
  128. #pragma alloc_text(PAGE, ArbpBuildAllocationStack)
  129. #pragma alloc_text(PAGE, ArbSortArbitrationList)
  130. #pragma alloc_text(PAGE, ArbCommitAllocation)
  131. #pragma alloc_text(PAGE, ArbRollbackAllocation)
  132. #pragma alloc_text(PAGE, ArbRetestAllocation)
  133. #pragma alloc_text(PAGE, ArbBootAllocation)
  134. #pragma alloc_text(PAGE, ArbArbiterHandler)
  135. #pragma alloc_text(PAGE, ArbBuildAssignmentOrdering)
  136. #pragma alloc_text(PAGE, ArbFindSuitableRange)
  137. #pragma alloc_text(PAGE, ArbAddAllocation)
  138. #pragma alloc_text(PAGE, ArbBacktrackAllocation)
  139. #pragma alloc_text(PAGE, ArbPreprocessEntry)
  140. #pragma alloc_text(PAGE, ArbAllocateEntry)
  141. #pragma alloc_text(PAGE, ArbGetNextAllocationRange)
  142. #pragma alloc_text(PAGE, ArbpGetRegistryValue)
  143. #pragma alloc_text(PAGE, ArbInitializeOrderingList)
  144. #pragma alloc_text(PAGE, ArbCopyOrderingList)
  145. #pragma alloc_text(PAGE, ArbAddOrdering)
  146. #pragma alloc_text(PAGE, ArbPruneOrdering)
  147. #pragma alloc_text(PAGE, ArbFreeOrderingList)
  148. #pragma alloc_text(PAGE, ArbOverrideConflict)
  149. #pragma alloc_text(PAGE, ArbpUpdatePriority)
  150. #pragma alloc_text(PAGE, ArbAddReserved)
  151. #pragma alloc_text(PAGE, ArbpQueryConflictCallback)
  152. #pragma alloc_text(PAGE, ArbQueryConflict)
  153. #pragma alloc_text(PAGE, ArbStartArbiter)
  154. #pragma alloc_text(PAGE, ArbShareDriverExclusive)
  155. #endif // ALLOC_PRAGMA
  156. //
  157. // Implementation
  158. //
  159. NTSTATUS
  160. ArbInitializeArbiterInstance(
  161. OUT PARBITER_INSTANCE Arbiter,
  162. IN PDEVICE_OBJECT BusDeviceObject,
  163. IN CM_RESOURCE_TYPE ResourceType,
  164. IN PWSTR Name,
  165. IN PWSTR OrderingName,
  166. IN PARBITER_TRANSLATE_ALLOCATION_ORDER TranslateOrdering OPTIONAL
  167. )
  168. /*++
  169. Routine Description:
  170. This routine initializes an arbiter instance and fills in any optional NULL
  171. dispatch table entries with system default functions.
  172. Parameters:
  173. Arbiter - A caller allocated arbiter instance structure.
  174. The UnpackRequirement, PackResource, UnpackResource and ScoreRequirement
  175. entries should be initialized with the appropriate routines as should
  176. any other entries if the default system routines are not sufficient.
  177. BusDeviceObject - The device object that exposes this arbiter - normally an
  178. FDO.
  179. ResourceType - The resource type this arbiter arbitrates.
  180. Name - A string used to identify the arbiter, used in debug messages and
  181. for registry storage
  182. OrderingName - The name of the preferred assignment ordering list under
  183. HKLM\System\CurrentControlSet\Control\SystemResources\AssignmentOrdering
  184. TranslateOrdering - Function that, if present, will be called to translate
  185. each descriptor from the ordering list
  186. Return Value:
  187. Status code that indicates whether or not the function was successful.
  188. Notes:
  189. --*/
  190. {
  191. NTSTATUS status;
  192. PAGED_CODE();
  193. ASSERT(Arbiter->UnpackRequirement);
  194. ASSERT(Arbiter->PackResource);
  195. ASSERT(Arbiter->UnpackResource);
  196. ARB_PRINT(2,("Initializing %S Arbiter...\n", Name));
  197. //
  198. // Initialize all pool allocation pointers to NULL so we can cleanup
  199. //
  200. ASSERT(Arbiter->MutexEvent == NULL
  201. && Arbiter->Allocation == NULL
  202. && Arbiter->PossibleAllocation == NULL
  203. && Arbiter->AllocationStack == NULL
  204. );
  205. //
  206. // We are an arbiter
  207. //
  208. Arbiter->Signature = ARBITER_INSTANCE_SIGNATURE;
  209. //
  210. // Remember the bus that produced us
  211. //
  212. Arbiter->BusDeviceObject = BusDeviceObject;
  213. //
  214. // Initialize state lock (KEVENT must be non-paged)
  215. //
  216. Arbiter->MutexEvent = ExAllocatePoolWithTag(NonPagedPool,
  217. sizeof(KEVENT),
  218. ARBITER_MISC_TAG
  219. );
  220. if (!Arbiter->MutexEvent) {
  221. status = STATUS_INSUFFICIENT_RESOURCES;
  222. goto cleanup;
  223. }
  224. KeInitializeEvent(Arbiter->MutexEvent, SynchronizationEvent, TRUE);
  225. //
  226. // Initialize the allocation stack to a reasonable size
  227. //
  228. Arbiter->AllocationStack = ExAllocatePoolWithTag(PagedPool,
  229. INITIAL_ALLOCATION_STATE_SIZE,
  230. ARBITER_ALLOCATION_STATE_TAG
  231. );
  232. if (!Arbiter->AllocationStack) {
  233. status = STATUS_INSUFFICIENT_RESOURCES;
  234. goto cleanup;
  235. }
  236. Arbiter->AllocationStackMaxSize = INITIAL_ALLOCATION_STATE_SIZE;
  237. //
  238. // Allocate buffers to hold the range lists
  239. //
  240. Arbiter->Allocation = ExAllocatePoolWithTag(PagedPool,
  241. sizeof(RTL_RANGE_LIST),
  242. ARBITER_RANGE_LIST_TAG
  243. );
  244. if (!Arbiter->Allocation) {
  245. status = STATUS_INSUFFICIENT_RESOURCES;
  246. goto cleanup;
  247. }
  248. Arbiter->PossibleAllocation = ExAllocatePoolWithTag(PagedPool,
  249. sizeof(RTL_RANGE_LIST),
  250. ARBITER_RANGE_LIST_TAG
  251. );
  252. if (!Arbiter->PossibleAllocation) {
  253. status = STATUS_INSUFFICIENT_RESOURCES;
  254. goto cleanup;
  255. }
  256. //
  257. // Initialize the range lists
  258. //
  259. RtlInitializeRangeList(Arbiter->Allocation);
  260. RtlInitializeRangeList(Arbiter->PossibleAllocation);
  261. //
  262. // Initialize the data fields
  263. //
  264. Arbiter->TransactionInProgress = FALSE;
  265. Arbiter->Name = Name;
  266. Arbiter->ResourceType = ResourceType;
  267. //
  268. // If the caller has not supplied the optional functions set them to the
  269. // defaults (If this were C++ we'd just inherit this loit but seeing as its
  270. // not we'll do it the old fashioned way...)
  271. //
  272. if (!Arbiter->TestAllocation) {
  273. Arbiter->TestAllocation = ArbTestAllocation;
  274. }
  275. if (!Arbiter->RetestAllocation) {
  276. Arbiter->RetestAllocation = ArbRetestAllocation;
  277. }
  278. if (!Arbiter->CommitAllocation) {
  279. Arbiter->CommitAllocation = ArbCommitAllocation;
  280. }
  281. if (!Arbiter->RollbackAllocation) {
  282. Arbiter->RollbackAllocation = ArbRollbackAllocation;
  283. }
  284. if (!Arbiter->AddReserved) {
  285. Arbiter->AddReserved = ArbAddReserved;
  286. }
  287. if (!Arbiter->PreprocessEntry) {
  288. Arbiter->PreprocessEntry = ArbPreprocessEntry;
  289. }
  290. if (!Arbiter->AllocateEntry) {
  291. Arbiter->AllocateEntry = ArbAllocateEntry;
  292. }
  293. if (!Arbiter->GetNextAllocationRange) {
  294. Arbiter->GetNextAllocationRange = ArbGetNextAllocationRange;
  295. }
  296. if (!Arbiter->FindSuitableRange) {
  297. Arbiter->FindSuitableRange = ArbFindSuitableRange;
  298. }
  299. if (!Arbiter->AddAllocation) {
  300. Arbiter->AddAllocation = ArbAddAllocation;
  301. }
  302. if (!Arbiter->BacktrackAllocation) {
  303. Arbiter->BacktrackAllocation = ArbBacktrackAllocation;
  304. }
  305. if (!Arbiter->OverrideConflict) {
  306. Arbiter->OverrideConflict = ArbOverrideConflict;
  307. }
  308. if (!Arbiter->BootAllocation) {
  309. Arbiter->BootAllocation = ArbBootAllocation;
  310. }
  311. if (!Arbiter->QueryConflict) {
  312. Arbiter->QueryConflict = ArbQueryConflict;
  313. }
  314. if (!Arbiter->StartArbiter) {
  315. Arbiter->StartArbiter = ArbStartArbiter;
  316. }
  317. //
  318. // Build the prefered assignment ordering - we assume that the reserved
  319. // ranges have the same name as the assignment ordering
  320. //
  321. status = ArbBuildAssignmentOrdering(Arbiter,
  322. OrderingName,
  323. OrderingName,
  324. TranslateOrdering
  325. );
  326. if (!NT_SUCCESS(status)) {
  327. goto cleanup;
  328. }
  329. return STATUS_SUCCESS;
  330. cleanup:
  331. if (Arbiter->MutexEvent) {
  332. ExFreePool(Arbiter->MutexEvent);
  333. }
  334. if (Arbiter->Allocation) {
  335. ExFreePool(Arbiter->Allocation);
  336. }
  337. if (Arbiter->PossibleAllocation) {
  338. ExFreePool(Arbiter->PossibleAllocation);
  339. }
  340. if (Arbiter->AllocationStack) {
  341. ExFreePool(Arbiter->AllocationStack);
  342. }
  343. return status;
  344. }
  345. VOID
  346. ArbReferenceArbiterInstance(
  347. IN PARBITER_INSTANCE Arbiter
  348. )
  349. {
  350. InterlockedIncrement(&Arbiter->ReferenceCount);
  351. }
  352. VOID
  353. ArbDereferenceArbiterInstance(
  354. IN PARBITER_INSTANCE Arbiter
  355. )
  356. {
  357. PAGED_CODE();
  358. InterlockedDecrement(&Arbiter->ReferenceCount);
  359. if (Arbiter->ReferenceCount == 0) {
  360. ArbDeleteArbiterInstance(Arbiter);
  361. }
  362. }
  363. VOID
  364. ArbDeleteArbiterInstance(
  365. IN PARBITER_INSTANCE Arbiter
  366. )
  367. {
  368. PAGED_CODE();
  369. if (Arbiter->MutexEvent) {
  370. ExFreePool(Arbiter->MutexEvent);
  371. }
  372. if (Arbiter->Allocation) {
  373. RtlFreeRangeList(Arbiter->Allocation);
  374. ExFreePool(Arbiter->Allocation);
  375. }
  376. if (Arbiter->PossibleAllocation) {
  377. RtlFreeRangeList(Arbiter->PossibleAllocation);
  378. ExFreePool(Arbiter->PossibleAllocation);
  379. }
  380. if (Arbiter->AllocationStack) {
  381. ExFreePool(Arbiter->AllocationStack);
  382. }
  383. ArbFreeOrderingList(&Arbiter->OrderingList);
  384. ArbFreeOrderingList(&Arbiter->ReservedList);
  385. #if ARB_DBG
  386. RtlFillMemory(Arbiter, sizeof(ARBITER_INSTANCE), 'A');
  387. #endif
  388. }
  389. NTSTATUS
  390. ArbTestAllocation(
  391. IN PARBITER_INSTANCE Arbiter,
  392. IN OUT PLIST_ENTRY ArbitrationList
  393. )
  394. /*++
  395. Routine Description:
  396. This is the default implementation of the arbiter Test Allocation action.
  397. It takes a list of requests for resources for particular devices and attempts
  398. to satisfy them.
  399. Parameters:
  400. Arbiter - The instance of the arbiter being called.
  401. ArbitrationList - A list of ARBITER_LIST_ENTRY entries which contain the
  402. requirements and associated devices.
  403. Return Value:
  404. Status code that indicates whether or not the function was successful.
  405. These include:
  406. STATUS_SUCCESSFUL - Arbitration suceeded and an allocation has been made for
  407. all the entries in the arbitration list.
  408. STATUS_UNSUCCESSFUL - Arbitration failed to find an allocation for all
  409. entries.
  410. STATUS_ARBITRATION_UNHANDLED - If returning this error the arbiter is
  411. partial (and therefore must have set the ARBITER_PARTIAL flag in its
  412. interface.) This status indicates that this arbiter doesn't handle the
  413. resources requested and the next arbiter towards the root of the device
  414. tree should be asked instead.
  415. --*/
  416. {
  417. NTSTATUS status;
  418. PARBITER_LIST_ENTRY current;
  419. PIO_RESOURCE_DESCRIPTOR alternative;
  420. ULONG count;
  421. PDEVICE_OBJECT previousOwner;
  422. PDEVICE_OBJECT currentOwner;
  423. LONG score;
  424. PAGED_CODE();
  425. ASSERT(Arbiter);
  426. //
  427. // Copy the current allocation
  428. //
  429. ARB_PRINT(3, ("Copy current allocation\n"));
  430. status = RtlCopyRangeList(Arbiter->PossibleAllocation, Arbiter->Allocation);
  431. if (!NT_SUCCESS(status)) {
  432. goto cleanup;
  433. }
  434. //
  435. // Free all the resources currently allocated to all the devices we
  436. // are arbitrating for
  437. //
  438. count = 0;
  439. previousOwner = NULL;
  440. FOR_ALL_IN_LIST(ARBITER_LIST_ENTRY, ArbitrationList, current) {
  441. count++;
  442. currentOwner = current->PhysicalDeviceObject;
  443. if (previousOwner != currentOwner) {
  444. previousOwner = currentOwner;
  445. ARB_PRINT(3,
  446. ("Delete 0x%08x's resources\n",
  447. currentOwner
  448. ));
  449. status = RtlDeleteOwnersRanges(Arbiter->PossibleAllocation,
  450. (PVOID)currentOwner
  451. );
  452. if (!NT_SUCCESS(status)) {
  453. goto cleanup;
  454. }
  455. }
  456. //
  457. // Score the entries in the arbitration list if a scoring function was
  458. // provided and this is not a legacy request (which is guaranteed to be
  459. // made of all fixed requests so sorting is pointless)
  460. //
  461. //
  462. // ISSUE-2000/03/06-andrewth
  463. // Ensure that in the start and enum cleanup the RequestSource is correctly passed in
  464. // so we can safely skip the unnecesary scoring and sorting
  465. // && !LEGACY_REQUEST(current);
  466. //
  467. current->WorkSpace = 0;
  468. if (Arbiter->ScoreRequirement != NULL) {
  469. FOR_ALL_IN_ARRAY(current->Alternatives,
  470. current->AlternativeCount,
  471. alternative) {
  472. ARB_PRINT(3,
  473. ("Scoring entry %p\n",
  474. currentOwner
  475. ));
  476. score = Arbiter->ScoreRequirement(alternative);
  477. //
  478. // Ensure the score is valid
  479. //
  480. if (score < 0) {
  481. status = STATUS_DEVICE_CONFIGURATION_ERROR;
  482. goto cleanup;
  483. }
  484. current->WorkSpace += score;
  485. }
  486. }
  487. }
  488. status = ArbSortArbitrationList(ArbitrationList);
  489. if (!NT_SUCCESS(status)) {
  490. goto cleanup;
  491. }
  492. //
  493. // Build the arbitration stack
  494. //
  495. status = ArbpBuildAllocationStack(Arbiter,
  496. ArbitrationList,
  497. count
  498. );
  499. if (!NT_SUCCESS(status)) {
  500. goto cleanup;
  501. }
  502. //
  503. // Attempt allocation
  504. //
  505. status = Arbiter->AllocateEntry(Arbiter, Arbiter->AllocationStack);
  506. if (NT_SUCCESS(status)) {
  507. //
  508. // Success.
  509. //
  510. return status;
  511. }
  512. cleanup:
  513. //
  514. // We didn't succeed so empty the possible allocation list...
  515. //
  516. RtlFreeRangeList(Arbiter->PossibleAllocation);
  517. return status;
  518. }
  519. NTSTATUS
  520. ArbpBuildAlternative(
  521. IN PARBITER_INSTANCE Arbiter,
  522. IN PIO_RESOURCE_DESCRIPTOR Requirement,
  523. OUT PARBITER_ALTERNATIVE Alternative
  524. )
  525. /*++
  526. Routine Description:
  527. This routine initializes a arbiter alternative from a given resource
  528. requirement descriptor
  529. Parameters:
  530. Arbiter - The arbiter instance data where the allocation stack should be
  531. placed.
  532. Requirement - The requirement descriptor describing this requirement
  533. Alternative - The alternative to be initialized
  534. Return Value:
  535. Status code that indicates whether or not the function was successful.
  536. --*/
  537. {
  538. NTSTATUS status;
  539. PAGED_CODE();
  540. ASSERT(Alternative && Requirement);
  541. Alternative->Descriptor = Requirement;
  542. //
  543. // Unpack the requirement into the alternatives table
  544. //
  545. status = Arbiter->UnpackRequirement(Requirement,
  546. &Alternative->Minimum,
  547. &Alternative->Maximum,
  548. &Alternative->Length,
  549. &Alternative->Alignment
  550. );
  551. if (!NT_SUCCESS(status)) {
  552. goto cleanup;
  553. }
  554. //
  555. // Align the minimum if necessary
  556. //
  557. if (Alternative->Minimum % Alternative->Alignment != 0) {
  558. ALIGN_ADDRESS_UP(Alternative->Minimum,
  559. Alternative->Alignment
  560. );
  561. }
  562. Alternative->Flags = 0;
  563. //
  564. // Check if this alternative is shared
  565. //
  566. if(Requirement->ShareDisposition == CmResourceShareShared) {
  567. Alternative->Flags |= ARBITER_ALTERNATIVE_FLAG_SHARED;
  568. }
  569. //
  570. // Check if this alternative is fixed
  571. //
  572. if (Alternative->Maximum - Alternative->Minimum + 1 == Alternative->Length) {
  573. Alternative->Flags |= ARBITER_ALTERNATIVE_FLAG_FIXED;
  574. }
  575. //
  576. // Check for validity
  577. //
  578. if (Alternative->Maximum < Alternative->Minimum) {
  579. Alternative->Flags |= ARBITER_ALTERNATIVE_FLAG_INVALID;
  580. }
  581. return STATUS_SUCCESS;
  582. cleanup:
  583. return status;
  584. }
  585. NTSTATUS
  586. ArbpBuildAllocationStack(
  587. IN PARBITER_INSTANCE Arbiter,
  588. IN PLIST_ENTRY ArbitrationList,
  589. IN ULONG ArbitrationListCount
  590. )
  591. /*++
  592. Routine Description:
  593. This routine initializes the allocation stack for the requests in
  594. ArbitrationList. It overwrites any previous allocation stack and allocates
  595. additional memory if more is required. Arbiter->AllocationStack contains
  596. the initialized stack on success.
  597. Parameters:
  598. Arbiter - The arbiter instance data where the allocation stack should be
  599. placed.
  600. ArbitrationList - A list of ARBITER_LIST_ENTRY entries which contain the
  601. requirements and associated devices.
  602. ArbitrationListCount - The number of entries in the ArbitrationList
  603. Return Value:
  604. Status code that indicates whether or not the function was successful.
  605. --*/
  606. {
  607. NTSTATUS status;
  608. PARBITER_LIST_ENTRY currentEntry;
  609. PARBITER_ALLOCATION_STATE currentState;
  610. ULONG stackSize = 0, allocationCount = ArbitrationListCount + 1;
  611. PARBITER_ALTERNATIVE currentAlternative;
  612. PIO_RESOURCE_DESCRIPTOR currentDescriptor;
  613. PAGED_CODE();
  614. //
  615. // Calculate the size the stack needs to be and the
  616. //
  617. FOR_ALL_IN_LIST(ARBITER_LIST_ENTRY, ArbitrationList, currentEntry) {
  618. if (currentEntry->AlternativeCount > 0) {
  619. stackSize += currentEntry->AlternativeCount
  620. * sizeof(ARBITER_ALTERNATIVE);
  621. } else {
  622. allocationCount--;
  623. }
  624. }
  625. stackSize += allocationCount * sizeof(ARBITER_ALLOCATION_STATE);
  626. //
  627. // Make sure the allocation stack is large enough
  628. //
  629. if (Arbiter->AllocationStackMaxSize < stackSize) {
  630. PARBITER_ALLOCATION_STATE temp;
  631. //
  632. // Enlarge the allocation stack
  633. //
  634. temp = ExAllocatePoolWithTag(PagedPool,
  635. stackSize,
  636. ARBITER_ALLOCATION_STATE_TAG
  637. );
  638. if (!temp) {
  639. return STATUS_INSUFFICIENT_RESOURCES;
  640. }
  641. ExFreePool(Arbiter->AllocationStack);
  642. Arbiter->AllocationStack = temp;
  643. }
  644. RtlZeroMemory(Arbiter->AllocationStack, stackSize);
  645. //
  646. // Fill in the locations
  647. //
  648. currentState = Arbiter->AllocationStack;
  649. currentAlternative = (PARBITER_ALTERNATIVE) (Arbiter->AllocationStack
  650. + ArbitrationListCount + 1);
  651. FOR_ALL_IN_LIST(ARBITER_LIST_ENTRY, ArbitrationList, currentEntry) {
  652. //
  653. // Do we need to allocate anything for this entry?
  654. //
  655. if (currentEntry->AlternativeCount > 0) {
  656. //
  657. // Initialize the stack location
  658. //
  659. currentState->Entry = currentEntry;
  660. currentState->AlternativeCount = currentEntry->AlternativeCount;
  661. currentState->Alternatives = currentAlternative;
  662. //
  663. // Initialize the start and end values to an invalid range so
  664. // that we don't skip the range 0-0 every time...
  665. //
  666. currentState->Start = 1;
  667. ASSERT(currentState->End == 0); // From RtlZeroMemory
  668. //
  669. // Initialize the alternatives table
  670. //
  671. FOR_ALL_IN_ARRAY(currentEntry->Alternatives,
  672. currentEntry->AlternativeCount,
  673. currentDescriptor) {
  674. status = ArbpBuildAlternative(Arbiter,
  675. currentDescriptor,
  676. currentAlternative
  677. );
  678. if (!NT_SUCCESS(status)) {
  679. goto cleanup;
  680. }
  681. //
  682. // Initialize the priority
  683. //
  684. currentAlternative->Priority = ARBITER_PRIORITY_NULL;
  685. //
  686. // Advance to the next alternative
  687. //
  688. currentAlternative++;
  689. }
  690. }
  691. currentState++;
  692. }
  693. //
  694. // Terminate the stack with NULL entry
  695. //
  696. currentState->Entry = NULL;
  697. return STATUS_SUCCESS;
  698. cleanup:
  699. //
  700. // We don't need to free the buffer as it is attached to the arbiter and
  701. // will be used next time
  702. //
  703. return status;
  704. }
  705. NTSTATUS
  706. ArbSortArbitrationList(
  707. IN OUT PLIST_ENTRY ArbitrationList
  708. )
  709. /*++
  710. Routine Description:
  711. This routine sorts the arbitration list in order of each entry's
  712. WorkSpace value.
  713. Parameters:
  714. ArbitrationList - The list to be sorted.
  715. Return Value:
  716. Status code that indicates whether or not the function was successful.
  717. --*/
  718. {
  719. BOOLEAN sorted = FALSE;
  720. PARBITER_LIST_ENTRY current, next;
  721. PAGED_CODE();
  722. ARB_PRINT(3, ("IoSortArbiterList(%p)\n", ArbitrationList));
  723. while (!sorted) {
  724. sorted = TRUE;
  725. for (current=(PARBITER_LIST_ENTRY) ArbitrationList->Flink,
  726. next=(PARBITER_LIST_ENTRY) current->ListEntry.Flink;
  727. (PLIST_ENTRY) current != ArbitrationList
  728. && (PLIST_ENTRY) next != ArbitrationList;
  729. current = (PARBITER_LIST_ENTRY) current->ListEntry.Flink,
  730. next = (PARBITER_LIST_ENTRY)current->ListEntry.Flink) {
  731. if (current->WorkSpace > next->WorkSpace) {
  732. PLIST_ENTRY before = current->ListEntry.Blink;
  733. PLIST_ENTRY after = next->ListEntry.Flink;
  734. //
  735. // Swap the locations of current and next
  736. //
  737. before->Flink = (PLIST_ENTRY) next;
  738. after->Blink = (PLIST_ENTRY) current;
  739. current->ListEntry.Flink = after;
  740. current->ListEntry.Blink = (PLIST_ENTRY) next;
  741. next->ListEntry.Flink = (PLIST_ENTRY) current;
  742. next->ListEntry.Blink = before;
  743. sorted = FALSE;
  744. }
  745. }
  746. }
  747. return STATUS_SUCCESS;
  748. }
  749. NTSTATUS
  750. ArbCommitAllocation(
  751. PARBITER_INSTANCE Arbiter
  752. )
  753. /*++
  754. Routine Description:
  755. This provides the default implementation of the CommitAllocation action.
  756. It frees the old allocation and replaces it with the new allocation.
  757. Parameters:
  758. Arbiter - The arbiter instance data for the arbiter being called.
  759. Return Value:
  760. Status code that indicates whether or not the function was successful.
  761. --*/
  762. {
  763. PRTL_RANGE_LIST temp;
  764. PAGED_CODE();
  765. //
  766. // Free up the current allocation
  767. //
  768. RtlFreeRangeList(Arbiter->Allocation);
  769. //
  770. // Swap the allocated and duplicate lists
  771. //
  772. temp = Arbiter->Allocation;
  773. Arbiter->Allocation = Arbiter->PossibleAllocation;
  774. Arbiter->PossibleAllocation = temp;
  775. return STATUS_SUCCESS;
  776. }
  777. NTSTATUS
  778. ArbRollbackAllocation(
  779. IN PARBITER_INSTANCE Arbiter
  780. )
  781. /*++
  782. Routine Description:
  783. This provides the default implementation of the RollbackAllocation action.
  784. It frees the possible allocation the last TestAllocation provided.
  785. Parameters:
  786. Arbiter - The arbiter instance data for the arbiter being called.
  787. Return Value:
  788. Status code that indicates whether or not the function was successful.
  789. --*/
  790. {
  791. PAGED_CODE();
  792. //
  793. // Free up the possible allocation
  794. //
  795. RtlFreeRangeList(Arbiter->PossibleAllocation);
  796. return STATUS_SUCCESS;
  797. }
  798. NTSTATUS
  799. ArbRetestAllocation(
  800. IN PARBITER_INSTANCE Arbiter,
  801. IN OUT PLIST_ENTRY ArbitrationList
  802. )
  803. /*++
  804. Routine Description:
  805. This provides the default implementation of the RetestAllocation action.
  806. It walks the arbitration list and updates the possible allocation to reflect
  807. the allocation entries of the list. For these entries to be valid
  808. TestAllocation must have been performed on this arbitration list.
  809. Parameters:
  810. Arbiter - The arbiter instance data for the arbiter being called.
  811. ArbitrationList - A list of ARBITER_LIST_ENTRY entries which contain the
  812. requirements and associated devices. TestAllocation for this arbiter
  813. should have been called on this list.
  814. Return Value:
  815. Status code that indicates whether or not the function was successful.
  816. --*/
  817. {
  818. NTSTATUS status;
  819. PARBITER_LIST_ENTRY current;
  820. ARBITER_ALLOCATION_STATE state;
  821. ARBITER_ALTERNATIVE alternative;
  822. ULONG length;
  823. PAGED_CODE();
  824. //
  825. // Initialize the state
  826. //
  827. RtlZeroMemory(&state, sizeof(ARBITER_ALLOCATION_STATE));
  828. RtlZeroMemory(&alternative, sizeof(ARBITER_ALTERNATIVE));
  829. state.AlternativeCount = 1;
  830. state.Alternatives = &alternative;
  831. state.CurrentAlternative = &alternative;
  832. state.Flags = ARBITER_STATE_FLAG_RETEST;
  833. //
  834. // Copy the current allocation and reserved
  835. //
  836. ARB_PRINT(2, ("Retest: Copy current allocation\n"));
  837. status = RtlCopyRangeList(Arbiter->PossibleAllocation, Arbiter->Allocation);
  838. if (!NT_SUCCESS(status)) {
  839. goto cleanup;
  840. }
  841. //
  842. // Free all the resources currently allocated to all the devices we
  843. // are arbitrating for
  844. //
  845. FOR_ALL_IN_LIST(ARBITER_LIST_ENTRY, ArbitrationList, current) {
  846. ARB_PRINT(3,
  847. ("Retest: Delete 0x%08x's resources\n",
  848. current->PhysicalDeviceObject
  849. ));
  850. status = RtlDeleteOwnersRanges(Arbiter->PossibleAllocation,
  851. (PVOID) current->PhysicalDeviceObject
  852. );
  853. if (!NT_SUCCESS(status)) {
  854. goto cleanup;
  855. }
  856. }
  857. //
  858. // Build an allocation state for the allocation and call AddAllocation to
  859. // update the range lists accordingly
  860. //
  861. FOR_ALL_IN_LIST(ARBITER_LIST_ENTRY, ArbitrationList, current) {
  862. ASSERT(current->Assignment && current->SelectedAlternative);
  863. state.WorkSpace = 0;
  864. state.Entry = current;
  865. //
  866. // Initialize the alternative
  867. //
  868. status = ArbpBuildAlternative(Arbiter,
  869. current->SelectedAlternative,
  870. &alternative
  871. );
  872. ASSERT(NT_SUCCESS(status));
  873. //
  874. // Update it with our allocation
  875. //
  876. status = Arbiter->UnpackResource(current->Assignment,
  877. &state.Start,
  878. &length
  879. );
  880. ASSERT(NT_SUCCESS(status));
  881. state.End = state.Start + length - 1;
  882. //
  883. // Do any preprocessing that is required
  884. //
  885. status = Arbiter->PreprocessEntry(Arbiter,&state);
  886. if (!NT_SUCCESS(status)) {
  887. goto cleanup;
  888. }
  889. //
  890. // If we had a requirement for length 0 then don't attemp to add the
  891. // range - it will fail!
  892. //
  893. if (length != 0) {
  894. Arbiter->AddAllocation(Arbiter, &state);
  895. }
  896. }
  897. return status;
  898. cleanup:
  899. RtlFreeRangeList(Arbiter->PossibleAllocation);
  900. return status;
  901. }
  902. NTSTATUS
  903. ArbBootAllocation(
  904. IN PARBITER_INSTANCE Arbiter,
  905. IN OUT PLIST_ENTRY ArbitrationList
  906. )
  907. /*++
  908. Routine Description:
  909. This provides the default implementation of the BootAllocation action.
  910. It walks the arbitration list and updates the allocation to reflect the fact
  911. that the allocation entries in the list are in use.
  912. Parameters:
  913. Arbiter - The arbiter instance data for the arbiter being called.
  914. ArbitrationList - A list of ARBITER_LIST_ENTRY entries which contain the
  915. requirements and associated devices. Each device should have one and
  916. only one requirement reflecting the resources it is currently consuming.
  917. Return Value:
  918. Status code that indicates whether or not the function was successful.
  919. --*/
  920. {
  921. NTSTATUS status;
  922. PARBITER_LIST_ENTRY current;
  923. PRTL_RANGE_LIST temp;
  924. ARBITER_ALLOCATION_STATE state;
  925. ARBITER_ALTERNATIVE alternative;
  926. PAGED_CODE();
  927. //
  928. // Initialize the state
  929. //
  930. RtlZeroMemory(&state, sizeof(ARBITER_ALLOCATION_STATE));
  931. RtlZeroMemory(&alternative, sizeof(ARBITER_ALTERNATIVE));
  932. state.AlternativeCount = 1;
  933. state.Alternatives = &alternative;
  934. state.CurrentAlternative = &alternative;
  935. state.Flags = ARBITER_STATE_FLAG_BOOT;
  936. state.RangeAttributes = ARBITER_RANGE_BOOT_ALLOCATED;
  937. //
  938. // Work on the possible allocation list
  939. //
  940. status = RtlCopyRangeList(Arbiter->PossibleAllocation, Arbiter->Allocation);
  941. FOR_ALL_IN_LIST(ARBITER_LIST_ENTRY, ArbitrationList, current) {
  942. ASSERT(current->AlternativeCount == 1);
  943. ASSERT(current->PhysicalDeviceObject);
  944. //
  945. // Build an alternative and state structure for this allocation and
  946. // add it to the range list
  947. //
  948. state.Entry = current;
  949. //
  950. // Initialize the alternative
  951. //
  952. status = ArbpBuildAlternative(Arbiter,
  953. &current->Alternatives[0],
  954. &alternative
  955. );
  956. ASSERT(NT_SUCCESS(status));
  957. ASSERT(alternative.Flags &
  958. (ARBITER_ALTERNATIVE_FLAG_FIXED | ARBITER_ALTERNATIVE_FLAG_INVALID)
  959. );
  960. state.Start = alternative.Minimum;
  961. state.End = alternative.Maximum;
  962. //
  963. // Blow away the old workspace and masks
  964. //
  965. state.WorkSpace = 0;
  966. state.RangeAvailableAttributes = 0;
  967. //
  968. // Validate the requirement
  969. //
  970. if (alternative.Length == 0
  971. || alternative.Alignment == 0
  972. || state.End < state.Start
  973. || state.Start % alternative.Alignment != 0
  974. || LENGTH_OF(state.Start, state.End) != alternative.Length) {
  975. ARB_PRINT(1,
  976. ("Skipping invalid boot allocation 0x%I64x-0x%I64x L 0x%x A 0x%x for 0x%08x\n",
  977. state.Start,
  978. state.End,
  979. alternative.Length,
  980. alternative.Alignment,
  981. current->PhysicalDeviceObject
  982. ));
  983. continue;
  984. }
  985. #if PLUG_FEST_HACKS
  986. if (alternative.Flags & ARBITER_ALTERNATIVE_FLAG_SHARED) {
  987. ARB_PRINT(1,
  988. ("Skipping shared boot allocation 0x%I64x-0x%I64x L 0x%x A 0x%x for 0x%08x\n",
  989. state.Start,
  990. state.End,
  991. alternative.Length,
  992. alternative.Alignment,
  993. current->PhysicalDeviceObject
  994. ));
  995. continue;
  996. }
  997. #endif
  998. //
  999. // Do any preprocessing that is required
  1000. //
  1001. status = Arbiter->PreprocessEntry(Arbiter,&state);
  1002. if (!NT_SUCCESS(status)) {
  1003. goto cleanup;;
  1004. }
  1005. Arbiter->AddAllocation(Arbiter, &state);
  1006. }
  1007. //
  1008. // Everything went OK so make this our allocated range
  1009. //
  1010. RtlFreeRangeList(Arbiter->Allocation);
  1011. temp = Arbiter->Allocation;
  1012. Arbiter->Allocation = Arbiter->PossibleAllocation;
  1013. Arbiter->PossibleAllocation = temp;
  1014. return STATUS_SUCCESS;
  1015. cleanup:
  1016. RtlFreeRangeList(Arbiter->PossibleAllocation);
  1017. return status;
  1018. }
  1019. NTSTATUS
  1020. ArbArbiterHandler(
  1021. IN PVOID Context,
  1022. IN ARBITER_ACTION Action,
  1023. IN OUT PARBITER_PARAMETERS Params
  1024. )
  1025. /*++
  1026. Routine Description:
  1027. This provides the default entry point to an arbiter.
  1028. Parameters:
  1029. Context - The context provided in the interface where this function was
  1030. called from. This is converted to an ARBITER_INSTANCE using the
  1031. ARBITER_CONTEXT_TO_INSTANCE macro which should be defined.
  1032. Action - The action the arbiter should perform.
  1033. Params - The parameters for the action.
  1034. Return Value:
  1035. Status code that indicates whether or not the function was successful.
  1036. Note:
  1037. The routines which implement each action are determined from the dispatch
  1038. table in the arbiter instance.
  1039. --*/
  1040. {
  1041. NTSTATUS status;
  1042. PARBITER_INSTANCE arbiter = Context;
  1043. PAGED_CODE();
  1044. ASSERT(Context);
  1045. ASSERT(Action >= 0 && Action <= ArbiterActionBootAllocation);
  1046. ASSERT(arbiter->Signature == ARBITER_INSTANCE_SIGNATURE);
  1047. //
  1048. // Acquire the state lock
  1049. //
  1050. ArbAcquireArbiterLock(arbiter);
  1051. //
  1052. // Announce ourselves
  1053. //
  1054. ARB_PRINT(2,
  1055. ("%s %S\n",
  1056. ArbpActionStrings[Action],
  1057. arbiter->Name
  1058. ));
  1059. //
  1060. // Check the transaction flag
  1061. //
  1062. if (Action == ArbiterActionTestAllocation
  1063. || Action == ArbiterActionRetestAllocation
  1064. || Action == ArbiterActionBootAllocation) {
  1065. ASSERT(!arbiter->TransactionInProgress);
  1066. } else if (Action == ArbiterActionCommitAllocation
  1067. || Action == ArbiterActionRollbackAllocation) {
  1068. ASSERT(arbiter->TransactionInProgress);
  1069. }
  1070. #if ARB_DBG
  1071. replay:
  1072. #endif
  1073. //
  1074. // Do the appropriate thing
  1075. //
  1076. switch (Action) {
  1077. case ArbiterActionTestAllocation:
  1078. //
  1079. // NTRAID #95564-2000/02/31-andrewth
  1080. // Until we support rebalance we don't deal with AllocateFrom
  1081. //
  1082. ASSERT(Params->Parameters.TestAllocation.AllocateFromCount == 0);
  1083. ASSERT(Params->Parameters.TestAllocation.AllocateFrom == NULL);
  1084. status = arbiter->TestAllocation(
  1085. arbiter,
  1086. Params->Parameters.TestAllocation.ArbitrationList
  1087. );
  1088. break;
  1089. case ArbiterActionRetestAllocation:
  1090. ASSERT(Params->Parameters.TestAllocation.AllocateFromCount == 0);
  1091. ASSERT(Params->Parameters.TestAllocation.AllocateFrom == NULL);
  1092. status = arbiter->RetestAllocation(
  1093. arbiter,
  1094. Params->Parameters.TestAllocation.ArbitrationList
  1095. );
  1096. break;
  1097. case ArbiterActionCommitAllocation:
  1098. status = arbiter->CommitAllocation(arbiter);
  1099. break;
  1100. case ArbiterActionRollbackAllocation:
  1101. status = arbiter->RollbackAllocation(arbiter);
  1102. break;
  1103. case ArbiterActionBootAllocation:
  1104. status = arbiter->BootAllocation(
  1105. arbiter,
  1106. Params->Parameters.BootAllocation.ArbitrationList
  1107. );
  1108. break;
  1109. case ArbiterActionQueryConflict:
  1110. status = arbiter->QueryConflict(
  1111. arbiter,
  1112. Params->Parameters.QueryConflict.PhysicalDeviceObject,
  1113. Params->Parameters.QueryConflict.ConflictingResource,
  1114. Params->Parameters.QueryConflict.ConflictCount,
  1115. Params->Parameters.QueryConflict.Conflicts
  1116. );
  1117. break;
  1118. case ArbiterActionQueryArbitrate:
  1119. case ArbiterActionQueryAllocatedResources:
  1120. case ArbiterActionWriteReservedResources:
  1121. case ArbiterActionAddReserved:
  1122. status = STATUS_NOT_IMPLEMENTED;
  1123. break;
  1124. default:
  1125. status = STATUS_INVALID_PARAMETER;
  1126. break;
  1127. }
  1128. #if ARB_DBG
  1129. //
  1130. // Check if we failed and want to stop or replay on errors
  1131. //
  1132. if (!NT_SUCCESS(status)) {
  1133. ARB_PRINT(1,
  1134. ("*** %s for %S FAILED status = %08x\n",
  1135. ArbpActionStrings[Action],
  1136. arbiter->Name,
  1137. status
  1138. ));
  1139. if (ArbStopOnError) {
  1140. DbgBreakPoint();
  1141. }
  1142. if (ArbReplayOnError) {
  1143. goto replay;
  1144. }
  1145. }
  1146. #endif // ARB_DBG
  1147. if (NT_SUCCESS(status)) {
  1148. if (Action == ArbiterActionTestAllocation
  1149. || Action == ArbiterActionRetestAllocation) {
  1150. arbiter->TransactionInProgress = TRUE;
  1151. } else if (Action == ArbiterActionCommitAllocation
  1152. || Action == ArbiterActionRollbackAllocation) {
  1153. arbiter->TransactionInProgress = FALSE;
  1154. }
  1155. }
  1156. ArbReleaseArbiterLock(arbiter);
  1157. return status;
  1158. }
  1159. NTSTATUS
  1160. ArbBuildAssignmentOrdering(
  1161. IN OUT PARBITER_INSTANCE Arbiter,
  1162. IN PWSTR AllocationOrderName,
  1163. IN PWSTR ReservedResourcesName,
  1164. IN PARBITER_TRANSLATE_ALLOCATION_ORDER Translate OPTIONAL
  1165. )
  1166. /*++
  1167. Routine Description:
  1168. This is called as part of arbiter initialization and extracts the allocation
  1169. ordering and reserved information from the registry and combines them into
  1170. an ordering list. The reserved ranges are put in Arbiter->ReservedList
  1171. and the initial ordering in Arbiter->OrderingList.
  1172. Parameters:
  1173. Arbiter - The instance data of the arbiter to be initialized.
  1174. AllocationOrderName - The name of the key under HKLM\System\
  1175. CurrentControlSet\Control\Arbiters\AllocationOrder the ordering
  1176. information should be taken from.
  1177. ReservedResourcesName - The name of the key under HKLM\System\
  1178. CurrentControlSet\Control\Arbiters\ReservedResources the reserved ranges
  1179. information should be taken from.
  1180. Translate - A function to be called for each range that will perform system
  1181. dependant translations required for this system.
  1182. Return Value:
  1183. Status code that indicates whether or not the function was successful.
  1184. --*/
  1185. {
  1186. NTSTATUS status;
  1187. HANDLE arbitersHandle = NULL, tempHandle = NULL;
  1188. UNICODE_STRING unicodeString;
  1189. PKEY_VALUE_FULL_INFORMATION info = NULL;
  1190. ULONG dummy;
  1191. PIO_RESOURCE_LIST resourceList;
  1192. PIO_RESOURCE_DESCRIPTOR current;
  1193. ULONGLONG start, end;
  1194. OBJECT_ATTRIBUTES attributes;
  1195. IO_RESOURCE_DESCRIPTOR translated;
  1196. PAGED_CODE();
  1197. ArbAcquireArbiterLock(Arbiter);
  1198. //
  1199. // If we are reinitializing the orderings free the old ones
  1200. //
  1201. ArbFreeOrderingList(&Arbiter->OrderingList);
  1202. ArbFreeOrderingList(&Arbiter->ReservedList);
  1203. //
  1204. // Initialize the orderings
  1205. //
  1206. status = ArbInitializeOrderingList(&Arbiter->OrderingList);
  1207. if (!NT_SUCCESS(status)) {
  1208. goto cleanup;
  1209. }
  1210. status = ArbInitializeOrderingList(&Arbiter->ReservedList);
  1211. if (!NT_SUCCESS(status)) {
  1212. goto cleanup;
  1213. }
  1214. //
  1215. // Open HKLM\System\CurrentControlSet\Control\Arbiters
  1216. //
  1217. ArbpWstrToUnicodeString(&unicodeString, PATH_ARBITERS);
  1218. InitializeObjectAttributes(&attributes,
  1219. &unicodeString,
  1220. OBJ_CASE_INSENSITIVE,
  1221. NULL,
  1222. (PSECURITY_DESCRIPTOR) NULL
  1223. );
  1224. status = ZwOpenKey(&arbitersHandle,
  1225. KEY_READ,
  1226. &attributes
  1227. );
  1228. if (!NT_SUCCESS(status)) {
  1229. goto cleanup;
  1230. }
  1231. //
  1232. // Open AllocationOrder
  1233. //
  1234. ArbpWstrToUnicodeString(&unicodeString, KEY_ALLOCATIONORDER);
  1235. InitializeObjectAttributes(&attributes,
  1236. &unicodeString,
  1237. OBJ_CASE_INSENSITIVE,
  1238. arbitersHandle,
  1239. (PSECURITY_DESCRIPTOR) NULL
  1240. );
  1241. status = ZwOpenKey(&tempHandle,
  1242. KEY_READ,
  1243. &attributes
  1244. );
  1245. if (!NT_SUCCESS(status)) {
  1246. goto cleanup;
  1247. }
  1248. //
  1249. // Extract the value the user asked for
  1250. //
  1251. status = ArbpGetRegistryValue(tempHandle,
  1252. AllocationOrderName,
  1253. &info
  1254. );
  1255. if (!NT_SUCCESS(status)) {
  1256. goto cleanup;
  1257. }
  1258. //
  1259. // Check if the value we retrieved was a string and if so then it was a
  1260. // short cut to a value of that name - open it.
  1261. //
  1262. if (info->Type == REG_SZ) {
  1263. PKEY_VALUE_FULL_INFORMATION tempInfo;
  1264. PWSTR shortcut = (PWSTR) FULL_INFO_DATA(info);
  1265. //
  1266. // Check its NUL terminated
  1267. //
  1268. if (shortcut[(info->DataLength/sizeof(WCHAR))-1] != UNICODE_NULL) {
  1269. status = STATUS_INVALID_PARAMETER;
  1270. goto cleanup;
  1271. }
  1272. status = ArbpGetRegistryValue(tempHandle,
  1273. shortcut,
  1274. &tempInfo
  1275. );
  1276. if (!NT_SUCCESS(status)) {
  1277. goto cleanup;
  1278. }
  1279. ExFreePool(info);
  1280. info = tempInfo;
  1281. }
  1282. ZwClose(tempHandle);
  1283. //
  1284. // We only support one level of short cuts so this should be a
  1285. // REG_RESOURCE_REQUIREMENTS_LIST
  1286. //
  1287. if (info->Type != REG_RESOURCE_REQUIREMENTS_LIST) {
  1288. status = STATUS_INVALID_PARAMETER;
  1289. goto cleanup;
  1290. }
  1291. //
  1292. // Extract the resource list
  1293. //
  1294. ASSERT(((PIO_RESOURCE_REQUIREMENTS_LIST) FULL_INFO_DATA(info))
  1295. ->AlternativeLists == 1);
  1296. resourceList = (PIO_RESOURCE_LIST) &((PIO_RESOURCE_REQUIREMENTS_LIST)
  1297. FULL_INFO_DATA(info))->List[0];
  1298. //
  1299. // Convert the resource list into an ordering list
  1300. //
  1301. FOR_ALL_IN_ARRAY(resourceList->Descriptors,
  1302. resourceList->Count,
  1303. current) {
  1304. //
  1305. // Perform any translation that is necessary on the resources
  1306. //
  1307. if (ARGUMENT_PRESENT(Translate)) {
  1308. status = (Translate)(&translated, current);
  1309. if (!NT_SUCCESS(status)) {
  1310. goto cleanup;
  1311. }
  1312. } else {
  1313. translated = *current;
  1314. }
  1315. if (translated.Type == Arbiter->ResourceType) {
  1316. status = Arbiter->UnpackRequirement(&translated,
  1317. &start,
  1318. &end,
  1319. &dummy, //length
  1320. &dummy //alignment
  1321. );
  1322. if (!NT_SUCCESS(status)) {
  1323. goto cleanup;
  1324. }
  1325. status = ArbAddOrdering(&Arbiter->OrderingList,
  1326. start,
  1327. end
  1328. );
  1329. if (!NT_SUCCESS(status)) {
  1330. goto cleanup;
  1331. }
  1332. }
  1333. }
  1334. //
  1335. // We're finished with info...
  1336. //
  1337. ExFreePool(info);
  1338. info = NULL;
  1339. //
  1340. // Open ReservedResources
  1341. //
  1342. ArbpWstrToUnicodeString(&unicodeString, KEY_RESERVEDRESOURCES);
  1343. InitializeObjectAttributes(&attributes,
  1344. &unicodeString,
  1345. OBJ_CASE_INSENSITIVE,
  1346. arbitersHandle,
  1347. (PSECURITY_DESCRIPTOR) NULL
  1348. );
  1349. status = ZwCreateKey(&tempHandle,
  1350. KEY_READ,
  1351. &attributes,
  1352. 0,
  1353. (PUNICODE_STRING) NULL,
  1354. REG_OPTION_NON_VOLATILE,
  1355. NULL
  1356. );
  1357. if (!NT_SUCCESS(status)) {
  1358. goto cleanup;
  1359. }
  1360. //
  1361. // Extract the arbiter's reserved resources
  1362. //
  1363. status = ArbpGetRegistryValue(tempHandle,
  1364. ReservedResourcesName,
  1365. &info
  1366. );
  1367. if (!NT_SUCCESS(status)) {
  1368. goto cleanup;
  1369. }
  1370. //
  1371. // Check if the value we retrieved was a string and if so then it was a
  1372. // short cut to a value of that name - open it.
  1373. //
  1374. if (info->Type == REG_SZ) {
  1375. PKEY_VALUE_FULL_INFORMATION tempInfo;
  1376. PWSTR shortcut = (PWSTR) FULL_INFO_DATA(info);
  1377. //
  1378. // Check its NUL terminated
  1379. //
  1380. if (shortcut[(info->DataLength/sizeof(WCHAR))-1] != UNICODE_NULL) {
  1381. status = STATUS_INVALID_PARAMETER;
  1382. goto cleanup;
  1383. }
  1384. status = ArbpGetRegistryValue(tempHandle,
  1385. shortcut,
  1386. &tempInfo
  1387. );
  1388. if (!NT_SUCCESS(status)) {
  1389. goto cleanup;
  1390. }
  1391. ExFreePool(info);
  1392. info = tempInfo;
  1393. }
  1394. ZwClose(tempHandle);
  1395. if (NT_SUCCESS(status)) {
  1396. ASSERT(((PIO_RESOURCE_REQUIREMENTS_LIST) FULL_INFO_DATA(info))
  1397. ->AlternativeLists == 1);
  1398. resourceList = (PIO_RESOURCE_LIST) &((PIO_RESOURCE_REQUIREMENTS_LIST)
  1399. FULL_INFO_DATA(info))->List[0];
  1400. //
  1401. // Apply the reserved ranges to the ordering
  1402. //
  1403. FOR_ALL_IN_ARRAY(resourceList->Descriptors,
  1404. resourceList->Count,
  1405. current) {
  1406. //
  1407. // Perform any translation that is necessary on the resources
  1408. //
  1409. if (ARGUMENT_PRESENT(Translate)) {
  1410. status = (Translate)(&translated, current);
  1411. if (!NT_SUCCESS(status)) {
  1412. goto cleanup;
  1413. }
  1414. } else {
  1415. translated = *current;
  1416. }
  1417. if (translated.Type == Arbiter->ResourceType) {
  1418. status = Arbiter->UnpackRequirement(&translated,
  1419. &start,
  1420. &end,
  1421. &dummy, //length
  1422. &dummy //alignment
  1423. );
  1424. if (!NT_SUCCESS(status)) {
  1425. goto cleanup;
  1426. }
  1427. //
  1428. // Add the reserved range to the reserved ordering
  1429. //
  1430. status = ArbAddOrdering(&Arbiter->ReservedList, start, end);
  1431. if (!NT_SUCCESS(status)) {
  1432. goto cleanup;
  1433. }
  1434. //
  1435. // Prune the reserved range from the current ordering
  1436. //
  1437. status = ArbPruneOrdering(&Arbiter->OrderingList, start, end);
  1438. if (!NT_SUCCESS(status)) {
  1439. goto cleanup;
  1440. }
  1441. }
  1442. }
  1443. ExFreePool(info);
  1444. }
  1445. //
  1446. // All done!
  1447. //
  1448. ZwClose(arbitersHandle);
  1449. #if ARB_DBG
  1450. {
  1451. PARBITER_ORDERING current;
  1452. FOR_ALL_IN_ARRAY(Arbiter->OrderingList.Orderings,
  1453. Arbiter->OrderingList.Count,
  1454. current) {
  1455. ARB_PRINT(2,
  1456. ("Ordering: 0x%I64x-0x%I64x\n",
  1457. current->Start,
  1458. current->End
  1459. ));
  1460. }
  1461. ARB_PRINT(2, ("\n"));
  1462. FOR_ALL_IN_ARRAY(Arbiter->ReservedList.Orderings,
  1463. Arbiter->ReservedList.Count,
  1464. current) {
  1465. ARB_PRINT(2,
  1466. ("Reserved: 0x%I64x-0x%I64x\n",
  1467. current->Start,
  1468. current->End
  1469. ));
  1470. }
  1471. }
  1472. #endif
  1473. ArbReleaseArbiterLock(Arbiter);
  1474. return STATUS_SUCCESS;
  1475. cleanup:
  1476. if (arbitersHandle) {
  1477. ZwClose(arbitersHandle);
  1478. }
  1479. if (tempHandle) {
  1480. ZwClose(tempHandle);
  1481. }
  1482. if (info) {
  1483. ExFreePool(info);
  1484. }
  1485. if (Arbiter->OrderingList.Orderings) {
  1486. ExFreePool(Arbiter->OrderingList.Orderings);
  1487. Arbiter->OrderingList.Count = 0;
  1488. Arbiter->OrderingList.Maximum = 0;
  1489. }
  1490. if (Arbiter->ReservedList.Orderings) {
  1491. ExFreePool(Arbiter->ReservedList.Orderings);
  1492. Arbiter->ReservedList.Count = 0;
  1493. Arbiter->ReservedList.Maximum = 0;
  1494. }
  1495. ArbReleaseArbiterLock(Arbiter);
  1496. return status;
  1497. }
  1498. BOOLEAN
  1499. ArbFindSuitableRange(
  1500. PARBITER_INSTANCE Arbiter,
  1501. PARBITER_ALLOCATION_STATE State
  1502. )
  1503. /*++
  1504. Routine Description:
  1505. This routine is called from AllocateEntry once we have decided where we want
  1506. to allocate from. It tries to find a free range that matches the
  1507. requirements in State while restricting its possible solutions to the range
  1508. State->CurrentMinimum to State->CurrentMaximum. On success State->Start and
  1509. State->End represent this range.
  1510. Arguments:
  1511. Arbiter - The instance data of the arbiter who was called.
  1512. State - The state of the current arbitration.
  1513. Return Value:
  1514. TRUE if we found a range, FALSE otherwise.
  1515. --*/
  1516. {
  1517. NTSTATUS status;
  1518. ULONG findRangeFlags = 0;
  1519. PAGED_CODE();
  1520. ASSERT(State->CurrentAlternative);
  1521. //
  1522. // Catch the case where we backtrack and advance past the maximum
  1523. //
  1524. if (State->CurrentMinimum > State->CurrentMaximum) {
  1525. return FALSE;
  1526. }
  1527. //
  1528. // If we are asking for zero ports then trivially succeed with the minimum
  1529. // value and remember that backtracking this is a recipe for infinite loops
  1530. //
  1531. if (State->CurrentAlternative->Length == 0) {
  1532. State->End = State->Start = State->CurrentMinimum;
  1533. return TRUE;
  1534. }
  1535. //
  1536. // For legacy requests from IoAssignResources (directly or by way of
  1537. // HalAssignSlotResources) or IoReportResourceUsage we consider preallocated
  1538. // resources to be available for backward compatibility reasons.
  1539. //
  1540. // If we are allocating a devices boot config then we consider all other
  1541. // boot configs to be available.
  1542. //
  1543. if (State->Entry->RequestSource == ArbiterRequestLegacyReported
  1544. || State->Entry->RequestSource == ArbiterRequestLegacyAssigned) {
  1545. State->RangeAvailableAttributes |= ARBITER_RANGE_BOOT_ALLOCATED;
  1546. }
  1547. //
  1548. // Check if null conflicts are OK...
  1549. //
  1550. if (State->Flags & ARBITER_STATE_FLAG_NULL_CONFLICT_OK) {
  1551. findRangeFlags |= RTL_RANGE_LIST_NULL_CONFLICT_OK;
  1552. }
  1553. //
  1554. // ...or we are shareable...
  1555. //
  1556. if (State->CurrentAlternative->Flags & ARBITER_ALTERNATIVE_FLAG_SHARED) {
  1557. findRangeFlags |= RTL_RANGE_LIST_SHARED_OK;
  1558. }
  1559. //
  1560. // Select the first free alternative from the current alternative
  1561. //
  1562. status = RtlFindRange(
  1563. Arbiter->PossibleAllocation,
  1564. State->CurrentMinimum,
  1565. State->CurrentMaximum,
  1566. State->CurrentAlternative->Length,
  1567. State->CurrentAlternative->Alignment,
  1568. findRangeFlags,
  1569. State->RangeAvailableAttributes,
  1570. Arbiter->ConflictCallbackContext,
  1571. Arbiter->ConflictCallback,
  1572. &State->Start
  1573. );
  1574. if (NT_SUCCESS(status)) {
  1575. //
  1576. // We found a suitable range
  1577. //
  1578. State->End = State->Start + State->CurrentAlternative->Length - 1;
  1579. return TRUE;
  1580. } else {
  1581. if (ArbShareDriverExclusive(Arbiter, State) == FALSE) {
  1582. //
  1583. // We couldn't find any range so check if we will allow this conflict
  1584. // - if so don'd fail!
  1585. //
  1586. return Arbiter->OverrideConflict(Arbiter, State);
  1587. }
  1588. return TRUE;
  1589. }
  1590. }
  1591. VOID
  1592. ArbAddAllocation(
  1593. IN PARBITER_INSTANCE Arbiter,
  1594. IN PARBITER_ALLOCATION_STATE State
  1595. )
  1596. /*++
  1597. Routine Description:
  1598. This routine is called from AllocateEntry once we have found a possible
  1599. solution (State->Start - State->End). It adds the ranges that will not be
  1600. available if we commit to this solution to Arbiter->PossibleAllocation.
  1601. Arguments:
  1602. Arbiter - The instance data of the arbiter who was called.
  1603. State - The state of the current arbitration.
  1604. Return Value:
  1605. None.
  1606. --*/
  1607. {
  1608. NTSTATUS status;
  1609. PAGED_CODE();
  1610. status = RtlAddRange(
  1611. Arbiter->PossibleAllocation,
  1612. State->Start,
  1613. State->End,
  1614. State->RangeAttributes,
  1615. RTL_RANGE_LIST_ADD_IF_CONFLICT +
  1616. (State->CurrentAlternative->Flags & ARBITER_ALTERNATIVE_FLAG_SHARED
  1617. ? RTL_RANGE_LIST_ADD_SHARED : 0),
  1618. NULL,
  1619. State->Entry->PhysicalDeviceObject
  1620. );
  1621. ASSERT(NT_SUCCESS(status));
  1622. }
  1623. VOID
  1624. ArbBacktrackAllocation(
  1625. IN PARBITER_INSTANCE Arbiter,
  1626. IN PARBITER_ALLOCATION_STATE State
  1627. )
  1628. /*++
  1629. Routine Description:
  1630. This routine is called from AllocateEntry if the possible solution
  1631. (State->Start - State->End) does not allow us to allocate resources to
  1632. the rest of the devices being considered. It deletes the ranges that were
  1633. added to Arbiter->PossibleAllocation by AddAllocation.
  1634. Arguments:
  1635. Arbiter - The instance data of the arbiter who was called.
  1636. State - The state of the current arbitration.
  1637. Return Value:
  1638. None.
  1639. --*/
  1640. {
  1641. NTSTATUS status;
  1642. PAGED_CODE();
  1643. //
  1644. // We couldn't allocate for the rest of the ranges then
  1645. // backtrack
  1646. //
  1647. status = RtlDeleteRange(
  1648. Arbiter->PossibleAllocation,
  1649. State->Start,
  1650. State->End,
  1651. State->Entry->PhysicalDeviceObject
  1652. );
  1653. ASSERT(NT_SUCCESS(status));
  1654. ARB_PRINT(2,
  1655. ("\t\tBacktracking on 0x%I64x-0x%I64x for %p\n",
  1656. State->Start,
  1657. State->End,
  1658. State->Entry->PhysicalDeviceObject
  1659. ));
  1660. }
  1661. NTSTATUS
  1662. ArbPreprocessEntry(
  1663. IN PARBITER_INSTANCE Arbiter,
  1664. IN PARBITER_ALLOCATION_STATE State
  1665. )
  1666. /*++
  1667. Routine Description:
  1668. This routine is called from AllocateEntry to allow preprocessing of
  1669. entries
  1670. Arguments:
  1671. Arbiter - The instance data of the arbiter who was called.
  1672. State - The state of the current arbitration.
  1673. Return Value:
  1674. None.
  1675. --*/
  1676. {
  1677. PAGED_CODE();
  1678. UNREFERENCED_PARAMETER (Arbiter);
  1679. UNREFERENCED_PARAMETER (State);
  1680. return STATUS_SUCCESS;
  1681. }
  1682. NTSTATUS
  1683. ArbAllocateEntry(
  1684. IN PARBITER_INSTANCE Arbiter,
  1685. IN PARBITER_ALLOCATION_STATE State
  1686. )
  1687. /*++
  1688. Routine Description:
  1689. This is the core arbitration routine and is called from TestAllocation
  1690. to allocate resources for all of the entries in the allocation stack.
  1691. It calls off to various helper routines (described above) to perform this
  1692. task.
  1693. Arguments:
  1694. Arbiter - The instance data of the arbiter who was called.
  1695. State - The state of the current arbitration.
  1696. Return Value:
  1697. None.
  1698. --*/
  1699. {
  1700. NTSTATUS status;
  1701. PARBITER_ALLOCATION_STATE currentState = State;
  1702. BOOLEAN backtracking = FALSE;
  1703. PAGED_CODE();
  1704. //
  1705. // Have we reached the end of the list? If so then we have a working
  1706. // allocation.
  1707. //
  1708. tryAllocation:
  1709. while(currentState >= State && currentState->Entry != NULL) {
  1710. //
  1711. // Do any preprocessing that is required
  1712. //
  1713. status = Arbiter->PreprocessEntry(Arbiter,currentState);
  1714. if (!NT_SUCCESS(status)) {
  1715. return status;
  1716. }
  1717. //
  1718. // If we need to backtrack do so!
  1719. //
  1720. if (backtracking) {
  1721. ULONGLONG possibleCurrentMinimum;
  1722. backtracking = FALSE;
  1723. //
  1724. // Clear the CurrentAlternative of the *next* alternative - this will
  1725. // cause the priorities to be recalculated next time through so we
  1726. // will attempt to explore the search space again
  1727. //
  1728. // The currentState+1 is guaranteed to be safe because the only way
  1729. // we can get here is from where we currentState-- below.
  1730. //
  1731. (currentState + 1)->CurrentAlternative = NULL;
  1732. //
  1733. // We can't backtrack length 0 requests because there is nothing to
  1734. // backtrack so we would get stuck in an inifinite loop...
  1735. //
  1736. if (currentState->CurrentAlternative->Length == 0) {
  1737. goto failAllocation;
  1738. }
  1739. //
  1740. // Backtrack
  1741. //
  1742. Arbiter->BacktrackAllocation(Arbiter, currentState);
  1743. //
  1744. // Reduce allocation window to not include the range we backtracked
  1745. // and check that that doesn't underflow the minimum or wrap
  1746. //
  1747. possibleCurrentMinimum = currentState->Start - 1;
  1748. if (possibleCurrentMinimum > currentState->CurrentMinimum // wrapped
  1749. || possibleCurrentMinimum < currentState->CurrentAlternative->Minimum) {
  1750. //
  1751. // We have run out space in this alternative move on to the next
  1752. //
  1753. goto continueWithNextAllocationRange;
  1754. } else {
  1755. currentState->CurrentMaximum = possibleCurrentMinimum;
  1756. //
  1757. // Get back into arbitrating at the right point
  1758. //
  1759. goto continueWithNextSuitableRange;
  1760. }
  1761. }
  1762. //
  1763. // Try to allocate for this entry
  1764. //
  1765. continueWithNextAllocationRange:
  1766. while (Arbiter->GetNextAllocationRange(Arbiter, currentState)) {
  1767. ARB_INDENT(2, (ULONG)(currentState - State));
  1768. ARB_PRINT(2,
  1769. ("Testing 0x%I64x-0x%I64x %s\n",
  1770. currentState->CurrentMinimum,
  1771. currentState->CurrentMaximum,
  1772. currentState->CurrentAlternative->Flags & ARBITER_ALTERNATIVE_FLAG_SHARED ?
  1773. "shared" : "non-shared"
  1774. ));
  1775. continueWithNextSuitableRange:
  1776. while (Arbiter->FindSuitableRange(Arbiter, currentState)) {
  1777. //
  1778. // We found a possible solution
  1779. //
  1780. ARB_INDENT(2, (ULONG)(currentState - State));
  1781. if (currentState->CurrentAlternative->Length != 0) {
  1782. ARB_PRINT(2,
  1783. ("Possible solution for %p = 0x%I64x-0x%I64x, %s\n",
  1784. currentState->Entry->PhysicalDeviceObject,
  1785. currentState->Start,
  1786. currentState->End,
  1787. currentState->CurrentAlternative->Flags & ARBITER_ALTERNATIVE_FLAG_SHARED ?
  1788. "shared" : "non-shared"
  1789. ));
  1790. //
  1791. // Update the arbiter with the possible allocation
  1792. //
  1793. Arbiter->AddAllocation(Arbiter, currentState);
  1794. } else {
  1795. ARB_PRINT(2,
  1796. ("Zero length solution solution for %p = 0x%I64x-0x%I64x, %s\n",
  1797. currentState->Entry->PhysicalDeviceObject,
  1798. currentState->Start,
  1799. currentState->End,
  1800. currentState->CurrentAlternative->Flags & ARBITER_ALTERNATIVE_FLAG_SHARED ?
  1801. "shared" : "non-shared"
  1802. ));
  1803. //
  1804. // Set the result in the arbiter appropriatley so that we
  1805. // don't try and translate this zero requirement - it won't!
  1806. //
  1807. currentState->Entry->Result = ArbiterResultNullRequest;
  1808. }
  1809. //
  1810. // Move on to the next entry
  1811. //
  1812. currentState++;
  1813. goto tryAllocation;
  1814. }
  1815. }
  1816. failAllocation:
  1817. //
  1818. // We couldn't allocate for this device
  1819. //
  1820. if (currentState == State) {
  1821. //
  1822. // We are at the top of the allocation stack to we can't backtrack -
  1823. // *** GAME OVER ***
  1824. //
  1825. return STATUS_UNSUCCESSFUL;
  1826. } else {
  1827. //
  1828. // Backtrack and try again
  1829. //
  1830. ARB_INDENT(2, (ULONG)(currentState - State));
  1831. ARB_PRINT(2,
  1832. ("Allocation failed for %p - backtracking\n",
  1833. currentState->Entry->PhysicalDeviceObject
  1834. ));
  1835. backtracking = TRUE;
  1836. //
  1837. // Pop the last state off the stack and try a different path
  1838. //
  1839. currentState--;
  1840. goto tryAllocation;
  1841. }
  1842. }
  1843. //
  1844. // We have successfully allocated for all ranges so fill in the allocation
  1845. //
  1846. currentState = State;
  1847. while (currentState->Entry != NULL) {
  1848. status = Arbiter->PackResource(
  1849. currentState->CurrentAlternative->Descriptor,
  1850. currentState->Start,
  1851. currentState->Entry->Assignment
  1852. );
  1853. ASSERT(NT_SUCCESS(status));
  1854. //
  1855. // Remember the alternative we chose from so we can retrieve it during retest
  1856. //
  1857. currentState->Entry->SelectedAlternative
  1858. = currentState->CurrentAlternative->Descriptor;
  1859. ARB_PRINT(2,
  1860. ("Assigned - 0x%I64x-0x%I64x\n",
  1861. currentState->Start,
  1862. currentState->End
  1863. ));
  1864. currentState++;
  1865. }
  1866. return STATUS_SUCCESS;
  1867. }
  1868. BOOLEAN
  1869. ArbGetNextAllocationRange(
  1870. IN PARBITER_INSTANCE Arbiter,
  1871. IN OUT PARBITER_ALLOCATION_STATE State
  1872. )
  1873. /*++
  1874. Routine Description:
  1875. This routine attempts to find the next range where allocation should be
  1876. tried. It updates State->CurrentMinimum, State->CurrentMaximum and
  1877. State->CurrentAlternative to indicate this range.
  1878. Arguments:
  1879. Arbiter - The instance data of the arbiter
  1880. State - The state of the current arbitration
  1881. Return Value:
  1882. TRUE if a range to attemp allocation in is found, FALSE otherwise
  1883. --*/
  1884. {
  1885. PARBITER_ALTERNATIVE current, lowestAlternative;
  1886. ULONGLONG min, max;
  1887. PARBITER_ORDERING ordering;
  1888. for (;;) {
  1889. if (State->CurrentAlternative) {
  1890. //
  1891. // Update the priority of the alternative we selected last time
  1892. //
  1893. ArbpUpdatePriority(Arbiter, State->CurrentAlternative);
  1894. } else {
  1895. //
  1896. // This is the first time we are looking at this alternative or a
  1897. // backtrack - either way we need to update all the priorities
  1898. //
  1899. FOR_ALL_IN_ARRAY(State->Alternatives,
  1900. State->AlternativeCount,
  1901. current) {
  1902. current->Priority = ARBITER_PRIORITY_NULL;
  1903. ArbpUpdatePriority(Arbiter, current);
  1904. }
  1905. }
  1906. //
  1907. // Find the lowest priority of the alternatives
  1908. //
  1909. lowestAlternative = State->Alternatives;
  1910. FOR_ALL_IN_ARRAY(State->Alternatives + 1,
  1911. State->AlternativeCount - 1,
  1912. current) {
  1913. if (current->Priority < lowestAlternative->Priority) {
  1914. lowestAlternative = current;
  1915. }
  1916. }
  1917. ARB_INDENT(2, (ULONG)(State - Arbiter->AllocationStack));
  1918. //
  1919. // Check if we have run out of allocation ranges
  1920. //
  1921. if (lowestAlternative->Priority == ARBITER_PRIORITY_EXHAUSTED) {
  1922. if (lowestAlternative->Flags & ARBITER_ALTERNATIVE_FLAG_FIXED) {
  1923. ARB_PRINT(2,("Fixed alternative exhausted\n"));
  1924. } else {
  1925. ARB_PRINT(2,("Alternative exhausted\n"));
  1926. }
  1927. return FALSE;
  1928. } else {
  1929. ARB_PRINT(2,(
  1930. "LowestAlternative: [%i] 0x%I64x-0x%I64x L=0x%08x A=0x%08x\n",
  1931. lowestAlternative->Priority,
  1932. lowestAlternative->Minimum,
  1933. lowestAlternative->Maximum,
  1934. lowestAlternative->Length,
  1935. lowestAlternative->Alignment
  1936. ));
  1937. }
  1938. //
  1939. // Check if we are now allowing reserved ranges
  1940. //
  1941. if (lowestAlternative->Priority == ARBITER_PRIORITY_RESERVED
  1942. || lowestAlternative->Priority == ARBITER_PRIORITY_PREFERRED_RESERVED) {
  1943. //
  1944. // Set min and max to be the Minimum and Maximum that the descriptor
  1945. // specified ignoring any reservations or orderings - this is our
  1946. // last chance
  1947. //
  1948. min = lowestAlternative->Minimum;
  1949. max = lowestAlternative->Maximum;
  1950. ARB_INDENT(2, (ULONG)(State - Arbiter->AllocationStack));
  1951. ARB_PRINT(2,("Allowing reserved ranges\n"));
  1952. } else {
  1953. ASSERT(ORDERING_INDEX_FROM_PRIORITY(lowestAlternative->Priority) <
  1954. Arbiter->OrderingList.Count);
  1955. //
  1956. // Locate the ordering we match
  1957. //
  1958. ordering = &Arbiter->OrderingList.Orderings
  1959. [ORDERING_INDEX_FROM_PRIORITY(lowestAlternative->Priority)];
  1960. //
  1961. // Make sure they overlap and are big enough - this is just paranoia
  1962. //
  1963. ASSERT(INTERSECT(lowestAlternative->Minimum,
  1964. lowestAlternative->Maximum,
  1965. ordering->Start,
  1966. ordering->End)
  1967. && INTERSECT_SIZE(lowestAlternative->Minimum,
  1968. lowestAlternative->Maximum,
  1969. ordering->Start,
  1970. ordering->End) >= lowestAlternative->Length);
  1971. //
  1972. // Calculate the allocation range
  1973. //
  1974. min = __max(lowestAlternative->Minimum, ordering->Start);
  1975. max = __min(lowestAlternative->Maximum, ordering->End);
  1976. }
  1977. //
  1978. // If this is a length 0 requirement then succeed now and avoid much
  1979. // trauma later
  1980. //
  1981. if (lowestAlternative->Length == 0) {
  1982. min = lowestAlternative->Minimum;
  1983. max = lowestAlternative->Maximum;
  1984. } else {
  1985. //
  1986. // Trim range to match alignment.
  1987. //
  1988. min += lowestAlternative->Alignment - 1;
  1989. min -= min % lowestAlternative->Alignment;
  1990. if ((lowestAlternative->Length - 1) > (max - min)) {
  1991. ARB_INDENT(3, (ULONG)(State - Arbiter->AllocationStack));
  1992. ARB_PRINT(3, ("Range cannot be aligned ... Skipping\n"));
  1993. //
  1994. // Set CurrentAlternative so we will update the priority of this
  1995. // alternative
  1996. //
  1997. State->CurrentAlternative = lowestAlternative;
  1998. continue;
  1999. }
  2000. max -= lowestAlternative->Length - 1;
  2001. max -= max % lowestAlternative->Alignment;
  2002. max += lowestAlternative->Length - 1;
  2003. }
  2004. //
  2005. // Check if we handed back the same range last time, for the same
  2006. // alternative, if so try to find another range
  2007. //
  2008. if (min == State->CurrentMinimum
  2009. && max == State->CurrentMaximum
  2010. && State->CurrentAlternative == lowestAlternative) {
  2011. ARB_INDENT(2, (ULONG)(State - Arbiter->AllocationStack));
  2012. ARB_PRINT(2,
  2013. ("Skipping identical allocation range\n"
  2014. ));
  2015. continue;
  2016. }
  2017. State->CurrentMinimum = min;
  2018. State->CurrentMaximum = max;
  2019. State->CurrentAlternative = lowestAlternative;
  2020. ARB_INDENT(2, (ULONG)(State - Arbiter->AllocationStack));
  2021. ARB_PRINT(1, ("AllocationRange: 0x%I64x-0x%I64x\n", min, max));
  2022. return TRUE;
  2023. }
  2024. }
  2025. NTSTATUS
  2026. ArbpGetRegistryValue(
  2027. IN HANDLE KeyHandle,
  2028. IN PWSTR ValueName,
  2029. OUT PKEY_VALUE_FULL_INFORMATION *Information
  2030. )
  2031. /*++
  2032. Routine Description:
  2033. This routine is invoked to retrieve the data for a registry key's value.
  2034. This is done by querying the value of the key with a zero-length buffer
  2035. to determine the size of the value, and then allocating a buffer and
  2036. actually querying the value into the buffer.
  2037. It is the responsibility of the caller to free the buffer.
  2038. Arguments:
  2039. KeyHandle - Supplies the key handle whose value is to be queried
  2040. ValueName - Supplies the null-terminated Unicode name of the value.
  2041. Information - Returns a pointer to the allocated data buffer.
  2042. Return Value:
  2043. The function value is the final status of the query operation.
  2044. Note:
  2045. The same as IopGetRegistryValue - it allows us to share the arbiter
  2046. code with pci.sys
  2047. --*/
  2048. {
  2049. UNICODE_STRING unicodeString;
  2050. NTSTATUS status;
  2051. PKEY_VALUE_FULL_INFORMATION infoBuffer;
  2052. ULONG keyValueLength;
  2053. PAGED_CODE();
  2054. RtlInitUnicodeString( &unicodeString, ValueName );
  2055. //
  2056. // Figure out how big the data value is so that a buffer of the
  2057. // appropriate size can be allocated.
  2058. //
  2059. status = ZwQueryValueKey( KeyHandle,
  2060. &unicodeString,
  2061. KeyValueFullInformationAlign64,
  2062. (PVOID) NULL,
  2063. 0,
  2064. &keyValueLength );
  2065. if (status != STATUS_BUFFER_OVERFLOW &&
  2066. status != STATUS_BUFFER_TOO_SMALL) {
  2067. return status;
  2068. }
  2069. //
  2070. // Allocate a buffer large enough to contain the entire key data value.
  2071. //
  2072. infoBuffer = ExAllocatePoolWithTag( PagedPool,
  2073. keyValueLength,
  2074. ARBITER_MISC_TAG
  2075. );
  2076. if (!infoBuffer) {
  2077. return STATUS_INSUFFICIENT_RESOURCES;
  2078. }
  2079. //
  2080. // Query the data for the key value.
  2081. //
  2082. status = ZwQueryValueKey( KeyHandle,
  2083. &unicodeString,
  2084. KeyValueFullInformationAlign64,
  2085. infoBuffer,
  2086. keyValueLength,
  2087. &keyValueLength );
  2088. if (!NT_SUCCESS( status )) {
  2089. ExFreePool( infoBuffer );
  2090. return status;
  2091. }
  2092. //
  2093. // Everything worked, so simply return the address of the allocated
  2094. // buffer to the caller, who is now responsible for freeing it.
  2095. //
  2096. *Information = infoBuffer;
  2097. return STATUS_SUCCESS;
  2098. }
  2099. #define ARBITER_ORDERING_LIST_INITIAL_SIZE 16
  2100. NTSTATUS
  2101. ArbInitializeOrderingList(
  2102. IN OUT PARBITER_ORDERING_LIST List
  2103. )
  2104. /*++
  2105. Routine Description:
  2106. This routine inititialize an arbiter ordering list.
  2107. Arguments:
  2108. List - The list to be initialized
  2109. Return Value:
  2110. Status code that indicates whether or not the function was successful.
  2111. --*/
  2112. {
  2113. PAGED_CODE();
  2114. ASSERT(List);
  2115. List->Orderings = ExAllocatePoolWithTag(PagedPool,
  2116. ARBITER_ORDERING_LIST_INITIAL_SIZE *
  2117. sizeof(ARBITER_ORDERING),
  2118. ARBITER_ORDERING_LIST_TAG
  2119. );
  2120. if (!List->Orderings) {
  2121. List->Maximum = 0;
  2122. List->Count = 0;
  2123. return STATUS_INSUFFICIENT_RESOURCES;
  2124. }
  2125. List->Count = 0;
  2126. List->Maximum = ARBITER_ORDERING_LIST_INITIAL_SIZE;
  2127. return STATUS_SUCCESS;
  2128. }
  2129. NTSTATUS
  2130. ArbCopyOrderingList(
  2131. OUT PARBITER_ORDERING_LIST Destination,
  2132. IN PARBITER_ORDERING_LIST Source
  2133. )
  2134. /*++
  2135. Routine Description:
  2136. This routine copies an arbiter ordering list.
  2137. Arguments:
  2138. Destination - An uninitialized arbiter ordering list where the data
  2139. should be copied from
  2140. Source - Arbiter ordering list to be copied
  2141. Return Value:
  2142. Status code that indicates whether or not the function was successful.
  2143. --*/
  2144. {
  2145. PAGED_CODE()
  2146. ASSERT(Source->Count <= Source->Maximum);
  2147. ASSERT(Source->Maximum > 0);
  2148. Destination->Orderings =
  2149. ExAllocatePoolWithTag(PagedPool,
  2150. Source->Maximum * sizeof(ARBITER_ORDERING),
  2151. ARBITER_ORDERING_LIST_TAG
  2152. );
  2153. if (Destination->Orderings == NULL) {
  2154. return STATUS_INSUFFICIENT_RESOURCES;
  2155. }
  2156. Destination->Count = Source->Count;
  2157. Destination->Maximum = Source->Maximum;
  2158. if (Source->Count > 0) {
  2159. RtlCopyMemory(Destination->Orderings,
  2160. Source->Orderings,
  2161. Source->Count * sizeof(ARBITER_ORDERING)
  2162. );
  2163. }
  2164. return STATUS_SUCCESS;
  2165. }
  2166. NTSTATUS
  2167. ArbAddOrdering(
  2168. OUT PARBITER_ORDERING_LIST List,
  2169. IN ULONGLONG Start,
  2170. IN ULONGLONG End
  2171. )
  2172. /*++
  2173. Routine Description:
  2174. This routine adds the range Start-End to the end of the ordering list. No
  2175. checking for overlaps or pruning is done (see ArbpPruneOrdering)
  2176. Arguments:
  2177. OrderingList - The list where the range should be added.
  2178. Start - The start of the range to be added.
  2179. End - The end of the range to be added.
  2180. Return Value:
  2181. Status code that indicates whether or not the function was successful.
  2182. --*/
  2183. {
  2184. PAGED_CODE()
  2185. //
  2186. // Validate parameters
  2187. //
  2188. if (End < Start) {
  2189. return STATUS_INVALID_PARAMETER;
  2190. }
  2191. //
  2192. // Check if the buffer is full
  2193. //
  2194. if (List->Count == List->Maximum) {
  2195. PARBITER_ORDERING temp;
  2196. //
  2197. // Out of space - grow the buffer
  2198. //
  2199. temp = ExAllocatePoolWithTag(PagedPool,
  2200. (List->Count + ARBITER_ORDERING_GROW_SIZE) *
  2201. sizeof(ARBITER_ORDERING),
  2202. ARBITER_ORDERING_LIST_TAG
  2203. );
  2204. if (!temp) {
  2205. return STATUS_INSUFFICIENT_RESOURCES;
  2206. }
  2207. //
  2208. // If we had any orderings copy them
  2209. //
  2210. if (List->Orderings) {
  2211. RtlCopyMemory(temp,
  2212. List->Orderings,
  2213. List->Count * sizeof(ARBITER_ORDERING)
  2214. );
  2215. ExFreePool(List->Orderings);
  2216. }
  2217. List->Maximum += ARBITER_ORDERING_GROW_SIZE;
  2218. List->Orderings = temp;
  2219. }
  2220. //
  2221. // Add the entry to the list
  2222. //
  2223. List->Orderings[List->Count].Start = Start;
  2224. List->Orderings[List->Count].End = End;
  2225. List->Count++;
  2226. ASSERT(List->Count <= List->Maximum);
  2227. return STATUS_SUCCESS;
  2228. }
  2229. NTSTATUS
  2230. ArbPruneOrdering(
  2231. IN OUT PARBITER_ORDERING_LIST OrderingList,
  2232. IN ULONGLONG Start,
  2233. IN ULONGLONG End
  2234. )
  2235. /*++
  2236. Routine Description:
  2237. This routine removes the range Start-End from all entries in the ordering
  2238. list, splitting ranges into two or deleting them as necessary.
  2239. Arguments:
  2240. OrderingList - The list to be pruned.
  2241. Start - The start of the range to be deleted.
  2242. End - The end of the range to be deleted.
  2243. Return Value:
  2244. Status code that indicates whether or not the function was successful.
  2245. Note:
  2246. In the comments below *** represents the range Start - End and --- the range
  2247. current->Start - current->End.
  2248. --*/
  2249. {
  2250. NTSTATUS status;
  2251. PARBITER_ORDERING current, currentInsert, newOrdering = NULL, temp = NULL;
  2252. USHORT count;
  2253. PAGED_CODE()
  2254. ASSERT(OrderingList);
  2255. ASSERT(OrderingList->Orderings);
  2256. //
  2257. // Validate parameters
  2258. //
  2259. if (End < Start) {
  2260. status = STATUS_INVALID_PARAMETER;
  2261. goto cleanup;
  2262. }
  2263. //
  2264. // Allocate a buffer big enough for all eventualities
  2265. //
  2266. newOrdering = ExAllocatePoolWithTag(PagedPool,
  2267. (OrderingList->Count * 2 + 1) *
  2268. sizeof(ARBITER_ORDERING),
  2269. ARBITER_ORDERING_LIST_TAG
  2270. );
  2271. if (!newOrdering) {
  2272. status = STATUS_INSUFFICIENT_RESOURCES;
  2273. goto cleanup;
  2274. }
  2275. currentInsert = newOrdering;
  2276. //
  2277. // Do we have a current ordering?
  2278. //
  2279. if (OrderingList->Count > 0) {
  2280. //
  2281. // Iterate through the current ordering and prune accordingly
  2282. //
  2283. FOR_ALL_IN_ARRAY(OrderingList->Orderings, OrderingList->Count, current) {
  2284. if (End < current->Start || Start > current->End) {
  2285. //
  2286. // **** or ****
  2287. // ---- ----
  2288. //
  2289. // We don't overlap so copy the range unchanged
  2290. //
  2291. *currentInsert++ = *current;
  2292. } else if (Start > current->Start) {
  2293. if (End < current->End) {
  2294. //
  2295. // ****
  2296. // --------
  2297. //
  2298. // Split the range into two
  2299. //
  2300. currentInsert->Start = End + 1;
  2301. currentInsert->End = current->End;
  2302. currentInsert++;
  2303. currentInsert->Start = current->Start;
  2304. currentInsert->End = Start - 1;
  2305. currentInsert++;
  2306. } else {
  2307. //
  2308. // **** or ****
  2309. // -------- --------
  2310. //
  2311. // Prune the end of the range
  2312. //
  2313. ASSERT(End >= current->End);
  2314. currentInsert->Start = current->Start;
  2315. currentInsert->End = Start - 1;
  2316. currentInsert++;
  2317. }
  2318. } else {
  2319. ASSERT(Start <= current->Start);
  2320. if (End < current->End) {
  2321. //
  2322. // **** or ****
  2323. // -------- --------
  2324. //
  2325. // Prune the start of the range
  2326. //
  2327. currentInsert->Start = End + 1;
  2328. currentInsert->End = current->End;
  2329. currentInsert++;
  2330. } else {
  2331. ASSERT(End >= current->End);
  2332. //
  2333. // ******** or ********
  2334. // ---- --------
  2335. //
  2336. // Don't copy the range (ie. Delete it)
  2337. //
  2338. }
  2339. }
  2340. }
  2341. }
  2342. ASSERT(currentInsert - newOrdering >= 0);
  2343. count = (USHORT)(currentInsert - newOrdering);
  2344. //
  2345. // Check if we have any orderings left
  2346. //
  2347. if (count > 0) {
  2348. if (count > OrderingList->Maximum) {
  2349. //
  2350. // There isn't enough space so allocate a new buffer
  2351. //
  2352. temp =
  2353. ExAllocatePoolWithTag(PagedPool,
  2354. count * sizeof(ARBITER_ORDERING),
  2355. ARBITER_ORDERING_LIST_TAG
  2356. );
  2357. if (!temp) {
  2358. status = STATUS_INSUFFICIENT_RESOURCES;
  2359. goto cleanup;
  2360. }
  2361. if (OrderingList->Orderings) {
  2362. ExFreePool(OrderingList->Orderings);
  2363. }
  2364. OrderingList->Orderings = temp;
  2365. OrderingList->Maximum = count;
  2366. }
  2367. //
  2368. // Copy the new ordering
  2369. //
  2370. RtlCopyMemory(OrderingList->Orderings,
  2371. newOrdering,
  2372. count * sizeof(ARBITER_ORDERING)
  2373. );
  2374. }
  2375. //
  2376. // Free our temporary buffer
  2377. //
  2378. ExFreePool(newOrdering);
  2379. OrderingList->Count = count;
  2380. return STATUS_SUCCESS;
  2381. cleanup:
  2382. if (newOrdering) {
  2383. ExFreePool(newOrdering);
  2384. }
  2385. if (temp) {
  2386. ExFreePool(temp);
  2387. }
  2388. return status;
  2389. }
  2390. VOID
  2391. ArbFreeOrderingList(
  2392. IN PARBITER_ORDERING_LIST List
  2393. )
  2394. /*++
  2395. Routine Description:
  2396. Frees storage associated with an ordering list.
  2397. Reverses ArbInitializeOrderingList.
  2398. Arguments:
  2399. List - The list to be fred
  2400. Return Value:
  2401. None
  2402. --*/
  2403. {
  2404. PAGED_CODE();
  2405. if (List->Orderings) {
  2406. ASSERT(List->Maximum);
  2407. ExFreePool(List->Orderings);
  2408. }
  2409. List->Count = 0;
  2410. List->Maximum = 0;
  2411. List->Orderings = NULL;
  2412. }
  2413. BOOLEAN
  2414. ArbOverrideConflict(
  2415. IN PARBITER_INSTANCE Arbiter,
  2416. IN PARBITER_ALLOCATION_STATE State
  2417. )
  2418. /*++
  2419. Routine Description:
  2420. This is the default implementation of override conflict which
  2421. Arguments:
  2422. Arbiter - The instance data of the arbiter who was called.
  2423. State - The state of the current arbitration.
  2424. Return Value:
  2425. TRUE if the conflict is allowable, false otherwise
  2426. --*/
  2427. {
  2428. PRTL_RANGE current;
  2429. RTL_RANGE_LIST_ITERATOR iterator;
  2430. BOOLEAN ok = FALSE;
  2431. PAGED_CODE();
  2432. if (!(State->CurrentAlternative->Flags & ARBITER_ALTERNATIVE_FLAG_FIXED)) {
  2433. return FALSE;
  2434. }
  2435. FOR_ALL_RANGES(Arbiter->PossibleAllocation, &iterator, current) {
  2436. //
  2437. // Only test the overlapping ones
  2438. //
  2439. if (INTERSECT(current->Start, current->End, State->CurrentMinimum, State->CurrentMaximum)) {
  2440. //
  2441. // Check if we should ignore the range because of its attributes
  2442. //
  2443. if (current->Attributes & State->RangeAvailableAttributes) {
  2444. //
  2445. // We DON'T set ok to true because we are just ignoring the range,
  2446. // as RtlFindRange would have and thus it can't be the cause of
  2447. // RtlFindRange failing, so ignoring it can't fix the conflict.
  2448. //
  2449. continue;
  2450. }
  2451. //
  2452. // Check if we are conflicting with ourselves AND the conflicting range
  2453. // is a fixed requirement
  2454. //
  2455. if (current->Owner == State->Entry->PhysicalDeviceObject
  2456. && State->CurrentAlternative->Flags & ARBITER_ALTERNATIVE_FLAG_FIXED) {
  2457. State->Start=State->CurrentMinimum;
  2458. State->End=State->CurrentMaximum;
  2459. ok = TRUE;
  2460. continue;
  2461. }
  2462. //
  2463. // The conflict is still valid
  2464. //
  2465. return FALSE;
  2466. }
  2467. }
  2468. return ok;
  2469. }
  2470. VOID
  2471. ArbpUpdatePriority(
  2472. PARBITER_INSTANCE Arbiter,
  2473. PARBITER_ALTERNATIVE Alternative
  2474. )
  2475. /*++
  2476. Routine Description:
  2477. This routine updates the priority of an arbiter alternative.
  2478. Arguments:
  2479. Arbiter - The arbiter we are operating on
  2480. Alternative - The alternative currently being considered
  2481. Return Value:
  2482. Status code that indicates whether or not the function was successful.
  2483. Note:
  2484. The priorities are a LONG values organised as:
  2485. <------Preferred priorities-----> <-----Ordinary Priorities----->
  2486. MINLONG--------------------------0-----------------------------MAXLONG
  2487. ^ ^ ^ ^
  2488. | | | |
  2489. NULL PREFERRED_RESERVED | |
  2490. RESERVED |
  2491. EXHAUSTED
  2492. An ordinary priority is calculated the (index + 1) of the next ordering it
  2493. intersects with (and has enough space for an allocation).
  2494. A preferred priority is the ordinary priority * - 1
  2495. In this way by examining each of the alternatives in priority order (lowest
  2496. first) we achieve the desired allocation order of:
  2497. (1) Preferred alternative with non-reserved resources
  2498. (2) Alternatives with non-reserved resources
  2499. (3) Preferred reserved resources
  2500. (4) Reserved Resources
  2501. MAXLONG the worst priority indicates that there are no more allocation ranges
  2502. left.
  2503. --*/
  2504. {
  2505. PARBITER_ORDERING ordering;
  2506. BOOLEAN preferred;
  2507. LONG priority;
  2508. PAGED_CODE();
  2509. priority = Alternative->Priority;
  2510. //
  2511. // If we have already tried the reserved resources then we are out of luck!
  2512. //
  2513. if (priority == ARBITER_PRIORITY_RESERVED
  2514. || priority == ARBITER_PRIORITY_PREFERRED_RESERVED) {
  2515. Alternative->Priority = ARBITER_PRIORITY_EXHAUSTED;
  2516. return;
  2517. }
  2518. //
  2519. // Check if this is a preferred value - we treat them specially
  2520. //
  2521. preferred = Alternative->Descriptor->Option & IO_RESOURCE_PREFERRED;
  2522. //
  2523. // If priority is NULL then we haven't started calculating one so we
  2524. // should start the search from the initial ordering
  2525. //
  2526. if (priority == ARBITER_PRIORITY_NULL) {
  2527. ordering = Arbiter->OrderingList.Orderings;
  2528. } else {
  2529. //
  2530. // If we are a fixed resource then there is no point
  2531. // in trying to find another range - it will be the
  2532. // same and thus still conflict. Mark this alternative as
  2533. // exhausted
  2534. //
  2535. if (Alternative->Flags & ARBITER_ALTERNATIVE_FLAG_FIXED) {
  2536. Alternative->Priority = ARBITER_PRIORITY_EXHAUSTED;
  2537. return;
  2538. }
  2539. ASSERT(ORDERING_INDEX_FROM_PRIORITY(Alternative->Priority) <
  2540. Arbiter->OrderingList.Count);
  2541. ordering = &Arbiter->OrderingList.Orderings
  2542. [ORDERING_INDEX_FROM_PRIORITY(Alternative->Priority) + 1];
  2543. }
  2544. //
  2545. // Now find the first member of the assignent ordering for this arbiter
  2546. // where we have an overlap big enough
  2547. //
  2548. FOR_REST_IN_ARRAY(Arbiter->OrderingList.Orderings,
  2549. Arbiter->OrderingList.Count,
  2550. ordering) {
  2551. //
  2552. // Is the ordering applicable?
  2553. //
  2554. if (INTERSECT(Alternative->Minimum, Alternative->Maximum,
  2555. ordering->Start, ordering->End)
  2556. && INTERSECT_SIZE(Alternative->Minimum, Alternative->Maximum,
  2557. ordering->Start,ordering->End) >= Alternative->Length) {
  2558. //
  2559. // This is out guy, calculate his priority
  2560. //
  2561. Alternative->Priority = (LONG)(ordering - Arbiter->OrderingList.Orderings + 1);
  2562. //
  2563. // Preferred priorities are -ve
  2564. //
  2565. if (preferred) {
  2566. Alternative->Priority *= -1;
  2567. }
  2568. return;
  2569. }
  2570. }
  2571. //
  2572. // We have runout of non-reserved resources so try the reserved ones
  2573. //
  2574. if (preferred) {
  2575. Alternative->Priority = ARBITER_PRIORITY_PREFERRED_RESERVED;
  2576. } else {
  2577. Alternative->Priority = ARBITER_PRIORITY_RESERVED;
  2578. }
  2579. }
  2580. NTSTATUS
  2581. ArbAddReserved(
  2582. IN PARBITER_INSTANCE Arbiter,
  2583. IN PIO_RESOURCE_DESCRIPTOR Requirement OPTIONAL,
  2584. IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Resource OPTIONAL
  2585. )
  2586. {
  2587. PAGED_CODE();
  2588. UNREFERENCED_PARAMETER (Arbiter);
  2589. UNREFERENCED_PARAMETER (Requirement);
  2590. UNREFERENCED_PARAMETER (Resource);
  2591. return STATUS_NOT_SUPPORTED;
  2592. }
  2593. BOOLEAN
  2594. ArbpQueryConflictCallback(
  2595. IN PVOID Context,
  2596. IN PRTL_RANGE Range
  2597. )
  2598. /*++
  2599. Routine Description:
  2600. This call back is called from FindSuitableRange (via RtlFindRange) when we
  2601. encounter an conflicting range.
  2602. Arguments:
  2603. Context - Actually a PRTL_RANGE * where we store the range we conflicted
  2604. with.
  2605. Range - The range we conflict with.
  2606. Return Value:
  2607. FALSE
  2608. --*/
  2609. {
  2610. PRTL_RANGE *conflictingRange = (PRTL_RANGE*)Context;
  2611. PAGED_CODE();
  2612. ARB_PRINT(2,("Possible conflict: (%p) 0x%I64x-0x%I64x Owner: %p",
  2613. Range,
  2614. Range->Start,
  2615. Range->End,
  2616. Range->Owner
  2617. ));
  2618. //
  2619. // Remember the conflicting range
  2620. //
  2621. *conflictingRange = Range;
  2622. //
  2623. // We want to allow the rest of FindSuitableRange to determine if this really
  2624. // is a conflict.
  2625. //
  2626. return FALSE;
  2627. }
  2628. NTSTATUS
  2629. ArbQueryConflict(
  2630. IN PARBITER_INSTANCE Arbiter,
  2631. IN PDEVICE_OBJECT PhysicalDeviceObject,
  2632. IN PIO_RESOURCE_DESCRIPTOR ConflictingResource,
  2633. OUT PULONG ConflictCount,
  2634. OUT PARBITER_CONFLICT_INFO *Conflicts
  2635. )
  2636. /*++
  2637. Routine Description:
  2638. This routine examines the arbiter state and returns a list of devices that
  2639. conflict with ConflictingResource
  2640. Arguments:
  2641. Arbiter - The arbiter to examine conflicts in
  2642. ConflictingResource - The resource we want to know the conflicts with
  2643. ConflictCount - On success contains the number of conflicts detected
  2644. ConflictList - On success contains a pointer to an array of conflicting
  2645. devices
  2646. Return Value:
  2647. Status code that indicates whether or not the function was successful.
  2648. --*/
  2649. {
  2650. //
  2651. // NTRAID #98568 - 2000/03/31 - andrewth
  2652. // ArbQueryConflict needs to be redesigned
  2653. //
  2654. NTSTATUS status;
  2655. RTL_RANGE_LIST backupAllocation;
  2656. BOOLEAN backedUp = FALSE;
  2657. ARBITER_LIST_ENTRY entry;
  2658. ARBITER_ALLOCATION_STATE state;
  2659. ARBITER_ALTERNATIVE alternative;
  2660. ULONG count = 0, size = 10;
  2661. PRTL_RANGE conflictingRange;
  2662. PARBITER_CONFLICT_INFO conflictInfo = NULL;
  2663. PVOID savedContext;
  2664. PRTL_CONFLICT_RANGE_CALLBACK savedCallback;
  2665. ULONG sz;
  2666. PAGED_CODE();
  2667. ASSERT(PhysicalDeviceObject);
  2668. ASSERT(ConflictingResource);
  2669. ASSERT(ConflictCount);
  2670. ASSERT(Conflicts);
  2671. //
  2672. // Set up our conflict callback
  2673. //
  2674. savedCallback = Arbiter->ConflictCallback;
  2675. savedContext = Arbiter->ConflictCallbackContext;
  2676. Arbiter->ConflictCallback = ArbpQueryConflictCallback;
  2677. Arbiter->ConflictCallbackContext = &conflictingRange;
  2678. //
  2679. // If there is a transaction in progress then we need to backup the
  2680. // the possible allocation so we can restore it when we are done.
  2681. //
  2682. if (Arbiter->TransactionInProgress) {
  2683. RtlInitializeRangeList(&backupAllocation);
  2684. status = RtlCopyRangeList(&backupAllocation, Arbiter->PossibleAllocation);
  2685. if (!NT_SUCCESS(status)) {
  2686. goto cleanup;
  2687. }
  2688. RtlFreeRangeList(Arbiter->PossibleAllocation);
  2689. backedUp = TRUE;
  2690. }
  2691. //
  2692. // Fake up the allocation state
  2693. //
  2694. status = RtlCopyRangeList(Arbiter->PossibleAllocation, Arbiter->Allocation);
  2695. if (!NT_SUCCESS(status)) {
  2696. goto cleanup;
  2697. }
  2698. status = ArbpBuildAlternative(Arbiter, ConflictingResource, &alternative);
  2699. if (!NT_SUCCESS(status)) {
  2700. goto cleanup;
  2701. }
  2702. RtlZeroMemory(&state, sizeof(ARBITER_ALLOCATION_STATE));
  2703. state.Start = alternative.Minimum;
  2704. state.End = alternative.Maximum;
  2705. state.CurrentMinimum = state.Start;
  2706. state.CurrentMaximum = state.End;
  2707. state.CurrentAlternative = &alternative;
  2708. state.AlternativeCount = 1;
  2709. state.Alternatives = &alternative;
  2710. state.Flags = ARBITER_STATE_FLAG_CONFLICT;
  2711. state.Entry = &entry;
  2712. RtlZeroMemory(&entry, sizeof(ARBITER_LIST_ENTRY));
  2713. entry.RequestSource = ArbiterRequestPnpEnumerated;
  2714. entry.PhysicalDeviceObject = PhysicalDeviceObject;
  2715. if (!NT_SUCCESS(IoGetDeviceProperty(PhysicalDeviceObject,DevicePropertyLegacyBusType,sizeof(entry.InterfaceType),&entry.InterfaceType,&sz))) {
  2716. entry.InterfaceType = Isa; // not what I want to do! However this has the right effect - good enough for conflict detection
  2717. }
  2718. if (!NT_SUCCESS(IoGetDeviceProperty(PhysicalDeviceObject,DevicePropertyBusNumber,sizeof(entry.InterfaceType),&entry.BusNumber,&sz))) {
  2719. entry.BusNumber = 0; // not what I want to do! However this has the right effect - good enough for conflict detection
  2720. }
  2721. //
  2722. // Initialize the return buffers
  2723. //
  2724. conflictInfo = ExAllocatePoolWithTag(PagedPool,
  2725. size * sizeof(ARBITER_CONFLICT_INFO),
  2726. ARBITER_CONFLICT_INFO_TAG
  2727. );
  2728. if (!conflictInfo) {
  2729. status = STATUS_INSUFFICIENT_RESOURCES;
  2730. goto cleanup;
  2731. }
  2732. //
  2733. // Perform any necessary preprocessing
  2734. //
  2735. status = Arbiter->PreprocessEntry(Arbiter, &state);
  2736. if (!NT_SUCCESS(status)) {
  2737. goto cleanup;
  2738. }
  2739. //
  2740. // Remove self from list of possible allocations
  2741. // status may be set, but can be ignored
  2742. // we take ourself out of test completely, so that a user can
  2743. // pick new values in context of rest of the world
  2744. // if we decide to use RtlDeleteRange instead
  2745. // make sure we do it for every alias formed in PreprocessEntry
  2746. //
  2747. status = RtlDeleteOwnersRanges(Arbiter->PossibleAllocation,
  2748. state.Entry->PhysicalDeviceObject
  2749. );
  2750. //
  2751. // Keep trying to find a suitable range and each time we fail remember why.
  2752. //
  2753. conflictingRange = NULL;
  2754. state.CurrentMinimum = state.Start;
  2755. state.CurrentMaximum = state.End;
  2756. while (!Arbiter->FindSuitableRange(Arbiter, &state)) {
  2757. if (count == size) {
  2758. //
  2759. // We need to resize the return buffer
  2760. //
  2761. PARBITER_CONFLICT_INFO temp = conflictInfo;
  2762. size += 5;
  2763. conflictInfo =
  2764. ExAllocatePoolWithTag(PagedPool,
  2765. size * sizeof(ARBITER_CONFLICT_INFO),
  2766. ARBITER_CONFLICT_INFO_TAG
  2767. );
  2768. if (!conflictInfo) {
  2769. status = STATUS_INSUFFICIENT_RESOURCES;
  2770. conflictInfo = temp;
  2771. goto cleanup;
  2772. }
  2773. RtlCopyMemory(conflictInfo,
  2774. temp,
  2775. count * sizeof(ARBITER_CONFLICT_INFO)
  2776. );
  2777. ExFreePool(temp);
  2778. }
  2779. if (conflictingRange != NULL) {
  2780. conflictInfo[count].OwningObject = conflictingRange->Owner;
  2781. conflictInfo[count].Start = conflictingRange->Start;
  2782. conflictInfo[count].End = conflictingRange->End;
  2783. count++;
  2784. //
  2785. // Delete the range we conflicted with so we don't loop forever
  2786. //
  2787. #if 0
  2788. status = RtlDeleteRange(Arbiter->PossibleAllocation,
  2789. conflictingRange->Start,
  2790. conflictingRange->End,
  2791. conflictingRange->Owner
  2792. );
  2793. #endif
  2794. status = RtlDeleteOwnersRanges(Arbiter->PossibleAllocation,
  2795. conflictingRange->Owner
  2796. );
  2797. if (!NT_SUCCESS(status)) {
  2798. goto cleanup;
  2799. }
  2800. } else {
  2801. //
  2802. // someone isn't playing by the rules (such as ACPI!)
  2803. //
  2804. ARB_PRINT(0,("Conflict detected - but someone hasn't set conflicting info\n"));
  2805. conflictInfo[count].OwningObject = NULL;
  2806. conflictInfo[count].Start = (ULONGLONG)0;
  2807. conflictInfo[count].End = (ULONGLONG)(-1);
  2808. count++;
  2809. //
  2810. // we daren't continue at risk of looping forever
  2811. //
  2812. break;
  2813. }
  2814. //
  2815. // reset for next round
  2816. //
  2817. conflictingRange = NULL;
  2818. state.CurrentMinimum = state.Start;
  2819. state.CurrentMaximum = state.End;
  2820. }
  2821. RtlFreeRangeList(Arbiter->PossibleAllocation);
  2822. if (Arbiter->TransactionInProgress) {
  2823. status = RtlCopyRangeList(Arbiter->PossibleAllocation, &backupAllocation);
  2824. if (!NT_SUCCESS(status)) {
  2825. goto cleanup;
  2826. }
  2827. RtlFreeRangeList(&backupAllocation);
  2828. }
  2829. Arbiter->ConflictCallback = savedCallback;
  2830. Arbiter->ConflictCallbackContext = savedContext;
  2831. *Conflicts = conflictInfo;
  2832. *ConflictCount = count;
  2833. return STATUS_SUCCESS;
  2834. cleanup:
  2835. if (conflictInfo) {
  2836. ExFreePool(conflictInfo);
  2837. }
  2838. RtlFreeRangeList(Arbiter->PossibleAllocation);
  2839. if (Arbiter->TransactionInProgress && backedUp) {
  2840. status = RtlCopyRangeList(Arbiter->PossibleAllocation, &backupAllocation);
  2841. RtlFreeRangeList(&backupAllocation);
  2842. }
  2843. Arbiter->ConflictCallback = savedCallback;
  2844. Arbiter->ConflictCallbackContext = savedContext;
  2845. *Conflicts = NULL;
  2846. return status;
  2847. }
  2848. NTSTATUS
  2849. ArbStartArbiter(
  2850. IN PARBITER_INSTANCE Arbiter,
  2851. IN PCM_RESOURCE_LIST StartResources
  2852. )
  2853. /*++
  2854. Routine Description:
  2855. This function is called by the driver that implements the arbiter once
  2856. it has been started and knowns what resources it can allocate to its
  2857. children.
  2858. It will eventually initialize the range lists correctly but for
  2859. now it is just an overloadable place holder as that work is done elsewhere.
  2860. Parameters:
  2861. Arbiter - The instance of the arbiter being called.
  2862. Return Value:
  2863. Status code that indicates whether or not the function was successful.
  2864. --*/
  2865. {
  2866. PAGED_CODE();
  2867. UNREFERENCED_PARAMETER (Arbiter);
  2868. UNREFERENCED_PARAMETER (StartResources);
  2869. return STATUS_SUCCESS;
  2870. }
  2871. BOOLEAN
  2872. ArbShareDriverExclusive(
  2873. IN PARBITER_INSTANCE Arbiter,
  2874. IN PARBITER_ALLOCATION_STATE State
  2875. )
  2876. /*++
  2877. Routine Description:
  2878. This routine implements support for CmResourceShareDriverExclusive disposition
  2879. by overriding conflict if the owner and request share at least one common
  2880. driver.
  2881. Arguments:
  2882. Arbiter - The instance data of the arbiter who was called.
  2883. State - The state of the current arbitration.
  2884. Return Value:
  2885. TRUE if the conflict is allowable, false otherwise
  2886. --*/
  2887. {
  2888. PRTL_RANGE current;
  2889. RTL_RANGE_LIST_ITERATOR iterator;
  2890. PDEVICE_OBJECT owner, other;
  2891. ULONG enumeratorNameLength;
  2892. WCHAR enumeratorName[sizeof(REGSTR_KEY_ROOTENUM) / sizeof(WCHAR)];
  2893. NTSTATUS status;
  2894. BOOLEAN isRootEnumerated;
  2895. PAGED_CODE();
  2896. owner = NULL;
  2897. isRootEnumerated = FALSE;
  2898. status = IoGetDeviceProperty(
  2899. State->Entry->PhysicalDeviceObject,
  2900. DevicePropertyEnumeratorName,
  2901. sizeof(enumeratorName),
  2902. enumeratorName,
  2903. &enumeratorNameLength);
  2904. if (NT_SUCCESS(status)) {
  2905. if (_wcsicmp(enumeratorName, REGSTR_KEY_ROOTENUM) == 0) {
  2906. isRootEnumerated = TRUE;
  2907. }
  2908. }
  2909. FOR_ALL_RANGES(Arbiter->PossibleAllocation, &iterator, current) {
  2910. //
  2911. // Only test the overlapping ones
  2912. //
  2913. if (INTERSECT(current->Start, current->End, State->CurrentMinimum, State->CurrentMaximum)) {
  2914. //
  2915. // Check if we should ignore the range because of its attributes
  2916. //
  2917. if (current->Attributes & State->RangeAvailableAttributes) {
  2918. //
  2919. // We DON'T set ok to true because we are just ignoring the range,
  2920. // as RtlFindRange would have and thus it can't be the cause of
  2921. // RtlFindRange failing, so ignoring it can't fix the conflict.
  2922. //
  2923. continue;
  2924. }
  2925. if (State->CurrentAlternative->Descriptor->ShareDisposition != CmResourceShareDriverExclusive &&
  2926. !(current->Attributes & ARBITER_RANGE_SHARE_DRIVER_EXCLUSIVE)) {
  2927. continue;
  2928. }
  2929. if (!current->Owner) {
  2930. continue;
  2931. }
  2932. //
  2933. // Special case ROOT enumerated devices.
  2934. //
  2935. if (isRootEnumerated) {
  2936. status = IoGetDeviceProperty(
  2937. current->Owner,
  2938. DevicePropertyEnumeratorName,
  2939. sizeof(enumeratorName),
  2940. enumeratorName,
  2941. &enumeratorNameLength);
  2942. if (NT_SUCCESS(status)) {
  2943. if (_wcsicmp(enumeratorName, REGSTR_KEY_ROOTENUM) != 0) {
  2944. isRootEnumerated = FALSE;
  2945. }
  2946. }
  2947. }
  2948. //
  2949. // If both devices are ROOT enumerated, override the conflict.
  2950. //
  2951. if (isRootEnumerated) {
  2952. if (owner != NULL) {
  2953. ARB_PRINT(2,
  2954. ("Overriding conflict on IRQ %04x for driver %wZ\n",
  2955. (ULONG)State->Start,
  2956. &owner->DriverObject->DriverName
  2957. ));
  2958. }
  2959. State->Start=State->CurrentMinimum;
  2960. State->End=State->CurrentMaximum;
  2961. if (State->CurrentAlternative->Descriptor->ShareDisposition == CmResourceShareDriverExclusive) {
  2962. State->RangeAttributes |= ARBITER_RANGE_SHARE_DRIVER_EXCLUSIVE;
  2963. }
  2964. return TRUE;
  2965. }
  2966. //
  2967. // Check if there is a common driver in the two stacks ignoring the
  2968. // one for the PDO.
  2969. //
  2970. owner = ((PDEVICE_OBJECT)(current->Owner))->AttachedDevice;
  2971. while (owner) {
  2972. other = (PDEVICE_OBJECT)(State->Entry->PhysicalDeviceObject)->AttachedDevice;
  2973. while (other) {
  2974. if (owner->DriverObject == other->DriverObject) {
  2975. ARB_PRINT(2,
  2976. ("Overriding conflict on IRQ %04x for driver %wZ\n",
  2977. (ULONG)State->Start,
  2978. &owner->DriverObject->DriverName
  2979. ));
  2980. State->Start=State->CurrentMinimum;
  2981. State->End=State->CurrentMaximum;
  2982. if (State->CurrentAlternative->Descriptor->ShareDisposition == CmResourceShareDriverExclusive) {
  2983. State->RangeAttributes |= ARBITER_RANGE_SHARE_DRIVER_EXCLUSIVE;
  2984. }
  2985. return TRUE;
  2986. }
  2987. other = other->AttachedDevice;
  2988. }
  2989. owner = owner->AttachedDevice;
  2990. }
  2991. }
  2992. }
  2993. //
  2994. // The conflict is still valid
  2995. //
  2996. return FALSE;
  2997. }
  2998. #if DBG
  2999. VOID
  3000. ArbpIndent(
  3001. IN ULONG Count
  3002. )
  3003. {
  3004. UCHAR spaces[80];
  3005. ASSERT(Count <= 80);
  3006. RtlFillMemory(spaces, Count, '*');
  3007. spaces[Count] = 0;
  3008. DbgPrint("%s", spaces);
  3009. }
  3010. #endif