summaryrefslogtreecommitdiffstats
path: root/private/ntos/nthals/halx86/i386/ixirql.asm
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/nthals/halx86/i386/ixirql.asm
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to 'private/ntos/nthals/halx86/i386/ixirql.asm')
-rw-r--r--private/ntos/nthals/halx86/i386/ixirql.asm1297
1 files changed, 1297 insertions, 0 deletions
diff --git a/private/ntos/nthals/halx86/i386/ixirql.asm b/private/ntos/nthals/halx86/i386/ixirql.asm
new file mode 100644
index 000000000..e18a0ce8b
--- /dev/null
+++ b/private/ntos/nthals/halx86/i386/ixirql.asm
@@ -0,0 +1,1297 @@
+ 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
+
+_DATA 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
+
+ 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
+
+;
+; 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
+
+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
+
+
+
+;++
+;
+; 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
+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 byte ptr PCR[PcIrql], HIGH_LEVEL ; set new irql
+
+ stdRET _HalpDisableAllInterrupts
+
+stdENDP _HalpDisableAllInterrupts
+
+ 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 SEGMENT DWORD PUBLIC 'CODE'
+ ASSUME DS:FLAT, ES:FLAT, SS:FLAT, FS:NOTHING, GS:NOTHING
+;++
+;
+; 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
+cPublicFpo 0, 0
+
+ push esi ; save caller's esi
+ 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:
+ pop esi ; restore caller's esi
+ sti ; enable interrupt
+ stdRET _HalpInitializePICs
+stdENDP _HalpInitializePICs
+
+
+_TEXT ends
+
+ end