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.

1397 lines
35 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  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. if (NT_SUCCESS(status)) {
  248. ASSERT(minResourceType == maxResourceType);
  249. Target->Type = minResourceType;
  250. return STATUS_SUCCESS;
  251. }
  252. }
  253. //
  254. // If we couldn't translate both ends of the range then we want to skip this
  255. // range - set its type to CmResourceTypeNull
  256. //
  257. ASSERT (!NT_SUCCESS(status));
  258. Target->Type = CmResourceTypeNull;
  259. return STATUS_SUCCESS;
  260. }
  261. //
  262. // Implementation
  263. //
  264. NTSTATUS
  265. IopPortInitialize(
  266. VOID
  267. )
  268. /*++
  269. Routine Description:
  270. This routine initializes the arbiter
  271. Parameters:
  272. None
  273. Return Value:
  274. None
  275. --*/
  276. {
  277. PAGED_CODE();
  278. //
  279. // Fill in the non-default action handlers
  280. //
  281. IopRootPortArbiter.FindSuitableRange = IopPortFindSuitableRange;
  282. IopRootPortArbiter.AddAllocation = IopPortAddAllocation;
  283. IopRootPortArbiter.BacktrackAllocation = IopPortBacktrackAllocation;
  284. IopRootPortArbiter.UnpackRequirement = IopGenericUnpackRequirement;
  285. IopRootPortArbiter.PackResource = IopGenericPackResource;
  286. IopRootPortArbiter.UnpackResource = IopGenericUnpackResource;
  287. IopRootPortArbiter.ScoreRequirement = IopGenericScoreRequirement;
  288. return ArbInitializeArbiterInstance(&IopRootPortArbiter,
  289. NULL, // Indicates ROOT arbiter
  290. CmResourceTypePort,
  291. L"RootPort",
  292. L"Root",
  293. IopGenericTranslateOrdering
  294. );
  295. }
  296. NTSTATUS
  297. IopMemInitialize(
  298. VOID
  299. )
  300. /*++
  301. Routine Description:
  302. This routine initializes the arbiter
  303. Parameters:
  304. None
  305. Return Value:
  306. None
  307. --*/
  308. {
  309. NTSTATUS status;
  310. PAGED_CODE();
  311. IopRootMemArbiter.UnpackRequirement = IopGenericUnpackRequirement;
  312. IopRootMemArbiter.PackResource = IopGenericPackResource;
  313. IopRootMemArbiter.UnpackResource = IopGenericUnpackResource;
  314. IopRootMemArbiter.ScoreRequirement = IopGenericScoreRequirement;
  315. IopRootMemArbiter.FindSuitableRange = IopMemFindSuitableRange;
  316. status = ArbInitializeArbiterInstance(&IopRootMemArbiter,
  317. NULL, // Indicates ROOT arbiter
  318. CmResourceTypeMemory,
  319. L"RootMemory",
  320. L"Root",
  321. IopGenericTranslateOrdering
  322. );
  323. if (!NT_SUCCESS(status)) {
  324. return status;
  325. }
  326. //
  327. // Allocate the first page of physical memory as the firmware uses it and
  328. // doesn't report it as so Mm doesn't reuse it.
  329. //
  330. status = RtlAddRange(IopRootMemArbiter.Allocation,
  331. 0,
  332. PAGE_SIZE - 1,
  333. 0, // RangeAttributes
  334. 0, // Flags
  335. NULL,
  336. NULL
  337. );
  338. return status;
  339. }
  340. //
  341. // Arbiter callbacks
  342. //
  343. NTSTATUS
  344. IopGenericUnpackRequirement(
  345. IN PIO_RESOURCE_DESCRIPTOR Descriptor,
  346. OUT PULONGLONG Minimum,
  347. OUT PULONGLONG Maximum,
  348. OUT PULONG Length,
  349. OUT PULONG Alignment
  350. )
  351. /*++
  352. Routine Description:
  353. This routine unpacks an resource requirement descriptor.
  354. Arguments:
  355. Descriptor - The descriptor describing the requirement to unpack.
  356. Minimum - Pointer to where the minimum acceptable start value should be
  357. unpacked to.
  358. Maximum - Pointer to where the maximum acceptable end value should be
  359. unpacked to.
  360. Length - Pointer to where the required length should be unpacked to.
  361. Minimum - Pointer to where the required alignment should be unpacked to.
  362. Return Value:
  363. Returns the status of this operation.
  364. --*/
  365. {
  366. PAGED_CODE();
  367. ASSERT(Descriptor);
  368. ASSERT(Descriptor->Type == CmResourceTypePort
  369. || Descriptor->Type == CmResourceTypeMemory);
  370. *Minimum = (ULONGLONG) Descriptor->u.Generic.MinimumAddress.QuadPart;
  371. *Maximum = (ULONGLONG) Descriptor->u.Generic.MaximumAddress.QuadPart;
  372. *Length = Descriptor->u.Generic.Length;
  373. *Alignment = Descriptor->u.Generic.Alignment;
  374. //
  375. // Fix the broken hardware that reports 0 alignment
  376. //
  377. if (*Alignment == 0) {
  378. *Alignment = 1;
  379. }
  380. //
  381. // Fix broken INF's that report they support 24bit memory > 0xFFFFFF
  382. //
  383. if (Descriptor->Type == CmResourceTypeMemory
  384. && Descriptor->Flags & CM_RESOURCE_MEMORY_24
  385. && Descriptor->u.Memory.MaximumAddress.QuadPart > 0xFFFFFF) {
  386. *Maximum = 0xFFFFFF;
  387. }
  388. ARB_PRINT(2,
  389. ("Unpacking %s requirement %p => 0x%I64x-0x%I64x length 0x%x alignment 0x%x\n",
  390. Descriptor->Type == CmResourceTypePort ? "port" : "memory",
  391. Descriptor,
  392. *Minimum,
  393. *Maximum,
  394. *Length,
  395. *Alignment
  396. ));
  397. return STATUS_SUCCESS;
  398. }
  399. LONG
  400. IopGenericScoreRequirement(
  401. IN PIO_RESOURCE_DESCRIPTOR Descriptor
  402. )
  403. /*++
  404. Routine Description:
  405. This routine scores a requirement based on how flexible it is. The least
  406. flexible devices are scored the least and so when the arbitration list is
  407. sorted we try to allocate their resources first.
  408. Arguments:
  409. Descriptor - The descriptor describing the requirement to score.
  410. Return Value:
  411. The score.
  412. --*/
  413. {
  414. LONG score;
  415. ULONGLONG start, end;
  416. LONGLONG bigscore;
  417. ULONG alignment;
  418. PAGED_CODE();
  419. #define MAX_SCORE MAXLONG
  420. ASSERT(Descriptor);
  421. ASSERT((Descriptor->Type == CmResourceTypePort) ||
  422. (Descriptor->Type == CmResourceTypeMemory));
  423. alignment = Descriptor->u.Generic.Alignment;
  424. //
  425. // Fix the broken hardware that reports 0 alignment
  426. // Since this is not a PCI device, set the alignment to 1.
  427. //
  428. //
  429. if (alignment == 0) {
  430. alignment = 1;
  431. }
  432. start = ALIGN_ADDRESS_UP(
  433. Descriptor->u.Generic.MinimumAddress.QuadPart,
  434. alignment
  435. );
  436. end = Descriptor->u.Generic.MaximumAddress.QuadPart;
  437. //
  438. // The score is the number of possible allocations that could be made
  439. // given the alignment and length constraints
  440. //
  441. bigscore = (((end - Descriptor->u.Generic.Length + 1) - start)
  442. / alignment) + 1;
  443. score = (LONG)bigscore;
  444. if (bigscore < 0) {
  445. score = -1;
  446. } else if (bigscore > MAX_SCORE) {
  447. score = MAX_SCORE;
  448. }
  449. ARB_PRINT(2,
  450. ("Scoring port resource %p(0x%I64x-0x%I64x) => %i\n",
  451. Descriptor->Type == CmResourceTypePort ? "port" : "memory",
  452. Descriptor,
  453. Descriptor->u.Generic.MinimumAddress.QuadPart,
  454. end,
  455. score
  456. ));
  457. return score;
  458. }
  459. NTSTATUS
  460. IopGenericPackResource(
  461. IN PIO_RESOURCE_DESCRIPTOR Requirement,
  462. IN ULONGLONG Start,
  463. OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor
  464. )
  465. /*++
  466. Routine Description:
  467. This routine packs an resource descriptor.
  468. Arguments:
  469. Requirement - The requirement from which this resource was chosen.
  470. Start - The start value of the resource.
  471. Descriptor - Pointer to the descriptor to pack into.
  472. Return Value:
  473. Returns the status of this operation.
  474. --*/
  475. {
  476. PAGED_CODE();
  477. ASSERT(Descriptor);
  478. ASSERT(Requirement);
  479. ASSERT(Requirement->Type == CmResourceTypePort
  480. || Requirement->Type == CmResourceTypeMemory);
  481. Descriptor->Type = Requirement->Type;
  482. Descriptor->Flags = Requirement->Flags;
  483. Descriptor->ShareDisposition = Requirement->ShareDisposition;
  484. Descriptor->u.Generic.Start.QuadPart = Start;
  485. Descriptor->u.Generic.Length = Requirement->u.Generic.Length;
  486. ARB_PRINT(2,
  487. ("Packing %s resource %p => 0x%I64x length 0x%x\n",
  488. Descriptor->Type == CmResourceTypePort ? "port" : "memory",
  489. Descriptor,
  490. Descriptor->u.Port.Start.QuadPart,
  491. Descriptor->u.Port.Length
  492. ));
  493. return STATUS_SUCCESS;
  494. }
  495. NTSTATUS
  496. IopGenericUnpackResource(
  497. IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor,
  498. OUT PULONGLONG Start,
  499. OUT PULONG Length
  500. )
  501. /*++
  502. Routine Description:
  503. This routine unpacks an resource descriptor.
  504. Arguments:
  505. Descriptor - The descriptor describing the resource to unpack.
  506. Start - Pointer to where the start value should be unpacked to.
  507. Length - Pointer to where the length value should be unpacked to.
  508. Return Value:
  509. Returns the status of this operation.
  510. --*/
  511. {
  512. PAGED_CODE();
  513. ASSERT(Descriptor);
  514. ASSERT(Descriptor->Type == CmResourceTypePort
  515. || Descriptor->Type == CmResourceTypeMemory);
  516. *Start = Descriptor->u.Generic.Start.QuadPart;
  517. *Length = Descriptor->u.Generic.Length;
  518. ARB_PRINT(2,
  519. ("Unpacking %s resource %p => 0x%I64x Length 0x%x\n",
  520. Descriptor->Type == CmResourceTypePort ? "port" : "memory",
  521. Descriptor,
  522. *Start,
  523. *Length
  524. ));
  525. return STATUS_SUCCESS;
  526. }
  527. #if 0
  528. NTSTATUS
  529. IopPortRetestAllocation(
  530. IN PARBITER_INSTANCE Arbiter,
  531. IN OUT PLIST_ENTRY ArbitrationList
  532. )
  533. /*++
  534. Routine Description:
  535. This providesa port specific implementation of the RetestAllocation action
  536. which takes into account ISA aliases and adds them where appropriate.
  537. It walks the arbitration list and updates the possible allocation to reflect
  538. the allocation entries of the list. For these entries to be valid
  539. TestAllocation must have been performed on this arbitration list.
  540. Parameters:
  541. Arbiter - The arbiter instance data for the arbiter being called.
  542. ArbitrationList - A list of ARBITER_LIST_ENTRY entries which contain the
  543. requirements and associated devices. TestAllocation for this arbiter
  544. should have been called on this list.
  545. Return Value:
  546. Status code that indicates whether or not the function was successful.
  547. --*/
  548. {
  549. NTSTATUS status;
  550. PARBITER_LIST_ENTRY current;
  551. PIO_RESOURCE_DESCRIPTOR alternative;
  552. ULONGLONG start;
  553. ULONG length;
  554. PAGED_CODE();
  555. //
  556. // Copy the current allocation and reserved
  557. //
  558. ARB_PRINT(3, ("Retest: Copy current allocation\n"));
  559. status = RtlCopyRangeList(Arbiter->PossibleAllocation, Arbiter->Allocation);
  560. if (!NT_SUCCESS(status)) {
  561. goto cleanup;
  562. }
  563. //
  564. // Free all the resources currently allocated to all the devices we
  565. // are arbitrating for
  566. //
  567. FOR_ALL_IN_LIST(ARBITER_LIST_ENTRY, ArbitrationList, current) {
  568. ARB_PRINT(2, ("Retest: Delete 0x%08x's resources\n", current->PhysicalDeviceObject));
  569. status = RtlDeleteOwnersRanges(Arbiter->PossibleAllocation,
  570. (PVOID) current->PhysicalDeviceObject
  571. );
  572. if (!NT_SUCCESS(status)) {
  573. goto cleanup;
  574. }
  575. }
  576. //
  577. // Copy the previous allocation into the range list
  578. //
  579. FOR_ALL_IN_LIST(ARBITER_LIST_ENTRY, ArbitrationList, current) {
  580. ASSERT(current->Assignment);
  581. status = Arbiter->UnpackResource(current->Assignment,
  582. &start,
  583. &length
  584. );
  585. ASSERT(NT_SUCCESS(status));
  586. //
  587. // If we had a requirement for length 0 then that will be seen as
  588. // end == start - 1 here so don't attempt to add the range - it will
  589. // fail!
  590. //
  591. if (length != 0) {
  592. status = RtlAddRange(
  593. Arbiter->PossibleAllocation,
  594. start,
  595. start + length - 1,
  596. 0,
  597. RTL_RANGE_LIST_ADD_IF_CONFLICT +
  598. (current->Assignment->ShareDisposition == CmResourceShareShared ?
  599. RTL_RANGE_LIST_ADD_SHARED : 0),
  600. NULL,
  601. current->PhysicalDeviceObject
  602. );
  603. ASSERT(NT_SUCCESS(status));
  604. //
  605. // Retireve the alternative from which the assignment was chosen from
  606. // then
  607. //
  608. alternative = current->SelectedAlternative;
  609. //
  610. // Add the aliases
  611. //
  612. if (alternative->Flags & CM_RESOURCE_PORT_10_BIT_DECODE
  613. || alternative->Flags & CM_RESOURCE_PORT_12_BIT_DECODE) {
  614. ULONGLONG alias = start;
  615. BOOLEAN shared = current->Assignment->ShareDisposition ==
  616. CmResourceShareShared;
  617. ARB_PRINT(3, ("Adding aliases\n"));
  618. while (IopPortGetNextAlias(alternative->Flags,
  619. alias,
  620. &alias)) {
  621. status = RtlAddRange(
  622. Arbiter->PossibleAllocation,
  623. alias,
  624. alias + length - 1,
  625. ARBITER_RANGE_ALIAS,
  626. RTL_RANGE_LIST_ADD_IF_CONFLICT +
  627. (shared ? RTL_RANGE_LIST_SHARED_OK : 0),
  628. NULL,
  629. current->PhysicalDeviceObject
  630. );
  631. //
  632. // We have already checked if these ranges are available
  633. // so we should not fail...
  634. //
  635. ASSERT(NT_SUCCESS(status));
  636. }
  637. }
  638. }
  639. }
  640. return status;
  641. cleanup:
  642. RtlFreeRangeList(Arbiter->PossibleAllocation);
  643. return status;
  644. }
  645. #endif
  646. VOID
  647. IopPortBacktrackAllocation(
  648. IN PARBITER_INSTANCE Arbiter,
  649. IN PARBITER_ALLOCATION_STATE State
  650. )
  651. /*++
  652. Routine Description:
  653. This routine is called from AllocateEntry if the possible solution
  654. (State->Start - State->End) does not allow us to allocate resources to
  655. the rest of the devices being considered. It deletes the ranges that were
  656. added to Arbiter->PossibleAllocation by AddAllocation including those
  657. associated with ISA aliases.
  658. Arguments:
  659. Arbiter - The instance data of the arbiter who was called.
  660. State - The state of the current arbitration.
  661. Return Value:
  662. None.
  663. --*/
  664. {
  665. NTSTATUS status;
  666. ULONGLONG alias = State->Start;
  667. PAGED_CODE();
  668. //
  669. // Delete the aliases
  670. //
  671. ARB_PRINT(2, ("\t\tDeleting aliases\n"));
  672. while (IopPortGetNextAlias(State->CurrentAlternative->Flags,
  673. alias,
  674. &alias)) {
  675. status = RtlDeleteRange(
  676. Arbiter->PossibleAllocation,
  677. alias,
  678. alias + State->CurrentAlternative->Length - 1,
  679. State->Entry->PhysicalDeviceObject
  680. );
  681. //
  682. // We should not fail...
  683. //
  684. ASSERT(NT_SUCCESS(status));
  685. }
  686. //
  687. // Now call the original function to delete the base range
  688. //
  689. ArbBacktrackAllocation(Arbiter, State);
  690. }
  691. BOOLEAN
  692. IopPortFindSuitableRange(
  693. PARBITER_INSTANCE Arbiter,
  694. PARBITER_ALLOCATION_STATE State
  695. )
  696. /*++
  697. Routine Description:
  698. This routine is called from AllocateEntry once we have decided where we want
  699. to allocate from. It tries to find a free range that matches the
  700. requirements in State while restricting its possible solutions to the range
  701. State->Start to State->CurrentMaximum. On success State->Start and
  702. State->End represent this range. Conflicts with ISA aliases are considered.
  703. Arguments:
  704. Arbiter - The instance data of the arbiter who was called.
  705. State - The state of the current arbitration.
  706. Return Value:
  707. TRUE if we found a range, FALSE otherwise.
  708. --*/
  709. {
  710. NTSTATUS status;
  711. UCHAR userFlagsMask = 0;
  712. PAGED_CODE();
  713. //
  714. // If we are asking for zero ports then trivially succeed with the minimum
  715. // value
  716. //
  717. if (State->CurrentAlternative->Length == 0) {
  718. State->End = State->Start;
  719. return TRUE;
  720. }
  721. //
  722. // For legacy requests from IoAssignResources (directly or by way of
  723. // HalAssignSlotResources) or IoReportResourceUsage we consider preallocated
  724. // resources to be available for backward compatibility reasons.
  725. //
  726. // If we are allocating a devices boot config then we consider all other
  727. // boot configs to be available.
  728. //
  729. if (State->Entry->RequestSource == ArbiterRequestLegacyReported
  730. || State->Entry->RequestSource == ArbiterRequestLegacyAssigned
  731. || State->Entry->Flags & ARBITER_FLAG_BOOT_CONFIG) {
  732. userFlagsMask = ARBITER_RANGE_BOOT_ALLOCATED;
  733. }
  734. //
  735. // Try to satisfy the request
  736. //
  737. while (State->CurrentMinimum <= State->CurrentMaximum) {
  738. //
  739. // Select the first free alternative from the current alternative
  740. //
  741. status = RtlFindRange(
  742. Arbiter->PossibleAllocation,
  743. State->CurrentMinimum,
  744. State->CurrentMaximum,
  745. State->CurrentAlternative->Length,
  746. State->CurrentAlternative->Alignment,
  747. State->CurrentAlternative->Flags &
  748. ARBITER_ALTERNATIVE_FLAG_SHARED ?
  749. RTL_RANGE_LIST_SHARED_OK : 0,
  750. userFlagsMask,
  751. Arbiter->ConflictCallbackContext,
  752. Arbiter->ConflictCallback,
  753. &State->Start
  754. );
  755. //
  756. // Did we find a range and if not can we override any conflict
  757. //
  758. if (NT_SUCCESS(status)
  759. || Arbiter->OverrideConflict(Arbiter, State)) {
  760. State->End = State->Start + State->CurrentAlternative->Length - 1;
  761. //
  762. // Check if the aliases are available
  763. //
  764. if (IopPortIsAliasedRangeAvailable(Arbiter, State)) {
  765. //
  766. // We found a suitable range so return
  767. //
  768. return TRUE;
  769. } else {
  770. //
  771. // This range's aliases arn't available so try the next range
  772. //
  773. State->Start += State->CurrentAlternative->Length;
  774. continue;
  775. }
  776. } else {
  777. //
  778. // We couldn't find a base range
  779. //
  780. break;
  781. }
  782. }
  783. return FALSE;
  784. }
  785. BOOLEAN
  786. IopPortGetNextAlias(
  787. ULONG IoDescriptorFlags,
  788. ULONGLONG LastAlias,
  789. PULONGLONG NextAlias
  790. )
  791. /*++
  792. Routine Description:
  793. This routine calculates the next alias of an IO port up to MAX_ALIAS_PORT.
  794. Arguments:
  795. IoDescriptorFlags - The flags from the requirement descriptor indicating the
  796. type of alias if any.
  797. LastAlias - The alias previous to this one.
  798. NextAlias - Point to where the next alias should be returned
  799. Return Value:
  800. TRUE if we found an alias, FALSE otherwise.
  801. --*/
  802. {
  803. ULONGLONG next;
  804. PAGED_CODE();
  805. if (IoDescriptorFlags & CM_RESOURCE_PORT_10_BIT_DECODE) {
  806. next = LastAlias + (((ULONGLONG)1) << 10);
  807. } else if (IoDescriptorFlags & CM_RESOURCE_PORT_12_BIT_DECODE) {
  808. next = LastAlias + (((ULONGLONG)1) << 12);
  809. } else {
  810. //
  811. // There are no aliases
  812. //
  813. return FALSE;
  814. }
  815. //
  816. // Check that we are below the maximum aliased port
  817. //
  818. if (next > MAX_ALIAS_PORT) {
  819. return FALSE;
  820. } else {
  821. *NextAlias = next;
  822. return TRUE;
  823. }
  824. }
  825. VOID
  826. IopPortAddAllocation(
  827. IN PARBITER_INSTANCE Arbiter,
  828. IN PARBITER_ALLOCATION_STATE State
  829. )
  830. /*++
  831. Routine Description:
  832. This routine is called from AllocateEntry once we have found a possible
  833. solution (State->Start - State->End). It adds the ranges that will not be
  834. available if we commit to this solution to Arbiter->PossibleAllocation.
  835. Arguments:
  836. Arbiter - The instance data of the arbiter who was called.
  837. State - The state of the current arbitration.
  838. Return Value:
  839. None.
  840. --*/
  841. {
  842. NTSTATUS status;
  843. ULONGLONG alias;
  844. PAGED_CODE();
  845. ASSERT(Arbiter);
  846. ASSERT(State);
  847. status = RtlAddRange(Arbiter->PossibleAllocation,
  848. State->Start,
  849. State->End,
  850. State->RangeAttributes,
  851. RTL_RANGE_LIST_ADD_IF_CONFLICT +
  852. (State->CurrentAlternative->Flags & ARBITER_ALTERNATIVE_FLAG_SHARED
  853. ? RTL_RANGE_LIST_ADD_SHARED : 0),
  854. NULL,
  855. State->Entry->PhysicalDeviceObject
  856. );
  857. ASSERT(NT_SUCCESS(status));
  858. //
  859. // Add any aliases
  860. //
  861. alias = State->Start;
  862. ARB_PRINT(2, ("Adding aliases\n"));
  863. while (IopPortGetNextAlias(State->CurrentAlternative->Descriptor->Flags,
  864. alias,
  865. &alias)) {
  866. status = RtlAddRange(Arbiter->PossibleAllocation,
  867. alias,
  868. alias + State->CurrentAlternative->Length - 1,
  869. (UCHAR) (State->RangeAttributes | ARBITER_RANGE_ALIAS),
  870. RTL_RANGE_LIST_ADD_IF_CONFLICT +
  871. (State->CurrentAlternative->Flags & ARBITER_ALTERNATIVE_FLAG_SHARED
  872. ? RTL_RANGE_LIST_ADD_SHARED : 0),
  873. NULL,
  874. State->Entry->PhysicalDeviceObject
  875. );
  876. //
  877. // We have already checked if these ranges are available
  878. // so we should not fail...
  879. //
  880. ASSERT(NT_SUCCESS(status));
  881. }
  882. }
  883. BOOLEAN
  884. IopPortIsAliasedRangeAvailable(
  885. PARBITER_INSTANCE Arbiter,
  886. PARBITER_ALLOCATION_STATE State
  887. )
  888. /*++
  889. Routine Description:
  890. This routine determines if the range (Start-(Length-1)) is available taking
  891. into account any aliases.
  892. Arguments:
  893. Arbiter - The instance data of the arbiter who was called.
  894. State - The state of the current arbitration.
  895. Return Value:
  896. TRUE if the range is available, FALSE otherwise.
  897. --*/
  898. {
  899. //
  900. // NTRAID #61146-2000/03/31-andrewth Root IO arbiter don't deal with aliases
  901. //
  902. // This is only an issue on machines where the root arbiters are called upon
  903. // to arbitrated aliased ranges - this means a pure ISA machine with no PCI.
  904. // I hope we won't support these soon and the root arbiters can be made a
  905. // lot worse.
  906. //
  907. #if defined(BUGFEST_HACKS)
  908. UNREFERENCED_PARAMETER( Arbiter );
  909. UNREFERENCED_PARAMETER( State );
  910. PAGED_CODE();
  911. //
  912. // For the purposes of the Bug^H^H^HPlugFest don't mind is aliases conflict
  913. // with any devices but still add them...
  914. //
  915. return TRUE;
  916. #else
  917. NTSTATUS status;
  918. ULONGLONG alias = State->Start;
  919. BOOLEAN aliasAvailable;
  920. UCHAR userFlagsMask = 0;
  921. PAGED_CODE();
  922. //
  923. // For legacy requests from IoAssignResources (directly or by way of
  924. // HalAssignSlotResources) or IoReportResourceUsage we consider preallocated
  925. // resources to be available for backward compatibility reasons.
  926. //
  927. if (State->Entry->RequestSource == ArbiterRequestLegacyReported
  928. || State->Entry->RequestSource == ArbiterRequestLegacyAssigned) {
  929. userFlagsMask |= ARBITER_RANGE_BOOT_ALLOCATED;
  930. }
  931. while (IopPortGetNextAlias(State->CurrentAlternative->Descriptor->Flags,
  932. alias,
  933. &alias)) {
  934. status = RtlIsRangeAvailable(
  935. Arbiter->PossibleAllocation,
  936. alias,
  937. alias + State->CurrentAlternative->Length - 1,
  938. State->CurrentAlternative->Flags & ARBITER_ALTERNATIVE_FLAG_SHARED ?
  939. RTL_RANGE_LIST_SHARED_OK : 0,
  940. userFlagsMask,
  941. Arbiter->ConflictCallbackContext,
  942. Arbiter->ConflictCallback,
  943. &aliasAvailable
  944. );
  945. ASSERT(NT_SUCCESS(status));
  946. if (!aliasAvailable) {
  947. ARBITER_ALLOCATION_STATE tempState;
  948. //
  949. // Check if we allow this conflict by calling OverrideConflict -
  950. // we will need to falsify ourselves an allocation state first
  951. //
  952. RtlCopyMemory(&tempState, State, sizeof(ARBITER_ALLOCATION_STATE));
  953. tempState.CurrentMinimum = alias;
  954. tempState.CurrentMaximum = alias + State->CurrentAlternative->Length - 1;
  955. if (Arbiter->OverrideConflict(Arbiter, &tempState)) {
  956. //
  957. // We decided this conflict was ok so contine checking the rest
  958. // of the aliases
  959. //
  960. continue;
  961. }
  962. //
  963. // An alias isn't available - get another possibility
  964. //
  965. ARB_PRINT(2,
  966. ("\t\tAlias 0x%x-0x%x not available\n",
  967. alias,
  968. alias + State->CurrentAlternative->Length - 1
  969. ));
  970. return FALSE;
  971. }
  972. }
  973. return TRUE;
  974. #endif
  975. }
  976. BOOLEAN
  977. IopMemFindSuitableRange(
  978. PARBITER_INSTANCE Arbiter,
  979. PARBITER_ALLOCATION_STATE State
  980. )
  981. /*++
  982. Routine Description:
  983. This routine is called from AllocateEntry once we have decided where we want
  984. to allocate from. It tries to find a free range that matches the
  985. requirements in State while restricting its possible solutions to the range
  986. State->Start to State->CurrentMaximum. On success State->Start and
  987. State->End represent this range. Conflicts between boot configs are allowed
  988. Arguments:
  989. Arbiter - The instance data of the arbiter who was called.
  990. State - The state of the current arbitration.
  991. Return Value:
  992. TRUE if we found a range, FALSE otherwise.
  993. --*/
  994. {
  995. //
  996. // If this was a boot config then consider other boot configs to be
  997. // available
  998. //
  999. if (State->Entry->Flags & ARBITER_FLAG_BOOT_CONFIG) {
  1000. State->RangeAvailableAttributes |= ARBITER_RANGE_BOOT_ALLOCATED;
  1001. }
  1002. //
  1003. // Do the default thing
  1004. //
  1005. return ArbFindSuitableRange(Arbiter, State);
  1006. }