;++ ; ;Copyright (c) 1992 NCR Corporation ; ;Module Name: ; ; ncrsyint.asm ; ;Abstract: ; ; This module implements the HAL routines to enable/disable system ; interrupts. ; ;Author: ; ; Richard Barton (o-richb) 24-Jan-1992 ; ;Environment: ; ; Kernel Mode ; ;Revision History: ; ;-- .486p .xlist include hal386.inc include callconv.inc ; calling convention macros include i386\ix8259.inc include i386\kimacro.inc include mac386.inc include i386\ncr.inc .list EXTRNP KfLowerIrql,1,,FASTCALL EXTRNP _NCRClearQicIpi,1 EXTRNP _HalQicRequestIpi,2 EXTRNP _NCRAdjustDynamicClaims,0 extrn KiI8259MaskTable:DWORD extrn _NCRLogicalNumberToPhysicalMask:DWORD extrn _NCRProcessorIDR:DWORD extrn _NCRNeverClaimIRQs:DWORD extrn _NCRMaxIRQsToClaim:DWORD extrn _NCRGlobalClaimedIRQs:DWORD ifdef DBG extrn _NCRProcessorClaimedIRQs:DWORD extrn _NCRClaimCount:DWORD extrn _NCRStolenCount:DWORD extrn _NCRUnclaimCount:DWORD endif ifdef IRQL_METRICS extrn HalPostponedIntCount:dword endif _TEXT SEGMENT DWORD USE32 PUBLIC 'CODE' ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING ;++ ;BOOLEAN ;HalBeginSystemInterrupt( ; IN KIRQL Irql ; IN CCHAR Vector, ; OUT PKIRQL OldIrql ; ) ; ; ; ;Routine Description: ; ; This routine is used to determine whether the given interrupt is ; spurious and to raise the irql to the given value. ; It is called before the interrupt service routine code is executed. ; ; N.B. This routine does NOT preserve EAX or EBX ; ; On a UP machine the interrupt dismissed at BeginSystemInterrupt time. ; This is fine since the irql is being raise to mask it off. ; HalEndSystemInterrupt is simply a LowerIrql request. ; ; ;Arguments: ; ; Irql - Supplies the IRQL to raise to ; ; Vector - Supplies the vector of the interrupt being handled ; ; OldIrql- Location to return OldIrql ; ; ;Return Value: ; ; FALSE - Interrupt is spurious and should be ignored ; ; TRUE - Interrupt is real and Irql raised. ; ;-- HbsiIrql equ byte ptr [esp+4] HbsiVector equ byte ptr [esp+8] HbsiOldIrql equ dword ptr [esp+12] cPublicProc _HalBeginSystemInterrupt ,3 cPublicFpo 3,0 movzx ebx,HbsiVector ; (eax) = System Vector sub ebx, PRIMARY_VECTOR_BASE ; (eax) = 8259 IRQ # cmp ebx, 1FH ; if greater then CPI ja HalpNotSpurious ; ; we could be spurious at irq 7 ; mov eax,ebx ; lets mask off whether it is and eax,0fh ; secondary or primary cmp eax, 7H jne HbsiCheckIrq0F align dword HbsiCheckIrq07: ; ; Check to see if this is a spurious interrupt at irq7 ; in al, PIC1_PORT0 ; (al) = content of PIC 1 ISR test al, 10000000B ; Is In-Service register set? jnz short HalpNotSpurious ; No, so this is NOT a spurious int xor eax, eax ; return FALSE stdRET _HalBeginSystemInterrupt align dword HbsiCheckIrq0F: ; ; we could be spurious with irq F ; mov eax,ebx ; lets mask off whether it is and eax,0fh ; secondary or primary cmp eax, 0FH jne HalpNotSpurious ; ; Check to see if this is a spurious interrupt at irq F ; in al, PIC2_PORT0 ; (al) = content of PIC 1 ISR test al, 10000000B ; Is In-Service register set? jnz short HalpNotSpurious ; No, this is NOT a spurious int, ; go do the normal interrupt stuff ; ; This is a spurious interrupt. ; Because the slave PIC is cascaded to irq2 of master PIC, we need to ; dismiss the interupt on master PIC's irq2. ; mov al, PIC2_EOI ; Specific eoi to master for pic2 eoi out PIC1_PORT0, al ; send irq2 specific eoi to master xor eax, eax ; return FALSE stdRET _HalBeginSystemInterrupt align dword HalpNotSpurious: if DBG cmp ebx, 4FH jbe @f int 3 align dword @@: endif ; ; Store OldIrql ; mov eax, HbsiOldIrql mov cl, PCR[PcIrql] mov [eax], cl ; ; Raise IRQL to requested level ; mov al, HbsiIrql ; (eax) = irql ; (ebx) = IRQ # ; ; Now we check to make sure the Irql of this interrupt > current Irql. ; If it is not, we dismiss it as spurious and set the appropriate bit ; in the IRR so we can dispatch the interrupt when Irql is lowered ; cmp al, cl jbe Hbsi300 ; ; now check for a cpi. ; cmp ebx, NCR_CPI_VECTOR_BASE - PRIMARY_VECTOR_BASE ; check for VIC ipi mov PCR[PcIrql], al ; set new Irql jb CheckClaim cmp ebx, NCR_QIC_CPI_VECTOR_BASE - PRIMARY_VECTOR_BASE ; check for QIC ipi jb VicEOI and ebx,7H ; only the mask of irq stdCall _NCRClearQicIpi, jmp NCRCPIEOId VicEOI: and bl, 7H ; only the mask of irq mov al, bl or al, PIC1_EOI_MASK ; create specific eoi mask for master out PIC1_PORT0, al ; dismiss the interrupt NCRCPIEOId: sti mov eax, 1 ; return TRUE, interrupt dismissed stdRET _HalBeginSystemInterrupt ;RMU ; ; Logic used to dynamicly claim device interrupts ; CheckClaim: mov ecx, ebx ; get vector ; ; Lets check for a status change interrupt because it is a broadcast interrupt ; and is sent to all processors. In this case we skip the Claim logic completely. ; If we try to claim this interrupt it will cause problems because it is valid for a ; processor to get this interrupt while another processor has it claimed. ; cmp ecx, 027h ; status change interrupt is at vector PRIMARY_VECTOR_BASE + 027H jz DontClaim ; done claim if equal ; ; ; and ecx, 0fh ; now is irql mov eax, 1 ; build irq mask shl eax, cl test eax, _NCRNeverClaimIRQs ; see if we should never claim it irq jnz DontClaim mov ecx, _NCRGlobalClaimedIRQs mov edx, PCR[PcHal.PcrMyClaimedIRQs] and ecx, eax ; set if irq claimed globally and edx, eax ; set if irq claimed privately test edx, ecx ; if irq already claimed jz AdjustClaim DontClaim: sti mov eax, 1 ; return TRUE, interrupt dismissed stdRET _HalBeginSystemInterrupt AdjustClaim: test edx, edx not edx ; is it claimed privately? jnz PrivateUnclaim ; yes, then clear claim test ecx,ecx ; is it claimed by another? jnz Unclaimed ; don't unclaim mov ecx, PCR[PcHal.PcrMyClaimedIRQsCount] ; see if you have our fair share cmp ecx, _NCRMaxIRQsToClaim ; of irqs claimed then handle if jl ClaimForMe ; but don't claim HandleNoClaim: sti mov eax, 1 ; return TRUE, interrupt dismissed stdRET _HalBeginSystemInterrupt ClaimForMe: mov edx, eax push ebx ; save vector mov ebx, PCR[PcHal.PcrMyClaimedIRQs] ; our claimed irqs or ebx, eax mov eax, _NCRGlobalClaimedIRQs ; what global claim should be GlobalClaim: test eax,edx ; this irq has been stolen jnz IRQStolen ; by another processor mov ecx,ebx or ecx,eax lock cmpxchg _NCRGlobalClaimedIRQs, ecx jne GlobalClaim add esp,4 ; throw away saved vector we do ; not need it ; ; Lets claim the interrupt now ; mov eax,ebx mov PCR[PcHal.PcrMyClaimedIRQs],eax ; claim irq privately VIC_WRITE ClaimRegLsb ; set VIC claim registers shr eax,8 VIC_WRITE ClaimRegMsb inc PCR[PcHal.PcrMyClaimedIRQsCount] mov eax,PCR[PcHal.PcrMyClaimedIRQsCount] VIC_WRITE ActivityReg ifdef DBG mov ecx,PCR[PcNumber] mov eax,PCR[PcHal.PcrMyClaimedIRQs] mov _NCRProcessorClaimedIRQs[ecx*4], eax inc _NCRClaimCount; endif ; done claiming ClaimDone: sti mov eax, 1 ; return TRUE, interrupt dismissed stdRET _HalBeginSystemInterrupt IRQStolen: ifdef DBG inc _NCRStolenCount; endif pop ebx ; restore vector and ebx, 0fh ; clear high nibble due to SMC or Status Change vector cmp ebx, 8 ; EOI to master or slave? mov al, bl jae short SHbsiEOIMaster ; EIO to both master and slave or al, PIC1_EOI_MASK ; create specific eoi mask for master out PIC1_PORT0, al ; dismiss the interrupt jmp short SHbsiMasterEOId SHbsiEOIMaster: mov al, OCW2_NON_SPECIFIC_EOI ; send non specific eoi to slave out PIC2_PORT0, al mov al, PIC2_EOI ; specific eoi to master for pic2 eoi out PIC1_PORT0, al ; send irq2 specific eoi to master SHbsiMasterEOId: xor eax, eax ; return FALSE, spurious interrupt stdRET _HalBeginSystemInterrupt align dword Hbsi300: ; ; Raise Irql to prevent it from happening again ; ; ; Get the PIC masks for Irql ; movzx eax, cl mov PCR[PcHal.PcrMyPICsIrql], eax mov eax, KiI8259MaskTable[eax*4] or eax, PCR[PcIDR] ; ; Write the new interrupt mask register back to the 8259 ; SET_IRQ_MASK ; ; if this isn't a CPI, EOI the interrupt to give the VIC a chance ; to reroute it ; cmp ebx, NCR_CPI_VECTOR_BASE - PRIMARY_VECTOR_BASE ; EOI for CPI? jae NCRPostponeCPI ; no need to EOI CPI ; ;RMU ; Logic used to unclaim interrupts. This is done when drivers have disabled ; an interrupt. ; ; mov ecx, ebx ; get vector and ecx, 0fh ; now is irql mov eax, 1 ; build irq mask shl eax, cl mov edx, PCR[PcHal.PcrMyClaimedIRQs] and edx, eax ; claiming fixed? jz Unclaimed ; don't unclaim mov ecx, PCR[PcHal.PcrMyClaimedIRQsCount] ; if we don't have our fair cmp ecx, _NCRMaxIRQsToClaim ; share of irqs claimed then jle Unclaimed ; don't unclaim not edx ; clear irq bit mov eax, _NCRGlobalClaimedIRQs ; what global claim should be GlobalUnclaim: mov ecx, edx and ecx, eax lock cmpxchg _NCRGlobalClaimedIRQs, ecx jne GlobalUnclaim PrivateUnclaim: mov eax, PCR[PcHal.PcrMyClaimedIRQs] and eax, edx mov PCR[PcHal.PcrMyClaimedIRQs],eax VIC_WRITE ClaimRegLsb shr eax,8 VIC_WRITE ClaimRegMsb dec PCR[PcHal.PcrMyClaimedIRQsCount] mov eax,PCR[PcHal.PcrMyClaimedIRQsCount] VIC_WRITE ActivityReg ifdef DBG mov ecx,PCR[PcNumber] mov eax,PCR[PcHal.PcrMyClaimedIRQs] mov _NCRProcessorClaimedIRQs[ecx*4], eax inc _NCRUnclaimCount; endif ; Unclaimed: and ebx, 0fh ; clear high nibble due to SMC or Status Change vector cmp ebx, 8 ; EOI to master or slave? mov al, bl jae short HbsiEOIMaster ; EIO to both master and slave or al, PIC1_EOI_MASK ; create specific eoi mask for master out PIC1_PORT0, al ; dismiss the interrupt jmp short HbsiMasterEOId HbsiEOIMaster: mov al, OCW2_NON_SPECIFIC_EOI ; send non specific eoi to slave out PIC2_PORT0, al mov al, PIC2_EOI ; specific eoi to master for pic2 eoi out PIC1_PORT0, al ; send irq2 specific eoi to master HbsiMasterEOId: ifdef IRQL_METRICS lock inc HalPostponedIntCount endif xor eax, eax ; return FALSE, spurious interrupt stdRET _HalBeginSystemInterrupt align dword NCRPostponeCPI: ; ; CPIs must be reissued since when we EOI them they're gone ; cmp ebx, NCR_QIC_CPI_VECTOR_BASE - PRIMARY_VECTOR_BASE ; check for QIC ipi jb VicCPI movzx ecx, bl sub ecx, NCR_QIC_CPI_VECTOR_BASE - PRIMARY_VECTOR_BASE and ecx, 7 ; ; Clear the current CPI so we can reissue it again ; push ecx stdCall _NCRClearQicIpi, pop ecx ; ; now reissue the same CPI... since our mask is raised and we've EOId ; the other we'll get this one when we lower our masks ; mov eax, PCR[PcHal.PcrMyLogicalMask] stdCall _HalQicRequestIpi, jmp ReissuedCPIDone VicCPI: movzx ecx, bl sub ecx, NCR_CPI_VECTOR_BASE - PRIMARY_VECTOR_BASE and ecx, 7 mov al, cl or al, PIC1_EOI_MASK ; create specific eoi mask for master out PIC1_PORT0, al ; dismiss the interrupt ; ; now reissue the same CPI...since our mask is raised and we've EOId ; the other we'll get this one when we lower our masks. ; shr ecx, 1 ; we're determining which VIC lea edx, [ecx*8] ; offset corresponds to the adc edx, VIC_BASE_ADDRESS ; given vector mov eax, PCR[PcHal.PcrMyLogicalNumber] mov eax, dword ptr _NCRLogicalNumberToPhysicalMask[eax*4] out dx, al ReissuedCPIDone: ifdef IRQL_METRICS lock inc HalPostponedIntCount endif xor eax, eax ; return FALSE, spurious interrupt stdRET _HalBeginSystemInterrupt stdENDP _HalBeginSystemInterrupt ;++ ;BOOLEAN ;HalEndSystemInterrupt( ; IN KIRQL Irql ; IN CCHAR Vector, ; ) ; ; ; ;Routine Description: ; ; This routine is used to dismiss the specified interrupt vector and ; to lower the irql to the given value. ; It is called after the interrupt service routine code is executed. ; ; N.B. This routine does NOT preserve EAX or EBX ; ;Arguments: ; ; Irql - Supplies the interrupt level of the interrupt to be dismissed ; ; Vector - Supplies the vector of the interrupt to be dismissed ; ;Return Value: ; ; None. ; ;-- HesiIrql equ [esp+4] HesiVector equ [esp+8] cPublicProc _HalEndSystemInterrupt ,2 cPublicFpo 2,0 movzx eax, byte ptr HesiVector ; (eax) = System Vector sub eax, PRIMARY_VECTOR_BASE ; (eax) = 8259 IRQ # if DBG cmp eax, 4FH jbe Hesi00 int 3 align dword Hesi00: endif ; ; Dismiss interrupt. Current interrupt is already masked off. note that ; cpi's are eoi'ed at the beginning. ; cmp eax, NCR_CPI_VECTOR_BASE - PRIMARY_VECTOR_BASE ; EOI for CPI? mov ecx, HesiIrql ; (cl) = NewIrql jae short Hesi10 ; no need to EOI CPI and eax, 0fh ; clear high nibble due to SMC or Status Change vector cmp eax, 8 ; EOI to master or slave? jae short Hesi100 ; EIO to both master and slave or al, PIC1_EOI_MASK ; create specific eoi mask for master out PIC1_PORT0, al ; dismiss the interrupt Hesi10: fstCall KfLowerIrql ; (cl) = NewIrql stdRet _HalEndSystemInterrupt Hesi100: mov al, OCW2_NON_SPECIFIC_EOI ; send non specific eoi to slave out PIC2_PORT0, al mov al, PIC2_EOI ; specific eoi to master for pic2 eoi out PIC1_PORT0, al ; send irq2 specific eoi to master fstCall KfLowerIrql ; (cl) = NewIrql stdRet _HalEndSystemInterrupt stdENDP _HalEndSystemInterrupt ;++ ;VOID ;HalDisableSystemInterrupt( ; IN CCHAR Vector, ; IN KIRQL Irql ; ) ; ; ; ;Routine Description: ; ; Disables a system interrupt. ; ;Arguments: ; ; Vector - Supplies the vector of the interrupt to be disabled ; ; Irql - Supplies the interrupt level of the interrupt to be disabled ; ;Return Value: ; ; None. ; ;-- cPublicProc _HalDisableSystemInterrupt ,2 cPublicFpo 2,0 ; movzx ecx, byte ptr [esp+4] ; (ecx) = Vector and ecx, 0FH ; (ecx) = 8259 irq # mov edx, 1 shl edx, cl ; (ebx) = bit in IMR to disable cli or PCR[PcIDR], edx ; ; save IDR in table for use by NCRAdjustDynamicClaims ; mov eax,PCR[PcNumber] or _NCRProcessorIDR[eax*4],edx ; xor eax, eax ; ; Get the current interrupt mask register from the 8259 ; in al, PIC2_PORT1 shl eax, 8 in al, PIC1_PORT1 ; ; Mask off the interrupt to be disabled ; or eax, edx ; ; Write the new interrupt mask register back to the 8259 ; out PIC1_PORT1, al shr eax, 8 out PIC2_PORT1, al PIC2DELAY sti stdCall _NCRAdjustDynamicClaims stdRET _HalDisableSystemInterrupt stdENDP _HalDisableSystemInterrupt ;++ ; ;BOOLEAN ;HalEnableSystemInterrupt( ; IN ULONG Vector, ; IN KIRQL Irql, ; IN KINTERRUPT_MODE InterruptMode ; ) ; ; ;Routine Description: ; ; Enables a system interrupt ; ;Arguments: ; ; Vector - Supplies the vector of the interrupt to be enabled ; ; Irql - Supplies the interrupt level of the interrupt to be enabled. ; ;Return Value: ; ; None. ; ;-- cPublicProc _HalEnableSystemInterrupt ,3 cPublicFpo 3,0 mov ecx, dword ptr [esp+4] ; (ecx) = Vector and ecx, 0FH mov eax, 1 shl eax, cl ; (ebx) = bit in IMR to enable not eax cli and PCR[PcIDR], eax ; ; save IDR in table for use by NCRAdjustDynamicClaims ; mov edx,PCR[PcNumber] and _NCRProcessorIDR[edx*4],eax ; ; Get the PIC masks for Irql 0 ; mov eax, KiI8259MaskTable[0] or eax, PCR[PcIDR] ; ; Write the new interrupt mask register back to the 8259 ; SET_IRQ_MASK sti stdCall _NCRAdjustDynamicClaims mov eax, 1 ; return TRUE stdRET _HalEnableSystemInterrupt stdENDP _HalEnableSystemInterrupt _TEXT ENDS END