Source code of Windows XP (NT5)
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.

1396 lines
33 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. pnpmemio.c
  5. Abstract:
  6. Root IO Port and Memory arbiter
  7. Author:
  8. Andy Thornton (andrewth) 04/17/97
  9. Revision History:
  10. --*/
  11. #include "pnpmgrp.h"
  12. #pragma hdrstop
  13. #define BUGFEST_HACKS
  14. //
  15. // Constants
  16. //
  17. #define MAX_ULONGLONG ((ULONGLONG) -1)
  18. #define MAX_ALIAS_PORT 0x0000FFFF
  19. typedef struct _PORT_ARBITER_EXTENSION {
  20. PRTL_RANGE_LIST Aliases;
  21. PRTL_RANGE_LIST PossibleAliases;
  22. RTL_RANGE_LIST RangeLists[2];
  23. } PORT_ARBITER_EXTENSION, *PPORT_ARBITER_EXTENSION;
  24. //
  25. // Prototypes
  26. //
  27. VOID
  28. IopPortBacktrackAllocation(
  29. IN PARBITER_INSTANCE Arbiter,
  30. IN PARBITER_ALLOCATION_STATE State
  31. );
  32. BOOLEAN
  33. IopPortGetNextAlias(
  34. ULONG IoDescriptorFlags,
  35. ULONGLONG LastAlias,
  36. PULONGLONG NextAlias
  37. );
  38. BOOLEAN
  39. IopPortFindSuitableRange(
  40. PARBITER_INSTANCE Arbiter,
  41. PARBITER_ALLOCATION_STATE State
  42. );
  43. BOOLEAN
  44. IopMemFindSuitableRange(
  45. PARBITER_INSTANCE Arbiter,
  46. PARBITER_ALLOCATION_STATE State
  47. );
  48. NTSTATUS
  49. IopGenericUnpackRequirement(
  50. IN PIO_RESOURCE_DESCRIPTOR Descriptor,
  51. OUT PULONGLONG Minimum,
  52. OUT PULONGLONG Maximum,
  53. OUT PULONG Length,
  54. OUT PULONG Alignment
  55. );
  56. NTSTATUS
  57. IopGenericPackResource(
  58. IN PIO_RESOURCE_DESCRIPTOR Requirement,
  59. IN ULONGLONG Start,
  60. OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor
  61. );
  62. LONG
  63. IopGenericScoreRequirement(
  64. IN PIO_RESOURCE_DESCRIPTOR Descriptor
  65. );
  66. NTSTATUS
  67. IopGenericUnpackResource(
  68. IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor,
  69. OUT PULONGLONG Start,
  70. OUT PULONG Length
  71. );
  72. BOOLEAN
  73. IopPortIsAliasedRangeAvailable(
  74. IN PARBITER_INSTANCE Arbiter,
  75. IN PARBITER_ALLOCATION_STATE State
  76. );
  77. NTSTATUS
  78. IopMemInitialize(
  79. VOID
  80. );
  81. VOID
  82. IopPortAddAllocation(
  83. IN PARBITER_INSTANCE Arbiter,
  84. IN PARBITER_ALLOCATION_STATE State
  85. );
  86. NTSTATUS
  87. IopTranslateBusAddress(
  88. IN PHYSICAL_ADDRESS SourceAddress,
  89. IN UCHAR SourceResourceType,
  90. OUT PPHYSICAL_ADDRESS TargetAddress,
  91. OUT PUCHAR TargetResourceType
  92. );
  93. //
  94. // Make everything pageable
  95. //
  96. #ifdef ALLOC_PRAGMA
  97. NTSTATUS
  98. IopGenericTranslateOrdering(
  99. OUT PIO_RESOURCE_DESCRIPTOR Target,
  100. IN PIO_RESOURCE_DESCRIPTOR Source
  101. );
  102. #pragma alloc_text(PAGE, IopGenericTranslateOrdering)
  103. #pragma alloc_text(PAGE, IopPortInitialize)
  104. #pragma alloc_text(PAGE, IopMemInitialize)
  105. #pragma alloc_text(PAGE, IopGenericUnpackRequirement)
  106. #pragma alloc_text(PAGE, IopGenericPackResource)
  107. #pragma alloc_text(PAGE, IopGenericScoreRequirement)
  108. #pragma alloc_text(PAGE, IopGenericUnpackResource)
  109. #pragma alloc_text(PAGE, IopPortBacktrackAllocation)
  110. #pragma alloc_text(PAGE, IopPortFindSuitableRange)
  111. #pragma alloc_text(PAGE, IopMemFindSuitableRange)
  112. #pragma alloc_text(PAGE, IopPortGetNextAlias)
  113. #pragma alloc_text(PAGE, IopPortAddAllocation)
  114. #pragma alloc_text(PAGE, IopPortIsAliasedRangeAvailable)
  115. #pragma alloc_text(PAGE, IopTranslateBusAddress)
  116. #endif // ALLOC_PRAGMA
  117. #define ADDRESS_SPACE_MEMORY 0x0
  118. #define ADDRESS_SPACE_PORT 0x1
  119. #define ADDRESS_SPACE_USER_MEMORY 0x2
  120. #define ADDRESS_SPACE_USER_PORT 0x3
  121. #define ADDRESS_SPACE_DENSE_MEMORY 0x4
  122. #define ADDRESS_SPACE_USER_DENSE_MEMORY 0x6
  123. NTSTATUS
  124. IopTranslateBusAddress(
  125. IN PHYSICAL_ADDRESS SourceAddress,
  126. IN UCHAR SourceResourceType,
  127. OUT PPHYSICAL_ADDRESS TargetAddress,
  128. OUT PUCHAR TargetResourceType
  129. )
  130. /*++
  131. Routine Description:
  132. This routine translates addresses.
  133. Parameters:
  134. SourceAddress - The address to translate
  135. ResourceType - The resource type (IO or Memory) we are translaing. If the
  136. address space changes from IO->Memory this will be updated.
  137. TargetAddress - Pointer to where the target should be translated to.
  138. Return Value:
  139. STATUS_SUCCESS or an error status
  140. --*/
  141. {
  142. ULONG sourceAddressSpace, targetAddressSpace;
  143. BOOLEAN translated;
  144. PAGED_CODE();
  145. //
  146. // Select the appropriate address space
  147. //
  148. if (SourceResourceType == CmResourceTypeMemory) {
  149. sourceAddressSpace = ADDRESS_SPACE_MEMORY;
  150. } else if (SourceResourceType == CmResourceTypePort) {
  151. sourceAddressSpace = ADDRESS_SPACE_PORT;
  152. } else {
  153. return STATUS_INVALID_PARAMETER;
  154. }
  155. ARB_PRINT(
  156. 2,
  157. ("Translating %s address 0x%I64x => ",
  158. SourceResourceType == CmResourceTypeMemory ? "Memory" : "I/O",
  159. SourceAddress.QuadPart
  160. ));
  161. //
  162. // HACKHACK Ask the HAL to translate on ISA bus - if we can't then just
  163. // don't translate because this must be a PCI system so the root arbiters
  164. // don't do much (Yes it's a steaming hack but it'll work for beta 1)
  165. //
  166. targetAddressSpace = sourceAddressSpace;
  167. translated = HalTranslateBusAddress(
  168. Isa,
  169. 0,
  170. SourceAddress,
  171. &targetAddressSpace,
  172. TargetAddress
  173. );
  174. if (!translated) {
  175. ARB_PRINT(2,("Translation failed!\n"));
  176. return STATUS_UNSUCCESSFUL;
  177. }
  178. //
  179. // Update the resource type in the target if we have gone from Io to Memory
  180. //
  181. //
  182. // BUBBUG - update the length for IO -> Memory (Dense vs Sparse)
  183. // I think the answer is dense -> spares is multiply length by 32
  184. //
  185. if (targetAddressSpace == ADDRESS_SPACE_MEMORY
  186. || targetAddressSpace == ADDRESS_SPACE_USER_MEMORY
  187. || targetAddressSpace == ADDRESS_SPACE_DENSE_MEMORY
  188. || targetAddressSpace == ADDRESS_SPACE_USER_DENSE_MEMORY) {
  189. *TargetResourceType = CmResourceTypeMemory;
  190. } else if (targetAddressSpace == ADDRESS_SPACE_PORT
  191. || targetAddressSpace == ADDRESS_SPACE_USER_PORT) {
  192. *TargetResourceType = CmResourceTypePort;
  193. } else {
  194. ASSERT(0 && "Translation has returned an unknown address space");
  195. return STATUS_INVALID_PARAMETER;
  196. }
  197. ARB_PRINT(
  198. 2,
  199. ("%s address 0x%I64x\n",
  200. *TargetResourceType == CmResourceTypeMemory ? "Memory" : "I/O",
  201. TargetAddress->QuadPart
  202. ));
  203. return STATUS_SUCCESS;
  204. }
  205. NTSTATUS
  206. IopGenericTranslateOrdering(
  207. OUT PIO_RESOURCE_DESCRIPTOR Target,
  208. IN PIO_RESOURCE_DESCRIPTOR Source
  209. )
  210. /*
  211. Routine Description:
  212. This routine is called during arbiter initialization to translate the
  213. orderings.
  214. Parameters:
  215. Target - Place to put the translated descriptor
  216. Source - Descriptor to translate
  217. Return Value:
  218. STATUS_SUCCESS
  219. */
  220. {
  221. NTSTATUS status;
  222. UCHAR initialResourceType, minResourceType, maxResourceType;
  223. PAGED_CODE();
  224. *Target = *Source;
  225. if (Source->Type != CmResourceTypeMemory
  226. && Source->Type != CmResourceTypePort) {
  227. return STATUS_SUCCESS;
  228. }
  229. initialResourceType = Source->Type;
  230. //
  231. // Translate the minimum
  232. //
  233. status = IopTranslateBusAddress(Source->u.Generic.MinimumAddress,
  234. initialResourceType,
  235. &Target->u.Generic.MinimumAddress,
  236. &minResourceType
  237. );
  238. if (NT_SUCCESS(status)) {
  239. //
  240. // Translate the maximum iff we could translate the minimum
  241. //
  242. status = IopTranslateBusAddress(Source->u.Generic.MaximumAddress,
  243. initialResourceType,
  244. &Target->u.Generic.MaximumAddress,
  245. &maxResourceType
  246. );
  247. }
  248. //
  249. // If we couldn't translate both ends of the range then we want to skip this
  250. // range - set it's type to CmResourceTypeNull
  251. //
  252. if (!NT_SUCCESS(status)) {
  253. Target->Type = CmResourceTypeNull;
  254. } else {
  255. ASSERT(minResourceType == maxResourceType);
  256. Target->Type = minResourceType;
  257. }
  258. return STATUS_SUCCESS;
  259. }
  260. //
  261. // Implementation
  262. //
  263. NTSTATUS
  264. IopPortInitialize(
  265. VOID
  266. )
  267. /*++
  268. Routine Description:
  269. This routine initializes the arbiter
  270. Parameters:
  271. None
  272. Return Value:
  273. None
  274. --*/
  275. {
  276. PAGED_CODE();
  277. //
  278. // Fill in the non-default action handlers
  279. //
  280. IopRootPortArbiter.FindSuitableRange = IopPortFindSuitableRange;
  281. IopRootPortArbiter.AddAllocation = IopPortAddAllocation;
  282. IopRootPortArbiter.BacktrackAllocation = IopPortBacktrackAllocation;
  283. IopRootPortArbiter.UnpackRequirement = IopGenericUnpackRequirement;
  284. IopRootPortArbiter.PackResource = IopGenericPackResource;
  285. IopRootPortArbiter.UnpackResource = IopGenericUnpackResource;
  286. IopRootPortArbiter.ScoreRequirement = IopGenericScoreRequirement;
  287. return ArbInitializeArbiterInstance(&IopRootPortArbiter,
  288. NULL, // Indicates ROOT arbiter
  289. CmResourceTypePort,
  290. L"RootPort",
  291. L"Root",
  292. IopGenericTranslateOrdering
  293. );
  294. }
  295. NTSTATUS
  296. IopMemInitialize(
  297. VOID
  298. )
  299. /*++
  300. Routine Description:
  301. This routine initializes the arbiter
  302. Parameters:
  303. None
  304. Return Value:
  305. None
  306. --*/
  307. {
  308. NTSTATUS status;
  309. PAGED_CODE();
  310. IopRootMemArbiter.UnpackRequirement = IopGenericUnpackRequirement;
  311. IopRootMemArbiter.PackResource = IopGenericPackResource;
  312. IopRootMemArbiter.UnpackResource = IopGenericUnpackResource;
  313. IopRootMemArbiter.ScoreRequirement = IopGenericScoreRequirement;
  314. IopRootMemArbiter.FindSuitableRange = IopMemFindSuitableRange;
  315. status = ArbInitializeArbiterInstance(&IopRootMemArbiter,
  316. NULL, // Indicates ROOT arbiter
  317. CmResourceTypeMemory,
  318. L"RootMemory",
  319. L"Root",
  320. IopGenericTranslateOrdering
  321. );
  322. if (!NT_SUCCESS(status)) {
  323. return status;
  324. }
  325. //
  326. // Allocate the first page of physical memory as the firmware uses it and
  327. // doesn't report it as so Mm doesn't reuse it.
  328. //
  329. status = RtlAddRange(IopRootMemArbiter.Allocation,
  330. 0,
  331. PAGE_SIZE - 1,
  332. 0, // RangeAttributes
  333. 0, // Flags
  334. NULL,
  335. NULL
  336. );
  337. return status;
  338. }
  339. //
  340. // Arbiter callbacks
  341. //
  342. NTSTATUS
  343. IopGenericUnpackRequirement(
  344. IN PIO_RESOURCE_DESCRIPTOR Descriptor,
  345. OUT PULONGLONG Minimum,
  346. OUT PULONGLONG Maximum,
  347. OUT PULONG Length,
  348. OUT PULONG Alignment
  349. )
  350. /*++
  351. Routine Description:
  352. This routine unpacks an resource requirement descriptor.
  353. Arguments:
  354. Descriptor - The descriptor describing the requirement to unpack.
  355. Minimum - Pointer to where the minimum acceptable start value should be
  356. unpacked to.
  357. Maximum - Pointer to where the maximum acceptable end value should be
  358. unpacked to.
  359. Length - Pointer to where the required length should be unpacked to.
  360. Minimum - Pointer to where the required alignment should be unpacked to.
  361. Return Value:
  362. Returns the status of this operation.
  363. --*/
  364. {
  365. PAGED_CODE();
  366. ASSERT(Descriptor);
  367. ASSERT(Descriptor->Type == CmResourceTypePort
  368. || Descriptor->Type == CmResourceTypeMemory);
  369. *Minimum = (ULONGLONG) Descriptor->u.Generic.MinimumAddress.QuadPart;
  370. *Maximum = (ULONGLONG) Descriptor->u.Generic.MaximumAddress.QuadPart;
  371. *Length = Descriptor->u.Generic.Length;
  372. *Alignment = Descriptor->u.Generic.Alignment;
  373. //
  374. // Fix the broken hardware that reports 0 alignment
  375. //
  376. if (*Alignment == 0) {
  377. *Alignment = 1;
  378. }
  379. //
  380. // Fix broken INF's that report they support 24bit memory > 0xFFFFFF
  381. //
  382. if (Descriptor->Type == CmResourceTypeMemory
  383. && Descriptor->Flags & CM_RESOURCE_MEMORY_24
  384. && Descriptor->u.Memory.MaximumAddress.QuadPart > 0xFFFFFF) {
  385. *Maximum = 0xFFFFFF;
  386. }
  387. ARB_PRINT(2,
  388. ("Unpacking %s requirement %p => 0x%I64x-0x%I64x length 0x%x alignment 0x%x\n",
  389. Descriptor->Type == CmResourceTypePort ? "port" : "memory",
  390. Descriptor,
  391. *Minimum,
  392. *Maximum,
  393. *Length,
  394. *Alignment
  395. ));
  396. return STATUS_SUCCESS;
  397. }
  398. LONG
  399. IopGenericScoreRequirement(
  400. IN PIO_RESOURCE_DESCRIPTOR Descriptor
  401. )
  402. /*++
  403. Routine Description:
  404. This routine scores a requirement based on how flexible it is. The least
  405. flexible devices are scored the least and so when the arbitration list is
  406. sorted we try to allocate their resources first.
  407. Arguments:
  408. Descriptor - The descriptor describing the requirement to score.
  409. Return Value:
  410. The score.
  411. --*/
  412. {
  413. LONG score;
  414. ULONGLONG start, end;
  415. LONGLONG bigscore;
  416. ULONG alignment;
  417. PAGED_CODE();
  418. #define MAX_SCORE MAXLONG
  419. ASSERT(Descriptor);
  420. ASSERT((Descriptor->Type == CmResourceTypePort) ||
  421. (Descriptor->Type == CmResourceTypeMemory));
  422. alignment = Descriptor->u.Generic.Alignment;
  423. //
  424. // Fix the broken hardware that reports 0 alignment
  425. // Since this is not a PCI device, set the alignment to 1.
  426. //
  427. //
  428. if (alignment == 0) {
  429. alignment = 1;
  430. }
  431. start = ALIGN_ADDRESS_UP(
  432. Descriptor->u.Generic.MinimumAddress.QuadPart,
  433. alignment
  434. );
  435. end = Descriptor->u.Generic.MaximumAddress.QuadPart;
  436. //
  437. // The score is the number of possible allocations that could be made
  438. // given the alignment and length constraints
  439. //
  440. bigscore = (((end - Descriptor->u.Generic.Length + 1) - start)
  441. / alignment) + 1;
  442. score = (LONG)bigscore;
  443. if (bigscore < 0) {
  444. score = -1;
  445. } else if (bigscore > MAX_SCORE) {
  446. score = MAX_SCORE;
  447. }
  448. ARB_PRINT(2,
  449. ("Scoring port resource %p(0x%I64x-0x%I64x) => %i\n",
  450. Descriptor->Type == CmResourceTypePort ? "port" : "memory",
  451. Descriptor,
  452. Descriptor->u.Generic.MinimumAddress.QuadPart,
  453. end,
  454. score
  455. ));
  456. return score;
  457. }
  458. NTSTATUS
  459. IopGenericPackResource(
  460. IN PIO_RESOURCE_DESCRIPTOR Requirement,
  461. IN ULONGLONG Start,
  462. OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor
  463. )
  464. /*++
  465. Routine Description:
  466. This routine packs an resource descriptor.
  467. Arguments:
  468. Requirement - The requirement from which this resource was chosen.
  469. Start - The start value of the resource.
  470. Descriptor - Pointer to the descriptor to pack into.
  471. Return Value:
  472. Returns the status of this operation.
  473. --*/
  474. {
  475. PAGED_CODE();
  476. ASSERT(Descriptor);
  477. ASSERT(Requirement);
  478. ASSERT(Requirement->Type == CmResourceTypePort
  479. || Requirement->Type == CmResourceTypeMemory);
  480. Descriptor->Type = Requirement->Type;
  481. Descriptor->Flags = Requirement->Flags;
  482. Descriptor->ShareDisposition = Requirement->ShareDisposition;
  483. Descriptor->u.Generic.Start.QuadPart = Start;
  484. Descriptor->u.Generic.Length = Requirement->u.Generic.Length;
  485. ARB_PRINT(2,
  486. ("Packing %s resource %p => 0x%I64x length 0x%x\n",
  487. Descriptor->Type == CmResourceTypePort ? "port" : "memory",
  488. Descriptor,
  489. Descriptor->u.Port.Start.QuadPart,
  490. Descriptor->u.Port.Length
  491. ));
  492. return STATUS_SUCCESS;
  493. }
  494. NTSTATUS
  495. IopGenericUnpackResource(
  496. IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor,
  497. OUT PULONGLONG Start,
  498. OUT PULONG Length
  499. )
  500. /*++
  501. Routine Description:
  502. This routine unpacks an resource descriptor.
  503. Arguments:
  504. Descriptor - The descriptor describing the resource to unpack.
  505. Start - Pointer to where the start value should be unpacked to.
  506. Length - Pointer to where the length value should be unpacked to.
  507. Return Value:
  508. Returns the status of this operation.
  509. --*/
  510. {
  511. PAGED_CODE();
  512. ASSERT(Descriptor);
  513. ASSERT(Descriptor->Type == CmResourceTypePort
  514. || Descriptor->Type == CmResourceTypeMemory);
  515. *Start = Descriptor->u.Generic.Start.QuadPart;
  516. *Length = Descriptor->u.Generic.Length;
  517. ARB_PRINT(2,
  518. ("Unpacking %s resource %p => 0x%I64x Length 0x%x\n",
  519. Descriptor->Type == CmResourceTypePort ? "port" : "memory",
  520. Descriptor,
  521. *Start,
  522. *Length
  523. ));
  524. return STATUS_SUCCESS;
  525. }
  526. #if 0
  527. NTSTATUS
  528. IopPortRetestAllocation(
  529. IN PARBITER_INSTANCE Arbiter,
  530. IN OUT PLIST_ENTRY ArbitrationList
  531. )
  532. /*++
  533. Routine Description:
  534. This providesa port specific implementation of the RetestAllocation action
  535. which takes into account ISA aliases and adds them where appropriate.
  536. It walks the arbitration list and updates the possible allocation to reflect
  537. the allocation entries of the list. For these entries to be valid
  538. TestAllocation must have been performed on this arbitration list.
  539. Parameters:
  540. Arbiter - The arbiter instance data for the arbiter being called.
  541. ArbitrationList - A list of ARBITER_LIST_ENTRY entries which contain the
  542. requirements and associated devices. TestAllocation for this arbiter
  543. should have been called on this list.
  544. Return Value:
  545. Status code that indicates whether or not the function was successful.
  546. --*/
  547. {
  548. NTSTATUS status;
  549. PARBITER_LIST_ENTRY current;
  550. PIO_RESOURCE_DESCRIPTOR alternative;
  551. ULONGLONG start;
  552. ULONG length;
  553. PAGED_CODE();
  554. //
  555. // Copy the current allocation and reserved
  556. //
  557. ARB_PRINT(3, ("Retest: Copy current allocation\n"));
  558. status = RtlCopyRangeList(Arbiter->PossibleAllocation, Arbiter->Allocation);
  559. if (!NT_SUCCESS(status)) {
  560. goto cleanup;
  561. }
  562. //
  563. // Free all the resources currently allocated to all the devices we
  564. // are arbitrating for
  565. //
  566. FOR_ALL_IN_LIST(ARBITER_LIST_ENTRY, ArbitrationList, current) {
  567. ARB_PRINT(2, ("Retest: Delete 0x%08x's resources\n", current->PhysicalDeviceObject));
  568. status = RtlDeleteOwnersRanges(Arbiter->PossibleAllocation,
  569. (PVOID) current->PhysicalDeviceObject
  570. );
  571. if (!NT_SUCCESS(status)) {
  572. goto cleanup;
  573. }
  574. }
  575. //
  576. // Copy the previous allocation into the range list
  577. //
  578. FOR_ALL_IN_LIST(ARBITER_LIST_ENTRY, ArbitrationList, current) {
  579. ASSERT(current->Assignment);
  580. status = Arbiter->UnpackResource(current->Assignment,
  581. &start,
  582. &length
  583. );
  584. ASSERT(NT_SUCCESS(status));
  585. //
  586. // If we had a requirement for length 0 then that will be seen as
  587. // end == start - 1 here so don't attempt to add the range - it will
  588. // fail!
  589. //
  590. if (length != 0) {
  591. status = RtlAddRange(
  592. Arbiter->PossibleAllocation,
  593. start,
  594. start + length - 1,
  595. 0,
  596. RTL_RANGE_LIST_ADD_IF_CONFLICT +
  597. (current->Assignment->ShareDisposition == CmResourceShareShared ?
  598. RTL_RANGE_LIST_ADD_SHARED : 0),
  599. NULL,
  600. current->PhysicalDeviceObject
  601. );
  602. ASSERT(NT_SUCCESS(status));
  603. //
  604. // Retireve the alternative from which the assignment was chosen from
  605. // then
  606. //
  607. alternative = current->SelectedAlternative;
  608. //
  609. // Add the aliases
  610. //
  611. if (alternative->Flags & CM_RESOURCE_PORT_10_BIT_DECODE
  612. || alternative->Flags & CM_RESOURCE_PORT_12_BIT_DECODE) {
  613. ULONGLONG alias = start;
  614. BOOLEAN shared = current->Assignment->ShareDisposition ==
  615. CmResourceShareShared;
  616. ARB_PRINT(3, ("Adding aliases\n"));
  617. while (IopPortGetNextAlias(alternative->Flags,
  618. alias,
  619. &alias)) {
  620. status = RtlAddRange(
  621. Arbiter->PossibleAllocation,
  622. alias,
  623. alias + length - 1,
  624. ARBITER_RANGE_ALIAS,
  625. RTL_RANGE_LIST_ADD_IF_CONFLICT +
  626. (shared ? RTL_RANGE_LIST_SHARED_OK : 0),
  627. NULL,
  628. current->PhysicalDeviceObject
  629. );
  630. //
  631. // We have already checked if these ranges are available
  632. // so we should not fail...
  633. //
  634. ASSERT(NT_SUCCESS(status));
  635. }
  636. }
  637. }
  638. }
  639. return status;
  640. cleanup:
  641. RtlFreeRangeList(Arbiter->PossibleAllocation);
  642. return status;
  643. }
  644. #endif
  645. VOID
  646. IopPortBacktrackAllocation(
  647. IN PARBITER_INSTANCE Arbiter,
  648. IN PARBITER_ALLOCATION_STATE State
  649. )
  650. /*++
  651. Routine Description:
  652. This routine is called from AllocateEntry if the possible solution
  653. (State->Start - State->End) does not allow us to allocate resources to
  654. the rest of the devices being considered. It deletes the ranges that were
  655. added to Arbiter->PossibleAllocation by AddAllocation including those
  656. associated with ISA aliases.
  657. Arguments:
  658. Arbiter - The instance data of the arbiter who was called.
  659. State - The state of the current arbitration.
  660. Return Value:
  661. None.
  662. --*/
  663. {
  664. NTSTATUS status;
  665. ULONGLONG alias = State->Start;
  666. PAGED_CODE();
  667. //
  668. // Delete the aliases
  669. //
  670. ARB_PRINT(2, ("\t\tDeleting aliases\n"));
  671. while (IopPortGetNextAlias(State->CurrentAlternative->Flags,
  672. alias,
  673. &alias)) {
  674. status = RtlDeleteRange(
  675. Arbiter->PossibleAllocation,
  676. alias,
  677. alias + State->CurrentAlternative->Length - 1,
  678. State->Entry->PhysicalDeviceObject
  679. );
  680. //
  681. // We should not fail...
  682. //
  683. ASSERT(NT_SUCCESS(status));
  684. }
  685. //
  686. // Now call the original function to delete the base range
  687. //
  688. ArbBacktrackAllocation(Arbiter, State);
  689. }
  690. BOOLEAN
  691. IopPortFindSuitableRange(
  692. PARBITER_INSTANCE Arbiter,
  693. PARBITER_ALLOCATION_STATE State
  694. )
  695. /*++
  696. Routine Description:
  697. This routine is called from AllocateEntry once we have decided where we want
  698. to allocate from. It tries to find a free range that matches the
  699. requirements in State while restricting its possible solutions to the range
  700. State->Start to State->CurrentMaximum. On success State->Start and
  701. State->End represent this range. Conflicts with ISA aliases are considered.
  702. Arguments:
  703. Arbiter - The instance data of the arbiter who was called.
  704. State - The state of the current arbitration.
  705. Return Value:
  706. TRUE if we found a range, FALSE otherwise.
  707. --*/
  708. {
  709. NTSTATUS status;
  710. UCHAR userFlagsMask = 0;
  711. PAGED_CODE();
  712. //
  713. // If we are asking for zero ports then trivially succeed with the minimum
  714. // value
  715. //
  716. if (State->CurrentAlternative->Length == 0) {
  717. State->End = State->Start;
  718. return TRUE;
  719. }
  720. //
  721. // For legacy requests from IoAssignResources (directly or by way of
  722. // HalAssignSlotResources) or IoReportResourceUsage we consider preallocated
  723. // resources to be available for backward compatibility reasons.
  724. //
  725. // If we are allocating a devices boot config then we consider all other
  726. // boot configs to be available.
  727. //
  728. if (State->Entry->RequestSource == ArbiterRequestLegacyReported
  729. || State->Entry->RequestSource == ArbiterRequestLegacyAssigned
  730. || State->Entry->Flags & ARBITER_FLAG_BOOT_CONFIG) {
  731. userFlagsMask = ARBITER_RANGE_BOOT_ALLOCATED;
  732. }
  733. //
  734. // Try to satisfy the request
  735. //
  736. while (State->CurrentMinimum <= State->CurrentMaximum) {
  737. //
  738. // Select the first free alternative from the current alternative
  739. //
  740. status = RtlFindRange(
  741. Arbiter->PossibleAllocation,
  742. State->CurrentMinimum,
  743. State->CurrentMaximum,
  744. State->CurrentAlternative->Length,
  745. State->CurrentAlternative->Alignment,
  746. State->CurrentAlternative->Flags &
  747. ARBITER_ALTERNATIVE_FLAG_SHARED ?
  748. RTL_RANGE_LIST_SHARED_OK : 0,
  749. userFlagsMask,
  750. Arbiter->ConflictCallbackContext,
  751. Arbiter->ConflictCallback,
  752. &State->Start
  753. );
  754. //
  755. // Did we find a range and if not can we override any conflict
  756. //
  757. if (NT_SUCCESS(status)
  758. || Arbiter->OverrideConflict(Arbiter, State)) {
  759. State->End = State->Start + State->CurrentAlternative->Length - 1;
  760. //
  761. // Check if the aliases are available
  762. //
  763. if (IopPortIsAliasedRangeAvailable(Arbiter, State)) {
  764. //
  765. // We found a suitable range so return
  766. //
  767. return TRUE;
  768. } else {
  769. //
  770. // This range's aliases arn't available so try the next range
  771. //
  772. State->Start += State->CurrentAlternative->Length;
  773. continue;
  774. }
  775. } else {
  776. //
  777. // We couldn't find a base range
  778. //
  779. break;
  780. }
  781. }
  782. return FALSE;
  783. }
  784. BOOLEAN
  785. IopPortGetNextAlias(
  786. ULONG IoDescriptorFlags,
  787. ULONGLONG LastAlias,
  788. PULONGLONG NextAlias
  789. )
  790. /*++
  791. Routine Description:
  792. This routine calculates the next alias of an IO port up to MAX_ALIAS_PORT.
  793. Arguments:
  794. IoDescriptorFlags - The flags from the requirement descriptor indicating the
  795. type of alias if any.
  796. LastAlias - The alias previous to this one.
  797. NextAlias - Point to where the next alias should be returned
  798. Return Value:
  799. TRUE if we found an alias, FALSE otherwise.
  800. --*/
  801. {
  802. ULONGLONG next;
  803. PAGED_CODE();
  804. if (IoDescriptorFlags & CM_RESOURCE_PORT_10_BIT_DECODE) {
  805. next = LastAlias + (1 << 10);
  806. } else if (IoDescriptorFlags & CM_RESOURCE_PORT_12_BIT_DECODE) {
  807. next = LastAlias + (1 << 12);
  808. } else {
  809. //
  810. // There are no aliases
  811. //
  812. return FALSE;
  813. }
  814. //
  815. // Check that we are below the maximum aliased port
  816. //
  817. if (next > MAX_ALIAS_PORT) {
  818. return FALSE;
  819. } else {
  820. *NextAlias = next;
  821. return TRUE;
  822. }
  823. }
  824. VOID
  825. IopPortAddAllocation(
  826. IN PARBITER_INSTANCE Arbiter,
  827. IN PARBITER_ALLOCATION_STATE State
  828. )
  829. /*++
  830. Routine Description:
  831. This routine is called from AllocateEntry once we have found a possible
  832. solution (State->Start - State->End). It adds the ranges that will not be
  833. available if we commit to this solution to Arbiter->PossibleAllocation.
  834. Arguments:
  835. Arbiter - The instance data of the arbiter who was called.
  836. State - The state of the current arbitration.
  837. Return Value:
  838. None.
  839. --*/
  840. {
  841. NTSTATUS status;
  842. ULONGLONG alias;
  843. PAGED_CODE();
  844. ASSERT(Arbiter);
  845. ASSERT(State);
  846. status = RtlAddRange(Arbiter->PossibleAllocation,
  847. State->Start,
  848. State->End,
  849. State->RangeAttributes,
  850. RTL_RANGE_LIST_ADD_IF_CONFLICT +
  851. (State->CurrentAlternative->Flags & ARBITER_ALTERNATIVE_FLAG_SHARED
  852. ? RTL_RANGE_LIST_ADD_SHARED : 0),
  853. NULL,
  854. State->Entry->PhysicalDeviceObject
  855. );
  856. ASSERT(NT_SUCCESS(status));
  857. //
  858. // Add any aliases
  859. //
  860. alias = State->Start;
  861. ARB_PRINT(2, ("Adding aliases\n"));
  862. while (IopPortGetNextAlias(State->CurrentAlternative->Descriptor->Flags,
  863. alias,
  864. &alias)) {
  865. status = RtlAddRange(Arbiter->PossibleAllocation,
  866. alias,
  867. alias + State->CurrentAlternative->Length - 1,
  868. (UCHAR) (State->RangeAttributes | ARBITER_RANGE_ALIAS),
  869. RTL_RANGE_LIST_ADD_IF_CONFLICT +
  870. (State->CurrentAlternative->Flags & ARBITER_ALTERNATIVE_FLAG_SHARED
  871. ? RTL_RANGE_LIST_ADD_SHARED : 0),
  872. NULL,
  873. State->Entry->PhysicalDeviceObject
  874. );
  875. //
  876. // We have already checked if these ranges are available
  877. // so we should not fail...
  878. //
  879. ASSERT(NT_SUCCESS(status));
  880. }
  881. }
  882. BOOLEAN
  883. IopPortIsAliasedRangeAvailable(
  884. PARBITER_INSTANCE Arbiter,
  885. PARBITER_ALLOCATION_STATE State
  886. )
  887. /*++
  888. Routine Description:
  889. This routine determines if the range (Start-(Length-1)) is available taking
  890. into account any aliases.
  891. Arguments:
  892. Arbiter - The instance data of the arbiter who was called.
  893. State - The state of the current arbitration.
  894. Return Value:
  895. TRUE if the range is available, FALSE otherwise.
  896. --*/
  897. {
  898. //
  899. // NTRAID #61146-2000/03/31-andrewth Root IO arbiter don't deal with aliases
  900. //
  901. // This is only an issue on machines where the root arbiters are called upon
  902. // to arbitrated aliased ranges - this means a pure ISA machine with no PCI.
  903. // I hope we won't support these soon and the root arbiters can be made a
  904. // lot worse.
  905. //
  906. #if defined(BUGFEST_HACKS)
  907. UNREFERENCED_PARAMETER( Arbiter );
  908. UNREFERENCED_PARAMETER( State );
  909. PAGED_CODE();
  910. //
  911. // For the purposes of the Bug^H^H^HPlugFest don't mind is aliases conflict
  912. // with any devices but still add them...
  913. //
  914. return TRUE;
  915. #else
  916. NTSTATUS status;
  917. ULONGLONG alias = State->Start;
  918. BOOLEAN aliasAvailable;
  919. UCHAR userFlagsMask = 0;
  920. PAGED_CODE();
  921. //
  922. // For legacy requests from IoAssignResources (directly or by way of
  923. // HalAssignSlotResources) or IoReportResourceUsage we consider preallocated
  924. // resources to be available for backward compatibility reasons.
  925. //
  926. if (State->Entry->RequestSource == ArbiterRequestLegacyReported
  927. || State->Entry->RequestSource == ArbiterRequestLegacyAssigned) {
  928. userFlagsMask |= ARBITER_RANGE_BOOT_ALLOCATED;
  929. }
  930. while (IopPortGetNextAlias(State->CurrentAlternative->Descriptor->Flags,
  931. alias,
  932. &alias)) {
  933. status = RtlIsRangeAvailable(
  934. Arbiter->PossibleAllocation,
  935. alias,
  936. alias + State->CurrentAlternative->Length - 1,
  937. State->CurrentAlternative->Flags & ARBITER_ALTERNATIVE_FLAG_SHARED ?
  938. RTL_RANGE_LIST_SHARED_OK : 0,
  939. userFlagsMask,
  940. Arbiter->ConflictCallbackContext,
  941. Arbiter->ConflictCallback,
  942. &aliasAvailable
  943. );
  944. ASSERT(NT_SUCCESS(status));
  945. if (!aliasAvailable) {
  946. ARBITER_ALLOCATION_STATE tempState;
  947. //
  948. // Check if we allow this conflict by calling OverrideConflict -
  949. // we will need to falsify ourselves an allocation state first
  950. //
  951. RtlCopyMemory(&tempState, State, sizeof(ARBITER_ALLOCATION_STATE));
  952. tempState.CurrentMinimum = alias;
  953. tempState.CurrentMaximum = alias + State->CurrentAlternative->Length - 1;
  954. if (Arbiter->OverrideConflict(Arbiter, &tempState)) {
  955. //
  956. // We decided this conflict was ok so contine checking the rest
  957. // of the aliases
  958. //
  959. continue;
  960. }
  961. //
  962. // An alias isn't available - get another possibility
  963. //
  964. ARB_PRINT(2,
  965. ("\t\tAlias 0x%x-0x%x not available\n",
  966. alias,
  967. alias + State->CurrentAlternative->Length - 1
  968. ));
  969. return FALSE;
  970. }
  971. }
  972. return TRUE;
  973. #endif
  974. }
  975. BOOLEAN
  976. IopMemFindSuitableRange(
  977. PARBITER_INSTANCE Arbiter,
  978. PARBITER_ALLOCATION_STATE State
  979. )
  980. /*++
  981. Routine Description:
  982. This routine is called from AllocateEntry once we have decided where we want
  983. to allocate from. It tries to find a free range that matches the
  984. requirements in State while restricting its possible solutions to the range
  985. State->Start to State->CurrentMaximum. On success State->Start and
  986. State->End represent this range. Conflicts between boot configs are allowed
  987. Arguments:
  988. Arbiter - The instance data of the arbiter who was called.
  989. State - The state of the current arbitration.
  990. Return Value:
  991. TRUE if we found a range, FALSE otherwise.
  992. --*/
  993. {
  994. //
  995. // If this was a boot config then consider other boot configs to be
  996. // available
  997. //
  998. if (State->Entry->Flags & ARBITER_FLAG_BOOT_CONFIG) {
  999. State->RangeAvailableAttributes |= ARBITER_RANGE_BOOT_ALLOCATED;
  1000. }
  1001. //
  1002. // Do the default thing
  1003. //
  1004. return ArbFindSuitableRange(Arbiter, State);
  1005. }