1129 lines
33 KiB
NASM
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
|