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.

1355 lines
33 KiB

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