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.

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