diff options
Diffstat (limited to '')
-rw-r--r-- | private/ntos/nthals/halx86/i386/ixirql.asm | 1297 |
1 files changed, 1297 insertions, 0 deletions
diff --git a/private/ntos/nthals/halx86/i386/ixirql.asm b/private/ntos/nthals/halx86/i386/ixirql.asm new file mode 100644 index 000000000..e18a0ce8b --- /dev/null +++ b/private/ntos/nthals/halx86/i386/ixirql.asm @@ -0,0 +1,1297 @@ + title "Irql Processing" +;++ +; +; Copyright (c) 1989 Microsoft Corporation +; +; Module Name: +; +; ixirql.asm +; +; Abstract: +; +; This module implements the code necessary to raise and lower i386 +; Irql and dispatch software interrupts with the 8259 PIC. +; +; Author: +; +; Shie-Lin Tzong (shielint) 8-Jan-1990 +; +; Environment: +; +; Kernel mode only. +; +; Revision History: +; +; John Vert (jvert) 27-Nov-1991 +; Moved from kernel into HAL +; +;-- + +.386p + .xlist +include hal386.inc +include callconv.inc ; calling convention macros +include i386\ix8259.inc +include i386\kimacro.inc +include mac386.inc + .list + + + EXTRNP _KeBugCheck,1,IMPORT + EXTRNP _KiDispatchInterrupt,0,IMPORT + + extrn _HalpApcInterrupt:near + extrn _HalpDispatchInterrupt:near + extrn _KiUnexpectedInterrupt:near + extrn _HalpBusType:DWORD + extrn _HalpApcInterrupt2ndEntry:NEAR + extrn _HalpDispatchInterrupt2ndEntry:NEAR + extrn HalpSpecialDismissLevelTable:dword + extrn HalpSpecialDismissTable:dword + extrn _HalpEisaELCR:dword + +; +; Initialization control words equates for the PICs +; + +ICW1_ICW4_NEEDED equ 01H +ICW1_CASCADE equ 00H +ICW1_INTERVAL8 equ 00H +ICW1_LEVEL_TRIG equ 08H +ICW1_EDGE_TRIG equ 00H +ICW1_ICW equ 10H + +ICW4_8086_MODE equ 001H +ICW4_NORM_EOI equ 000H +ICW4_NON_BUF_MODE equ 000H +ICW4_SPEC_FULLY_NESTED equ 010H +ICW4_NOT_SPEC_FULLY_NESTED equ 000H + +OCW2_NON_SPECIFIC_EOI equ 020H +OCW2_SPECIFIC_EOI equ 060H +OCW2_SET_PRIORITY equ 0c0H + +PIC_SLAVE_IRQ equ 2 +PIC1_BASE equ 30H +PIC2_BASE equ 38H + +; +; Interrupt flag bit maks for EFLAGS +; + +EFLAGS_IF equ 200H +EFLAGS_SHIFT equ 9 + +; +; Hardware irq active masks +; + +IRQ_ACTIVE_MASK equ 0fffffff0h + +_DATA SEGMENT DWORD PUBLIC 'DATA' + +; +; PICsInitializationString - Master PIC initialization command string +; + +ifdef MCA + +PICsInitializationString dw PIC1_PORT0 + +; +; Master PIC initialization command +; + + db ICW1_ICW + ICW1_LEVEL_TRIG + ICW1_INTERVAL8 +\ + ICW1_CASCADE + ICW1_ICW4_NEEDED + db PIC1_BASE + db 1 SHL PIC_SLAVE_IRQ + db ICW4_NOT_SPEC_FULLY_NESTED + \ + ICW4_NON_BUF_MODE + \ + ICW4_NORM_EOI + \ + ICW4_8086_MODE +; +; Slave PIC initialization command strings +; + + dw PIC2_PORT0 + db ICW1_ICW + ICW1_LEVEL_TRIG + ICW1_INTERVAL8 +\ + ICW1_CASCADE + ICW1_ICW4_NEEDED + db PIC2_BASE + db PIC_SLAVE_IRQ + db ICW4_NOT_SPEC_FULLY_NESTED + \ + ICW4_NON_BUF_MODE + \ + ICW4_NORM_EOI + \ + ICW4_8086_MODE + dw 0 ; end of string + +else + +PICsInitializationString dw PIC1_PORT0 + +; +; Master PIC initialization command +; + + db ICW1_ICW + ICW1_EDGE_TRIG + ICW1_INTERVAL8 +\ + ICW1_CASCADE + ICW1_ICW4_NEEDED + db PIC1_BASE + db 1 SHL PIC_SLAVE_IRQ + db ICW4_NOT_SPEC_FULLY_NESTED + \ + ICW4_NON_BUF_MODE + \ + ICW4_NORM_EOI + \ + ICW4_8086_MODE +; +; Slave PIC initialization command strings +; + + dw PIC2_PORT0 + db ICW1_ICW + ICW1_EDGE_TRIG + ICW1_INTERVAL8 +\ + ICW1_CASCADE + ICW1_ICW4_NEEDED + db PIC2_BASE + db PIC_SLAVE_IRQ + db ICW4_NOT_SPEC_FULLY_NESTED + \ + ICW4_NON_BUF_MODE + \ + ICW4_NORM_EOI + \ + ICW4_8086_MODE + dw 0 ; end of string +endif + + align 4 + public KiI8259MaskTable +KiI8259MaskTable label dword + dd 00000000000000000000000000000000B ; irql 0 + dd 00000000000000000000000000000000B ; irql 1 + dd 00000000000000000000000000000000B ; irql 2 + dd 00000000000000000000000000000000B ; irql 3 + dd 11111111100000000000000000000000B ; irql 4 + dd 11111111110000000000000000000000B ; irql 5 + dd 11111111111000000000000000000000B ; irql 6 + dd 11111111111100000000000000000000B ; irql 7 + dd 11111111111110000000000000000000B ; irql 8 + dd 11111111111111000000000000000000B ; irql 9 + dd 11111111111111100000000000000000B ; irql 10 + dd 11111111111111110000000000000000B ; irql 11 + dd 11111111111111111000000000000000B ; irql 12 + dd 11111111111111111100000000000000B ; irql 13 + dd 11111111111111111110000000000000B ; irql 14 + dd 11111111111111111111000000000000B ; irql 15 + dd 11111111111111111111100000000000B ; irql 16 + dd 11111111111111111111110000000000B ; irql 17 + dd 11111111111111111111111000000000B ; irql 18 + dd 11111111111111111111111000000000B ; irql 19 + dd 11111111111111111111111010000000B ; irql 20 + dd 11111111111111111111111011000000B ; irql 21 + dd 11111111111111111111111011100000B ; irql 22 + dd 11111111111111111111111011110000B ; irql 23 + dd 11111111111111111111111011111000B ; irql 24 + dd 11111111111111111111111011111000B ; irql 25 + dd 11111111111111111111111011111010B ; irql 26 + dd 11111111111111111111111111111010B ; irql 27 + dd 11111111111111111111111111111011B ; irql 28 + dd 11111111111111111111111111111011B ; irql 29 + dd 11111111111111111111111111111011B ; irql 30 + dd 11111111111111111111111111111011B ; irql 31 + +; +; This table is used to mask all pending interrupts below a given Irql +; out of the IRR +; + align 4 + + public FindHigherIrqlMask +FindHigherIrqlMask label dword + dd 11111111111111111111111111111110B ; irql 0 + dd 11111111111111111111111111111100B ; irql 1 (APC) + dd 11111111111111111111111111111000B ; irql 2 (DISPATCH) + dd 11111111111111111111111111110000B ; irql 3 + dd 00000111111111111111111111110000B ; irql 4 + dd 00000011111111111111111111110000B ; irql 5 + dd 00000001111111111111111111110000B ; irql 6 + dd 00000000111111111111111111110000B ; irql 7 + dd 00000000011111111111111111110000B ; irql 8 + dd 00000000001111111111111111110000B ; irql 9 + dd 00000000000111111111111111110000B ; irql 10 + dd 00000000000011111111111111110000B ; irql 11 + dd 00000000000001111111111111110000B ; irql 12 + dd 00000000000000111111111111110000B ; irql 13 + dd 00000000000000011111111111110000B ; irql 14 + dd 00000000000000001111111111110000B ; irql 15 + dd 00000000000000000111111111110000B ; irql 16 + dd 00000000000000000011111111110000B ; irql 17 + dd 00000000000000000001111111110000B ; irql 18 + dd 00000000000000000001111111110000B ; irql 19 + dd 00000000000000000001011111110000B ; irql 20 + dd 00000000000000000001001111110000B ; irql 20 + dd 00000000000000000001000111110000B ; irql 22 + dd 00000000000000000001000011110000B ; irql 23 + dd 00000000000000000001000001110000B ; irql 24 + dd 00000000000000000001000000110000B ; irql 25 + dd 00000000000000000001000000010000B ; irql 26 + dd 00000000000000000000000000010000B ; irql 27 + dd 00000000000000000000000000000000B ; irql 28 + dd 00000000000000000000000000000000B ; irql 29 + dd 00000000000000000000000000000000B ; irql 30 + dd 00000000000000000000000000000000B ; irql 31 + + align 4 +; +; The following tables define the addresses of software interrupt routers +; + +; +; Use this table if there is NO machine state frame on stack already +; + + public SWInterruptHandlerTable +SWInterruptHandlerTable label dword + dd offset FLAT:_KiUnexpectedInterrupt ; irql 0 + dd offset FLAT:_HalpApcInterrupt ; irql 1 + dd offset FLAT:_HalpDispatchInterrupt2 ; irql 2 + dd offset FLAT:_KiUnexpectedInterrupt ; irql 3 + dd offset FLAT:HalpHardwareInterrupt00 ; 8259 irq#0 + dd offset FLAT:HalpHardwareInterrupt01 ; 8259 irq#1 + dd offset FLAT:HalpHardwareInterrupt02 ; 8259 irq#2 + dd offset FLAT:HalpHardwareInterrupt03 ; 8259 irq#3 + dd offset FLAT:HalpHardwareInterrupt04 ; 8259 irq#4 + dd offset FLAT:HalpHardwareInterrupt05 ; 8259 irq#5 + dd offset FLAT:HalpHardwareInterrupt06 ; 8259 irq#6 + dd offset FLAT:HalpHardwareInterrupt07 ; 8259 irq#7 + dd offset FLAT:HalpHardwareInterrupt08 ; 8259 irq#8 + dd offset FLAT:HalpHardwareInterrupt09 ; 8259 irq#9 + dd offset FLAT:HalpHardwareInterrupt10 ; 8259 irq#10 + dd offset FLAT:HalpHardwareInterrupt11 ; 8259 irq#11 + dd offset FLAT:HalpHardwareInterrupt12 ; 8259 irq#12 + dd offset FLAT:HalpHardwareInterrupt13 ; 8259 irq#13 + dd offset FLAT:HalpHardwareInterrupt14 ; 8259 irq#14 + dd offset FLAT:HalpHardwareInterrupt15 ; 8259 irq#15 + +; +; Use this table if there is already a machine state frame on stack +; + + public SWInterruptHandlerTable2 +SWInterruptHandlerTable2 label dword + dd offset FLAT:_KiUnexpectedInterrupt ; irql 0 + dd offset FLAT:_HalpApcInterrupt2ndEntry ; irql 1 + dd offset FLAT:_HalpDispatchInterrupt2ndEntry ; irql 2 + +; +; The following table picks up the highest pending software irq level +; from software irr +; + + public SWInterruptLookUpTable +SWInterruptLookUpTable label byte + db 0 ; SWIRR=0, so highest pending SW irql= 0 + db 0 ; SWIRR=1, so highest pending SW irql= 0 + db 1 ; SWIRR=2, so highest pending SW irql= 1 + db 1 ; SWIRR=3, so highest pending SW irql= 1 + db 2 ; SWIRR=4, so highest pending SW irql= 2 + db 2 ; SWIRR=5, so highest pending SW irql= 2 + db 2 ; SWIRR=6, so highest pending SW irql= 2 + db 2 ; SWIRR=7, so highest pending SW irql= 2 + +ifdef IRQL_METRICS + + public HalRaiseIrqlCount + public HalLowerIrqlCount + public HalQuickLowerIrqlCount + public HalApcSoftwareIntCount + public HalDpcSoftwareIntCount + public HalHardwareIntCount + public HalPostponedIntCount + public Hal8259MaskCount + +HalRaiseIrqlCount dd 0 +HalLowerIrqlCount dd 0 +HalQuickLowerIrqlCount dd 0 +HalApcSoftwareIntCount dd 0 +HalDpcSoftwareIntCount dd 0 +HalHardwareIntCount dd 0 +HalPostponedIntCount dd 0 +Hal8259MaskCount dd 0 + +endif +_DATA ENDS + + page ,132 + subttl "Raise Irql" + +_TEXT$01 SEGMENT PARA PUBLIC 'CODE' + ASSUME DS:FLAT, ES:FLAT, SS:FLAT, FS:NOTHING, GS:NOTHING +;++ +; +; KIRQL +; KfRaiseIrql ( +; IN KIRQL NewIrql, +; ) +; +; Routine Description: +; +; This routine is used to raise IRQL to the specified value. +; Also, a mask will be used to mask off all the lower lever 8259 +; interrupts. +; +; Arguments: +; +; (cl) = NewIrql - the new irql to be raised to +; +; Return Value: +; +; OldIrql - the addr of a variable which old irql should be stored +; +;-- + +cPublicFastCall KfRaiseIrql,1 +cPublicFpo 0, 0 + + xor eax, eax ; Eliminate partial stall on return to caller + mov al, PCR[PcIrql] ; (al) = Old Irql + mov PCR[PcIrql], cl ; set new irql + +ifdef IRQL_METRICS + inc HalRaiseIrqlCount +endif + +if DBG + cmp al, cl ; old > new? + ja short Kri99 ; yes, go bugcheck + + fstRET KfRaiseIrql + +cPublicFpo 2, 2 +Kri99: + movzx eax, al + movzx ecx, cl + push ecx ; put new irql where we can find it + push eax ; put old irql where we can find it + mov byte ptr PCR[PcIrql],0 ; avoid recursive error + stdCall _KeBugCheck, <IRQL_NOT_GREATER_OR_EQUAL> ; never return +endif + fstRET KfRaiseIrql + +fstENDP KfRaiseIrql + +;++ +; +; KIRQL +; KeRaiseIrqlToDpcLevel ( +; ) +; +; Routine Description: +; +; This routine is used to raise IRQL to DPC level. +; +; Arguments: +; +; Return Value: +; +; OldIrql - the addr of a variable which old irql should be stored +; +;-- + +cPublicProc _KeRaiseIrqlToDpcLevel,0 +cPublicFpo 0, 0 + + xor eax, eax ; Eliminate partial stall + mov al, PCR[PcIrql] ; (al) = Old Irql + mov byte ptr PCR[PcIrql], DISPATCH_LEVEL ; set new irql + +ifdef IRQL_METRICS + inc HalRaiseIrqlCount +endif +if DBG + cmp al, DISPATCH_LEVEL ; old > new? + ja short Krid99 ; yes, go bugcheck +endif + + stdRET _KeRaiseIrqlToDpcLevel + +if DBG +cPublicFpo 0,1 +Krid99: movzx eax, al + push eax ; put old irql where we can find it + stdCall _KeBugCheck, <IRQL_NOT_GREATER_OR_EQUAL> ; never return + stdRET _KeRaiseIrqlToDpcLevel +endif + +stdENDP _KeRaiseIrqlToDpcLevel + + +;++ +; +; KIRQL +; KeRaiseIrqlToSynchLevel ( +; ) +; +; Routine Description: +; +; This routine is used to raise IRQL to SYNC level. +; +; Arguments: +; +; Return Value: +; +; OldIrql - the addr of a variable which old irql should be stored +; +;-- + +cPublicProc _KeRaiseIrqlToSynchLevel,0 +cPublicFpo 0, 0 + + xor eax, eax ; Eliminate partial stall + mov al, PCR[PcIrql] ; (al) = Old Irql + mov byte ptr PCR[PcIrql], SYNCH_LEVEL ; set new irql + +ifdef IRQL_METRICS + inc HalRaiseIrqlCount +endif +if DBG + cmp al, SYNCH_LEVEL ; old > new? + ja short Kris99 ; yes, go bugcheck +endif + + stdRET _KeRaiseIrqlToSynchLevel + +if DBG +cPublicFpo 0,1 +Kris99: movzx eax, al + push eax ; put old irql where we can find it + stdCall _KeBugCheck, <IRQL_NOT_GREATER_OR_EQUAL> ; never return + stdRET _KeRaiseIrqlToSynchLevel +endif + +stdENDP _KeRaiseIrqlToSynchLevel + +;++ +; +; VOID +; KfLowerIrql ( +; IN KIRQL NewIrql +; ) +; +; Routine Description: +; +; This routine is used to lower IRQL to the specified value. +; The IRQL and PIRQL will be updated accordingly. Also, this +; routine checks to see if any software interrupt should be +; generated. The following condition will cause software +; interrupt to be simulated: +; any software interrupt which has higher priority than +; current IRQL's is pending. +; +; NOTE: This routine simulates software interrupt as long as +; any pending SW interrupt level is higher than the current +; IRQL, even when interrupts are disabled. +; +; Arguments: +; +; (cl) = NewIrql - the new irql to be set. +; +; Return Value: +; +; None. +; +;-- + +cPublicFastCall KfLowerIrql,1 +cPublicFpo 0, 0 + and ecx, 0ffh + +ifdef IRQL_METRICS + inc HalLowerIrqlCount +endif + +if DBG + cmp cl,PCR[PcIrql] ; Make sure we are not lowering to + ja KliBug ; ABOVE current level +endif + pushfd + cli + mov PCR[PcIrql], ecx + mov edx, PCR[PcIRR] + and edx, FindHigherIrqlMask[ecx*4] ; (edx) is the bitmask of + ; pending interrupts we need to + ; dispatch now. + jnz short Kli10 ; go dispatch pending interrupts + +; +; no interrupts pending, return quickly. +; + + popfd + +ifdef IRQL_METRICS + inc HalQuickLowerIrqlCount +endif + fstRET KfLowerIrql + +cPublicFpo 1, 1 +align 4 +Kli10: + +; +; If there is a pending hardware interrupt, then the PICs have been +; masked to reflect the actual Irql. +; + + bsr ecx, edx ; (ecx) = Pending irq level + cmp ecx, DISPATCH_LEVEL + ja short Kli40 + + call SWInterruptHandlerTable[ecx*4] ; Dispatch the pending int. + popfd + +cPublicFpo 1, 0 + fstRET KfLowerIrql + +Kli40: +; +; Clear all the interrupt masks +; + + mov eax, PCR[PcIDR] + SET_8259_MASK + + mov edx, 1 + shl edx, cl + xor PCR[PcIRR], edx ; clear bit in IRR + call SWInterruptHandlerTable[ecx*4] ; Dispatch the pending int. + popfd + +cPublicFpo 1, 0 + fstRET KfLowerIrql + +if DBG +cPublicFpo 1, 2 +KliBug: + push ecx ; new irql for debugging + push PCR[PcIrql] ; old irql for debugging + mov byte ptr PCR[PcIrql],HIGH_LEVEL ; avoid recursive error + stdCall _KeBugCheck, <IRQL_NOT_LESS_OR_EQUAL> ; never return +endif + +fstENDP KfLowerIrql + +;++ +; +; VOID +; HalEndSystemInterrupt +; IN KIRQL NewIrql, +; IN ULONG Vector +; ) +; +; Routine Description: +; +; This routine is used to lower IRQL to the specified value. +; The IRQL and PIRQL will be updated accordingly. Also, this +; routine checks to see if any software interrupt should be +; generated. The following condition will cause software +; interrupt to be simulated: +; any software interrupt which has higher priority than +; current IRQL's is pending. +; +; NOTE: This routine simulates software interrupt as long as +; any pending SW interrupt level is higher than the current +; IRQL, even when interrupts are disabled. +; +; Arguments: +; +; NewIrql - the new irql to be set. +; +; Vector - Vector number of the interrupt +; +; Note that esp+12 is the beginning of interrupt/trap frame and upon +; entering to this routine the interrupts are off. +; +; Return Value: +; +; None. +; +;-- + +HeiNewIrql equ [esp + 4] + +cPublicProc _HalEndSystemInterrupt ,2 +cPublicFpo 2, 0 + + xor ecx, ecx + mov cl, byte ptr HeiNewIrql ; get new irql value + +ifdef IRQL_METRICS + inc HalLowerIrqlCount +endif + + mov edx, PCR[PcIRR] + and edx, FindHigherIrqlMask[ecx*4] ; (edx) is the bitmask of + ; pending interrupts we need to + ; dispatch now. + mov PCR[PcIrql], ecx + jnz short Hei10 ; go dispatch pending interrupts + +; +; no interrupts pending, return quickly. +; + + +ifdef IRQL_METRICS + inc HalQuickLowerIrqlCount +endif + stdRET _HalEndSystemInterrupt + +align 4 +Hei10: + +; +; If there is any delayed hardware interrupt being serviced, we leave +; the interrupt masked and simply return. +; + + test PCR[PcIrrActive], IRQ_ACTIVE_MASK + jnz short Hei50 + + bsr ecx, edx ; (eax) = Pending irq level + cmp ecx, DISPATCH_LEVEL + jle short Hei40 + +; +; Clear all the interrupt masks +; + +align 4 +Hei15: + mov eax, PCR[PcIDR] + SET_8259_MASK +; +; The pending interrupt is a hardware interrupt. To prevent the delayed +; interrupts from overflowing stack, we check if the pending level is already +; active. If yes, we simply return and let the higher level EndSystemInterrupt +; handle it. +; +; (ecx) = pending vector +; + + mov edx, 1 + shl edx, cl + test PCR[PcIrrActive], edx ; if the pending int is being + ; processed, just return. + jne short Hei50 + or PCR[PcIrrActive], edx ; Set Active bit + xor PCR[PcIRR], edx ; clear bit in IRR + call SWInterruptHandlerTable[ecx*4] ; Note, it destroys eax + xor PCR[PcIrrActive], edx ; Clear bit in ActiveIrql + mov eax, PCR[PcIRR] ; Reload IRR + mov ecx, PCR[PcIrql] + and eax, FindHigherIrqlMask[ecx*4] ; Is any interrupt pending + jz short Hei50 ; (Most time it will be zero.) + bsr ecx, eax ; (edx) = Pending irq level + cmp ecx, DISPATCH_LEVEL + ja short Hei15 + +Hei40: + +; +; The pending interrupt is at Software Level. We simply make current +; interrupt frame the new pending software interrupt's frame and +; jmp to the handler routine. +; + + add esp, 12 + jmp SWInterruptHandlerTable2[ecx*4] ; Note, it destroys eax + + +Hei50: + stdRET _HalEndSystemInterrupt + +stdENDP _HalEndSystemInterrupt + +;++ +; +; VOID +; HalpEndSoftwareInterrupt +; IN KIRQL NewIrql, +; ) +; +; Routine Description: +; +; This routine is used to lower IRQL from software interrupt +; leverl to the specified value. +; The IRQL and PIRQL will be updated accordingly. Also, this +; routine checks to see if any software interrupt should be +; generated. The following condition will cause software +; interrupt to be simulated: +; any software interrupt which has higher priority than +; current IRQL's is pending. +; +; NOTE: This routine simulates software interrupt as long as +; any pending SW interrupt level is higher than the current +; IRQL, even when interrupts are disabled. +; +; Arguments: +; +; NewIrql - the new irql to be set. +; +; Note that esp+8 is the beginning of interrupt/trap frame and upon +; entering to this routine the interrupts are off. +; +; Return Value: +; +; None. +; +;-- + +HesNewIrql equ [esp + 4] + +cPublicProc _HalpEndSoftwareInterrupt ,1 +cPublicFpo 1, 0 + + movzx ecx, byte ptr HesNewIrql ; get new irql value + mov edx, PCR[PcIRR] + and edx, FindHigherIrqlMask[ecx*4] ; (edx) is the bitmask of + ; pending interrupts we need to + ; dispatch now. + mov PCR[PcIrql], ecx + jnz short Hes10 + + stdRET _HalpEndSoftwareInterrupt + +align 4 +Hes10: +; +; Check if any delayed hardware interrupt is being serviced. If yes, we +; simply return. +; + + test PCR[PcIrrActive], IRQ_ACTIVE_MASK + jnz short Hes90 + +; +; If there is a pending hardware interrupt, then the PICs have been +; masked to reflect the actual Irql. +; + + bsr ecx, edx ; (ecx) = Pending irq level + cmp ecx, DISPATCH_LEVEL + ja short Hes20 + +; +; Pending interrupt is a soft interrupt. Recycle stack frame +; + + add esp, 8 + jmp SWInterruptHandlerTable2[ecx*4] ; Note, it destroys eax + +Hes20: +; +; Clear all the interrupt masks +; + + mov eax, PCR[PcIDR] + SET_8259_MASK + +; +; (ecx) = Pending level +; + + mov edx, 1 + shl edx, cl + + or PCR[PcIrrActive], edx ; Set Active bit + xor PCR[PcIRR], edx ; clear bit in IRR + + call SWInterruptHandlerTable[ecx*4] ; Dispatch the pending int. + + xor PCR[PcIrrActive], edx ; Clear bit in ActiveIrql + + movzx ecx, byte ptr HesNewIrql ; get new irql value + mov edx, PCR[PcIRR] + and edx, FindHigherIrqlMask[ecx*4] ; (edx) is the bitmask of + ; pending interrupts we need to + ; dispatch now. + jnz short Hes10 + +Hes90: stdRET _HalpEndSoftwareInterrupt + +stdENDP _HalpEndSoftwareInterrupt + + page ,132 + subttl "DispatchInterrupt 2" + +;++ +; +; VOID +; HalpDispatchInterrupt2( +; VOID +; ); +; +; Routine Description: +; +; The functional description is the same as HalpDispatchInterrupt. +; +; This function differs from HalpDispatchInterrupt in how it has been +; optimized. This function is optimized for dispatching dispatch interrupts +; for LowerIrql, ReleaseSpinLock, and RequestSoftwareInterrupt. +; +; Arguments: +; +; None +; Interrupt is disabled +; +; Return Value: +; +; (edx) = 1 shl DISPATCH_LEVEL +; +; Warnings: +; +; Not all SW int handles this hal uses save all the registers +; callers to SWInterruptHandler for H/W interrupts assume that +; ONLY EAX & ECX are destroyed. +; +; Note: this function saves EBX since KiDispatchInterrupt uses +; the value without preserving it. +;-- + +cPublicProc _HalpDispatchInterrupt2 +cPublicFpo 0, 2 + + xor ecx, ecx + and dword ptr PCR[PcIRR], not (1 shl DISPATCH_LEVEL) ; clear the pending bit in IRR + + mov cl, PCR[PcIrql] + + mov byte ptr PCR[PcIrql], DISPATCH_LEVEL; set new irql + push ecx ; Save OldIrql + +; +; Now it is safe to enable interrupt to allow higher priority interrupt +; to come in. +; + sti + + push ebx + stdCall _KiDispatchInterrupt ; Handle DispatchInterrupt + pop ebx + pop ecx ; (ecx) = OldIrql + mov edx, 1 shl DISPATCH_LEVEL + + cli + + mov eax, PCR[PcIRR] + mov PCR[PcIrql], ecx ; restore current irql + + and eax, FindHigherIrqlMask[ecx*4] ; (eax) is the bitmask of + ; pending interrupts we need to + ; dispatch now. + + jnz short diq10 ; go dispatch pending interrupts + stdRET _HalpDispatchInterrupt2 + +diq10: +; +; If there is a pending hardware interrupt, then the PICs have been +; masked to reflect the actual Irql. +; + + bsr ecx, eax ; (ecx) = Pending irq level + cmp ecx, DISPATCH_LEVEL + jbe short diq20 + +; +; Clear all the interrupt masks +; + + mov eax, PCR[PcIDR] + SET_8259_MASK + + mov edx, 1 + shl edx, cl + xor PCR[PcIRR], edx ; clear bit in IRR + +diq20: +; +; (ecx) = Pending level +; + + jmp SWInterruptHandlerTable[ecx*4] ; Dispatch the pending int. +diq90: stdRET _HalpDispatchInterrupt2 + +stdENDP _HalpDispatchInterrupt2 + + page ,132 + subttl "Get current irql" + +;++ +; +; KIRQL +; KeGetCurrentIrql (VOID) +; +; Routine Description: +; +; This routine returns to current IRQL. +; +; Arguments: +; +; None. +; +; Return Value: +; +; The current IRQL. +; +;-- + +cPublicProc _KeGetCurrentIrql ,0 +cPublicFpo 0, 0 + + movzx eax, byte ptr PCR[PcIrql] ; Current irql is in the PCR + stdRET _KeGetCurrentIrql +stdENDP _KeGetCurrentIrql + + + +;++ +; +; VOID +; HalpDisableAllInterrupts (VOID) +; +; Routine Description: +; +; This routine is called during a system crash. The hal needs all +; interrupts disabled. +; +; Arguments: +; +; None. +; +; Return Value: +; +; None - all interrupts are masked off +; +;-- + +cPublicProc _HalpDisableAllInterrupts,0 +cPublicFpo 0, 0 + + ; + ; Mask interrupts off at PIC + ; (raising to high_level does not work on lazy irql implementation) + ; + mov eax, KiI8259MaskTable[HIGH_LEVEL*4]; get pic masks for the new irql + or eax, PCR[PcIDR] ; mask irqs which are disabled + SET_8259_MASK ; set 8259 masks + + mov byte ptr PCR[PcIrql], HIGH_LEVEL ; set new irql + + stdRET _HalpDisableAllInterrupts + +stdENDP _HalpDisableAllInterrupts + + page ,132 + subttl "Postponed Hardware Interrupt Dispatcher" +;++ +; +; VOID +; HalpHardwareInterruptNN ( +; VOID +; ); +; +; Routine Description: +; +; These routines branch through the IDT to simulate the appropriate +; hardware interrupt. They use the "INT nn" instruction to do this. +; +; Arguments: +; +; None. +; +; Returns: +; +; None. +; +; Environment: +; +; IRET frame is on the stack +; +;-- +cPublicProc _HalpHardwareInterruptTable, 0 +cPublicFpo 0,0 + + public HalpHardwareInterrupt00 +HalpHardwareInterrupt00 label byte +ifdef IRQL_METRICS + lock inc HalHardwareIntCount +endif + int PRIMARY_VECTOR_BASE + 0 + ret + + public HalpHardwareInterrupt01 +HalpHardwareInterrupt01 label byte +ifdef IRQL_METRICS + lock inc HalHardwareIntCount +endif + int PRIMARY_VECTOR_BASE + 1 + ret + + public HalpHardwareInterrupt02 +HalpHardwareInterrupt02 label byte +ifdef IRQL_METRICS + lock inc HalHardwareIntCount +endif + int PRIMARY_VECTOR_BASE + 2 + ret + + public HalpHardwareInterrupt03 +HalpHardwareInterrupt03 label byte +ifdef IRQL_METRICS + lock inc HalHardwareIntCount +endif + int PRIMARY_VECTOR_BASE + 3 + ret + + public HalpHardwareInterrupt04 +HalpHardwareInterrupt04 label byte +ifdef IRQL_METRICS + lock inc HalHardwareIntCount +endif + int PRIMARY_VECTOR_BASE + 4 + ret + + public HalpHardwareInterrupt05 +HalpHardwareInterrupt05 label byte +ifdef IRQL_METRICS + lock inc HalHardwareIntCount +endif + int PRIMARY_VECTOR_BASE + 5 + ret + + public HalpHardwareInterrupt06 +HalpHardwareInterrupt06 label byte +ifdef IRQL_METRICS + lock inc HalHardwareIntCount +endif + int PRIMARY_VECTOR_BASE + 6 + ret + + public HalpHardwareInterrupt07 +HalpHardwareInterrupt07 label byte +ifdef IRQL_METRICS + lock inc HalHardwareIntCount +endif + int PRIMARY_VECTOR_BASE + 7 + ret + + public HalpHardwareInterrupt08 +HalpHardwareInterrupt08 label byte +ifdef IRQL_METRICS + lock inc HalHardwareIntCount +endif + int PRIMARY_VECTOR_BASE + 8 + ret + + public HalpHardwareInterrupt09 +HalpHardwareInterrupt09 label byte +ifdef IRQL_METRICS + lock inc HalHardwareIntCount +endif + int PRIMARY_VECTOR_BASE + 9 + ret + + public HalpHardwareInterrupt10 +HalpHardwareInterrupt10 label byte +ifdef IRQL_METRICS + lock inc HalHardwareIntCount +endif + int PRIMARY_VECTOR_BASE + 10 + ret + + public HalpHardwareInterrupt11 +HalpHardwareInterrupt11 label byte +ifdef IRQL_METRICS + lock inc HalHardwareIntCount +endif + int PRIMARY_VECTOR_BASE + 11 + ret + + public HalpHardwareInterrupt12 +HalpHardwareInterrupt12 label byte +ifdef IRQL_METRICS + lock inc HalHardwareIntCount +endif + int PRIMARY_VECTOR_BASE + 12 + ret + + public HalpHardwareInterrupt13 +HalpHardwareInterrupt13 label byte +ifdef IRQL_METRICS + lock inc HalHardwareIntCount +endif + int PRIMARY_VECTOR_BASE + 13 + ret + + public HalpHardwareInterrupt14 +HalpHardwareInterrupt14 label byte +ifdef IRQL_METRICS + lock inc HalHardwareIntCount +endif + int PRIMARY_VECTOR_BASE + 14 + ret + + public HalpHardwareInterrupt15 +HalpHardwareInterrupt15 label byte +ifdef IRQL_METRICS + lock inc HalHardwareIntCount +endif + int PRIMARY_VECTOR_BASE + 15 + ret + + public HalpHardwareInterruptLevel +HalpHardwareInterruptLevel label byte +cPublicFpo 0,0 + xor eax, eax + mov al, PCR[PcIrql] + mov ecx, PCR[PcIRR] + and ecx, FindHigherIrqlMask[eax*4] ; (ecx) is the bitmask of + ; pending interrupts we need to + ; dispatch now. + jz short lvl_90 ; no pending ints + + test PCR[PcIrrActive], IRQ_ACTIVE_MASK + jnz short lvl_90 ; let guy furture down the stack handle it + + mov eax, ecx ; (eax) = bitmask + bsr ecx, eax ; (cl) = set bit + + mov eax, 1 + shl eax, cl + xor PCR[PcIRR], eax ; clear bit in IRR + + call SWInterruptHandlerTable[ecx*4] ; Dispatch the pending int. +align 4 +lvl_90: + ret + +stdENDP _HalpHardwareInterruptTable + + +_TEXT$01 ends + + page ,132 + subttl "Interrupt Controller Chip Initialization" + +_TEXT SEGMENT DWORD PUBLIC 'CODE' + ASSUME DS:FLAT, ES:FLAT, SS:FLAT, FS:NOTHING, GS:NOTHING +;++ +; +; VOID +; HalpInitializePICs ( +; ) +; +; Routine Description: +; +; This routine sends the 8259 PIC initialization commands and +; masks all the interrupts on 8259s. +; +; Arguments: +; +; None +; +; Return Value: +; +; None. +; +;-- +cPublicProc _HalpInitializePICs ,0 +cPublicFpo 0, 0 + + push esi ; save caller's esi + cli ; disable interrupt + lea esi, PICsInitializationString + lodsw ; (AX) = PIC port 0 address +Hip10: movzx edx, ax + outsb ; output ICW1 + IODelay + inc edx ; (DX) = PIC port 1 address + outsb ; output ICW2 + IODelay + outsb ; output ICW3 + IODelay + outsb ; output ICW4 + IODelay + mov al, 0FFH ; mask all 8259 irqs + out dx,al ; write mask to PIC + lodsw + cmp ax, 0 ; end of init string? + jne short Hip10 ; go init next PIC + +; +; Read EISA defined ELCR. If it looks good save it away. +; If a PCI interrupts is later connected, the vector will +; be assumed level if it's in the ELCR. +; + mov edx, 4d1h ; Eisa Edge/Level port + in al, dx ; get e/l irq 8-f + mov ah, al + dec edx + in al, dx ; get e/l irq 0-7 + and eax, 0def8h ; clear reserved bits + cmp eax, 0def8h ; all set? + je short Hip50 ; Yes, register not implemented + + mov _HalpEisaELCR, eax ; Save possible ELCR settings + + +; +; If this is an EISA machine, mark all interrupts in the EISA ELCR +; as level interrupts +; + cmp _HalpBusType, MACHINE_TYPE_EISA + jne short Hip50 + +; +; Verify this isn't an OPTI chipset machine which claims to be +; EISA, but neglects to follow the EISA spec... +; + + mov edx, 0481h ; DmaPageHighPort.Channel2 + mov al, 055h + out dx, al ; out to Eisa DMA register + in al, dx ; read it back + cmp al, 055h ; if it doesn't stick, then machine + jne short Hip50 ; isn't support all eisa registers + +; +; Ok - loop and mark all EISA level interrupts +; + + mov eax, _HalpEisaELCR + xor ecx, ecx ; start at irq 0 +Hip30: + test eax, 1 ; is level bit set? + jz short Hip40 ; no, go to next + +; +; Found a level sensitive interrupt: +; Set the SWInterruptHandler for the irql to be a NOP. +; Set the SpecialDismiss entry for the irq to be the level version +; + mov SWInterruptHandlerTable+4*4[ecx], offset HalpHardwareInterruptLevel + + mov edx, HalpSpecialDismissLevelTable[ecx] + mov HalpSpecialDismissTable[ecx], edx + +Hip40: + add ecx, 4 ; next vector + shr eax, 1 ; shift bits down + jnz short Hip30 ; more set bits, then loop + + +Hip50: + pop esi ; restore caller's esi + sti ; enable interrupt + stdRET _HalpInitializePICs +stdENDP _HalpInitializePICs + + +_TEXT ends + + end |