Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

667 lines
22 KiB

title "Irql Processing"
;++
;
; Copyright (c) 1989-1993 Microsoft Corporation
; Copyright (c) 1992, 1993 Wyse Technology
;
; Module Name:
;
; wyirql.asm
;
; Abstract:
;
; Wyse7000i IRQL
;
; This module implements the code necessary to raise and lower i386
; Irql and dispatch software interrupts with the Wyse ICU hardware.
;
; 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
;
; John Fuller (o-johnf) 2-Apr-1992
; Converted to Wyse hardware.
;
; John Fuller (o-johnf) 31-Aug-1993
; Mods for Lazy IRQLs
;--
.386p
.xlist
include hal386.inc
include callconv.inc ; calling convention macros
include i386\ix8259.inc
include i386\kimacro.inc
include i386\wy7000mp.inc
.list
EXTRNP _KeBugCheck,1,IMPORT
extrn _HalpApcInterrupt:near
extrn _HalpDispatchInterrupt:near
extrn _KiUnexpectedInterrupt:near
extrn ReadMyCpuReg:NEAR
extrn WriteMyCpuReg:NEAR
EXTRNP _HalpClockInterrupt,0
EXTRNP _HalpIPInterrupt,0
;
; 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
;
; Interrupt flag bit maks for EFLAGS
;
EFLAGS_IF equ 200H
EFLAGS_SHIFT equ 9
;
_DATA SEGMENT DWORD PUBLIC 'DATA'
;
; 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
db not (1 shl PIC_SLAVE_IRQ) ;OCW1
;
; 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
db 0FFh ;OCW1
dw 0 ; end of string
.errnz PROFILE_LEVEL-27 ;error if defines don't match tables
.errnz CLOCK2_LEVEL-28 ;error if defines don't match tables
.errnz IPI_LEVEL-29 ;error if defines don't match tables
.errnz POWER_LEVEL-30 ;error if defines don't match tables
.errnz HIGH_LEVEL-31 ;error if defines don't match tables
;;;;;;;;;;;;;;;;
;
; The following tables are generated from this information:
;
;KIRQL H/W pri CPL Vector Source Common use Name
;----- ------- --- ------ ------ ---------- ----
; 00 31
; 01 31 APC_LEVEL
; 02 31 DISPATCH_LEVEL
; 03 31 WAKE_LEVEL
; 04 31
; 05 31
; 06 31
; 07 31
; 08 22 (lo) 22 VB2+7 Local/IPI level 7 reserved
; 09 21 21 VB2+6 Local/IPI level 6 reserved
; 10 20 20 VB2+5 Local/IPI level 5 reserved
; 11 19 19 VB0+7 EISA IRQ7 LPT1
; 12 18 18 VB0+6 EISA IRQ6 Flpy
; 13 17 17 VB0+5 EISA IRQ5 LPT2
; 14 16 16 VB0+4 EISA IRQ4 COM1
; 15 15 15 VB0+3 EISA IRQ3 COM2
; 16 14 14 VB1+7 EISA IRQ15
; 17 13 13 VB1+6 EISA IRQ14 AT disk
; 18 12 12 VB1+5 EISA IRQ13 DMA chaining
; 19 11 11 VB1+4 EISA IRQ12
; 20 10 10 VB1+3 EISA IRQ11
; 21 9 9 VB1+2 EISA IRQ10
; 22 8 8 VB1+1 EISA IRQ9
; 23 7 7 VB1+0 EISA IRQ8 RTC
; 24 6 6 VB2+4 Local/IPI level 4 reserved
; 25 5 5 VB0+1 EISA IRQ1 Kbd
; 26 4 4 VB0+0 EISA IRQ0 8254
; 27 3 3 VB2+3 Local/IPI level 3 Global IPI PROFILE_LEVEL
; 28 2 2 VB2+2 Local/IPI level 2 Local Timer CLOCK2_LEVEL
; 29 1 1 VB2+1 Local/IPI level 1 Slot IPI IPI_LEVEL
; 30 1 POWER_LEVEL
; 31 0 (high) 0 VB2+0 Spurious local interrupt HIGH_LEVEL
;
;;;;;;;;;;;;;;;;
; CCHAR HalpIRQLtoCPL[36]; this array is used to get the value
; for the hardware current priority level
; (CPL) register from the KIRQL.
Public _HalpIRQLtoCPL
_HalpIRQLtoCPL Label Byte ;don't know how to make this symbolic
db 31,31,31,31,31,31,31,31,22
db 21,20,19,18,17,16,15,14,13
db 12,11,10, 9, 8, 7, 6, 5, 4
db 3, 2, 1, 1, 0
db 0, 0, 0, 0 ;four extra levels for good luck
; CCHAR HalpIRQLtoVector[36]; this array is used to get the interrupt
; vector used for a given KIRQL, zero
; means no vector is used for the KIRQL
Public _HalpIRQLtoVector
_HalpIRQLtoVector Label Byte
db 0
db 0 ;APC_LEVEL
db 0 ;DISPATCH_LEVEL
db 0 ;WAKE_LEVEL
db 0
db 0
db 0
db 0
db PRIMARY_VECTOR_BASE+23
db PRIMARY_VECTOR_BASE+22
db PRIMARY_VECTOR_BASE+21
db PRIMARY_VECTOR_BASE+7
db PRIMARY_VECTOR_BASE+6
db PRIMARY_VECTOR_BASE+5
db PRIMARY_VECTOR_BASE+4
db PRIMARY_VECTOR_BASE+3
db PRIMARY_VECTOR_BASE+15
db PRIMARY_VECTOR_BASE+14
db PRIMARY_VECTOR_BASE+13
db PRIMARY_VECTOR_BASE+12
db PRIMARY_VECTOR_BASE+11
db PRIMARY_VECTOR_BASE+10
db PRIMARY_VECTOR_BASE+9
db PRIMARY_VECTOR_BASE+8
db PRIMARY_VECTOR_BASE+20
db PRIMARY_VECTOR_BASE+1
db PRIMARY_VECTOR_BASE
db PRIMARY_VECTOR_BASE+19 ;PROFILE_LEVEL
db PRIMARY_VECTOR_BASE+18 ;CLOCK2_LEVEL
db PRIMARY_VECTOR_BASE+17 ;IPI_LEVEL
db 0 ;POWER_LEVEL
db 0 ;prevent CPL 0 enable changes ;HIGH_LEVEL
db 0, 0, 0, 0 ;four extra levels for good luck
; CCHAR HalpVectorToIRQL[24]; this array is used to obtain the
; required IRQL from an interrupt
; vector, it is indexed by
; interrupt vector-PRIMARY_VECTOR_BASE
Public _HalpVectorToIRQL
_HalpVectorToIRQL Label Byte
db PROFILE_LEVEL-1 ;IRQ0
db PROFILE_LEVEL-2 ;IRQ1
db HIGH_LEVEL ;IRQ2--cascade
db PROFILE_LEVEL-12 ;IRQ3
db PROFILE_LEVEL-13 ;IRQ4
db PROFILE_LEVEL-14 ;IRQ5
db PROFILE_LEVEL-15 ;IRQ6
db PROFILE_LEVEL-16 ;IRQ7
db PROFILE_LEVEL-4 ;IRQ8
db PROFILE_LEVEL-5 ;IRQ9
db PROFILE_LEVEL-6 ;IRQ10
db PROFILE_LEVEL-7 ;IRQ11
db PROFILE_LEVEL-8 ;IRQ12
db PROFILE_LEVEL-9 ;IRQ13
db PROFILE_LEVEL-10 ;IRQ14
db PROFILE_LEVEL-11 ;IRQ15
db HIGH_LEVEL ;Local/IPI level 0 (spurious)
db IPI_LEVEL ;Local/IPI level 1
db CLOCK2_LEVEL ;Local/IPI level 2
db PROFILE_LEVEL ;Local/IPI level 3
db PROFILE_LEVEL-3 ;Local/IPI level 4
db PROFILE_LEVEL-17 ;Local/IPI level 5
db PROFILE_LEVEL-18 ;Local/IPI level 6
db PROFILE_LEVEL-19 ;Local/IPI level 7
align 4
;
; The following table is a bit map of IRQLs that use ICU local interrpt ptr
; (it must indicate those IRQLs corresponding to levels used in the ICU_LIPTR)
;
public _HalpLocalInts
_HalpLocalInts dd (1 shl CLOCK2_LEVEL)+(1 shl IPI_LEVEL)+(1 shl PROFILE_LEVEL)
;
; 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:_HalpDispatchInterrupt ; irql 2
dd offset FLAT:_KiUnexpectedInterrupt ; irql 3
dd offset FLAT:_KiUnexpectedInterrupt ; irql 4
dd offset FLAT:_KiUnexpectedInterrupt ; irql 5
dd offset FLAT:_KiUnexpectedInterrupt ; irql 6
dd offset FLAT:_KiUnexpectedInterrupt ; irql 7
dd offset FLAT:_KiUnexpectedInterrupt ; irql 8
dd offset FLAT:_KiUnexpectedInterrupt ; irql 9
dd offset FLAT:_KiUnexpectedInterrupt ; irql 10
dd offset FLAT:_KiUnexpectedInterrupt ; irql 11
dd offset FLAT:_KiUnexpectedInterrupt ; irql 12
dd offset FLAT:_KiUnexpectedInterrupt ; irql 13
dd offset FLAT:_KiUnexpectedInterrupt ; irql 14
dd offset FLAT:_KiUnexpectedInterrupt ; irql 15
dd offset FLAT:_KiUnexpectedInterrupt ; irql 16
dd offset FLAT:_KiUnexpectedInterrupt ; irql 17
dd offset FLAT:_KiUnexpectedInterrupt ; irql 18
dd offset FLAT:_KiUnexpectedInterrupt ; irql 19
dd offset FLAT:_KiUnexpectedInterrupt ; irql 20
dd offset FLAT:_KiUnexpectedInterrupt ; irql 21
dd offset FLAT:_KiUnexpectedInterrupt ; irql 22
dd offset FLAT:_KiUnexpectedInterrupt ; irql 23
dd offset FLAT:_KiUnexpectedInterrupt ; irql 24
dd offset FLAT:_KiUnexpectedInterrupt ; irql 25
dd offset FLAT:_KiUnexpectedInterrupt ; irql 26
dd offset FLAT:_KiUnexpectedInterrupt ; irql 27
dd offset FLAT:_KiUnexpectedInterrupt ; irql 28
dd offset FLAT:_KIUnexpectedInterrupt ; irql 29
;
; 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
db 3 ; SWIRR=8, so highest pending SW irql= 3
db 3 ; SWIRR=9, so highest pending SW irql= 3
db 3 ; SWIRR=A, so highest pending SW irql= 3
db 3 ; SWIRR=B, so highest pending SW irql= 3
db 3 ; SWIRR=C, so highest pending SW irql= 3
db 3 ; SWIRR=D, so highest pending SW irql= 3
db 3 ; SWIRR=E, so highest pending SW irql= 3
db 3 ; SWIRR=F, so highest pending SW irql= 3
db 4 ; SWIRR=10, so highest pending SW irql= 4
db 4 ; SWIRR=11, so highest pending SW irql= 4
db 4 ; SWIRR=12, so highest pending SW irql= 4
db 4 ; SWIRR=13, so highest pending SW irql= 4
db 4 ; SWIRR=14, so highest pending SW irql= 4
db 4 ; SWIRR=15, so highest pending SW irql= 4
db 4 ; SWIRR=16, so highest pending SW irql= 4
db 4 ; SWIRR=17, so highest pending SW irql= 4
db 4 ; SWIRR=18, so highest pending SW irql= 4
db 4 ; SWIRR=19, so highest pending SW irql= 4
db 4 ; SWIRR=1A, so highest pending SW irql= 4
db 4 ; SWIRR=1B, so highest pending SW irql= 4
db 4 ; SWIRR=1C, so highest pending SW irql= 4
db 4 ; SWIRR=1D, so highest pending SW irql= 4
db 4 ; SWIRR=1E, so highest pending SW irql= 4
db 4 ; SWIRR=1F, so highest pending SW irql= 4
_DATA ENDS
page ,132
subttl "Raise Irql"
_TEXT SEGMENT DWORD PUBLIC 'CODE'
ASSUME DS:FLAT, ES:FLAT, SS:FLAT, FS:NOTHING, GS:NOTHING
;++
;
; KIRQL
; FASTCALL
; KfRaiseIrql (
; IN KIRQL NewIrql
; )
;
; Routine Description:
;
; This routine is used to raise IRQL to the specified value.
; The 'lazy irql' algorythm is used, which is to say that the
; hardware interrupt priority level will not be programmed unless
; a lower priority interrupt actually comes in.
;
; Arguments:
;
; (cl) NewIrql - the new irql to be raised to
;
;
; Return Value:
;
; OldIrql
;
;--
; equates for accessing arguments
cPublicFastCall KfRaiseIrql,1
cPublicFpo 0, 0
;
; Note it is very important that we set the OldIrql AFTER we raised to
; the new irql. Otherwise, if there is an interrupt comes in between and
; the OldIrql is not a local variable, the caller will get wrong OldIrql.
; The bottom line is the raising irql and returning old irql has to be
; atomic to the caller.
;
mov al, Fs:PcIrql ; (al) = Old Irql
mov Fs:PcIrql, cl ; set new irql
if DBG
cmp al, cl ; old > new?
ja short Kri99 ; yes, go bugcheck
fstRET KfRaiseIrql
cPublicFpo 2, 2
Kri99:
push ecx ; put new irql where we can find it
push eax ; put old irql where we can find it
mov byte ptr Fs:PcIrql,0 ; avoid recursive error
stdCall _KeBugCheck, <IRQL_NOT_GREATER_OR_EQUAL> ; never return
endif
fstRET KfRaiseIrql
fstENDP KfRaiseIrql
page ,132
subttl "Lower irql"
;++
;
; VOID
; FASTCALL
; 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
mov al, cl ; get new irql value
if DBG
cmp al, Fs:PcIrql
ja short KliBug
endif
pushfd
cli
mov Fs:PcIrql, al ;save new irql
cmp al, Fs:PcHal.pchHwIrql ;does hardware need reprogramming?
jb short @F ;jump if it does
popfd
fstRET KfLowerIrql
@@: mov Fs:PcHal.pchHwIrql, al
and eax, 0FFh
mov al, _HalpIRQLtoCPL[eax]
mov dx, My+CpuPriortyLevel
out dx, ax ;set hardware level down
@@: mov eax, Fs:PcIRR ;look for software interrupts
and eax, 1Fh
jz short @F ;jump if none
mov al, SWInterruptLookUpTable[eax] ;get swint's irql
cmp al, Fs:PcIrql ;high enough to do this int?
jbe short @F ;jump if not
call SWInterruptHandlerTable[eax*4]
jmp @B
@@: popfd
fstRET KfLowerIrql
if DBG
KliBug:
push eax ; new irql for debugging
push Fs:PcIrql ; old irql for debugging
mov byte ptr Fs:PcIrql,HIGH_LEVEL ; avoid recursive error
stdCall _KeBugCheck, <IRQL_NOT_LESS_OR_EQUAL> ; never return
endif
fstENDP KfLowerIrql
cPublicProc _HalpEndSoftwareInterrupt,1
cPublicFpo 1,0
mov ecx, [esp+4]
fstCall KfLowerIrql
stdRet _HalpEndSoftwareInterrupt
stdENDP _HalpEndSoftwareInterrupt
;++
;
; VOID
; KIRQL
; KeRaiseIrqlToDpcLevel (
; )
;
; Routine Description:
;
; This routine is used to raise IRQL to DPC level.
; The APIC TPR is used to block all lower-priority HW interrupts.
;
; Arguments:
;
; Return Value:
;
; OldIrql - the addr of a variable which old irql should be stored
;
;--
cPublicProc _KeRaiseIrqlToDpcLevel,0
cPublicFpo 0, 0
mov ecx, DISPATCH_LEVEL
jmp @KfRaiseIrql
stdENDP _KeRaiseIrqlToDpcLevel
;++
;
; VOID
; KIRQL
; KeRaiseIrqlToSynchLevel (
; )
;
; Routine Description:
;
; This routine is used to raise IRQL to SYNC level.
; The APIC TPR is used to block all lower-priority HW interrupts.
;
; Arguments:
;
; Return Value:
;
; OldIrql - the addr of a variable which old irql should be stored
;
;--
cPublicProc _KeRaiseIrqlToSynchLevel,0
mov ecx, SYNCH_LEVEL
jmp @KfRaiseIrql
stdENDP _KeRaiseIrqlToSynchLevel
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
movzx eax, byte ptr fs:PcIrql ; Current irql is in the PCR
stdRET _KeGetCurrentIrql
stdENDP _KeGetCurrentIrql
;++
;
; VOID
; HalpDisableAllInterrupts (VOID)
;
; Routine Description:
;
; This routine is called during a system crash. The hal needs all
; interrupts disabled.
;
; Arguments:
;
; None.
;
; Return Value:
;
; None - all interrupts are masked off
;
;--
cPublicProc _HalpDisableAllInterrupts,0
;
; Raising to HIGH_LEVEL disables interrupts for the Wyse HAL
;
mov ecx, HIGH_LEVEL
fstCall KfRaiseIrql
mov al, _HalpIRQLtoCPL[HIGH_LEVEL]
mov dx, My+CpuPriortyLevel
out dx, ax
mov Fs:PcHal.pchHwIrql, HIGH_LEVEL
stdRET _HalpDisableAllInterrupts
stdENDP _HalpDisableAllInterrupts
page ,132
subttl "Interrupt Controller Chip Initialization"
;++
;
; VOID
; HalpInitializePICs (
; )
;
; Routine Description:
;
; This routine sends the 8259 PIC initialization commands and
; masks all the interrupts on 8259s.
;
; Arguments:
;
; None
;
; Return Value:
;
; None.
;
;--
cPublicProc _HalpInitializePICs ,0
push esi ; save caller's esi
cli ; disable interrupt
lea esi, PICsInitializationString
Hip00:
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
outsb ; output OCW1 (interrupt mask)
lodsw
cmp ax, 0 ; end of init string?
jne short Hip10 ; go init next PIC
pop esi ; restore caller's esi
sti ; enable interrupt
stdRET _HalpInitializePICs
stdENDP _HalpInitializePICs
_TEXT ends
end