|
|
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
|