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.

979 lines
27 KiB

  1. TITLE "Interrupt Object Support Routines"
  2. ;++
  3. ;
  4. ; Copyright (c) 1989 Microsoft Corporation
  5. ;
  6. ; Module Name:
  7. ;
  8. ; intsup.asm
  9. ;
  10. ; Abstract:
  11. ;
  12. ; This module implements the code necessary to support interrupt objects.
  13. ; It contains the interrupt dispatch code and the code template that gets
  14. ; copied into an interrupt object.
  15. ;
  16. ; Author:
  17. ;
  18. ; Shie-Lin Tzong (shielint) 20-Jan-1990
  19. ;
  20. ; Environment:
  21. ;
  22. ; Kernel mode only.
  23. ;
  24. ; Revision History:
  25. ;
  26. ;--
  27. .386p
  28. .xlist
  29. KERNELONLY equ 1
  30. include ks386.inc
  31. include i386\kimacro.inc
  32. include mac386.inc
  33. include callconv.inc
  34. .list
  35. EXTRNP KfRaiseIrql,1,IMPORT,FASTCALL
  36. EXTRNP KfLowerIrql,1,IMPORT,FASTCALL
  37. EXTRNP _KeBugCheck,1
  38. EXTRNP _KeBugCheckEx,5
  39. EXTRNP _KiDeliverApc,3
  40. EXTRNP _HalBeginSystemInterrupt,3,IMPORT
  41. EXTRNP _HalEndSystemInterrupt,2,IMPORT
  42. EXTRNP Kei386EoiHelper
  43. EXTRNP PerfInfoLogInterrupt,4,,FASTCALL
  44. if DBG
  45. extrn _DbgPrint:near
  46. extrn _MsgISRTimeout:BYTE
  47. extrn _KiISRTimeout:DWORD
  48. endif
  49. extrn _DbgPrint:near
  50. extrn _MsgISROverflow:BYTE
  51. extrn _KeTickCount:DWORD
  52. extrn _KiISROverflow:WORD
  53. extrn _KdDebuggerEnabled:BYTE
  54. extrn _PPerfGlobalGroupMask:DWORD
  55. MI_MOVEDI EQU 0BFH ; op code for mov edi, constant
  56. MI_DIRECTJMP EQU 0E9H ; op code for indirect jmp
  57. ; or index registers
  58. if DBG
  59. DETECT_INT_STORM EQU 1
  60. else
  61. DETECT_INT_STORM EQU 0
  62. endif
  63. if DETECT_INT_STORM
  64. INT_TICK_MASK EQU 03FH
  65. ;
  66. ; Macro to check for an interrupt storm on a particular interrupt object
  67. ;
  68. CHECK_INT_STORM macro Prefix
  69. mov eax, _KeTickCount ; current time
  70. and eax, NOT INT_TICK_MASK ; mask to closest 640ms
  71. cmp eax, dword ptr [edi].InTickCount ; in same 640ms second range
  72. jg Prefix&_overflowreset ; tick count has advanced since last interrupt, reset counts
  73. jl Prefix&_waittick ; we have already overflowed interrupt count for this tick, do nothing
  74. ; until the clock advances to the next tick period
  75. dec word ptr [edi].InDispatchCount
  76. jz Prefix&_interruptoverflow ; interrupt count has just overflowed
  77. Prefix&_dbg2:
  78. endm
  79. CHECK_INT_STORM_TAIL macro Prefix, BugCheckID
  80. Prefix&_interruptoverflow:
  81. dec word ptr [edi].InDispatchCount+2
  82. jz short @f
  83. add eax, INT_TICK_MASK+1
  84. mov [edi].InTickCount, eax ; bump tick count to next tick
  85. jmp short Prefix&_overflowreset2
  86. @@:
  87. cmp _KdDebuggerEnabled, 0
  88. jnz short @f
  89. stdCall _KeBugCheckEx, <HARDWARE_INTERRUPT_STORM, [edi].InServiceRoutine, [edi].InServiceContext, edi, BugCheckID>
  90. ;
  91. ; Debugger is enabled so do a BP instead of bugchecking
  92. ;
  93. @@:
  94. push [edi].InServiceRoutine
  95. push offset FLAT:_MsgISROverflow
  96. call _DbgPrint
  97. add esp, 8
  98. int 3
  99. mov eax, _KeTickCount ; current time
  100. and eax, NOT INT_TICK_MASK ; mask to closest 20 second
  101. ;
  102. ; deliberately fall through to reset the count
  103. ;
  104. Prefix&_overflowreset:
  105. mov dword ptr [edi].InTickCount, eax ; initialize time
  106. mov word ptr [edi].InDispatchCount+2, 64 ;
  107. Prefix&_overflowreset2:
  108. mov ax, _KiISROverflow
  109. mov word ptr [edi].InDispatchCount, ax ; reset count
  110. jmp Prefix&_dbg2
  111. ;
  112. ; Additional work we do here in Prefix&_waittick is to make sure the tickcount
  113. ; didn't actually wrap and send us here.
  114. ;
  115. Prefix&_waittick:
  116. add eax, INT_TICK_MASK+1
  117. cmp eax, dword ptr [edi].InTickCount
  118. je Prefix&_dbg2 ; exactly one tick apart, do nothing
  119. ;
  120. ; tick count must have wrapped - reset all counters
  121. ;
  122. mov eax, _KeTickCount
  123. jmp short Prefix&_overflowreset
  124. endm
  125. else
  126. CHECK_INT_STORM macro Prefix
  127. endm
  128. CHECK_INT_STORM_TAIL macro Prefix, BugCheckID
  129. endm
  130. endif
  131. page ,132
  132. subttl "Syn0chronize Execution"
  133. _TEXT$00 SEGMENT PARA PUBLIC 'CODE'
  134. ;++
  135. ;
  136. ; BOOLEAN
  137. ; KeSynchronizeExecution (
  138. ; IN PKINTERRUPT Interrupt,
  139. ; IN PKSYNCHRONIZE_ROUTINE SynchronizeRoutine,
  140. ; IN PVOID SynchronizeContext
  141. ; )
  142. ;
  143. ; Routine Description:
  144. ;
  145. ; This function synchronizes the execution of the specified routine with the
  146. ; execution of the service routine associated with the specified interrupt
  147. ; object.
  148. ;
  149. ; Arguments:
  150. ;
  151. ; Interrupt - Supplies a pointer to a control object of type interrupt.
  152. ;
  153. ; SynchronizeRoutine - Supplies a pointer to a function whose execution
  154. ; is to be synchronized with the execution of the service routine
  155. ; associated with the specified interrupt object.
  156. ;
  157. ; SynchronizeContext - Supplies a pointer to an arbitrary data structure
  158. ; which is to be passed to the function specified by the
  159. ; SynchronizeRoutine parameter.
  160. ;
  161. ; Return Value:
  162. ;
  163. ; The value returned by the SynchronizeRoutine function is returned as the
  164. ; function value.
  165. ;
  166. ;--
  167. ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
  168. cPublicProc _KeSynchronizeExecution ,3
  169. push ebx ; save nonvolatile register
  170. mov ebx, 8[esp] ; get interrupt object address
  171. mov ecx, InSynchronizeIrql[ebx] ; get synchronization IRQL
  172. fstCall KfRaiseIrql ; raise IRQL to synchronization level
  173. push eax ; save previous IRQL
  174. ifndef NT_UP
  175. mov ebx,InActualLock[ebx] ; get actual lock address
  176. kse10: ACQUIRE_SPINLOCK ebx,<short kse20> ; acquire spin lock
  177. endif
  178. push 20[esp] ; push synchronization context routine
  179. CAPSTART <_KeSynchronizeExecution@12,[esp+20]>
  180. call 20[esp] ; call synchronization routine
  181. CAPEND <_KeSynchronizeExecution@12>
  182. ifndef NT_UP
  183. RELEASE_SPINLOCK ebx ; release spin lock
  184. endif
  185. mov ebx, eax ; save synchronization routine value
  186. pop ecx ; retrieve previous IRQL
  187. fstCall KfLowerIrql ; lower IRQL to previous value
  188. mov eax, ebx ; set return value
  189. pop ebx ; restore nonvolatile register
  190. stdRET _KeSynchronizeExecution
  191. ifndef NT_UP
  192. kse20: SPIN_ON_SPINLOCK ebx,<short kse10> ; wait until lock is free
  193. endif
  194. stdENDP _KeSynchronizeExecution
  195. page ,132
  196. subttl "Chained Dispatch"
  197. ;++
  198. ;
  199. ; Routine Description:
  200. ;
  201. ; This routine is entered as the result of an interrupt being generated
  202. ; via a vector that is connected to more than one interrupt object.
  203. ;
  204. ; Arguments:
  205. ;
  206. ; edi - Supplies a pointer to the interrupt object.
  207. ; esp - Supplies a pointer to the top of trap frame
  208. ; ebp - Supplies a pointer to the top of trap frame
  209. ;
  210. ; Return Value:
  211. ;
  212. ; None.
  213. ;
  214. ;--
  215. align 16
  216. cPublicProc _KiChainedDispatch ,0
  217. .FPO (2, 0, 0, 0, 0, 1)
  218. ;
  219. ; update statistic
  220. ;
  221. inc dword ptr PCR[PcPrcbData+PbInterruptCount]
  222. ;
  223. ; set ebp to the top of trap frame. We don't need to save ebp because
  224. ; it is saved in trap frame already.
  225. ;
  226. mov ebp, esp ; (ebp)->trap frame
  227. ;
  228. ; Save previous IRQL and set new priority level
  229. ;
  230. mov eax, [edi].InVector ; save vector
  231. push eax
  232. sub esp, 4 ; make room for OldIrql
  233. mov ecx, [edi].InIrql ; Irql
  234. ;
  235. ; esp - pointer to OldIrql
  236. ; eax - vector
  237. ; ecx - Irql
  238. ;
  239. stdCall _HalBeginSystemInterrupt, <ecx, eax, esp>
  240. or eax, eax ; check for spurious int.
  241. jz kid_spuriousinterrupt
  242. stdCall _KiChainedDispatch2ndLvl
  243. INTERRUPT_EXIT ; will do an iret
  244. stdENDP _KiChainedDispatch
  245. page ,132
  246. subttl "Chained Dispatch 2nd Level"
  247. ;++
  248. ;
  249. ; Routine Description:
  250. ;
  251. ; This routine is entered as the result of an interrupt being generated
  252. ; via a vector that is either connected to more than one interrupt object,
  253. ; or is being 2nd level dispatched. Its function is to walk the list
  254. ; of connected interrupt objects and call each interrupt service routine.
  255. ; If the mode of the interrupt is latched, then a complete traversal of
  256. ; the chain must be performed. If any of the routines require saving the
  257. ; floating point machine state, then it is only saved once.
  258. ;
  259. ; Arguments:
  260. ;
  261. ; edi - Supplies a pointer to the interrupt object.
  262. ;
  263. ; Return Value:
  264. ;
  265. ; None.
  266. ; Uses all registers
  267. ;
  268. ;--
  269. public _KiInterruptDispatch2ndLvl@0
  270. _KiInterruptDispatch2ndLvl@0:
  271. nop
  272. cPublicProc _KiChainedDispatch2ndLvl,0
  273. cPublicFpo 0, 3
  274. push ebp
  275. sub esp, 20 ; Make room for scratch and local values
  276. ;
  277. ; [esp] OldIrql
  278. ; [esp+4] Scratch
  279. ; [esp+8] TimeStamp
  280. ; [esp+16] ISRTracingOn
  281. ;
  282. xor ebp, ebp ; init (ebp) = Interrupthandled = FALSE
  283. lea ebx, [edi].InInterruptListEntry
  284. ; (ebx)->Interrupt Head List
  285. cmp _PPerfGlobalGroupMask, 0 ; Is event tracing on?
  286. mov [esp+16], 0 ; ISRTracingOn = 0
  287. jne kcd120
  288. ;
  289. ; Walk the list of connected interrupt objects and call the appropriate dispatch
  290. ; routine.
  291. ;
  292. kcd40:
  293. ;
  294. ; Raise irql level to the SynchronizeIrql level if it is not equal to current
  295. ; irql.
  296. ;
  297. mov cl, [edi+InIrql] ; [cl] = Current Irql
  298. mov esi,[edi+InActualLock]
  299. cmp [edi+InSynchronizeIrql], cl ; Is SyncIrql > current IRQL?
  300. je short kcd50 ; if e, no, go kcd50
  301. ;
  302. ; Arg1 ecx : Irql to raise to
  303. ;
  304. mov ecx, [edi+InSynchronizeIrql] ; (ecx) = Irql to raise to
  305. fstCall KfRaiseIrql
  306. mov [esp], eax ; Save OldIrql
  307. ;
  308. ; Acquire the service routine spin lock and call the service routine.
  309. ;
  310. kcd50:
  311. ACQUIRE_SPINLOCK esi,kcd110
  312. ;
  313. ; Check for an interrupt storm on this interrupt object
  314. ;
  315. CHECK_INT_STORM kcd
  316. if DBG
  317. mov eax, _KeTickCount ; Grab ISR start time
  318. mov [esp+4], eax ; save to local varible
  319. endif
  320. mov eax, InServiceContext[edi] ; set parameter value
  321. push eax
  322. push edi ; pointer to interrupt object
  323. CAPSTART <_KiInterruptDispatch2ndLvl@0,InServiceRoutine[edi]>
  324. call InServiceRoutine[edi] ; call specified routine
  325. CAPEND <_KiInterruptDispatch2ndLvl@0>
  326. if DBG
  327. mov ecx, [esp+4] ; (ecx) = time isr started
  328. add ecx, _KiISRTimeout ; adjust for timeout
  329. cmp _KeTickCount, ecx ; Did ISR timeout?
  330. jnc kcd200
  331. kcd51:
  332. endif
  333. ;
  334. ; Release the service routine spin lock and check to determine if end of loop.
  335. ;
  336. RELEASE_SPINLOCK esi
  337. ;
  338. ; Lower IRQL to earlier level if we raised it to SynchronizedLevel.
  339. ;
  340. mov cl, [edi+InIrql]
  341. cmp [edi+InSynchronizeIrql], cl ; Is SyncIrql > current IRQL?
  342. je short kcd55 ; if e, no, go kcd55
  343. mov esi, eax ; save ISR returned value
  344. ;
  345. ; Arg1 : Irql to Lower to
  346. ;
  347. mov ecx, [esp]
  348. fstCall KfLowerIrql
  349. mov eax, esi ; [eax] = ISR returned value
  350. kcd55:
  351. cmp [esp+16], 0 ; check if ISR logging is enabled
  352. jne kcd140
  353. kcd57:
  354. or al,al ; Is interrupt handled?
  355. je short kcd60 ; if eq, interrupt not handled
  356. cmp word ptr InMode[edi], InLevelSensitive
  357. je short kcd70 ; if eq, level sensitive interrupt
  358. mov ebp, eax ; else edge shared int is handled. Remember it.
  359. kcd60: mov edi, [edi].InInterruptListEntry
  360. ; (edi)->next obj's addr of listentry
  361. cmp ebx, edi ; Are we at end of interrupt list?
  362. je short kcd65 ; if eq, reach end of list
  363. sub edi, InInterruptListEntry; (edi)->addr of next interrupt object
  364. cmp [esp+16], 0 ; check if ISR logging is enabled
  365. jne kcd130 ; If enable, grab the begin time
  366. jmp kcd40
  367. kcd65:
  368. ;
  369. ; If this is edge shared interrupt, we need to loop till no one handle the
  370. ; interrupt. In theory only shared edge triggered interrupts come here.
  371. ;
  372. sub edi, InInterruptListEntry; (edi)->addr of next interrupt object
  373. cmp word ptr InMode[edi], InLevelSensitive
  374. je short kcd70 ; if level, exit. No one handle the interrupt?
  375. test ebp, 0fh ; does anyone handle the interrupt?
  376. je short kcd70 ; if e, no one, we can exit.
  377. xor ebp, ebp ; init local var to no one handle the int
  378. cmp [esp+16], 0 ; check if ISR logging is enabled
  379. jne kcd130 ; If enable, grab the begin time
  380. jmp kcd40 ; restart the loop.
  381. ;
  382. ; Either the interrupt is level sensitive and has been handled or the end of
  383. ; the interrupt object chain has been reached.
  384. ;
  385. ; restore frame pointer, and deallocate trap frame.
  386. kcd70:
  387. add esp, 20 ; clear local variable space
  388. pop ebp
  389. stdRet _KiChainedDispatch2ndLvl
  390. ; Service routine Lock is currently owned, spin until free and then
  391. ; attempt to acquire lock again.
  392. ifndef NT_UP
  393. kcd110: SPIN_ON_SPINLOCK esi, kcd50,,DbgMp
  394. endif
  395. ;
  396. ; If ISR event tracing is on, note that it is and take a timestamp
  397. ;
  398. kcd120:
  399. mov edx, _PPerfGlobalGroupMask ; Load the ptr into edx
  400. cmp edx, 0 ; catch race here
  401. jz kcd40
  402. test dword ptr [edx+PERF_INTERRUPT_OFFSET], PERF_INTERRUPT_FLAG
  403. jz kcd40 ; return if our flag is not set
  404. mov [esp+16], 1 ; records that ISR tracing is enabled
  405. ;
  406. ; Get the timestamp before the ISR is called
  407. ;
  408. kcd130:
  409. PERF_GET_TIMESTAMP ; Places 64bit in edx:eax and trashes ecx
  410. mov [esp+8], eax ; Time saved on the stack
  411. mov [esp+12], edx
  412. jmp kcd40
  413. ;
  414. ; Log the ISR, initial time, and return value
  415. ;
  416. kcd140:
  417. push eax ; save the ISRs return value
  418. mov edx, eax ; pass ISRs return value
  419. mov eax, [esp+12] ; push the initial timestamp
  420. mov ecx, [esp+16]
  421. push ecx
  422. push eax
  423. mov ecx, InServiceRoutine[edi]
  424. fstCall PerfInfoLogInterrupt
  425. pop eax ; restore the ISRs return value
  426. jmp kcd57
  427. ;
  428. ; ISR took a long time to complete, abort to debugger
  429. ;
  430. if DBG
  431. kcd200: push eax ; save return code
  432. push InServiceRoutine[edi]
  433. push offset FLAT:_MsgISRTimeout
  434. call _DbgPrint
  435. add esp,8
  436. pop eax
  437. int 3
  438. jmp kcd51 ; continue
  439. endif
  440. CHECK_INT_STORM_TAIL kcd, 2
  441. stdENDP _KiChainedDispatch2ndLvl
  442. page ,132
  443. subttl "Floating Dispatch"
  444. ;++
  445. ;
  446. ; Routine Description:
  447. ;
  448. ; This routine is entered as the result of an interrupt being generated
  449. ; via a vector that is connected to an interrupt object. Its function is
  450. ; to save the machine state and floating state and then call the specified
  451. ; interrupt service routine.
  452. ;
  453. ; Arguments:
  454. ;
  455. ; edi - Supplies a pointer to the interrupt object.
  456. ; esp - Supplies a pointer to the top of trap frame
  457. ; ebp - Supplies a pointer to the top of trap frame
  458. ;
  459. ; Return Value:
  460. ;
  461. ; None.
  462. ;
  463. ;--
  464. align 16
  465. cPublicProc _KiFloatingDispatch ,0
  466. .FPO (2, 0, 0, 0, 0, 1)
  467. ;
  468. ; update statistic
  469. ;
  470. inc dword ptr PCR[PcPrcbData+PbInterruptCount]
  471. ; set ebp to the top of trap frame. We don't need to save ebp because
  472. ; it is saved in trap frame already.
  473. ;
  474. mov ebp, esp ; (ebp)->trap frame
  475. ;
  476. ; Save previous IRQL and set new priority level to interrupt obj's SyncIrql
  477. ;
  478. mov eax, [edi].InVector
  479. mov ecx, [edi].InSynchronizeIrql ; Irql
  480. push eax ; save vector
  481. sub esp, 4 ; make room for OldIrql
  482. ; arg3 - ptr to OldIrql
  483. ; arg2 - vector
  484. ; arg1 - Irql
  485. stdCall _HalBeginSystemInterrupt, <ecx, eax, esp>
  486. or eax, eax ; check for spurious int.
  487. jz kid_spuriousinterrupt
  488. sub esp, 12 ; make room for ISRTracingOn and InitialTime
  489. cmp _PPerfGlobalGroupMask, 0 ; Is event tracing on?
  490. mov [ebp-12], 0 ; ISRTracingOn = 0
  491. jne kfd110
  492. kfd20:
  493. ;
  494. ; Acquire the service routine spin lock and call the service routine.
  495. ;
  496. kfd30: mov esi,[edi+InActualLock]
  497. ACQUIRE_SPINLOCK esi,kfd100
  498. ;
  499. ; Check for an interrupt storm on this interrupt object
  500. ;
  501. CHECK_INT_STORM kfd
  502. if DBG
  503. mov ebx, _KeTickCount ; Grab current tick time
  504. endif
  505. mov eax, InServiceContext[edi] ; set parameter value
  506. push eax
  507. push edi ; pointer to interrupt object
  508. CAPSTART <_KiFloatingDispatch,InServiceRoutine[edi]>
  509. call InServiceRoutine[edi] ; call specified routine
  510. CAPEND <_KiFloatingDispatch>
  511. if DBG
  512. add ebx, _KiISRTimeout ; adjust for ISR timeout
  513. cmp _KeTickCount, ebx ; Did ISR timeout?
  514. jnc kfd200
  515. kfd31:
  516. endif
  517. ;
  518. ; Release the service routine spin lock.
  519. ;
  520. RELEASE_SPINLOCK esi
  521. cmp [ebp-12], 0 ; check if ISR logging is enabled
  522. jne kfd120
  523. kfd40:
  524. add esp, 12
  525. ;
  526. ; Do interrupt exit processing
  527. ;
  528. INTERRUPT_EXIT ; will do an iret
  529. ;
  530. ; Service routine Lock is currently owned; spin until free and
  531. ; then attempt to acquire lock again.
  532. ;
  533. ifndef NT_UP
  534. kfd100: SPIN_ON_SPINLOCK esi,kfd30,,DbgMp
  535. endif
  536. ;
  537. ; If ISR event tracing is on, collect a time stamp and record that we did.
  538. ;
  539. kfd110:
  540. mov edx, _PPerfGlobalGroupMask ; Load the ptr into edx
  541. cmp edx, 0 ; catch race here
  542. jz kfd20
  543. test dword ptr [edx+PERF_INTERRUPT_OFFSET], PERF_INTERRUPT_FLAG
  544. jz kfd20 ; return if our flag is not set
  545. PERF_GET_TIMESTAMP ; Places 64bit in edx:eax and trashes ecx
  546. mov [ebp-16], eax ; Time saved on the stack
  547. mov [ebp-20], edx
  548. mov [ebp-12], 1 ; Records that timestamp is on stack
  549. jmp kfd20
  550. ;
  551. ; Log the ISR, initial time, and return value
  552. ;
  553. kfd120:
  554. mov edx, eax ; pass ISRs return value
  555. mov eax, [ebp-16] ; push InitialTime
  556. mov ecx, [ebp-20]
  557. push ecx
  558. push eax
  559. mov ecx, InServiceRoutine[edi]
  560. fstCall PerfInfoLogInterrupt
  561. jmp kfd40
  562. ;
  563. ; ISR took a long time to complete, abort to debugger
  564. ;
  565. if DBG
  566. kfd200: push InServiceRoutine[edi] ; timed out
  567. push offset FLAT:_MsgISRTimeout
  568. call _DbgPrint
  569. add esp,8
  570. int 3
  571. jmp kfd31 ; continue
  572. endif
  573. CHECK_INT_STORM_TAIL kfd, 1
  574. stdENDP _KiFloatingDispatch
  575. page ,132
  576. subttl "Interrupt Dispatch"
  577. ;++
  578. ;
  579. ; Routine Description:
  580. ;
  581. ; This routine is entered as the result of an interrupt being generated
  582. ; via a vector that is connected to an interrupt object. Its function is
  583. ; to directly call the specified interrupt service routine.
  584. ;
  585. ; Arguments:
  586. ;
  587. ; edi - Supplies a pointer to the interrupt object.
  588. ; esp - Supplies a pointer to the top of trap frame
  589. ; ebp - Supplies a pointer to the top of trap frame
  590. ;
  591. ; Return Value:
  592. ;
  593. ; None.
  594. ;
  595. ;--
  596. align 16
  597. cPublicProc _KiInterruptDispatch ,0
  598. .FPO (2, 0, 0, 0, 0, 1)
  599. ;
  600. ; update statistic
  601. ;
  602. inc dword ptr PCR[PcPrcbData+PbInterruptCount]
  603. ;
  604. ; set ebp to the top of trap frame. We don't need to save ebp because
  605. ; it is saved in trap frame already.
  606. ;
  607. mov ebp, esp ; (ebp)->trap frame
  608. ;
  609. ; Save previous IRQL and set new priority level
  610. ;
  611. mov eax, [edi].InVector ; save vector
  612. mov ecx, [edi].InSynchronizeIrql ; Irql to raise to
  613. push eax
  614. sub esp, 4 ; make room for OldIrql
  615. stdCall _HalBeginSystemInterrupt,<ecx, eax, esp>
  616. or eax, eax ; check for spurious int.
  617. jz kid_spuriousinterrupt
  618. sub esp, 12 ; make room for ISRTracingOn and InitialTime
  619. cmp _PPerfGlobalGroupMask, 0 ; Is event tracing on?
  620. mov [ebp-12], 0 ; ISRTracingOn = 0
  621. jne kid110 ; check if ISR logging is enabled
  622. kid20:
  623. ;
  624. ; Acquire the service routine spin lock and call the service routine.
  625. ;
  626. kid30: mov esi,[edi+InActualLock]
  627. ACQUIRE_SPINLOCK esi,kid100
  628. ;
  629. ; Check for an interrupt storm on this interrupt object
  630. ;
  631. CHECK_INT_STORM kid
  632. if DBG
  633. mov ebx, _KeTickCount
  634. endif
  635. mov eax, InServiceContext[edi] ; set parameter value
  636. push eax
  637. push edi ; pointer to interrupt object
  638. CAPSTART <_KiInterruptDispatch,InServiceRoutine[edi]>
  639. call InServiceRoutine[edi] ; call specified routine
  640. CAPEND <_KiInterruptDispatch>
  641. if DBG
  642. add ebx, _KiISRTimeout ; adjust for ISR timeout
  643. cmp _KeTickCount, ebx ; Did ISR timeout?
  644. jnc kid200
  645. kid31:
  646. endif
  647. ;
  648. ; Release the service routine spin lock, retrieve the return address,
  649. ; deallocate stack storage, and return.
  650. ;
  651. RELEASE_SPINLOCK esi
  652. cmp [ebp-12], 0 ; check if ISR logging is enabled
  653. jne kid120
  654. kid40:
  655. add esp, 12
  656. ;
  657. ; Do interrupt exit processing
  658. ;
  659. INTERRUPT_EXIT ; will do an iret
  660. add esp, 8 ; clean stack
  661. kid_spuriousinterrupt:
  662. add esp, 8 ; Irql wasn't raised, exit interrupt
  663. SPURIOUS_INTERRUPT_EXIT ; without eoi or lower irql
  664. ;
  665. ; Lock is currently owned; spin until free and then attempt to acquire
  666. ; lock again.
  667. ;
  668. ifndef NT_UP
  669. kid100: SPIN_ON_SPINLOCK esi,kid30,,DbgMp
  670. endif
  671. ;
  672. ; If ISR event tracing is on, collect a time stamp and record that we did.
  673. ;
  674. kid110:
  675. mov edx, _PPerfGlobalGroupMask ; Load the ptr into edx
  676. cmp edx, 0 ; catch race here
  677. jz kid20
  678. test dword ptr [edx+PERF_INTERRUPT_OFFSET], PERF_INTERRUPT_FLAG
  679. jz kid20 ; return if our flag is not set
  680. PERF_GET_TIMESTAMP ; Places 64bit in edx:eax and trashes ecx
  681. mov [ebp-16], eax ; Time saved on the stack
  682. mov [ebp-20], edx
  683. mov [ebp-12], 1 ; Records that timestamp is on stack
  684. jmp kid20
  685. ;
  686. ; Log the ISR, initial time, and return value
  687. ;
  688. kid120:
  689. mov edx, eax ; pass the ISRs return value
  690. mov eax, [ebp-16] ; push InitialTime
  691. mov ecx, [ebp-20]
  692. push ecx
  693. push eax
  694. mov ecx, InServiceRoutine[edi]
  695. fstCall PerfInfoLogInterrupt
  696. jmp kid40
  697. ;
  698. ; ISR took a long time to complete, abort to debugger
  699. ;
  700. if DBG
  701. kid200: push InServiceRoutine[edi] ; timed out
  702. push offset FLAT:_MsgISRTimeout
  703. call _DbgPrint
  704. add esp,8
  705. int 3
  706. jmp kid31 ; continue
  707. endif
  708. CHECK_INT_STORM_TAIL kid, 0
  709. stdENDP _KiInterruptDispatch
  710. page ,132
  711. subttl "Interrupt Template"
  712. ;++
  713. ;
  714. ; Routine Description:
  715. ;
  716. ; This routine is a template that is copied into each interrupt object. Its
  717. ; function is to save machine state and pass the address of the respective
  718. ; interrupt object and transfer control to the appropriate interrupt
  719. ; dispatcher.
  720. ;
  721. ; Control comes here through i386 interrupt gate and, upon entry, the
  722. ; interrupt is disabled.
  723. ;
  724. ; Note: If the length of this template changed, the corresponding constant
  725. ; defined in Ki.h needs to be updated accordingly.
  726. ;
  727. ; Arguments:
  728. ;
  729. ; None
  730. ;
  731. ; Return Value:
  732. ;
  733. ; edi - addr of interrupt object
  734. ; esp - top of trap frame
  735. ; interrupts are disabled
  736. ;
  737. ;--
  738. _KiShutUpAssembler proc
  739. public _KiInterruptTemplate
  740. _KiInterruptTemplate label byte
  741. ; Save machine state on trap frame
  742. ENTER_INTERRUPT kit_a, kit_t
  743. ;
  744. ; the following instruction gets the addr of associated interrupt object.
  745. ; the value ? will be replaced by REAL interrupt object address at
  746. ; interrupt object initialization time.
  747. ; mov edi, addr of interrupt object
  748. ;
  749. ; Template modifications made to support BBT, include replacing bogus
  750. ; insructions (created by db and dd) with real instructions.
  751. ; This stuff gets overwritten anyway. BBT just needs to see real instructions.
  752. public _KiInterruptTemplate2ndDispatch
  753. _KiInterruptTemplate2ndDispatch equ this dword
  754. mov edi,0
  755. public _KiInterruptTemplateObject
  756. _KiInterruptTemplateObject equ this dword
  757. ; the following instruction transfers control to the appropriate dispatcher
  758. ; code. The value ? will be replaced by real InterruptObj.DispatchAddr
  759. ; at interrupt initialization time. The dispatcher routine will be any one
  760. ; of _KiInterruptDispatch, _KiFloatingDispatch, or _KiChainDispatch.
  761. ; jmp [IntObj.DispatchAddr]
  762. jmp _KeSynchronizeExecution
  763. public _KiInterruptTemplateDispatch
  764. _KiInterruptTemplateDispatch equ this dword
  765. ENTER_DR_ASSIST kit_a, kit_t
  766. ; end of _KiInterruptTemplate
  767. if ($ - _KiInterruptTemplate) GT DISPATCH_LENGTH
  768. .err
  769. %out <InterruptTemplate greater than dispatch_length>
  770. endif
  771. _KiShutUpAssembler endp
  772. page ,132
  773. subttl "Unexpected Interrupt"
  774. ;++
  775. ;
  776. ; Routine Description:
  777. ;
  778. ; This routine is entered as the result of an interrupt being generated
  779. ; via a vector that is not connected to an interrupt object.
  780. ;
  781. ; For any unconnected vector, its associated 8259 irq is masked out at
  782. ; Initialization time. So, this routine should NEVER be called.
  783. ; If somehow, this routine gets control we simple raise a BugCheck and
  784. ; stop the system.
  785. ;
  786. ; Arguments:
  787. ;
  788. ; None
  789. ; Interrupt is disabled
  790. ;
  791. ; Return Value:
  792. ;
  793. ; None.
  794. ;
  795. ;--
  796. public _KiUnexpectedInterrupt
  797. _KiUnexpectedInterrupt proc
  798. cPublicFpo 0,0
  799. ; stop the system
  800. stdCall _KeBugCheck, <TRAP_CAUSE_UNKNOWN>
  801. nop
  802. _KiUnexpectedInterrupt endp
  803. _TEXT$00 ends
  804. end