2020-09-30 17:17:25 +02:00

1129 lines
33 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
.list
EXTRNP _KeBugCheck,1
EXTRNP _KiDispatchInterrupt,0
extrn _HalpApcInterrupt:near
extrn _HalpDispatchInterrupt:near
extrn _KiUnexpectedInterrupt:near
extrn _HalpApcInterrupt2ndEntry:NEAR
extrn _HalpDispatchInterrupt2ndEntry:NEAR
extrn HalpEisaELCR:dword
extrn HalpIRR:dword
extrn HalpIRRActive:dword
extrn HalpIDR:dword
extrn _KiPCR: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 'CODE'
;
; PICsInitializationString - Master PIC initialization command string
;
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
align 4
public KiI8259MaskTable
KiI8259MaskTable label dword
dd 00000000000000000000000000000000B ; irql 0 (NORMAL)
dd 00000000000000000000000000000000B ; irql 1 (APC)
dd 00000000000000000000000000000000B ; irql 2 (DISPATCH)
dd 00000000000000000000000000000000B ; irql 3
dd 11111111110000000000000000000000B ; irql 4
dd 11111111111000000000000000000000B ; irql 5
dd 11111111111100000000000000000000B ; irql 6
dd 11111111111110000000000000000000B ; irql 7
dd 11111111111111000000000000000000B ; irql 8
dd 11111111111111100000000000000000B ; irql 9
dd 11111111111111110000000000000000B ; irql 10
dd 11111111111111111000000000000000B ; irql 11
dd 11111111111111111100000000000000B ; irql 12
dd 11111111111111111110000000000000B ; irql 13
dd 11111111111111111110000000000000B ; irql 14
dd 11111111111111111110100000000000B ; irql 15
dd 11111111111111111110110000000000B ; irql 16
dd 11111111111111111110111000000000B ; irql 17
dd 11111111111111111110111000000000B ; irql 18
dd 11111111111111111110111010000000B ; irql 19
dd 11111111111111111110111011000000B ; irql 20
dd 11111111111111111110111011100000B ; irql 21
dd 11111111111111111110111011110000B ; irql 22
dd 11111111111111111110111011111000B ; irql 23
dd 11111111111111111110111011111000B ; irql 24
dd 11111111111111111110111011111010B ; irql 25
dd 11111111111111111110111111111010B ; irql 26 (PROFILE)
dd 11111111111111111111111111111010B ; irql 27 (SCI)
dd 11111111111111111111111111111011B ; irql 28 (CLOCK)
dd 11111111111111111111111111111011B ; irql 29 (IPI)
dd 11111111111111111111111111111011B ; irql 30 (POWER)
dd 11111111111111111111111111111011B ; irql 31 (HIGH)
;
; 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 (NORMAL)
dd 11111111111111111111111111111100B ; irql 1 (APC)
dd 11111111111111111111111111111000B ; irql 2 (DISPATCH)
dd 11111111111111111111111111110000B ; irql 3
dd 00000011111111111111111111110000B ; irql 4
dd 00000001111111111111111111110000B ; irql 5
dd 00000000111111111111111111110000B ; irql 6
dd 00000000011111111111111111110000B ; irql 7
dd 00000000001111111111111111110000B ; irql 8
dd 00000000000111111111111111110000B ; irql 9
dd 00000000000011111111111111110000B ; irql 10
dd 00000000000001111111111111110000B ; irql 11
dd 00000000000000111111111111110000B ; irql 12
dd 00000000000000011111111111110000B ; irql 13
dd 00000000000000011111111111110000B ; irql 14
dd 00000000000000010111111111110000B ; irql 15
dd 00000000000000010011111111110000B ; irql 16
dd 00000000000000010001111111110000B ; irql 17
dd 00000000000000010001111111110000B ; irql 18
dd 00000000000000010001011111110000B ; irql 19
dd 00000000000000010001001111110000B ; irql 20
dd 00000000000000010001000111110000B ; irql 21
dd 00000000000000010001000011110000B ; irql 22
dd 00000000000000010001000001110000B ; irql 23
dd 00000000000000010001000000110000B ; irql 24
dd 00000000000000010001000000010000B ; irql 25
dd 00000000000000010000000000010000B ; irql 26 (PROFILE)
dd 00000000000000000000000000010000B ; irql 27 (SCI)
dd 00000000000000000000000000000000B ; irql 28 (CLOCK)
dd 00000000000000000000000000000000B ; irql 29 (IPI)
dd 00000000000000000000000000000000B ; irql 30 (POWER)
dd 00000000000000000000000000000000B ; irql 31 (HIGH)
_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 'CODE'
ASSUME DS:FLAT, ES:FLAT, SS:FLAT, FS:NOTHING, GS:NOTHING
;
; 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
;++
;
; 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, PCRB[PcIrql] ; (al) = Old Irql
mov PCRB[PcIrql], cl ; set new irql
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 PCRB[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, PCRB[PcIrql] ; (al) = Old Irql
mov PCRB[PcIrql], DISPATCH_LEVEL ; set new irql
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, PCRB[PcIrql] ; (al) = Old Irql
mov PCRB[PcIrql], SYNCH_LEVEL ; set new irql
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
if DBG
cmp cl,PCRB[PcIrql] ; Make sure we are not lowering to
ja KliBug ; ABOVE current level
endif
pushfd
cli
mov PCR[PcIrql], ecx
mov edx, HalpIRR
and edx, FindHigherIrqlMask[ecx*4] ; (edx) is the bitmask of
; pending interrupts we need to
; dispatch now.
jnz short Kli10 ; go dispatch pending interrupts
ifdef DEVKIT
mov eax, PCR[PcPrcbData+PbDebugHaltThread] ; find out if the
test eax,eax ; debugger wants to break into
jnz Kli20 ; this thread
endif
;
; no interrupts pending, return quickly.
;
popfd
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, HalpIDR
SET_8259_MASK
mov edx, 1
shl edx, cl
xor HalpIRR, 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 PCRB[PcIrql],HIGH_LEVEL ; avoid recursive error
stdCall _KeBugCheck, <IRQL_NOT_LESS_OR_EQUAL> ; never return
endif
ifdef DEVKIT
cPublicFpo 0, 0
Kli20:
test ecx,ecx ; only break if lowering to
jne Kli21 ; PASSIVE_LEVEL
call eax ; find out whether to stop
test al, al
je short Kli21
sti
int 3h
Kli21:
popfd
fstRet KfLowerIrql
endif
fstENDP KfLowerIrql
;++
;
; VOID
; FASTCALL
; HalEndSystemLevelInterrupt(
; IN KIRQL NewIrql
; )
;
; Routine Description:
;
; This routine acknowledges the supplied level interrupt and then falls
; into HalEndSystemInterrupt.
;
; Arguments:
;
; eax - BusInterruptLevel
;
; NewIrql - the new irql to be set.
;
; Note that esp+4 is the beginning of interrupt/trap frame and upon
; entering to this routine the interrupts are off.
;
; Return Value:
;
; None.
;
;--
cPublicFastCall HalEndSystemLevelInterrupt ,1
cmp eax, 8 ; EOI to master or slave?
jae short Heil10
or al, PIC1_EOI_MASK ; create specific eoi mask for master
out PIC1_PORT0, al ; dismiss the interrupt
jmp @HalEndSystemInterrupt@4
align 4
Heil10:
add al, OCW2_SPECIFIC_EOI - 8 ; specific eoi to slave
out PIC2_PORT0, al
;
; fall into HalEndSystemInterrupt
;
;++
;
; VOID
; FASTCALL
; HalEndSystemInterrupt(
; 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:
;
; NewIrql - the new irql to be set.
;
; Note that esp+4 is the beginning of interrupt/trap frame and upon
; entering to this routine the interrupts are off.
;
; Return Value:
;
; None.
;
;--
cPublicFastCall HalEndSystemInterrupt ,1
mov edx, HalpIRR
and edx, FindHigherIrqlMask[ecx*4] ; (edx) is the bitmask of
; pending interrupts we need to
; dispatch now.
mov PCR[PcIrql], ecx
jnz Hei10 ; go dispatch pending interrupts
;
; no interrupts pending, fall into Kei386EoiHelper
;
;++
;
; Kei386EoiHelper
;
; Routine Description:
;
; This code is transfered to at the end of an interrupt. (via the
; exit_interrupt macro). It checks for user APC dispatching and
; performs the exit_all for the interrupt.
;
; NOTE: This code is jumped to, not called.
;
; Arguments:
;
; (esp) -> base of trap frame.
; interrupts are disabled
;
; Return Value:
;
; None.
;
;--
cPublicProc Kei386EoiHelper, 0
;.FPO (0, 0, 0, 0, 0, FPO_TRAPFRAME)
ASSERT_FS
EXIT_ALL ,,NoPreviousMode
stdENDP Kei386EoiHelper
align 4
Hei10:
;
; If there is any delayed hardware interrupt being serviced, we leave
; the interrupt masked and simply return.
;
test HalpIRRActive, 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, HalpIDR
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 HalpIRRActive, edx ; if the pending int is being
; processed, just return.
jne short Hei50
or HalpIRRActive, edx ; Set Active bit
xor HalpIRR, edx ; clear bit in IRR
call SWInterruptHandlerTable[ecx*4] ; Note, it destroys eax
xor HalpIRRActive, edx ; Clear bit in ActiveIrql
mov eax, HalpIRR ; 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.
;
jmp SWInterruptHandlerTable2[ecx*4] ; Note, it destroys eax
Hei50:
jmp Kei386EoiHelper@0
fstENDP HalEndSystemInterrupt
fstENDP HalEndSystemLevelInterrupt
;++
;
; 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, HalpIRR
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 HalpIRRActive, 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, HalpIDR
SET_8259_MASK
;
; (ecx) = Pending level
;
mov edx, 1
shl edx, cl
or HalpIRRActive, edx ; Set Active bit
xor HalpIRR, edx ; clear bit in IRR
call SWInterruptHandlerTable[ecx*4] ; Dispatch the pending int.
xor HalpIRRActive, edx ; Clear bit in ActiveIrql
movzx ecx, byte ptr HesNewIrql ; get new irql value
mov edx, HalpIRR
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 HalpIRR, not (1 shl DISPATCH_LEVEL) ; clear the pending bit in IRR
mov cl, PCRB[PcIrql]
mov PCRB[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, HalpIRR
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, HalpIDR
SET_8259_MASK
mov edx, 1
shl edx, cl
xor HalpIRR, 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, PCRB[PcIrql] ; Current irql is in the PCR
stdRET _KeGetCurrentIrql
stdENDP _KeGetCurrentIrql
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
int PRIMARY_VECTOR_BASE + 0
ret
public HalpHardwareInterrupt01
HalpHardwareInterrupt01 label byte
int PRIMARY_VECTOR_BASE + 1
ret
public HalpHardwareInterrupt02
HalpHardwareInterrupt02 label byte
int PRIMARY_VECTOR_BASE + 2
ret
public HalpHardwareInterrupt03
HalpHardwareInterrupt03 label byte
int PRIMARY_VECTOR_BASE + 3
ret
public HalpHardwareInterrupt04
HalpHardwareInterrupt04 label byte
int PRIMARY_VECTOR_BASE + 4
ret
public HalpHardwareInterrupt05
HalpHardwareInterrupt05 label byte
int PRIMARY_VECTOR_BASE + 5
ret
public HalpHardwareInterrupt06
HalpHardwareInterrupt06 label byte
int PRIMARY_VECTOR_BASE + 6
ret
public HalpHardwareInterrupt07
HalpHardwareInterrupt07 label byte
int PRIMARY_VECTOR_BASE + 7
ret
public HalpHardwareInterrupt08
HalpHardwareInterrupt08 label byte
int PRIMARY_VECTOR_BASE + 8
ret
public HalpHardwareInterrupt09
HalpHardwareInterrupt09 label byte
int PRIMARY_VECTOR_BASE + 9
ret
public HalpHardwareInterrupt10
HalpHardwareInterrupt10 label byte
int PRIMARY_VECTOR_BASE + 10
ret
public HalpHardwareInterrupt11
HalpHardwareInterrupt11 label byte
int PRIMARY_VECTOR_BASE + 11
ret
public HalpHardwareInterrupt12
HalpHardwareInterrupt12 label byte
int PRIMARY_VECTOR_BASE + 12
ret
public HalpHardwareInterrupt13
HalpHardwareInterrupt13 label byte
int PRIMARY_VECTOR_BASE + 13
ret
public HalpHardwareInterrupt14
HalpHardwareInterrupt14 label byte
int PRIMARY_VECTOR_BASE + 14
ret
public HalpHardwareInterrupt15
HalpHardwareInterrupt15 label byte
int PRIMARY_VECTOR_BASE + 15
ret
stdENDP _HalpHardwareInterruptTable
page ,132
subttl "Interrupt Controller Chip Initialization"
;++
;
; VOID
; HalpInitializePICs (
; VOID
; )
;
; 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.
;
;--
cPublicProc _HalpInitializePICs ,0
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
or [esp], EFLAGS_INTERRUPT_MASK ; enable interrupts
popfd
pop esi ; restore caller's esi
stdRET _HalpInitializePICs
stdENDP _HalpInitializePICs
_TEXT ends
end