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.

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