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.

1302 lines
36 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. mpsysbus.c
  5. Abstract:
  6. Author:
  7. Environment:
  8. Revision History:
  9. --*/
  10. #include "halp.h"
  11. #include "pci.h"
  12. #include "apic.inc"
  13. #include "pcmp_nt.inc"
  14. ULONG HalpDefaultInterruptAffinity = 0;
  15. #ifndef ACPI_HAL
  16. ULONG
  17. HalpGetEisaInterruptVector(
  18. IN PBUS_HANDLER BusHandler,
  19. IN PBUS_HANDLER RootHandler,
  20. IN ULONG BusInterruptLevel,
  21. IN ULONG BusInterruptVector,
  22. OUT PKIRQL Irql,
  23. OUT PKAFFINITY Affinity
  24. );
  25. #else
  26. #undef HalpGetEisaInterruptVector
  27. #define HalpGetEisaInterruptVector HalpGetSystemInterruptVector
  28. extern BUS_HANDLER HalpFakePciBusHandler;
  29. #endif
  30. extern UCHAR HalpVectorToIRQL[];
  31. extern UCHAR HalpIRQLtoTPR[];
  32. extern USHORT HalpVectorToINTI[];
  33. extern KSPIN_LOCK HalpAccountingLock;
  34. extern struct HalpMpInfo HalpMpInfoTable;
  35. extern UCHAR HalpMaxProcsPerCluster;
  36. extern INTERRUPT_DEST HalpIntDestMap[];
  37. ULONG HalpINTItoVector[MAX_INTI];
  38. UCHAR HalpPICINTToVector[16];
  39. extern ULONG HalpMaxNode;
  40. extern KAFFINITY HalpNodeAffinity[MAX_NODES];
  41. UCHAR HalpNodeBucket[MAX_NODES];
  42. #ifdef ALLOC_PRAGMA
  43. #pragma alloc_text(PAGELK,HalpGetSystemInterruptVector)
  44. #pragma alloc_text(PAGE, HalIrqTranslateResourceRequirementsRoot)
  45. #pragma alloc_text(PAGE, HalTranslatorReference)
  46. #pragma alloc_text(PAGE, HalTranslatorDereference)
  47. #endif
  48. BOOLEAN
  49. HalpFindBusAddressTranslation(
  50. IN PHYSICAL_ADDRESS BusAddress,
  51. IN OUT PULONG AddressSpace,
  52. OUT PPHYSICAL_ADDRESS TranslatedAddress,
  53. IN OUT PULONG_PTR Context,
  54. IN BOOLEAN NextBus
  55. )
  56. /*++
  57. Routine Description:
  58. This routine performs a very similar function to HalTranslateBusAddress
  59. except that InterfaceType and BusNumber are not known by the caller.
  60. This function will walk all busses known by the HAL looking for a
  61. valid translation for the input BusAddress of type AddressSpace.
  62. This function is recallable using the input/output Context parameter.
  63. On the first call to this routine for a given translation the ULONG_PTR
  64. Context should be NULL. Note: Not the address of it but the contents.
  65. If the caller decides the returned translation is not the desired
  66. translation, it calls this routine again passing Context in as it
  67. was returned on the previous call. This allows this routine to
  68. traverse the bus structures until the correct translation is found
  69. and is provided because on multiple bus systems, it is possible for
  70. the same resource to exist in the independent address spaces of
  71. multiple busses.
  72. Arguments:
  73. BusAddress Address to be translated.
  74. AddressSpace 0 = Memory
  75. 1 = IO (There are other possibilities).
  76. N.B. This argument is a pointer, the value
  77. will be modified if the translated address
  78. is of a different address space type from
  79. the untranslated bus address.
  80. TranslatedAddress Pointer to where the translated address
  81. should be stored.
  82. Context Pointer to a ULONG_PTR. On the initial call,
  83. for a given BusAddress, it should contain
  84. 0. It will be modified by this routine,
  85. on subsequent calls for the same BusAddress
  86. the value should be handed in again,
  87. unmodified by the caller.
  88. NextBus FALSE if we should attempt this translation
  89. on the same bus as indicated by Context,
  90. TRUE if we should be looking for another
  91. bus.
  92. Return Value:
  93. TRUE if translation was successful,
  94. FALSE otherwise.
  95. --*/
  96. {
  97. //
  98. // First, make sure the context parameter was supplied and is
  99. // being used correctly. This also ensures that the caller
  100. // doesn't get stuck in a loop looking for subsequent translations
  101. // for the same thing. We won't succeed the same translation twice
  102. // unless the caller reinits the context.
  103. //
  104. if ((!Context) || (*Context && (NextBus == TRUE))) {
  105. return FALSE;
  106. }
  107. *Context = 1;
  108. //
  109. // PC/AT (halx86) case is simplest, there is no translation.
  110. //
  111. *TranslatedAddress = BusAddress;
  112. return TRUE;
  113. }
  114. BOOLEAN
  115. HalpTranslateSystemBusAddress(
  116. IN PBUS_HANDLER BusHandler,
  117. IN PBUS_HANDLER RootHandler,
  118. IN PHYSICAL_ADDRESS BusAddress,
  119. IN OUT PULONG AddressSpace,
  120. OUT PPHYSICAL_ADDRESS TranslatedAddress
  121. )
  122. /*++
  123. Routine Description:
  124. This function translates a bus-relative address space and address into
  125. a system physical address.
  126. Arguments:
  127. BusAddress - Supplies the bus-relative address
  128. AddressSpace - Supplies the address space number.
  129. Returns the host address space number.
  130. AddressSpace == 0 => memory space
  131. AddressSpace == 1 => I/O space
  132. TranslatedAddress - Supplies a pointer to return the translated address
  133. Return Value:
  134. A return value of TRUE indicates that a system physical address
  135. corresponding to the supplied bus relative address and bus address
  136. number has been returned in TranslatedAddress.
  137. A return value of FALSE occurs if the translation for the address was
  138. not possible
  139. --*/
  140. {
  141. BOOLEAN status;
  142. PSUPPORTED_RANGE pRange;
  143. status = FALSE;
  144. switch (*AddressSpace) {
  145. case 0:
  146. if (BusHandler->InterfaceType != PCIBus) {
  147. // verify memory address is within buses memory limits
  148. pRange = &BusHandler->BusAddresses->Memory;
  149. while (!status && pRange) {
  150. status = BusAddress.QuadPart >= pRange->Base &&
  151. BusAddress.QuadPart <= pRange->Limit;
  152. pRange = pRange->Next;
  153. }
  154. pRange = &BusHandler->BusAddresses->PrefetchMemory;
  155. while (!status && pRange) {
  156. status = BusAddress.QuadPart >= pRange->Base &&
  157. BusAddress.QuadPart <= pRange->Limit;
  158. pRange = pRange->Next;
  159. }
  160. } else {
  161. //
  162. // This is a PCI bus and SystemBase is constant for all ranges
  163. //
  164. pRange = &BusHandler->BusAddresses->Memory;
  165. status = TRUE;
  166. }
  167. break;
  168. case 1:
  169. if (BusHandler->InterfaceType != PCIBus) {
  170. // verify IO address is within buses IO limits
  171. pRange = &BusHandler->BusAddresses->IO;
  172. while (!status && pRange) {
  173. status = BusAddress.QuadPart >= pRange->Base &&
  174. BusAddress.QuadPart <= pRange->Limit;
  175. pRange = pRange->Next;
  176. }
  177. } else {
  178. //
  179. // This is a PCI bus and SystemBase is constant for all ranges
  180. //
  181. pRange = &BusHandler->BusAddresses->IO;
  182. status = TRUE;
  183. }
  184. break;
  185. default:
  186. status = FALSE;
  187. break;
  188. }
  189. if (status) {
  190. *TranslatedAddress = BusAddress;
  191. }
  192. #if !defined(_WIN64)
  193. else {
  194. _asm { nop }; // good for debugging
  195. }
  196. #endif
  197. return status;
  198. }
  199. #define MAX_SYSTEM_IRQL 31
  200. #define MAX_FREE_IRQL 26
  201. #define MIN_FREE_IRQL 4
  202. #define MAX_FREE_IDTENTRY 0xbf
  203. #define MIN_FREE_IDTENTRY 0x51
  204. #define IDTENTRY_BASE 0x50
  205. #define MAX_VBUCKET 7
  206. #define AllocateVectorIn(index) \
  207. vBucket[index]++; \
  208. ASSERT (vBucket[index] < 16);
  209. #define GetIDTEntryFrom(index) \
  210. (UCHAR) ( index*16 + IDTENTRY_BASE + vBucket[index] )
  211. // note: device levels 50,60,70,80,90,A0,B0 are not allocatable
  212. #define GetIrqlFrom(index) (KIRQL) ( index + MIN_FREE_IRQL )
  213. UCHAR nPriority[MAX_NODES][MAX_VBUCKET];
  214. ULONG
  215. HalpGetSystemInterruptVector (
  216. IN PBUS_HANDLER BusHandler,
  217. IN PBUS_HANDLER RootHandler,
  218. IN ULONG InterruptLevel,
  219. IN ULONG InterruptVector,
  220. OUT PKIRQL Irql,
  221. OUT PKAFFINITY Affinity
  222. )
  223. /*++
  224. Routine Description:
  225. This function returns the system interrupt vector and IRQL
  226. corresponding to the specified bus interrupt level and/or
  227. vector. The system interrupt vector and IRQL are suitable
  228. for use in a subsequent call to KeInitializeInterrupt.
  229. Arguments:
  230. InterruptLevel - Supplies the bus specific interrupt level.
  231. InterruptVector - Supplies the bus specific interrupt vector.
  232. Irql - Returns the system request priority.
  233. Affinity - Returns the system wide irq affinity.
  234. Return Value:
  235. Returns the system interrupt vector corresponding to the specified device.
  236. --*/
  237. {
  238. ULONG SystemVector;
  239. USHORT ApicInti;
  240. UCHAR IDTEntry;
  241. ULONG Bucket, i, OldLevel;
  242. BOOLEAN Found;
  243. PVOID LockHandle;
  244. ULONG Node;
  245. PUCHAR vBucket;
  246. UNREFERENCED_PARAMETER( InterruptVector );
  247. //
  248. // TODO: Remove when Affinity becomes IN OUT.
  249. *Affinity = ~0;
  250. //
  251. // Restrict Affinity if required.
  252. if (HalpMaxProcsPerCluster == 0) {
  253. *Affinity &= HalpDefaultInterruptAffinity;
  254. }
  255. //
  256. // Find closest child bus to this handler
  257. //
  258. if (RootHandler != BusHandler) {
  259. while (RootHandler->ParentHandler != BusHandler) {
  260. RootHandler = RootHandler->ParentHandler;
  261. }
  262. }
  263. //
  264. // Find Interrupt's APIC Inti connection
  265. //
  266. Found = HalpGetApicInterruptDesc (
  267. RootHandler->InterfaceType,
  268. RootHandler->BusNumber,
  269. InterruptLevel,
  270. &ApicInti
  271. );
  272. if (!Found) {
  273. return 0;
  274. }
  275. //
  276. // If device interrupt vector mapping is not already allocated,
  277. // then do it now
  278. //
  279. if (!HalpINTItoVector[ApicInti]) {
  280. //
  281. // Vector is not allocated - synchronize and check again
  282. //
  283. LockHandle = MmLockPagableCodeSection (&HalpGetSystemInterruptVector);
  284. OldLevel = HalpAcquireHighLevelLock (&HalpAccountingLock);
  285. if (!HalpINTItoVector[ApicInti]) {
  286. //
  287. // Still not allocated
  288. //
  289. //
  290. // Pick a node. In the future, Affinity will be INOUT and
  291. // we will have to screen the node against the input affinity.
  292. if (HalpMaxNode == 1) {
  293. Node = 1;
  294. } else {
  295. //
  296. // Find a node that meets the affinity requirements.
  297. // Nodes are numbered 1..n, so 0 means we are done.
  298. for (i = HalpMaxNode; i; i--) {
  299. if ((*Affinity & HalpNodeAffinity[i-1]) == 0)
  300. continue;
  301. Node = i;
  302. break;
  303. }
  304. ASSERT(Node != 0);
  305. //
  306. // Look for a "less busy" alternative.
  307. for (i = Node-1; i; i--) {
  308. //
  309. // Check input Affinity to see if this node is permitted.
  310. if ((*Affinity & HalpNodeAffinity[i-1]) == 0)
  311. continue;
  312. //
  313. // Take the least busy of the permitted nodes.
  314. if (HalpNodeBucket[i-1] < HalpNodeBucket[Node-1]) {
  315. Node = i;
  316. }
  317. }
  318. }
  319. HalpNodeBucket[Node-1]++;
  320. *Affinity = HalpNodeAffinity[Node-1];
  321. vBucket = nPriority[Node-1];
  322. //
  323. // Choose the least busy priority on the node.
  324. Bucket = MAX_VBUCKET-1;
  325. for (i = Bucket-1; i; i--) {
  326. if (vBucket[i] < vBucket[Bucket]) {
  327. Bucket = i;
  328. }
  329. }
  330. AllocateVectorIn (Bucket);
  331. //
  332. // Now form the vector for the kernel.
  333. IDTEntry = GetIDTEntryFrom (Bucket);
  334. SystemVector = HalpVector(Node, IDTEntry);
  335. ASSERT(IDTEntry <= MAX_FREE_IDTENTRY);
  336. ASSERT(IDTEntry >= MIN_FREE_IDTENTRY);
  337. #if defined(_AMD64_)
  338. *Irql = (KIRQL)(IDTEntry >> 4);
  339. #else
  340. *Irql = GetIrqlFrom (Bucket);
  341. #endif
  342. ASSERT(*Irql <= MAX_FREE_IRQL);
  343. #if !defined(_WIN64)
  344. ASSERT((UCHAR) (HalpIRQLtoTPR[*Irql] & 0xf0) == (UCHAR) (IDTEntry & 0xf0) );
  345. #endif
  346. HalpVectorToIRQL[IDTEntry >> 4] = (UCHAR) *Irql;
  347. HalpVectorToINTI[SystemVector] = (USHORT) ApicInti;
  348. HalpINTItoVector[ApicInti] = SystemVector;
  349. //
  350. // If this assigned interrupt is connected to the machines PIC,
  351. // then remember the PIC->SystemVector mapping.
  352. //
  353. if (RootHandler->BusNumber == 0 && InterruptLevel < 16 &&
  354. RootHandler->InterfaceType == DEFAULT_PC_BUS) {
  355. HalpPICINTToVector[InterruptLevel] = (UCHAR) SystemVector;
  356. }
  357. }
  358. HalpReleaseHighLevelLock (&HalpAccountingLock, OldLevel);
  359. MmUnlockPagableImageSection (LockHandle);
  360. }
  361. //
  362. // Return this ApicInti's system vector & irql
  363. //
  364. SystemVector = HalpINTItoVector[ApicInti];
  365. *Irql = HalpVectorToIRQL[HalVectorToIDTEntry(SystemVector) >> 4];
  366. ASSERT(HalpVectorToINTI[SystemVector] == (USHORT) ApicInti);
  367. //
  368. // Find an appropriate affinity.
  369. //
  370. Node = HalpVectorToNode(SystemVector);
  371. *Affinity &= HalpNodeAffinity[Node-1];
  372. if (!*Affinity) {
  373. return 0;
  374. }
  375. return SystemVector;
  376. }
  377. VOID
  378. HalpSetInternalVector (
  379. IN ULONG InternalVector,
  380. IN PHAL_INTERRUPT_SERVICE_ROUTINE HalInterruptServiceRoutine,
  381. IN PVOID Context,
  382. IN KIRQL Irql
  383. )
  384. /*++
  385. Routine Description:
  386. Used at init time to set IDT vectors for internal use.
  387. --*/
  388. {
  389. //
  390. // Remember this vector so it's reported as Hal internal usage
  391. //
  392. // HalpRegisterVector (
  393. // InternalUsage,
  394. // InternalVector,
  395. // InternalVector,
  396. // HalpVectorToIRQL[InternalVector >> 4]
  397. // );
  398. //
  399. // Connect the IDT
  400. //
  401. KiSetHandlerAddressToIDTIrql(InternalVector,
  402. HalInterruptServiceRoutine,
  403. Context,
  404. Irql);
  405. }
  406. //
  407. // This section implements a "translator," which is the PnP-WDM way
  408. // of doing the same thing that the first part of this file does.
  409. //
  410. VOID
  411. HalTranslatorReference(
  412. PVOID Context
  413. )
  414. {
  415. return;
  416. }
  417. VOID
  418. HalTranslatorDereference(
  419. PVOID Context
  420. )
  421. {
  422. return;
  423. }
  424. NTSTATUS
  425. HalIrqTranslateResourcesRoot(
  426. IN PVOID Context,
  427. IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Source,
  428. IN RESOURCE_TRANSLATION_DIRECTION Direction,
  429. IN ULONG AlternativesCount, OPTIONAL
  430. IN IO_RESOURCE_DESCRIPTOR Alternatives[], OPTIONAL
  431. IN PDEVICE_OBJECT PhysicalDeviceObject,
  432. OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR Target
  433. )
  434. /*++
  435. Routine Description:
  436. This function takes a CM_PARTIAL_RESOURCE_DESCRIPTOR and translates
  437. it to an IO-bus-relative from a Processor-bus-relative form, or the other
  438. way around. In this x86-specific example, an IO-bus-relative form is the
  439. ISA IRQ and the Processor-bus-relative form is the IDT entry and the
  440. associated IRQL.
  441. N.B. This funtion has an associated "Direction." These are not exactly
  442. reciprocals. This has to be the case because the output from
  443. HalIrqTranslateResourceRequirementsRoot will be used as the input
  444. for the ParentToChild case.
  445. ChildToParent:
  446. Level (ISA IRQ) -> IRQL
  447. Vector (ISA IRQ) -> x86 IDT entry
  448. Affinity (not refereced)-> KAFFINITY
  449. ParentToChild:
  450. Level (not referenced) -> (ISA IRQ)
  451. Vector (IDT entry) -> (ISA IRQ)
  452. Affinity -> 0xffffffff
  453. Arguments:
  454. Context - unused
  455. Source - descriptor that we are translating
  456. Direction - direction of translation (parent to child or child to parent)
  457. AlternativesCount - unused
  458. Alternatives - unused
  459. PhysicalDeviceObject- unused
  460. Target - translated descriptor
  461. Return Value:
  462. status
  463. --*/
  464. {
  465. NTSTATUS status = STATUS_SUCCESS;
  466. PBUS_HANDLER bus;
  467. KAFFINITY affinity;
  468. KIRQL irql;
  469. ULONG vector;
  470. USHORT inti;
  471. #ifdef ACPI_HAL
  472. BUS_HANDLER fakeIsaBus;
  473. #endif
  474. PAGED_CODE();
  475. UNREFERENCED_PARAMETER(AlternativesCount);
  476. UNREFERENCED_PARAMETER(Alternatives);
  477. UNREFERENCED_PARAMETER(PhysicalDeviceObject);
  478. ASSERT(Source->Type == CmResourceTypeInterrupt);
  479. switch (Direction) {
  480. case TranslateChildToParent:
  481. #ifdef ACPI_HAL
  482. RtlCopyMemory(&fakeIsaBus, &HalpFakePciBusHandler, sizeof(BUS_HANDLER));
  483. fakeIsaBus.InterfaceType = Isa;
  484. fakeIsaBus.ParentHandler = &fakeIsaBus;
  485. bus = &fakeIsaBus;
  486. #else
  487. if ((INTERFACE_TYPE)Context == InterfaceTypeUndefined) { // special "IDE" cookie
  488. ASSERT(Source->u.Interrupt.Level == Source->u.Interrupt.Vector);
  489. bus = HalpFindIdeBus(Source->u.Interrupt.Vector);
  490. } else {
  491. bus = HaliHandlerForBus((INTERFACE_TYPE)Context, 0);
  492. }
  493. if (!bus) {
  494. return STATUS_NOT_FOUND;
  495. }
  496. #endif
  497. //
  498. // Copy everything
  499. //
  500. *Target = *Source;
  501. //
  502. // Translate the IRQ
  503. //
  504. vector = HalpGetEisaInterruptVector(bus,
  505. bus,
  506. Source->u.Interrupt.Level,
  507. Source->u.Interrupt.Vector,
  508. &irql,
  509. &affinity);
  510. if (vector == 0) {
  511. return STATUS_UNSUCCESSFUL;
  512. }
  513. Target->u.Interrupt.Level = irql;
  514. Target->u.Interrupt.Vector = vector;
  515. Target->u.Interrupt.Affinity = affinity;
  516. if (NT_SUCCESS(status)) {
  517. status = STATUS_TRANSLATION_COMPLETE;
  518. }
  519. break;
  520. case TranslateParentToChild:
  521. //
  522. // Copy everything
  523. //
  524. *Target = *Source;
  525. //
  526. // There is no inverse to HalpGetSystemInterruptVector, so we
  527. // just do what that function would do.
  528. //
  529. inti = HalpVectorToINTI[Source->u.Interrupt.Vector];
  530. Target->u.Interrupt.Level = Target->u.Interrupt.Vector =
  531. HalpInti2BusInterruptLevel(inti);
  532. Target->u.Interrupt.Affinity = 0xFFFFFFFF;
  533. status = STATUS_SUCCESS;
  534. break;
  535. default:
  536. status = STATUS_INVALID_PARAMETER;
  537. }
  538. return status;
  539. }
  540. NTSTATUS
  541. HalIrqTranslateResourceRequirementsRoot(
  542. IN PVOID Context,
  543. IN PIO_RESOURCE_DESCRIPTOR Source,
  544. IN PDEVICE_OBJECT PhysicalDeviceObject,
  545. OUT PULONG TargetCount,
  546. OUT PIO_RESOURCE_DESCRIPTOR *Target
  547. )
  548. /*++
  549. Routine Description:
  550. This function takes an IO_RESOURCE_DESCRIPTOR and translates
  551. it from an IO-bus-relative to a Processor-bus-relative form. In this
  552. x86-specific example, an IO-bus-relative form is the ISA IRQ and the
  553. Processor-bus-relative form is the IDT entry and the associated IRQL.
  554. This is essentially a PnP form of HalGetInterruptVector.
  555. Arguments:
  556. Context - unused
  557. Source - descriptor that we are translating
  558. PhysicalDeviceObject- unused
  559. TargetCount - 1
  560. Target - translated descriptor
  561. Return Value:
  562. status
  563. --*/
  564. {
  565. PBUS_HANDLER bus;
  566. KAFFINITY affinity;
  567. KIRQL irql;
  568. ULONG vector;
  569. BOOLEAN success = TRUE;
  570. #ifdef ACPI_HAL
  571. BUS_HANDLER fakeIsaBus;
  572. #endif
  573. PAGED_CODE();
  574. ASSERT(Source->Type == CmResourceTypeInterrupt);
  575. #ifdef ACPI_HAL
  576. RtlCopyMemory(&fakeIsaBus, &HalpFakePciBusHandler, sizeof(BUS_HANDLER));
  577. fakeIsaBus.InterfaceType = Isa;
  578. fakeIsaBus.ParentHandler = &fakeIsaBus;
  579. bus = &fakeIsaBus;
  580. #else
  581. if ((INTERFACE_TYPE)Context == InterfaceTypeUndefined) { // special "IDE" cookie
  582. ASSERT(Source->u.Interrupt.MinimumVector == Source->u.Interrupt.MaximumVector);
  583. bus = HalpFindIdeBus(Source->u.Interrupt.MinimumVector);
  584. } else {
  585. bus = HaliHandlerForBus((INTERFACE_TYPE)Context, 0);
  586. }
  587. if (!bus) {
  588. //
  589. // There is no valid translation.
  590. //
  591. *TargetCount = 0;
  592. return STATUS_TRANSLATION_COMPLETE;
  593. }
  594. #endif
  595. //
  596. // The interrupt requirements were obtained by calling HalAdjustResourceList
  597. // so we don't need to call it again.
  598. //
  599. *Target = ExAllocatePoolWithTag(PagedPool,
  600. sizeof(IO_RESOURCE_DESCRIPTOR),
  601. HAL_POOL_TAG
  602. );
  603. if (!*Target) {
  604. return STATUS_INSUFFICIENT_RESOURCES;
  605. }
  606. *TargetCount = 1;
  607. //
  608. // Copy the requirement unchanged
  609. //
  610. **Target = *Source;
  611. //
  612. // Perform the translation of the minimum & maximum
  613. //
  614. vector = HalpGetEisaInterruptVector(bus,
  615. bus,
  616. Source->u.Interrupt.MinimumVector,
  617. Source->u.Interrupt.MinimumVector,
  618. &irql,
  619. &affinity);
  620. if (!vector) {
  621. success = FALSE;
  622. }
  623. (*Target)->u.Interrupt.MinimumVector = vector;
  624. vector = HalpGetEisaInterruptVector(bus,
  625. bus,
  626. Source->u.Interrupt.MaximumVector,
  627. Source->u.Interrupt.MaximumVector,
  628. &irql,
  629. &affinity);
  630. if (!vector) {
  631. success = FALSE;
  632. }
  633. (*Target)->u.Interrupt.MaximumVector = vector;
  634. if (!success) {
  635. ExFreePool(*Target);
  636. *TargetCount = 0;
  637. }
  638. return STATUS_TRANSLATION_COMPLETE;
  639. }
  640. #if 0
  641. // HALMPS doesn't provide this function. It is left here as documentation
  642. // for HALs which must provide translation.
  643. NTSTATUS
  644. HalpTransMemIoResourceRequirement(
  645. IN PVOID Context,
  646. IN PIO_RESOURCE_DESCRIPTOR Source,
  647. IN PDEVICE_OBJECT PhysicalDeviceObject,
  648. OUT PULONG TargetCount,
  649. OUT PIO_RESOURCE_DESCRIPTOR *Target
  650. )
  651. /*++
  652. Routine Description:
  653. This routine translates memory and IO resource requirements.
  654. Parameters:
  655. Context - The context from the TRANSLATOR_INTERFACE
  656. Source - The interrupt requirement to translate
  657. PhysicalDeviceObject - The device requesting the resource
  658. TargetCount - Pointer to where to return the number of descriptors this
  659. requirement translates into
  660. Target - Pointer to where a pointer to a callee allocated buffer containing
  661. the translated descriptors should be placed.
  662. Return Value:
  663. STATUS_SUCCESS or an error status
  664. Note:
  665. We do not perform any translation.
  666. --*/
  667. {
  668. ASSERT(Source);
  669. ASSERT(Target);
  670. ASSERT(TargetCount);
  671. ASSERT(Source->Type == CmResourceTypeMemory ||
  672. Source->Type == CmResourceTypePort);
  673. //
  674. // Allocate space for the target
  675. //
  676. *Target = ExAllocatePoolWithTag(PagedPool,
  677. sizeof(IO_RESOURCE_DESCRIPTOR),
  678. HAL_POOL_TAG
  679. );
  680. if (!*Target) {
  681. return STATUS_INSUFFICIENT_RESOURCES;
  682. }
  683. //
  684. // Copy the source to target and update the fields that have changed
  685. //
  686. **Target = *Source;
  687. *TargetCount = 1;
  688. return STATUS_SUCCESS;
  689. }
  690. NTSTATUS
  691. HalpTransMemIoResource(
  692. IN PVOID Context,
  693. IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Source,
  694. IN RESOURCE_TRANSLATION_DIRECTION Direction,
  695. IN ULONG AlternativesCount, OPTIONAL
  696. IN IO_RESOURCE_DESCRIPTOR Alternatives[], OPTIONAL
  697. IN PDEVICE_OBJECT PhysicalDeviceObject,
  698. OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR Target
  699. )
  700. /*++
  701. Routine Description:
  702. This routine translates memory and IO resources. On generic x86
  703. machines, such as those that use this HAL, there isn't actually
  704. any translation.
  705. Parameters:
  706. Context - The context from the TRANSLATOR_INTERFACE
  707. Source - The interrupt resource to translate
  708. Direction - The direction in relation to the Pnp device tree translation
  709. should occur in.
  710. AlternativesCount - The number of alternatives this resource was selected
  711. from.
  712. Alternatives - Array of alternatives this resource was selected from.
  713. PhysicalDeviceObject - The device requesting the resource
  714. Target - Pointer to a caller allocated buffer to hold the translted resource
  715. descriptor.
  716. Return Value:
  717. STATUS_SUCCESS or an error status
  718. --*/
  719. {
  720. NTSTATUS status;
  721. //
  722. // Copy the target to the source
  723. //
  724. *Target = *Source;
  725. switch (Direction) {
  726. case TranslateChildToParent:
  727. //
  728. // Make sure PnP knows it doesn't have to walk up the tree
  729. // translating at each point.
  730. //
  731. status = STATUS_TRANSLATION_COMPLETE;
  732. break;
  733. case TranslateParentToChild:
  734. //
  735. // We do not translate requirements so do nothing...
  736. //
  737. status = STATUS_SUCCESS;
  738. break;
  739. default:
  740. status = STATUS_INVALID_PARAMETER;
  741. }
  742. return status;
  743. }
  744. #endif
  745. NTSTATUS
  746. HaliGetInterruptTranslator(
  747. IN INTERFACE_TYPE ParentInterfaceType,
  748. IN ULONG ParentBusNumber,
  749. IN INTERFACE_TYPE BridgeInterfaceType,
  750. IN USHORT Size,
  751. IN USHORT Version,
  752. OUT PTRANSLATOR_INTERFACE Translator,
  753. IN OUT PULONG BridgeBusNumber
  754. )
  755. /*++
  756. Routine Description:
  757. Arguments:
  758. ParentInterfaceType - The type of the bus the bridge lives on (normally PCI).
  759. ParentBusNumber - The number of the bus the bridge lives on.
  760. BridgeInterfaceType - The bus type the bridge provides (ie ISA for a PCI-ISA bridge).
  761. ResourceType - The resource type we want to translate.
  762. Size - The size of the translator buffer.
  763. Version - The version of the translator interface requested.
  764. Translator - Pointer to the buffer where the translator should be returned
  765. BridgeBusNumber - Pointer the bus number of the bus that the bridge represents
  766. Return Value:
  767. Returns the status of this operation.
  768. --*/
  769. #define BRIDGE_HEADER_BUFFER_SIZE (FIELD_OFFSET(PCI_COMMON_CONFIG, u.type1.SubordinateBus) + 1)
  770. #define USE_INT_LINE_REGISTER_TOKEN 0xffffffff
  771. #define DEFAULT_BRIDGE_TRANSLATOR 0x80000000
  772. {
  773. PAGED_CODE();
  774. ASSERT(Version == HAL_IRQ_TRANSLATOR_VERSION);
  775. ASSERT(Size >= sizeof(TRANSLATOR_INTERFACE));
  776. //
  777. // Fill in the common bits.
  778. //
  779. RtlZeroMemory(Translator, sizeof(TRANSLATOR_INTERFACE));
  780. Translator->Size = sizeof(TRANSLATOR_INTERFACE);
  781. Translator->Version = HAL_IRQ_TRANSLATOR_VERSION;
  782. Translator->Context = (PVOID)BridgeInterfaceType;
  783. Translator->InterfaceReference = HalTranslatorReference;
  784. Translator->InterfaceDereference = HalTranslatorDereference;
  785. switch (BridgeInterfaceType) {
  786. case Eisa:
  787. case Isa:
  788. case InterfaceTypeUndefined: // special "IDE" cookie
  789. //
  790. // Set IRQ translator for (E)ISA interrupts.
  791. //
  792. Translator->TranslateResources = HalIrqTranslateResourcesIsa;
  793. Translator->TranslateResourceRequirements =
  794. HalIrqTranslateResourceRequirementsIsa;
  795. return STATUS_SUCCESS;
  796. case MicroChannel:
  797. //
  798. // Set IRQ translator for MCA interrupts.
  799. //
  800. Translator->TranslateResources = HalIrqTranslateResourcesRoot;
  801. Translator->TranslateResourceRequirements =
  802. HalIrqTranslateResourceRequirementsRoot;
  803. return STATUS_SUCCESS;
  804. case PCIBus:
  805. #ifndef ACPI_HAL
  806. //
  807. // Set of of two IRQ translators for PCI busses.
  808. //
  809. {
  810. UCHAR mpsBusNumber = 0;
  811. UCHAR pciBusNumber, parentPci, childPci;
  812. PCI_SLOT_NUMBER bridgeSlot;
  813. PCI_COMMON_CONFIG pciData;
  814. ULONG bytesRead, d, f, possibleContext;
  815. BOOLEAN describedByMps;
  816. NTSTATUS status;
  817. Translator->TranslateResources = HalpIrqTranslateResourcesPci;
  818. Translator->TranslateResourceRequirements =
  819. HalpIrqTranslateRequirementsPci;
  820. //
  821. // Look for this bus in the MPS tables.
  822. //
  823. status = HalpPci2MpsBusNumber((UCHAR)*BridgeBusNumber,
  824. &mpsBusNumber);
  825. if (NT_SUCCESS(status)) {
  826. //
  827. // This bus has corresponding entries for its PCI
  828. // devices in the MPS tables. So eject the translator
  829. // that understands them.
  830. //
  831. if (HalpInterruptsDescribedByMpsTable(mpsBusNumber)) {
  832. Translator->Context = (PVOID)mpsBusNumber;
  833. return STATUS_SUCCESS;
  834. }
  835. }
  836. //
  837. // Do a quick check to see if we can avoid searching PCI
  838. // configuration space for a bridge. This code is really
  839. // redundant, but it's worth trying to avoid touching
  840. // PCI space.
  841. //
  842. if (ParentInterfaceType != PCIBus) {
  843. //
  844. // This was a PCI bus that doesn't contain
  845. // mappings for PCI devices.
  846. //
  847. Translator->TranslateResources =
  848. HalpIrqTranslateResourcesPci;
  849. Translator->TranslateResourceRequirements =
  850. HalpIrqTranslateRequirementsPci;
  851. Translator->Context = (PVOID)USE_INT_LINE_REGISTER_TOKEN;
  852. return STATUS_SUCCESS;
  853. }
  854. //
  855. // We didn't find this PCI bus in the MPS tables. So there
  856. // are two cases.
  857. //
  858. // 1) This matters, because the parent bus is fully described
  859. // in the MPS tables and we need to do translations on
  860. // the vector as it passes through the bridges.
  861. //
  862. // 2) This doesn't matter, because the parent busses, while
  863. // they may be in the MPS tables, they don't have any
  864. // of their interrupts described. So we just use the
  865. // interrupt line register anyhow.
  866. //
  867. // At this point we need to find the PCI bridge that
  868. // generates this bus, either because we will eventually
  869. // need to know the slot number to fill in the context, or
  870. // because we will need to know the primary bus number to
  871. // look up the tree.
  872. //
  873. parentPci = (UCHAR)ParentBusNumber;
  874. childPci = (UCHAR)(*BridgeBusNumber);
  875. while (TRUE) {
  876. //
  877. // Find the bridge.
  878. //
  879. bridgeSlot.u.AsULONG = 0;
  880. for (d = 0; d < PCI_MAX_DEVICES; d++) {
  881. for (f = 0; f < PCI_MAX_FUNCTION; f++) {
  882. bridgeSlot.u.bits.DeviceNumber = d;
  883. bridgeSlot.u.bits.FunctionNumber = f;
  884. bytesRead = HalGetBusDataByOffset(PCIConfiguration,
  885. parentPci,
  886. bridgeSlot.u.AsULONG,
  887. &pciData,
  888. 0,
  889. BRIDGE_HEADER_BUFFER_SIZE);
  890. if (bytesRead == (ULONG)BRIDGE_HEADER_BUFFER_SIZE) {
  891. if ((pciData.VendorID != PCI_INVALID_VENDORID) &&
  892. (PCI_CONFIGURATION_TYPE((&pciData)) != PCI_DEVICE_TYPE)) {
  893. //
  894. // This is a bridge of some sort.
  895. //
  896. if (pciData.u.type1.SecondaryBus == childPci) {
  897. //
  898. // And it is the bridge we are looking for.
  899. // Store information about
  900. //
  901. if (childPci == *BridgeBusNumber) {
  902. //
  903. // It is also the bridge that creates the
  904. // PCI bus that the translator is describing.
  905. //
  906. // N.B. This should only happen the first time
  907. // we search through a bus. (i.e. the first
  908. // trip through the outer while loop)
  909. //
  910. possibleContext = ((bridgeSlot.u.AsULONG & 0xffff) |
  911. (ParentBusNumber << 16));
  912. }
  913. goto HGITFoundBridge1;
  914. }
  915. }
  916. }
  917. }
  918. }
  919. //
  920. // No bridge found.
  921. //
  922. if (parentPci == 0) {
  923. return STATUS_NOT_FOUND;
  924. }
  925. parentPci--;
  926. continue;
  927. HGITFoundBridge1:
  928. status = HalpPci2MpsBusNumber(parentPci, &mpsBusNumber);
  929. if (NT_SUCCESS(status)) {
  930. if (HalpInterruptsDescribedByMpsTable(mpsBusNumber)) {
  931. //
  932. // Case 1 above.
  933. //
  934. Translator->TranslateResources = HalIrqTranslateResourcesPciBridge;
  935. Translator->TranslateResourceRequirements =
  936. HalIrqTranslateRequirementsPciBridge;
  937. Translator->Context = (PVOID)possibleContext;
  938. return STATUS_SUCCESS;
  939. }
  940. if (HalpMpsBusIsRootBus(mpsBusNumber)) {
  941. Translator->TranslateResources =
  942. HalpIrqTranslateResourcesPci;
  943. Translator->TranslateResourceRequirements =
  944. HalpIrqTranslateRequirementsPci;
  945. Translator->Context = (PVOID)USE_INT_LINE_REGISTER_TOKEN;
  946. return STATUS_SUCCESS;
  947. }
  948. }
  949. //
  950. // Try again one bus higher.
  951. //
  952. childPci = parentPci;
  953. parentPci--;
  954. }
  955. }
  956. #endif
  957. break;
  958. }
  959. //
  960. // If we got here, we don't have an interface.
  961. //
  962. return STATUS_NOT_IMPLEMENTED;
  963. }