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.

606 lines
16 KiB

  1. // TITLE("Interrupt Object Support Routines")
  2. //++
  3. //
  4. // Module Name:
  5. //
  6. // intsup.s
  7. //
  8. // Abstract:
  9. //
  10. // This module implements the code necessary to support interrupt objects.
  11. // It contains the interrupt dispatch code and the code template that gets
  12. // copied into an interrupt object.
  13. //
  14. // Author:
  15. //
  16. // Bernard Lint 20-Nov-1995
  17. //
  18. // Environment:
  19. //
  20. // Kernel mode only.
  21. //
  22. // Revision History:
  23. //
  24. // Based on MIPS version (David N. Cutler (davec) 2-Apr-1990)
  25. //
  26. //--
  27. #include "ksia64.h"
  28. //
  29. SBTTL("Synchronize Execution")
  30. //++
  31. //
  32. // BOOLEAN
  33. // KeSynchronizeExecution (
  34. // IN PKINTERRUPT Interrupt,
  35. // IN PKSYNCHRONIZE_ROUTINE SynchronizeRoutine,
  36. // IN PVOID SynchronizeContext
  37. // )
  38. //
  39. // Routine Description:
  40. //
  41. // This function synchronizes the execution of the specified routine with the
  42. // execution of the service routine associated with the specified interrupt
  43. // object.
  44. //
  45. // Arguments:
  46. //
  47. // Interrupt (a0) - Supplies a pointer to a control object of type interrupt.
  48. //
  49. // SynchronizeRoutine (a1) - Supplies a pointer to a function whose execution
  50. // is to be synchronized with the execution of the service routine associated
  51. // with the specified interrupt object.
  52. //
  53. // SynchronizeContext (a2) - Supplies a pointer to an arbitrary data structure
  54. // which is to be passed to the function specified by the SynchronizeRoutine
  55. // parameter.
  56. //
  57. // Return Value:
  58. //
  59. // The value returned by the SynchronizeRoutine function is returned as the
  60. // function value.
  61. //
  62. //--
  63. NESTED_ENTRY(KeSynchronizeExecution)
  64. NESTED_SETUP(3,4,1,0)
  65. add t2 = InSynchronizeIrql, a0 // -> sync IRQL
  66. ;;
  67. PROLOGUE_END
  68. //
  69. // Register aliases for entire procedure
  70. //
  71. rOldIrql = loc2 // saved IRQL value
  72. rpSpinLock= loc3 // address of spin lock
  73. //
  74. // Raise IRQL to the synchronization level and acquire the associated
  75. // spin lock.
  76. //
  77. ld8.nt1 t1 = [a1], PlGlobalPointer-PlEntryPoint
  78. ld1.nt1 t3 = [t2], InActualLock-InSynchronizeIrql
  79. mov out0 = a2 // get synchronize context
  80. ;;
  81. #if !defined(NT_UP)
  82. ld8.nt1 rpSpinLock = [t2] // get address of spin lock
  83. #endif // !defined(NT_UP)
  84. SWAP_IRQL (t3) // raise IRQL
  85. #if !defined(NT_UP)
  86. ACQUIRE_SPINLOCK(rpSpinLock, rpSpinLock, Kse10)
  87. #endif // !defined(NT_UP)
  88. //
  89. // Call specified routine passing the specified context parameter.
  90. //
  91. ld8.nt1 gp = [a1]
  92. mov bt0 = t1 // setup br
  93. mov rOldIrql = v0
  94. br.call.sptk.many brp = bt0 // call routine
  95. //
  96. // Release spin lock, lower IRQL to its previous level, and return the value
  97. // returned by the specified routine.
  98. //
  99. #if !defined(NT_UP)
  100. RELEASE_SPINLOCK(rpSpinLock)
  101. #endif // !defined(NT_UP)
  102. SET_IRQL(rOldIrql) // lower IRQL to previous level
  103. NESTED_RETURN
  104. NESTED_EXIT(KeSynchronizeExecution)
  105. //
  106. SBTTL("Chained Dispatch")
  107. //++
  108. //
  109. // Routine Description:
  110. //
  111. // This routine is entered as the result of an interrupt being generated
  112. // via a vector that is connected to more than one interrupt object. Its
  113. // function is to walk the list of connected interrupt objects and call
  114. // each interrupt service routine. If the mode of the interrupt is latched,
  115. // then a complete traversal of the chain must be performed. If any of the
  116. // routines require saving the volatile floating point machine state, then
  117. // it is only saved once.
  118. //
  119. // N.B. On entry to this routine only the volatile integer registers have
  120. // been saved. Also the volatile lower floating point registers saved.
  121. //
  122. // N.B. gp will be destroyed by the interrupt service routine; if this code
  123. // uses the gp of this module after the call, then it must save and
  124. // restore gp.
  125. //
  126. // Arguments:
  127. //
  128. // a0 - Supplies a function pointer to the ISR (in the interrupt object
  129. // dispatch code).
  130. //
  131. // a1 - Supplies a pointer to a trap frame.
  132. //
  133. // Return Value:
  134. //
  135. // None.
  136. //
  137. //--
  138. NESTED_ENTRY(KiChainedDispatch)
  139. NESTED_SETUP(2,8,2,0)
  140. .save pr, loc7
  141. mov loc7 = pr
  142. PROLOGUE_END
  143. //
  144. // Register aliases
  145. //
  146. rpSpinLock = loc2 // pointer to spinlock
  147. rMode = loc3 // interrupt mode (level sensitive)
  148. rpEntry = loc4 // current list entry
  149. rIrql = loc5 // source interrupt IRQL
  150. rSirql = loc6 // new interrupt IRQL
  151. rpI1 = t0 // temp pointer
  152. rpI2 = t1 // temp pointer
  153. rpFptr = t2 // pointer to ISR fptr
  154. rpCtxt = t3 // pointer to service context
  155. rFptr = t4 // ISR fptr
  156. pLoop1 = pt1 // do another loop
  157. pLoop2 = pt2 // do another loop
  158. pNEqual = ps0 // true if source IRQL != sync IRQL
  159. //
  160. // Initialize loop variables.
  161. //
  162. add out0 = -InDispatchCode, a0 // out0 -> interrupt object
  163. ;;
  164. add rpEntry = InInterruptListEntry, out0 // set addr of listhead
  165. add rpI1 = InMode, out0 // -> mode of interrupt
  166. add rpI2 = InIrql, out0 // -> interrupt source IRQL
  167. ;;
  168. ld1.nt1 rMode = [rpI1] // get mode of interrupt
  169. ld1.nt1 rIrql = [rpI2] // get interrupt source IRQL
  170. //
  171. // Walk the list of connected interrupt objects and call the respective
  172. // interrupt service routines.
  173. //
  174. // Raise IRQL to synchronization level if synchronization level is not
  175. // equal to the interrupt source level.
  176. //
  177. Kcd_Loop:
  178. add rpI1 = InSynchronizeIrql, out0
  179. ;;
  180. ld1 rSirql = [rpI1], InActualLock-InSynchronizeIrql
  181. ;;
  182. cmp.ne pNEqual = rIrql, rSirql // if ne, IRQL levels are
  183. // not the same
  184. ;;
  185. PSET_IRQL(pNEqual, rSirql) // raise to synchronization IRQL
  186. //
  187. //
  188. // Acquire the service routine spin lock and call the service routine.
  189. //
  190. #if !defined(NT_UP)
  191. ld8.nt1 rpSpinLock = [rpI1] // get address of spin lock
  192. ACQUIRE_SPINLOCK(rpSpinLock, rpSpinLock, Kcd_Lock)
  193. #endif // !defined(NT_UP)
  194. add rpFptr = InServiceRoutine, out0 // pointer to fptr
  195. add rpCtxt = InServiceContext, out0 // pointer to service context
  196. ;;
  197. LDPTR (rFptr, rpFptr) // get fptr
  198. LDPTR (out1, rpCtxt) // get service context
  199. ;;
  200. ld8.nt1 t5 = [rFptr], PlGlobalPointer-PlEntryPoint
  201. ;;
  202. ld8.nt1 gp = [rFptr]
  203. mov bt0 = t5 // set br address
  204. br.call.sptk brp = bt0 // call ISR
  205. //
  206. // Release the service routine spin lock.
  207. //
  208. #if !defined(NT_UP)
  209. RELEASE_SPINLOCK(rpSpinLock)
  210. #endif
  211. //
  212. // Lower IRQL to the interrupt source level if synchronization level is not
  213. // the same as the interrupt source level.
  214. //
  215. PSET_IRQL(pNEqual,rIrql)
  216. //
  217. // Get next list entry and check for end of loop.
  218. //
  219. add rpI1 = LsFlink, rpEntry // -> next entry
  220. ;;
  221. LDPTR (rpEntry, rpI1) // -> next interrupt object
  222. ;;
  223. //
  224. // Loop if (1) interrrupt not handled and not end of list or
  225. // if (2) interrupt handled, and not level sensistive, and not end of list
  226. //
  227. cmp4.eq pLoop1 = zero, zero // initialize pLoop1
  228. cmp4.eq pLoop2 = zero, zero // initialize pLoop2
  229. add out0 = InDispatchCode-InInterruptListEntry, rpEntry // -> ISR if done
  230. ;;
  231. cmp4.eq.and pLoop1 = zero, v0 // if eq, interrupt not handled
  232. cmp.ne.and pLoop1, pLoop2 = a0, out0 // if ne, not end of list
  233. ;;
  234. add out0 = -InInterruptListEntry, rpEntry // -> next interrupt object
  235. (pLoop1) br.dptk Kcd_Loop // loop to handle next enrty
  236. ;;
  237. cmp4.ne.and pLoop2 = zero, v0 // if ne, interrupt handled
  238. cmp4.ne.and pLoop2 = zero, rMode // if ne, not level sensitive
  239. (pLoop2) br.dptk Kcd_Loop // loop to handle next enrty
  240. ;;
  241. //
  242. // Either the interrupt is level sensitive and has been handled or the end of
  243. // the interrupt object chain has been reached.
  244. //
  245. mov pr = loc7, -2
  246. NESTED_RETURN
  247. NESTED_EXIT(KiChainedDispatch)
  248. SBTTL("Interrupt Dispatch - Raise IRQL")
  249. //++
  250. //
  251. // Routine Description:
  252. //
  253. // This routine is entered as the result of an interrupt being generated
  254. // via a vector that is connected to an interrupt object. Its function is
  255. // to directly call the specified interrupt service routine.
  256. //
  257. // N.B. On entry to this routine only the volatile integer registers have
  258. // been saved. Also volatile lower floating point registers saved.
  259. //
  260. // N.B. This routine raises the interrupt level to the synchronization
  261. // level specified in the interrupt object.
  262. //
  263. // N.B. gp will be destroyed by the interrupt service routine; if this code
  264. // uses the gp of this module after the call, then it must save and
  265. // restore gp.
  266. //
  267. // Arguments:
  268. //
  269. // a0 - Supplies a function pointer to the ISR (in the interrupt object
  270. // dispatch code).
  271. //
  272. // a1 - Supplies a pointer to a trap frame.
  273. //
  274. // Return Value:
  275. //
  276. // None.
  277. //
  278. //--
  279. NESTED_ENTRY(KiInterruptDispatchRaise)
  280. NESTED_SETUP(2,4,2,0)
  281. PROLOGUE_END
  282. //
  283. // Register aliases
  284. //
  285. rpSpinLock = loc2
  286. rSirql = loc3 // sync IRQL
  287. //
  288. // Raise IRQL to synchronization level.
  289. //
  290. add t1 = InSynchronizeIrql-InDispatchCode, a0
  291. add t2 = InActualLock-InDispatchCode, a0
  292. add out0 = -InDispatchCode, a0 // out0 -> interrupt object
  293. ;;
  294. ld1.nt1 rSirql = [t1], InActualLock-InSynchronizeIrql
  295. #if !defined(NT_UP)
  296. ld8.nt1 rpSpinLock = [t2] // get address of spin lock
  297. #endif // !defined(NT_UP)
  298. add t5 = InServiceRoutine, out0 // pointer to fptr
  299. ;;
  300. ld8.nt1 t5 = [t5] // get function pointer
  301. SET_IRQL (rSirql) // raise to synchronization IRQL
  302. add t3 = InServiceContext, out0 // pointer to service context
  303. ;;
  304. ld8.nt1 t6 = [t5], PlGlobalPointer-PlEntryPoint
  305. ld8.nt1 out1 = [t3] // get service context
  306. //
  307. //
  308. // Acquire the service routine spin lock and call the service routine.
  309. //
  310. #if !defined(NT_UP)
  311. ACQUIRE_SPINLOCK(rpSpinLock, rpSpinLock, Kidr_Lock)
  312. #endif // !defined(NT_UP)
  313. ;;
  314. ld8.nt1 gp = [t5]
  315. mov bt0 = t6 // set br address
  316. br.call.sptk brp = bt0 // call ISR
  317. ;;
  318. //
  319. // Release the service routine spin lock.
  320. //
  321. #if !defined(NT_UP)
  322. RELEASE_SPINLOCK(rpSpinLock)
  323. #endif // !defined(NT_UP)
  324. //
  325. // IRQL lowered to the previous level in the external handler.
  326. //
  327. NESTED_RETURN
  328. NESTED_EXIT(KiInterruptDispatchRaise)
  329. //
  330. SBTTL("Interrupt Dispatch - Same IRQL")
  331. //++
  332. //
  333. // Routine Description:
  334. //
  335. // This routine is entered as the result of an interrupt being generated
  336. // via a vector that is connected to an interrupt object. Its function is
  337. // to directly call the specified interrupt service routine.
  338. //
  339. // N.B. On entry to this routine only the volatile integer registers have
  340. // been saved. Also the volatile lower float point registers.
  341. //
  342. // N.B. gp will be destroyed by the interrupt service routine; if this code
  343. // uses the gp of this module after the call, then it must save and
  344. // restore gp.
  345. //
  346. // Arguments:
  347. //
  348. // a0 - Supplies a function pointer to the ISR (in the interrupt object
  349. // dispatch code).
  350. //
  351. // a1 - Supplies a pointer to a trap frame..
  352. //
  353. // Return Value:
  354. //
  355. // None.
  356. //
  357. //--
  358. #if defined(NT_UP)
  359. LEAF_ENTRY(KiInterruptDispatchSame)
  360. alloc t3 = ar.pfs, 2, 0, 0, 0
  361. add a0 = -InDispatchCode, a0 // a0 points to interrupt object
  362. ;;
  363. add t2 = InServiceRoutine, a0 // -> service routine fptr
  364. add t1 = InServiceContext, a0 // -> service context
  365. ;;
  366. ld8.nt1 t2 = [t2] // service routine fptr
  367. ld8.nt1 a1 = [t1] // service context
  368. ;;
  369. ld8.nt1 t5 = [t2], PlGlobalPointer-PlEntryPoint
  370. ;;
  371. ld8.nt1 gp = [t2]
  372. mov bt0 = t5
  373. br.sptk.many bt0 // branch to service routine
  374. //
  375. // N.B.: Return to trap handler from ISR.
  376. //
  377. LEAF_EXIT(KiInterruptDispatchSame)
  378. #else
  379. NESTED_ENTRY(KiInterruptDispatchSame)
  380. NESTED_SETUP(2,3,2,0)
  381. PROLOGUE_END
  382. //
  383. // Register aliases
  384. //
  385. rpSpinLock = loc2
  386. //
  387. //
  388. // Acquire the service routine spin lock and call the service routine.
  389. //
  390. add out0 = -InDispatchCode, a0 // -> interrupt object
  391. ;;
  392. add t7 = InServiceRoutine, out0 // addr of function pointer
  393. add t1 = InActualLock, out0 // pointer to address of lock
  394. ;;
  395. ld8.nt1 t7 = [t7] // get function pointer
  396. ld8.nt1 rpSpinLock = [t1], InServiceContext-InActualLock
  397. add t6 = InServiceContext, out0
  398. ;;
  399. ACQUIRE_SPINLOCK(rpSpinLock, rpSpinLock, Kids_Lock)
  400. ld8.nt1 t5 = [t7], PlGlobalPointer-PlEntryPoint
  401. ld8.nt1 out1 = [t1] // get service context
  402. ;;
  403. ld8.nt1 gp = [t7]
  404. mov bt0 = t5 // set br address
  405. br.call.sptk.many brp = bt0 // call ISR
  406. ;;
  407. //
  408. // Release the service routine spin lock.
  409. //
  410. RELEASE_SPINLOCK(rpSpinLock)
  411. NESTED_RETURN
  412. NESTED_EXIT(KiInterruptDispatchSame)
  413. #endif // !defined(NT_UP)
  414. SBTTL("Disable Interrupts")
  415. //++
  416. //
  417. // BOOLEAN
  418. // KeDisableInterrupts (
  419. // VOID
  420. // )
  421. //
  422. // Routine Description:
  423. //
  424. // This function disables interrupts and returns whether interrupts
  425. // were previously enabled.
  426. //
  427. // Arguments:
  428. //
  429. // None.
  430. //
  431. // Return Value:
  432. //
  433. // A boolean value that determines whether interrupts were previously
  434. // enabled (TRUE) or disabled(FALSE).
  435. //
  436. //--
  437. LEAF_ENTRY(KeDisableInterrupts)
  438. DISABLE_INTERRUPTS(t0) // t0 = previous state
  439. ;;
  440. tbit.nz pt0, pt1 = t0, PSR_I // pt0 = 1, if enabled; pt1 = 1 if disabled
  441. ;;
  442. (pt0) mov v0 = TRUE // set return value -- TRUE if enabled
  443. (pt1) mov v0 = FALSE // FALSE if disabled
  444. LEAF_RETURN
  445. LEAF_EXIT(KeDisableInterrupts)
  446. //++
  447. //
  448. // VOID
  449. // KiPassiveRelease (
  450. // VOID
  451. // )
  452. //
  453. // Routine Description:
  454. //
  455. // This function is called when an interrupt has been passively released.
  456. //
  457. // Arguments:
  458. //
  459. // None.
  460. //
  461. // Return Value:
  462. //
  463. // None.
  464. //
  465. //--
  466. LEAF_ENTRY(KiPassiveRelease)
  467. LEAF_RETURN
  468. LEAF_EXIT(KiPassiveRelease)
  469. SBTTL("Unexpected Interrupt")
  470. //++
  471. //
  472. // Routine Description:
  473. //
  474. // This routine is entered as the result of an interrupt being generated
  475. // via a vector that is not connected to an interrupt object. Its function
  476. // is to report the error and dismiss the interrupt.
  477. //
  478. // N.B. On entry to this routine only the volatile integer registers have
  479. // been saved. Also the volatile lower float point registers.
  480. //
  481. // Arguments:
  482. //
  483. // a0 - Supplies a function pointer to the ISR (in the interrupt object
  484. // dispatch code).
  485. //
  486. // a1 - Supplies a pointer to a trap frame.
  487. //
  488. // Return Value:
  489. //
  490. // None.
  491. //
  492. //--
  493. LEAF_ENTRY(KiUnexpectedInterrupt)
  494. LEAF_RETURN
  495. LEAF_EXIT(KiUnexpectedInterrupt)
  496. LEAF_ENTRY(KiFloatingDispatch)
  497. LEAF_RETURN
  498. LEAF_EXIT(KiFloatingDispatch)