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.

639 lines
18 KiB

  1. ;++
  2. ;
  3. ;Copyright (c) 1991 Microsoft Corporation
  4. ;
  5. ;Module Name:
  6. ;
  7. ; ixsysint.asm
  8. ;
  9. ;Abstract:
  10. ;
  11. ; This module implements the HAL routines to enable/disable system
  12. ; interrupts.
  13. ;
  14. ;Author:
  15. ;
  16. ; John Vert (jvert) 22-Jul-1991
  17. ;
  18. ;Environment:
  19. ;
  20. ; Kernel Mode
  21. ;
  22. ;Revision History:
  23. ;
  24. ;--
  25. .386p
  26. .xlist
  27. include hal386.inc
  28. include callconv.inc ; calling convention macros
  29. include i386\ix8259.inc
  30. include i386\kimacro.inc
  31. include mac386.inc
  32. .list
  33. extrn KiI8259MaskTable:DWORD
  34. EXTRNP _KeBugCheck,1,IMPORT
  35. ifdef IRQL_METRICS
  36. extrn HalPostponedIntCount:dword
  37. endif
  38. extrn _HalpEisaELCR:dword ; Set bit indicates LEVEL
  39. extrn _HalpEisaIrqIgnore:dword
  40. extrn SWInterruptHandlerTable:dword
  41. extrn _HalpIrqMiniportInitialized:dword
  42. extrn HalpHardwareInterruptLevel:proc
  43. extrn _PciirqmpGetTrigger@4:proc
  44. extrn _PciirqmpSetTrigger@4:proc
  45. ;
  46. ; Constants used to initialize CMOS/Real Time Clock
  47. ;
  48. CMOS_CONTROL_PORT EQU 70h ; command port for cmos
  49. CMOS_DATA_PORT EQU 71h ; cmos data port
  50. ;
  51. ; Macros to Read/Write/Reset CMOS to initialize RTC
  52. ;
  53. ; CMOS_READ
  54. ;
  55. ; Description: This macro read a byte from the CMOS register specified
  56. ; in (AL).
  57. ;
  58. ; Parameter: (AL) = address/register to read
  59. ; Return: (AL) = data
  60. ;
  61. CMOS_READ MACRO
  62. OUT CMOS_CONTROL_PORT,al ; ADDRESS LOCATION AND DISABLE NMI
  63. IODelay ; I/O DELAY
  64. IN AL,CMOS_DATA_PORT ; READ IN REQUESTED CMOS DATA
  65. IODelay ; I/O DELAY
  66. ENDM
  67. _DATA SEGMENT DWORD PUBLIC 'DATA'
  68. align dword
  69. ;
  70. ; HalDismissSystemInterrupt does an indirect jump through this table so it
  71. ; can quickly execute specific code for different interrupts.
  72. ;
  73. public HalpSpecialDismissTable
  74. HalpSpecialDismissTable label dword
  75. dd offset FLAT:HalpDismissNormal ; irq 0
  76. dd offset FLAT:HalpDismissNormal ; irq 1
  77. dd offset FLAT:HalpDismissNormal ; irq 2
  78. dd offset FLAT:HalpDismissNormal ; irq 3
  79. dd offset FLAT:HalpDismissNormal ; irq 4
  80. dd offset FLAT:HalpDismissNormal ; irq 5
  81. dd offset FLAT:HalpDismissNormal ; irq 6
  82. dd offset FLAT:HalpDismissIrq07 ; irq 7
  83. dd offset FLAT:HalpDismissNormal ; irq 8
  84. dd offset FLAT:HalpDismissNormal ; irq 9
  85. dd offset FLAT:HalpDismissNormal ; irq A
  86. dd offset FLAT:HalpDismissNormal ; irq B
  87. dd offset FLAT:HalpDismissNormal ; irq C
  88. dd offset FLAT:HalpDismissIrq0d ; irq D
  89. dd offset FLAT:HalpDismissNormal ; irq E
  90. dd offset FLAT:HalpDismissIrq0f ; irq F
  91. dd offset FLAT:HalpDismissNormal ; irq 10
  92. dd offset FLAT:HalpDismissNormal ; irq 11
  93. dd offset FLAT:HalpDismissNormal ; irq 12
  94. dd offset FLAT:HalpDismissNormal ; irq 13
  95. dd offset FLAT:HalpDismissNormal ; irq 14
  96. dd offset FLAT:HalpDismissNormal ; irq 15
  97. dd offset FLAT:HalpDismissNormal ; irq 16
  98. dd offset FLAT:HalpDismissNormal ; irq 17
  99. dd offset FLAT:HalpDismissNormal ; irq 18
  100. dd offset FLAT:HalpDismissNormal ; irq 19
  101. dd offset FLAT:HalpDismissNormal ; irq 1A
  102. dd offset FLAT:HalpDismissNormal ; irq 1B
  103. dd offset FLAT:HalpDismissNormal ; irq 1C
  104. dd offset FLAT:HalpDismissNormal ; irq 1D
  105. dd offset FLAT:HalpDismissNormal ; irq 1E
  106. dd offset FLAT:HalpDismissNormal ; irq 1F
  107. dd offset FLAT:HalpDismissNormal ; irq 20
  108. dd offset FLAT:HalpDismissNormal ; irq 21
  109. dd offset FLAT:HalpDismissNormal ; irq 22
  110. dd offset FLAT:HalpDismissNormal ; irq 23
  111. _DATA ENDS
  112. _TEXT SEGMENT DWORD PUBLIC 'DATA'
  113. public HalpSpecialDismissLevelTable
  114. HalpSpecialDismissLevelTable label dword
  115. dd offset FLAT:HalpDismissLevel ; irq 0
  116. dd offset FLAT:HalpDismissLevel ; irq 1
  117. dd offset FLAT:HalpDismissLevel ; irq 2
  118. dd offset FLAT:HalpDismissLevel ; irq 3
  119. dd offset FLAT:HalpDismissLevel ; irq 4
  120. dd offset FLAT:HalpDismissLevel ; irq 5
  121. dd offset FLAT:HalpDismissLevel ; irq 6
  122. dd offset FLAT:HalpDismissIrq07Level ; irq 7
  123. dd offset FLAT:HalpDismissLevel ; irq 8
  124. dd offset FLAT:HalpDismissLevel ; irq 9
  125. dd offset FLAT:HalpDismissLevel ; irq A
  126. dd offset FLAT:HalpDismissLevel ; irq B
  127. dd offset FLAT:HalpDismissLevel ; irq C
  128. dd offset FLAT:HalpDismissIrq0dLevel ; irq D
  129. dd offset FLAT:HalpDismissLevel ; irq E
  130. dd offset FLAT:HalpDismissIrq0fLevel ; irq F
  131. _TEXT ENDS
  132. _TEXT$01 SEGMENT DWORD PUBLIC 'CODE'
  133. ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
  134. ;++
  135. ;BOOLEAN
  136. ;HalBeginSystemInterrupt(
  137. ; IN KIRQL Irql
  138. ; IN CCHAR Vector,
  139. ; OUT PKIRQL OldIrql
  140. ; )
  141. ;
  142. ;
  143. ;
  144. ;Routine Description:
  145. ;
  146. ; This routine is used to dismiss the specified vector number. It is called
  147. ; before any interrupt service routine code is executed.
  148. ;
  149. ; N.B. This routine does NOT preserve EAX or EBX
  150. ;
  151. ; On a UP machine the interrupt dismissed at BeginSystemInterrupt time.
  152. ; This is fine since the irql is being raise to mask it off.
  153. ; HalEndSystemInterrupt is simply a LowerIrql request.
  154. ;
  155. ;
  156. ;Arguments:
  157. ;
  158. ; Irql - Supplies the IRQL to raise to
  159. ;
  160. ; Vector - Supplies the vector of the interrupt to be dismissed
  161. ;
  162. ; OldIrql- Location to return OldIrql
  163. ;
  164. ;
  165. ;Return Value:
  166. ;
  167. ; FALSE - Interrupt is spurious and should be ignored
  168. ;
  169. ; TRUE - Interrupt successfully dismissed and Irql raised.
  170. ;
  171. ;--
  172. align dword
  173. HbsiIrql equ byte ptr [esp+4]
  174. HbsiVector equ byte ptr [esp+8]
  175. HbsiOldIrql equ dword ptr [esp+12]
  176. cPublicProc _HalBeginSystemInterrupt ,3
  177. .FPO ( 0, 3, 0, 0, 0, 0 )
  178. xor ecx, ecx
  179. mov cl, HbsiVector ; (ecx) = System Vector
  180. sub ecx, PRIMARY_VECTOR_BASE ; (ecx) = 8259 IRQ #
  181. if DBG
  182. cmp ecx, 1fh
  183. jbe hbsi00
  184. int 3
  185. hbsi00:
  186. endif
  187. jmp HalpSpecialDismissTable[ecx*4]
  188. HalpDismissIrq0f:
  189. ;
  190. ; Check to see if this is a spurious interrupt
  191. ;
  192. mov al, OCW3_READ_ISR ; tell 8259 we want to read ISR
  193. out PIC2_PORT0, al
  194. IODelay ; delay
  195. in al, PIC2_PORT0 ; (al) = content of PIC 1 ISR
  196. test al, 10000000B ; Is In-Service register set?
  197. jnz short HalpDismissNormal ; No, this is NOT a spurious int,
  198. ; go do the normal interrupt stuff
  199. HalpIrq0fSpurious:
  200. ;
  201. ; This is a spurious interrupt.
  202. ; Because the slave PIC is cascaded to irq2 of master PIC, we need to
  203. ; dismiss the interupt on master PIC's irq2.
  204. ;
  205. mov al, PIC2_EOI ; Specific eoi to master for pic2 eoi
  206. out PIC1_PORT0, al ; send irq2 specific eoi to master
  207. mov eax,0 ; return FALSE
  208. stdRET _HalBeginSystemInterrupt
  209. HalpDismissIrq07:
  210. ;
  211. ; Check to see if this is a spurious interrupt
  212. ;
  213. mov al, OCW3_READ_ISR ; tell 8259 we want to read ISR
  214. out PIC1_PORT0, al
  215. IODelay ; delay
  216. in al, PIC1_PORT0 ; (al) = content of PIC 1 ISR
  217. test al, 10000000B ; Is In-Service register set?
  218. jnz HalpDismissNormal ; No, so this is NOT a spurious int
  219. mov eax, 0 ; return FALSE
  220. stdRET _HalBeginSystemInterrupt
  221. HalpDismissIrq0d:
  222. ;
  223. ; Clear the NPX busy latch.
  224. ;
  225. xor al,al
  226. out I386_80387_BUSY_PORT, al
  227. align 4
  228. HalpDismissNormal:
  229. ;
  230. ; Raise IRQL to requested level
  231. ;
  232. xor ebx,ebx
  233. mov al, HbsiIrql ; (al) = New irql
  234. ; (ecx) = IRQ #
  235. mov bl, PCR[PcIrql] ; (ebx) = Current Irql
  236. ;
  237. ; Now we check to make sure the Irql of this interrupt > current Irql.
  238. ; If it is not, we dismiss it as spurious and set the appropriate bit
  239. ; in the IRR so we can dispatch the interrupt when Irql is lowered
  240. ;
  241. cmp al, bl
  242. jbe Hdsi300
  243. mov PCR[PcIrql], al ; set new Irql
  244. mov edx, HbsiOldIrql ; save current irql to OldIrql variable
  245. mov byte ptr [edx], bl
  246. ;
  247. ; Dismiss interrupt.
  248. ;
  249. mov eax, ecx ; (eax) = IRQ #
  250. cmp eax, 8 ; EOI to master or slave?
  251. jae short Hbsi100 ; EIO to both master and slave
  252. or al, PIC1_EOI_MASK ; create specific eoi mask for master
  253. out PIC1_PORT0, al ; dismiss the interrupt
  254. sti
  255. mov eax, 1 ; return TRUE
  256. stdRET _HalBeginSystemInterrupt
  257. align 4
  258. Hbsi100:
  259. add al, OCW2_SPECIFIC_EOI - 8 ; specific eoi to slave
  260. out PIC2_PORT0, al
  261. mov al, PIC2_EOI ; specific eoi to master for pic2 eoi
  262. out PIC1_PORT0, al ; send irq2 specific eoi to master
  263. sti
  264. mov eax, 1 ; return TRUE
  265. stdRET _HalBeginSystemInterrupt
  266. align 4
  267. Hdsi300:
  268. ;
  269. ; An interrupt has come in at a lower Irql, so we dismiss it as spurious and
  270. ; set the appropriate bit in the IRR so that KeLowerIrql knows to dispatch
  271. ; it when Irql is lowered.
  272. ;
  273. ; (ecx) = 8259 IRQ#
  274. ; (al) = New Irql
  275. ; (ebx) = Current Irql
  276. ;
  277. mov eax, 1
  278. add ecx, 4 ; (ecx) = Irq # + 4
  279. shl eax, cl
  280. or PCR[PcIRR], eax
  281. ;
  282. ; Raise Irql to prevent it from happening again
  283. ;
  284. ;
  285. ; Get the PIC masks for Irql
  286. ;
  287. mov eax, KiI8259MaskTable[ebx*4]
  288. or eax, PCR[PcIDR]
  289. ;
  290. ; Write the new interrupt mask register back to the 8259
  291. ;
  292. SET_8259_MASK
  293. Hbsi390:
  294. ifdef IRQL_METRICS
  295. lock inc HalPostponedIntCount
  296. endif
  297. xor eax, eax ; return FALSE, spurious interrupt
  298. stdRET _HalBeginSystemInterrupt
  299. HalpDismissIrq0fLevel:
  300. ;
  301. ; Check to see if this is a spurious interrupt
  302. ;
  303. mov al, OCW3_READ_ISR ; tell 8259 we want to read ISR
  304. out PIC2_PORT0, al
  305. IODelay ; delay
  306. in al, PIC2_PORT0 ; (al) = content of PIC 1 ISR
  307. test al, 10000000B ; Is In-Service register set?
  308. jnz short HalpDismissLevel ; No, this is NOT a spurious int,
  309. ; go do the normal interrupt stuff
  310. jmp HalpIrq0fSpurious
  311. HalpDismissIrq07Level:
  312. ;
  313. ; Check to see if this is a spurious interrupt
  314. ;
  315. mov al, OCW3_READ_ISR ; tell 8259 we want to read ISR
  316. out PIC1_PORT0, al
  317. IODelay ; delay
  318. in al, PIC1_PORT0 ; (al) = content of PIC 1 ISR
  319. test al, 10000000B ; Is In-Service register set?
  320. jnz short HalpDismissLevel ; No, so this is NOT a spurious int
  321. mov eax, 0 ; return FALSE
  322. stdRET _HalBeginSystemInterrupt
  323. HalpDismissIrq0dLevel:
  324. ;
  325. ; Clear the NPX busy latch.
  326. ;
  327. xor al,al
  328. out I386_80387_BUSY_PORT, al
  329. align 4
  330. HalpDismissLevel:
  331. ;
  332. ; Mask this level interrupt off
  333. ; (ecx) = 8259 IRQ#
  334. ;
  335. mov al, HbsiIrql ; (al) = New irql
  336. mov eax, KiI8259MaskTable[eax*4] ; get 8259's masks
  337. or eax, PCR[PcIDR] ; mask disabled irqs
  338. SET_8259_MASK ; send mask to 8259s
  339. ;
  340. ; The SWInterruptHandler for this vector has been set to a NOP.
  341. ; Set the vector's IRR so that Lower Irql will clear the 8259 mask for this
  342. ; Irq when the irql is lowered below this level.
  343. ;
  344. mov eax, ecx ; (eax) = Irq #
  345. mov ebx, 1
  346. add ecx, 4 ; (ecx) = Irq # + 4
  347. shl ebx, cl
  348. or PCR[PcIRR], ebx
  349. ;
  350. ; Dismiss interrupt. Current interrupt is already masked off.
  351. ; Then check to make sure the Irql of this interrupt > current Irql.
  352. ; If it is not, we dismiss it as spurious - since this is a level interrupt
  353. ; when the 8259's are unmasked the interrupt will reoccur
  354. ;
  355. mov cl, HbsiIrql
  356. mov bl, PCR[PcIrql]
  357. mov edx, HbsiOldIrql
  358. cmp eax, 8 ; EOI to master or slave?
  359. jae short Hbsi450 ; EIO to both master and slave
  360. or al, PIC1_EOI_MASK ; create specific eoi mask for master
  361. out PIC1_PORT0, al ; dismiss the interrupt
  362. cmp cl, bl
  363. jbe short Hbsi390 ; Spurious?
  364. mov PCR[PcIrql], cl ; raise to new irql
  365. mov byte ptr [edx], bl ; return old irql
  366. sti
  367. mov eax, 1 ; return TRUE
  368. stdRET _HalBeginSystemInterrupt
  369. align 4
  370. Hbsi450:
  371. add al, OCW2_SPECIFIC_EOI - 8 ; specific eoi to slave
  372. out PIC2_PORT0, al
  373. mov al, PIC2_EOI ; specific eoi to master for pic2 eoi
  374. out PIC1_PORT0, al ; send irq2 specific eoi to master
  375. cmp cl, bl
  376. jbe Hbsi390 ; Spurious?
  377. mov PCR[PcIrql], cl ; raise to new irql
  378. mov byte ptr [edx], bl ; return old irql
  379. sti
  380. mov eax, 1 ; return TRUE
  381. stdRET _HalBeginSystemInterrupt
  382. stdENDP _HalBeginSystemInterrupt
  383. ;++
  384. ;VOID
  385. ;HalDisableSystemInterrupt(
  386. ; IN CCHAR Vector,
  387. ; IN KIRQL Irql
  388. ; )
  389. ;
  390. ;
  391. ;
  392. ;Routine Description:
  393. ;
  394. ; Disables a system interrupt.
  395. ;
  396. ;Arguments:
  397. ;
  398. ; Vector - Supplies the vector of the interrupt to be disabled
  399. ;
  400. ; Irql - Supplies the interrupt level of the interrupt to be disabled
  401. ;
  402. ;Return Value:
  403. ;
  404. ; None.
  405. ;
  406. ;--
  407. cPublicProc _HalDisableSystemInterrupt ,2
  408. .FPO ( 0, 2, 0, 0, 0, 0 )
  409. ;
  410. movzx ecx, byte ptr [esp+4] ; (ecx) = Vector
  411. sub ecx, PRIMARY_VECTOR_BASE ; (ecx) = 8259 irq #
  412. mov edx, 1
  413. shl edx, cl ; (ebx) = bit in IMR to disable
  414. cli
  415. or PCR[PcIDR], edx
  416. xor eax, eax
  417. ;
  418. ; Get the current interrupt mask register from the 8259
  419. ;
  420. in al, PIC2_PORT1
  421. shl eax, 8
  422. in al, PIC1_PORT1
  423. ;
  424. ; Mask off the interrupt to be disabled
  425. ;
  426. or eax, edx
  427. ;
  428. ; Write the new interrupt mask register back to the 8259
  429. ;
  430. out PIC1_PORT1, al
  431. shr eax, 8
  432. out PIC2_PORT1, al
  433. PIC2DELAY
  434. sti
  435. stdRET _HalDisableSystemInterrupt
  436. stdENDP _HalDisableSystemInterrupt
  437. ;++
  438. ;
  439. ;BOOLEAN
  440. ;HalEnableSystemInterrupt(
  441. ; IN ULONG Vector,
  442. ; IN KIRQL Irql,
  443. ; IN KINTERRUPT_MODE InterruptMode
  444. ; )
  445. ;
  446. ;
  447. ;Routine Description:
  448. ;
  449. ; Enables a system interrupt
  450. ;
  451. ;Arguments:
  452. ;
  453. ; Vector - Supplies the vector of the interrupt to be enabled
  454. ;
  455. ; Irql - Supplies the interrupt level of the interrupt to be enabled.
  456. ;
  457. ;Return Value:
  458. ;
  459. ; None.
  460. ;
  461. ;--
  462. cPublicProc _HalEnableSystemInterrupt ,3
  463. .FPO ( 0, 3, 0, 0, 0, 0 )
  464. movzx ecx, byte ptr [esp+4] ; (ecx) = vector
  465. sub ecx, PRIMARY_VECTOR_BASE
  466. jc hes_error
  467. cmp ecx, CLOCK2_LEVEL
  468. jnc hes_error
  469. ;
  470. ; Use the IRQ miniport to get the HW state.
  471. ;
  472. cmp _HalpIrqMiniportInitialized, 0
  473. jz hes_noMPGet
  474. push ecx
  475. lea eax, _HalpEisaELCR
  476. push eax
  477. call _PciirqmpGetTrigger@4
  478. pop ecx
  479. hes_noMPGet:
  480. bt _HalpEisaIrqIgnore,ecx ;;Is this Eisa Ignore bit set?
  481. jc short hes_ProgPic
  482. ;
  483. ; Clear or set the edge\level mask bit depending on what the caller wants.
  484. ;
  485. btr _HalpEisaELCR, ecx
  486. mov al, [esp+12]
  487. cmp al, 0
  488. jnz short hes_edge
  489. bt _HalpEisaELCR, ecx
  490. jc short @F
  491. ; Caller wants level triggered interrupts
  492. ; if IRQ routing is turned on, try and provide it
  493. cmp _HalpIrqMiniportInitialized, 0
  494. jz short @F
  495. bts _HalpEisaELCR, ecx
  496. @@:
  497. mov SWInterruptHandlerTable+4*4[ecx*4], offset HalpHardwareInterruptLevel
  498. mov edx, HalpSpecialDismissLevelTable[ecx*4]
  499. mov HalpSpecialDismissTable[ecx*4], edx
  500. hes_edge:
  501. cmp _HalpIrqMiniportInitialized, 0
  502. jz hes_ProgPIC
  503. ;
  504. ; Program the HW to make it match the callers request.
  505. ;
  506. mov eax, _HalpEisaELCR
  507. push ecx
  508. push eax
  509. call _PciirqmpSetTrigger@4
  510. pop ecx
  511. if 0
  512. .err
  513. ;;
  514. ;; We can't just arbitrarily blast ports. This makes machines do really weird things
  515. ;;
  516. hes_noMPSet:
  517. mov edx, 4d0h
  518. out dx, al
  519. inc edx
  520. mov al, ah
  521. out dx, al
  522. endif
  523. hes_ProgPIC:
  524. mov eax, 1
  525. shl eax, cl ; (ebx) = bit in IMR to enable
  526. not eax
  527. cli
  528. and PCR[PcIDR], eax
  529. ;
  530. ; Get the PIC masks for Irql 0
  531. ;
  532. mov eax, KiI8259MaskTable[0]
  533. or eax, PCR[PcIDR]
  534. ;
  535. ; Write the new interrupt mask register back to the 8259
  536. ;
  537. SET_8259_MASK
  538. sti
  539. mov eax, 1 ; return TRUE
  540. stdRET _HalEnableSystemInterrupt
  541. hes_error:
  542. if DBG
  543. int 3
  544. endif
  545. xor eax, eax ; FALSE
  546. stdRET _HalEnableSystemInterrupt
  547. stdENDP _HalEnableSystemInterrupt
  548. _TEXT$01 ENDS
  549. END