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.

812 lines
20 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. ixsysbus.c
  5. Abstract:
  6. Author:
  7. Environment:
  8. Revision History:
  9. --*/
  10. #include "halp.h"
  11. #ifdef WANT_IRQ_ROUTING
  12. #include "ixpciir.h"
  13. #endif
  14. KAFFINITY HalpDefaultInterruptAffinity;
  15. #ifdef ALLOC_PRAGMA
  16. #pragma alloc_text(PAGE,HalpGetSystemInterruptVector)
  17. #pragma alloc_text(PAGE,HalTranslatorReference)
  18. #pragma alloc_text(PAGE,HalTranslatorDereference)
  19. #pragma alloc_text(PAGE,HalIrqTranslateResourcesRoot)
  20. #pragma alloc_text(PAGE,HalIrqTranslateResourceRequirementsRoot)
  21. #pragma alloc_text(PAGE,HalpTransMemIoResource)
  22. #pragma alloc_text(PAGE,HalpTransMemIoResourceRequirement)
  23. #pragma alloc_text(PAGE,HaliGetInterruptTranslator)
  24. #endif
  25. BOOLEAN
  26. HalpFindBusAddressTranslation(
  27. IN PHYSICAL_ADDRESS BusAddress,
  28. IN OUT PULONG AddressSpace,
  29. OUT PPHYSICAL_ADDRESS TranslatedAddress,
  30. IN OUT PULONG_PTR Context,
  31. IN BOOLEAN NextBus
  32. )
  33. /*++
  34. Routine Description:
  35. This routine performs a very similar function to HalTranslateBusAddress
  36. except that InterfaceType and BusNumber are not known by the caller.
  37. This function will walk all busses known by the HAL looking for a
  38. valid translation for the input BusAddress of type AddressSpace.
  39. This function is recallable using the input/output Context parameter.
  40. On the first call to this routine for a given translation the ULONG_PTR
  41. Context should be NULL. Note: Not the address of it but the contents.
  42. If the caller decides the returned translation is not the desired
  43. translation, it calls this routine again passing Context in as it
  44. was returned on the previous call. This allows this routine to
  45. traverse the bus structures until the correct translation is found
  46. and is provided because on multiple bus systems, it is possible for
  47. the same resource to exist in the independent address spaces of
  48. multiple busses.
  49. Arguments:
  50. BusAddress Address to be translated.
  51. AddressSpace 0 = Memory
  52. 1 = IO (There are other possibilities).
  53. N.B. This argument is a pointer, the value
  54. will be modified if the translated address
  55. is of a different address space type from
  56. the untranslated bus address.
  57. TranslatedAddress Pointer to where the translated address
  58. should be stored.
  59. Context Pointer to a ULONG_PTR. On the initial call,
  60. for a given BusAddress, it should contain
  61. 0. It will be modified by this routine,
  62. on subsequent calls for the same BusAddress
  63. the value should be handed in again,
  64. unmodified by the caller.
  65. NextBus FALSE if we should attempt this translation
  66. on the same bus as indicated by Context,
  67. TRUE if we should be looking for another
  68. bus.
  69. Return Value:
  70. TRUE if translation was successful,
  71. FALSE otherwise.
  72. --*/
  73. {
  74. //
  75. // First, make sure the context parameter was supplied and is
  76. // being used correctly. This also ensures that the caller
  77. // doesn't get stuck in a loop looking for subsequent translations
  78. // for the same thing. We won't succeed the same translation twice
  79. // unless the caller reinits the context.
  80. //
  81. if ((!Context) || (*Context && (NextBus == TRUE))) {
  82. return FALSE;
  83. }
  84. *Context = 1;
  85. //
  86. // PC/AT (halx86) case is simplest, there is no translation.
  87. //
  88. *TranslatedAddress = BusAddress;
  89. return TRUE;
  90. }
  91. BOOLEAN
  92. HalpTranslateSystemBusAddress(
  93. IN PBUS_HANDLER BusHandler,
  94. IN PBUS_HANDLER RootHandler,
  95. IN PHYSICAL_ADDRESS BusAddress,
  96. IN OUT PULONG AddressSpace,
  97. OUT PPHYSICAL_ADDRESS TranslatedAddress
  98. )
  99. /*++
  100. Routine Description:
  101. This function translates a bus-relative address space and address into
  102. a system physical address.
  103. Arguments:
  104. BusAddress - Supplies the bus-relative address
  105. AddressSpace - Supplies the address space number.
  106. Returns the host address space number.
  107. AddressSpace == 0 => memory space
  108. AddressSpace == 1 => I/O space
  109. TranslatedAddress - Supplies a pointer to return the translated address
  110. Return Value:
  111. A return value of TRUE indicates that a system physical address
  112. corresponding to the supplied bus relative address and bus address
  113. number has been returned in TranslatedAddress.
  114. A return value of FALSE occurs if the translation for the address was
  115. not possible
  116. --*/
  117. {
  118. PSUPPORTED_RANGE pRange;
  119. pRange = NULL;
  120. //
  121. // If this fails, it means someone has given us a RESOURCE_TYPE with some decode type flags
  122. // set. We should probably handle this.
  123. //
  124. ASSERT (*AddressSpace == 0 ||
  125. *AddressSpace == 1);
  126. //
  127. // The checking of bus ranges for PCI busses is performed by the PCI driver
  128. // in NT5 (or Windows 2000 or whatever its called) so only check for none
  129. // PCI busses.
  130. //
  131. switch (*AddressSpace) {
  132. case 0:
  133. if (BusHandler->InterfaceType != PCIBus) {
  134. // verify memory address is within buses memory limits
  135. for (pRange = &BusHandler->BusAddresses->PrefetchMemory; pRange; pRange = pRange->Next) {
  136. if (BusAddress.QuadPart >= pRange->Base &&
  137. BusAddress.QuadPart <= pRange->Limit) {
  138. break;
  139. }
  140. }
  141. if (!pRange) {
  142. for (pRange = &BusHandler->BusAddresses->Memory; pRange; pRange = pRange->Next) {
  143. if (BusAddress.QuadPart >= pRange->Base &&
  144. BusAddress.QuadPart <= pRange->Limit) {
  145. break;
  146. }
  147. }
  148. }
  149. } else {
  150. //
  151. // This is a PCI bus and SystemBase is constant for all ranges
  152. //
  153. pRange = &BusHandler->BusAddresses->Memory;
  154. }
  155. break;
  156. case 1:
  157. if (BusHandler->InterfaceType != PCIBus) {
  158. // verify IO address is within buses IO limits
  159. for (pRange = &BusHandler->BusAddresses->IO; pRange; pRange = pRange->Next) {
  160. if (BusAddress.QuadPart >= pRange->Base &&
  161. BusAddress.QuadPart <= pRange->Limit) {
  162. break;
  163. }
  164. }
  165. break;
  166. } else {
  167. //
  168. // This is a PCI bus and SystemBase is constant for all ranges
  169. //
  170. pRange = &BusHandler->BusAddresses->IO;
  171. }
  172. }
  173. if (pRange) {
  174. TranslatedAddress->QuadPart = BusAddress.QuadPart + pRange->SystemBase;
  175. *AddressSpace = pRange->SystemAddressSpace;
  176. return TRUE;
  177. }
  178. return FALSE;
  179. }
  180. ULONG
  181. HalpGetRootInterruptVector(
  182. IN ULONG InterruptLevel,
  183. IN ULONG InterruptVector,
  184. OUT PKIRQL Irql,
  185. OUT PKAFFINITY Affinity
  186. )
  187. {
  188. ULONG SystemVector;
  189. UNREFERENCED_PARAMETER( InterruptLevel );
  190. SystemVector = InterruptLevel + PRIMARY_VECTOR_BASE;
  191. if ((SystemVector < PRIMARY_VECTOR_BASE) ||
  192. (SystemVector > PRIMARY_VECTOR_BASE + HIGHEST_LEVEL_FOR_8259) ) {
  193. //
  194. // This is an illegal BusInterruptVector and cannot be connected.
  195. //
  196. return(0);
  197. }
  198. *Irql = (KIRQL)(HIGHEST_LEVEL_FOR_8259 + PRIMARY_VECTOR_BASE - SystemVector);
  199. *Affinity = HalpDefaultInterruptAffinity;
  200. ASSERT(HalpDefaultInterruptAffinity);
  201. return SystemVector;
  202. }
  203. ULONG
  204. HalpGetSystemInterruptVector(
  205. IN PBUS_HANDLER BusHandler,
  206. IN PBUS_HANDLER RootHandler,
  207. IN ULONG BusInterruptLevel,
  208. IN ULONG BusInterruptVector,
  209. OUT PKIRQL Irql,
  210. OUT PKAFFINITY Affinity
  211. )
  212. /*++
  213. Routine Description:
  214. Arguments:
  215. BusInterruptLevel - Supplies the bus specific interrupt level.
  216. BusInterruptVector - Supplies the bus specific interrupt vector.
  217. Irql - Returns the system request priority.
  218. Affinity - Returns the system wide irq affinity.
  219. Return Value:
  220. Returns the system interrupt vector corresponding to the specified device.
  221. --*/
  222. {
  223. ULONG SystemVector;
  224. UNREFERENCED_PARAMETER( BusHandler );
  225. UNREFERENCED_PARAMETER( RootHandler );
  226. SystemVector = HalpGetRootInterruptVector(BusInterruptLevel,
  227. BusInterruptVector,
  228. Irql,
  229. Affinity);
  230. if (HalpIDTUsageFlags[SystemVector].Flags & IDTOwned ) {
  231. //
  232. // This is an illegal BusInterruptVector and cannot be connected.
  233. //
  234. return(0);
  235. }
  236. return SystemVector;
  237. }
  238. //
  239. // This section implements a "translator," which is the PnP-WDM way
  240. // of doing the same thing that the first part of this file does.
  241. //
  242. VOID
  243. HalTranslatorReference(
  244. PVOID Context
  245. )
  246. {
  247. return;
  248. }
  249. VOID
  250. HalTranslatorDereference(
  251. PVOID Context
  252. )
  253. {
  254. return;
  255. }
  256. NTSTATUS
  257. HalIrqTranslateResourcesRoot(
  258. IN PVOID Context,
  259. IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Source,
  260. IN RESOURCE_TRANSLATION_DIRECTION Direction,
  261. IN ULONG AlternativesCount, OPTIONAL
  262. IN IO_RESOURCE_DESCRIPTOR Alternatives[], OPTIONAL
  263. IN PDEVICE_OBJECT PhysicalDeviceObject,
  264. OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR Target
  265. )
  266. /*++
  267. Routine Description:
  268. This function takes a CM_PARTIAL_RESOURCE_DESCRIPTOR and translates
  269. it to an IO-bus-relative from a Processor-bus-relative form, or the other
  270. way around. In this x86-specific example, an IO-bus-relative form is the
  271. ISA IRQ and the Processor-bus-relative form is the IDT entry and the
  272. associated IRQL.
  273. N.B. This funtion has an associated "Direction." These are not exactly
  274. reciprocals. This has to be the case because the output from
  275. HalIrqTranslateResourceRequirementsRoot will be used as the input
  276. for the ParentToChild case.
  277. ChildToParent:
  278. Level (ISA IRQ) -> IRQL
  279. Vector (ISA IRQ) -> x86 IDT entry
  280. Affinity (not refereced)-> KAFFINITY
  281. ParentToChild:
  282. Level (not referenced) -> (ISA IRQ)
  283. Vector (IDT entry) -> (ISA IRQ)
  284. Affinity -> 0xffffffff
  285. Arguments:
  286. Context - unused
  287. Source - descriptor that we are translating
  288. Direction - direction of translation (parent to child or child to parent)
  289. AlternativesCount - unused
  290. Alternatives - unused
  291. PhysicalDeviceObject- unused
  292. Target - translated descriptor
  293. Return Value:
  294. status
  295. --*/
  296. {
  297. NTSTATUS status = STATUS_UNSUCCESSFUL;
  298. KAFFINITY affinity;
  299. KIRQL irql;
  300. ULONG vector;
  301. UNREFERENCED_PARAMETER(AlternativesCount);
  302. UNREFERENCED_PARAMETER(Alternatives);
  303. UNREFERENCED_PARAMETER(PhysicalDeviceObject);
  304. PAGED_CODE();
  305. ASSERT(Source->Type == CmResourceTypeInterrupt);
  306. //
  307. // Copy everything
  308. //
  309. *Target = *Source;
  310. switch (Direction) {
  311. case TranslateChildToParent:
  312. //
  313. // Translate the IRQ
  314. //
  315. vector = HalpGetRootInterruptVector(Source->u.Interrupt.Level,
  316. Source->u.Interrupt.Vector,
  317. &irql,
  318. &affinity);
  319. if (vector != 0) {
  320. Target->u.Interrupt.Level = irql;
  321. Target->u.Interrupt.Vector = vector;
  322. Target->u.Interrupt.Affinity = affinity;
  323. status = STATUS_TRANSLATION_COMPLETE;
  324. }
  325. break;
  326. case TranslateParentToChild:
  327. //
  328. // There is no inverse to HalpGetSystemInterruptVector, so we
  329. // just do what that function would do.
  330. //
  331. Target->u.Interrupt.Level = Target->u.Interrupt.Vector =
  332. Source->u.Interrupt.Vector - PRIMARY_VECTOR_BASE;
  333. Target->u.Interrupt.Affinity = 0xFFFFFFFF;
  334. status = STATUS_SUCCESS;
  335. break;
  336. default:
  337. status = STATUS_INVALID_PARAMETER;
  338. }
  339. return status;
  340. }
  341. NTSTATUS
  342. HalIrqTranslateResourceRequirementsRoot(
  343. IN PVOID Context,
  344. IN PIO_RESOURCE_DESCRIPTOR Source,
  345. IN PDEVICE_OBJECT PhysicalDeviceObject,
  346. OUT PULONG TargetCount,
  347. OUT PIO_RESOURCE_DESCRIPTOR *Target
  348. )
  349. /*++
  350. Routine Description:
  351. This function takes an IO_RESOURCE_DESCRIPTOR and translates
  352. it from an IO-bus-relative to a Processor-bus-relative form. In this
  353. x86-specific example, an IO-bus-relative form is the ISA IRQ and the
  354. Processor-bus-relative form is the IDT entry and the associated IRQL.
  355. This is essentially a PnP form of HalGetInterruptVector.
  356. Arguments:
  357. Context - unused
  358. Source - descriptor that we are translating
  359. PhysicalDeviceObject- unused
  360. TargetCount - 1
  361. Target - translated descriptor
  362. Return Value:
  363. status
  364. --*/
  365. {
  366. KAFFINITY affinity;
  367. KIRQL irql;
  368. ULONG vector;
  369. PAGED_CODE();
  370. ASSERT(Source->Type == CmResourceTypeInterrupt);
  371. //
  372. // The interrupt requirements were obtained by calling HalAdjustResourceList
  373. // so we don't need to call it again.
  374. //
  375. *Target = ExAllocatePoolWithTag(PagedPool,
  376. sizeof(IO_RESOURCE_DESCRIPTOR),
  377. HAL_POOL_TAG
  378. );
  379. if (!*Target) {
  380. return STATUS_INSUFFICIENT_RESOURCES;
  381. }
  382. *TargetCount = 1;
  383. //
  384. // Copy the requirement unchanged
  385. //
  386. **Target = *Source;
  387. //
  388. // Perform the translation of the minimum & maximum
  389. //
  390. vector = HalpGetRootInterruptVector(Source->u.Interrupt.MinimumVector,
  391. Source->u.Interrupt.MinimumVector,
  392. &irql,
  393. &affinity);
  394. (*Target)->u.Interrupt.MinimumVector = vector;
  395. vector = HalpGetRootInterruptVector(Source->u.Interrupt.MaximumVector,
  396. Source->u.Interrupt.MaximumVector,
  397. &irql,
  398. &affinity);
  399. (*Target)->u.Interrupt.MaximumVector = vector;
  400. return STATUS_TRANSLATION_COMPLETE;
  401. }
  402. NTSTATUS
  403. HalpTransMemIoResourceRequirement(
  404. IN PVOID Context,
  405. IN PIO_RESOURCE_DESCRIPTOR Source,
  406. IN PDEVICE_OBJECT PhysicalDeviceObject,
  407. OUT PULONG TargetCount,
  408. OUT PIO_RESOURCE_DESCRIPTOR *Target
  409. )
  410. /*++
  411. Routine Description:
  412. This routine translates memory and IO resource requirements.
  413. Parameters:
  414. Context - The context from the TRANSLATOR_INTERFACE
  415. Source - The interrupt requirement to translate
  416. PhysicalDeviceObject - The device requesting the resource
  417. TargetCount - Pointer to where to return the number of descriptors this
  418. requirement translates into
  419. Target - Pointer to where a pointer to a callee allocated buffer containing
  420. the translated descriptors should be placed.
  421. Return Value:
  422. STATUS_SUCCESS or an error status
  423. Note:
  424. We do not perform any translation.
  425. --*/
  426. {
  427. ASSERT(Source);
  428. ASSERT(Target);
  429. ASSERT(TargetCount);
  430. ASSERT(Source->Type == CmResourceTypeMemory ||
  431. Source->Type == CmResourceTypePort);
  432. //
  433. // Allocate space for the target
  434. //
  435. *Target = ExAllocatePoolWithTag(PagedPool,
  436. sizeof(IO_RESOURCE_DESCRIPTOR),
  437. HAL_POOL_TAG
  438. );
  439. if (!*Target) {
  440. return STATUS_INSUFFICIENT_RESOURCES;
  441. }
  442. //
  443. // Copy the source to target and update the fields that have changed
  444. //
  445. **Target = *Source;
  446. *TargetCount = 1;
  447. return STATUS_SUCCESS;
  448. }
  449. NTSTATUS
  450. HalpTransMemIoResource(
  451. IN PVOID Context,
  452. IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Source,
  453. IN RESOURCE_TRANSLATION_DIRECTION Direction,
  454. IN ULONG AlternativesCount, OPTIONAL
  455. IN IO_RESOURCE_DESCRIPTOR Alternatives[], OPTIONAL
  456. IN PDEVICE_OBJECT PhysicalDeviceObject,
  457. OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR Target
  458. )
  459. /*++
  460. Routine Description:
  461. This routine translates memory and IO resources. On generic x86
  462. machines, such as those that use this HAL, there isn't actually
  463. any translation.
  464. Parameters:
  465. Context - The context from the TRANSLATOR_INTERFACE
  466. Source - The interrupt resource to translate
  467. Direction - The direction in relation to the Pnp device tree translation
  468. should occur in.
  469. AlternativesCount - The number of alternatives this resource was selected
  470. from.
  471. Alternatives - Array of alternatives this resource was selected from.
  472. PhysicalDeviceObject - The device requesting the resource
  473. Target - Pointer to a caller allocated buffer to hold the translted resource
  474. descriptor.
  475. Return Value:
  476. STATUS_SUCCESS or an error status
  477. --*/
  478. {
  479. NTSTATUS status;
  480. //
  481. // Copy the target to the source
  482. //
  483. *Target = *Source;
  484. switch (Direction) {
  485. case TranslateChildToParent:
  486. //
  487. // Make sure PnP knows it doesn't have to walk up the tree
  488. // translating at each point.
  489. //
  490. status = STATUS_TRANSLATION_COMPLETE;
  491. break;
  492. case TranslateParentToChild:
  493. //
  494. // We do not translate requirements so do nothing...
  495. //
  496. status = STATUS_SUCCESS;
  497. break;
  498. default:
  499. status = STATUS_INVALID_PARAMETER;
  500. }
  501. return status;
  502. }
  503. NTSTATUS
  504. HaliGetInterruptTranslator(
  505. IN INTERFACE_TYPE ParentInterfaceType,
  506. IN ULONG ParentBusNumber,
  507. IN INTERFACE_TYPE BridgeInterfaceType,
  508. IN USHORT Size,
  509. IN USHORT Version,
  510. OUT PTRANSLATOR_INTERFACE Translator,
  511. OUT PULONG BridgeBusNumber
  512. )
  513. /*++
  514. Routine Description:
  515. Arguments:
  516. ParentInterfaceType - The type of the bus the bridge lives on (normally PCI).
  517. ParentBusNumber - The number of the bus the bridge lives on.
  518. ParentSlotNumber - The slot number the bridge lives in (where valid).
  519. BridgeInterfaceType - The bus type the bridge provides (ie ISA for a PCI-ISA bridge).
  520. ResourceType - The resource type we want to translate.
  521. Size - The size of the translator buffer.
  522. Version - The version of the translator interface requested.
  523. Translator - Pointer to the buffer where the translator should be returned
  524. BridgeBusNumber - Pointer to where the bus number of the bridge bus should be returned
  525. Return Value:
  526. Returns the status of this operation.
  527. --*/
  528. {
  529. PAGED_CODE();
  530. UNREFERENCED_PARAMETER(ParentInterfaceType);
  531. UNREFERENCED_PARAMETER(ParentBusNumber);
  532. ASSERT(Version == HAL_IRQ_TRANSLATOR_VERSION);
  533. ASSERT(Size >= sizeof(TRANSLATOR_INTERFACE));
  534. #ifdef WANT_IRQ_ROUTING
  535. //
  536. // Dont provide Irq translator iff Pci Irq Routing
  537. // is enabled.
  538. //
  539. if (IsPciIrqRoutingEnabled()) {
  540. HalPrint(("Not providing Isa Irq Translator since Pci Irq routing is enabled!\n"));
  541. return STATUS_NOT_SUPPORTED;
  542. }
  543. #endif
  544. //
  545. // Fill in the common bits.
  546. //
  547. RtlZeroMemory(Translator, sizeof (TRANSLATOR_INTERFACE));
  548. Translator->Size = sizeof(TRANSLATOR_INTERFACE);
  549. Translator->Version = HAL_IRQ_TRANSLATOR_VERSION;
  550. Translator->Context = (PVOID)BridgeInterfaceType;
  551. Translator->InterfaceReference = HalTranslatorReference;
  552. Translator->InterfaceDereference = HalTranslatorDereference;
  553. switch (BridgeInterfaceType) {
  554. case Eisa:
  555. case Isa:
  556. case InterfaceTypeUndefined: // special "IDE" cookie
  557. //
  558. // Set IRQ translator for (E)ISA interrupts.
  559. //
  560. Translator->TranslateResources = HalIrqTranslateResourcesIsa;
  561. Translator->TranslateResourceRequirements =
  562. HalIrqTranslateResourceRequirementsIsa;
  563. return STATUS_SUCCESS;
  564. case MicroChannel:
  565. case PCIBus:
  566. //
  567. // Set IRQ translator for the MCA interrupts.
  568. //
  569. Translator->TranslateResources = HalIrqTranslateResourcesRoot;
  570. Translator->TranslateResourceRequirements =
  571. HalIrqTranslateResourceRequirementsRoot;
  572. return STATUS_SUCCESS;
  573. }
  574. //
  575. // If we got here, we don't have an interface.
  576. //
  577. return STATUS_NOT_SUPPORTED;
  578. }