windows-nt/Source/XPSP1/NT/base/hals/halx86/i386/ixirql.asm
2020-09-26 16:20:57 +08:00

1360 lines
38 KiB
NASM

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
_TEXT 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
_TEXT ENDS
_DATA SEGMENT DWORD PUBLIC 'DATA'
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
_DATA ENDS
_TEXT SEGMENT DWORD PUBLIC 'DATA'
;
; 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
_TEXT ENDS
_DATA SEGMENT DWORD PUBLIC 'DATA'
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
;++
;
; KIRQL
; HalpDisableAllInterrupts (VOID)
;
; Routine Description:
;
; This routine is called during a system crash. The hal needs all
; interrupts disabled.
;
; Arguments:
;
; None.
;
; Return Value:
;
; Old Irql level
;
;--
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 al, byte ptr PCR[PcIrql]
mov byte ptr PCR[PcIrql], HIGH_LEVEL ; set new irql
stdRET _HalpDisableAllInterrupts
stdENDP _HalpDisableAllInterrupts
;++
;
; VOID
; HalpReenableInterrupts (
; IN KIRQL Irql
; )
;
; Routine Description:
;
; This routine restores the PIC to a given state.
;
; Arguments:
;
; Irql - Irql state to restore to.
;
; Return Value:
;
; None
;
;--
HriNewIrql equ [esp + 4]
cPublicProc _HalpReenableInterrupts,1
cPublicFpo 1, 0
mov al, HriNewIrql
mov byte ptr PCR[PcIrql],al ; set new irql
mov eax, PCR[PcIDR] ; mask irqs which are disabled
SET_8259_MASK ; set 8259 masks
stdRET _HalpReenableInterrupts
stdENDP _HalpReenableInterrupts
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$02 SEGMENT DWORD PUBLIC 'CODE'
ASSUME DS:FLAT, ES:FLAT, SS:FLAT, FS:NOTHING, GS:NOTHING
;++
;
; VOID
; HalpInitializePICs (
; BOOLEAN EnableInterrupts
; )
;
; Routine Description:
;
; This routine sends the 8259 PIC initialization commands and
; masks all the interrupts on 8259s.
;
; Arguments:
;
; EnableInterrupts - If this is true, then this function will
; explicitly enable interrupts at the end,
; as it always did in the past. If this
; is false, then it will preserve the interrupt
; flag.
;
; Return Value:
;
; None.
;
;--
EnableInterrupts equ [esp + 0ch]
cPublicProc _HalpInitializePICs ,1
cPublicFpo 0, 0
push esi ; save caller's esi
pushfd
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:
mov al, EnableInterrupts
.if (al != 0)
or [esp], EFLAGS_INTERRUPT_MASK ; enable interrupts
.endif
popfd
pop esi ; restore caller's esi
stdRET _HalpInitializePICs
stdENDP _HalpInitializePICs
_TEXT$02 ends
end