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.
 
 
 
 
 
 

613 lines
16 KiB

title "System Interrupt"
;++
;
; Copyright (c) 1991 Microsoft Corporation
; Copyright (c) 1993 Sequent Computer Systems, Inc.
;
; Module Name:
;
; w3sysint.asm
;
; Abstract:
;
; This module implements the HAL routines to begin a system interrupt,
; end a system interrupt, and enable/disable system interrupts
; for the WinServer 3000.
;
; Author:
;
; Phil Hochstetler ([email protected]) 3-30-93
;
; Environment:
;
; Kernel Mode
;
; Revision History:
;
;--
.386p
.xlist
include hal386.inc
include callconv.inc ; calling convention macros
include i386\kimacro.inc
include mac386.inc
include i386\apic.inc
include i386\w3.inc
.list
EXTRNP _KeBugCheck,1
EXTRNP _KeLowerIrql,1
extrn _HalpIrql2TPR:byte
extrn _HalpLocalUnitBase:dword
extrn _HalpIOunitTwoBase:dword
extrn _HalpIOunitBase:dword
extrn _HalpK2Rdir2Irq:byte
extrn _HalpELCRImage:word
extrn _HalpK2EbsIOunitRedirectionTable:dword
extrn _HalpBeginW3InterruptTable:dword
extrn _HalpK2Vector2RdirTabEntry:byte
extrn _HalpK2EISAIrq2Irql:byte
extrn _HalpK2Irql2Eisa:byte
extrn _HalpK2Vector2EISA:byte
extrn FindHigherIrqlMask:dword
extrn HalpDispatchInterrupt2ndEntry:NEAR
extrn HalpApcInterrupt2ndEntry:NEAR
extrn _HalpMASKED:WORD
_DATA SEGMENT DWORD PUBLIC 'DATA'
_DATA ENDS
_TEXT SEGMENT DWORD PUBLIC 'CODE'
ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
;++
; BOOLEAN
; HalBeginSystemInterrupt(
; IN KIRQL Irql
; IN CCHAR Vector,
; OUT PKIRQL OldIrql
; )
;
;
;
;Routine Description:
;
; This routine handles the initial interrupt sequence for all
; external APIC interrupts for both single processor and multiple
; processor WinServer 3000 systems. On the WinServer 3000 we use
; the APIC to generate all I/O interrupts and their respective
; priorities. We do not abstract the prioritization of interrupts
; from the hardware since the APIC accomodates all Windows NT
; requirements for IRQLs. In addition to I/O interrupts the APIC
; is used to generate software interrupts for APCs and DPCs.
; The APCs and DPCs are generated by a CPU via it's
; local APIC interrupt command register. The interrupts are sent
; as a self directed interrupt. It is required by NT that software
; interrupts are always handled by the CPU which issues them.
;
; Note: Wakeup is included also in the above fashion
;
; This routine does not process an 8259 generated interrupt which
; is not tied to the APIC. This processing is done in the w3ipi.asm
; module. A subset of IRQs 0-15 are not wired through the EBS APIC.
; This is because the APIC on the EBS only accomodates 16 interrupts
; We have a total of 24 on a WS3000. We chose to have all system bus
; generated interrupts 16-23 tied to the EBS APIC. The remaining
; 8 are divided up for EISA cards. TheHalpK2EbsIounitRedirectionTable
; in k2space.asm describes the EISA IRQs chosen for the EBS APIC.
;
; Prioritization of 8259 interrupts is done by generating an APIC
; interrupt with the appropriate APIC vector which corresponds to
; the incoming 8259 IRQ number. Thus, 2 interrupts are always
; generated by an 8259 interrupt. The first is the 8259 interrupt
; and the second is the APIC interrupt.
;
; The APIC interrupt is then appropriately prioritized by the hardware
; and received accordingly via this routine.
;
;Arguments:
;
; Irql - Supplies the IRQL to raise to
;
; Vector - Supplies the vector of the interrupt to be dismissed
;
; OldIrql- Location to return OldIrql
;
;
;Return Value:
;
; FALSE - Interrupt is spurious and should be ignored
;
; TRUE - Valid interrupt and Irql raised appropriately.
;
;--
HbsiOldIrql equ dword ptr [esp+16]
HbsiVector equ byte ptr [esp+12]
HbsiIrql equ byte ptr [esp+8]
align 4
cPublicProc _HalBeginSystemInterrupt ,3
push ebx
movzx ebx, HbsiVector ; (ebx) = System Vector
jmp _HalpBeginW3InterruptTable[ebx*4]
;
; --- Process APIC external interrupt, i.e., generated via EBS I/O APIC
; - simply raise the Irql to the interrupt level of the
; current interrupt, EOI APIC, and return TRUE
;
align 4
public _HalpBeginW3APICInterrupt
_HalpBeginW3APICInterrupt:
mov edx, _HalpLocalUnitBase ; Get address of Local APIC
movzx eax, HbsiIrql ; Get New IRQL
mov cl, PCR[PcHal.ProcIrql] ; Get current irql
cli ; Don't trust caller..
if DBG
cmp al, cl
ja @f ; New IRQL is > Current
push eax ; New IRQL
push ebx ; Vector
push ecx ; Old IRQL
push [edx+LU_TPR] ;
mov dword ptr [edx+LU_TPR], 0FFH
mov PCR[PcHal.ProcIrql], HIGH_LEVEL ; Set to avoid recursive error
stdCall _KeBugCheck, <0Bh>
@@:
endif
;
; --- Do to the fact that some drivers like the i8042prt driver
; and possibly other foolhardy drivers which don't use the IRQL
; returned by the HalGetInterrupt routine when they do an IoConnectInt
; we have to use the IRQL passed and not use the vector to set the
; TPR...THESE TYPE OF DRIVERS HAVE TO BE EDGE SENSITIVE DEVICES TO
; WORK IF THEY DO THIS CRAP....We allow changes in the IRQL as long
; as it is a higher IRQL than the one returned by the HAL
;
mov PCR[PcHal.ProcIrql], al ; Set new irql
movzx eax, _HalpIrql2TPR[eax]
mov [edx+LU_TPR], eax ; Set task priority register
mov eax, [edx+LU_TPR] ; Read it to make sure write occurs
mov eax, HbsiOldIrql ; get addr to store old irql
mov [eax], cl ; save old irql in the return variable
;
; --- EOI the APIC if the interrupt is not a level sensitive EISA interrupt
; Level sensitive interrupts are EOI'ed in EndSystemInterrupt
;
xor ah, ah
mov al, _HalpK2Vector2EISA[ebx] ; Get EISA IRQ #
mov cx, _HalpELCRImage ; Get edge/level register value
mov bx, _HalpMASKED ; get PIC level interrupts
not bx
and cx, bx ; clear level bits from PIC
bt cx, ax ; test appropriate bit
jc short @f
mov [edx+LU_EOI], eax ; EOI APIC
@@:
mov eax, 1 ; True interrupt
sti ; Let interrupts go
pop ebx
stdRET _HalBeginSystemInterrupt
;
; --- Invalid or illegal vector
;
align 4
public _HalpBeginW3InvalidInterrupt
_HalpBeginW3InvalidInterrupt:
mov eax,0 ; return False
pop ebx
stdRET _HalBeginSystemInterrupt
stdENDP _HalBeginSystemInterrupt
;++
;VOID
;HalDisableSystemInterrupt(
; IN CCHAR Vector,
; IN KIRQL Irql
; )
;
;
;
;Routine Description:
;
; Disables a system interrupt via the EBS APIC Redirection table
; entries or the 8259 Interrupt mask registers
;
;Arguments:
;
; Vector - Supplies the vector of the interrupt to be disabled
;
; Irql - Supplies the interrupt level of the interrupt to be disabled
;
;Return Value:
;
; None.
;
;--
cPublicProc _HalDisableSystemInterrupt ,2
cPublicFpo 2, 0
;
; --- Exit if this is not the base processor
;
movzx ecx, byte ptr [esp+4] ; (ecx) = Vector
movzx eax, byte ptr PCR[PcHal.PcrNumber]
cmp al, 0
jne HalDisableInt999 ; Exit if not base proc
cPublicFpo 2, 1
pushfd
cli ; Disable interrupts
;
; --- Enable/Disable does not get called for the interrupt vectors
; which are used for the 8259 generated interrupts. It only gets
; called for the the APIC vectors which correspond to the 8259 ints...
;
cmp ecx, APIC_DMA_VECTOR ; Is this for the 8259 DMA?
jne short HalDisableInt10 ; No - branch
mov ecx, 13 ; EISA DMA IRQ
jmp HalDisableInt60 ; Enable 8259 Int
HalDisableInt10:
cmp ecx, APIC_KBD_VECTOR ; Is this the keyboard vector?
jne short HalDisableInt20 ; Yes - branch
mov ecx, 1 ; Keyboard IRQ
jmp HalDisableInt60 ; Enable 8259 Int
HalDisableInt20:
cmp ecx, APIC_CLOCK_VECTOR ; 8259 clock?
jne short HalDisableInt30 ; Yes - branch
mov ecx, 0 ; Clock IRQ
jmp HalDisableInt60
HalDisableInt30:
cmp ecx, APIC_RTC_VECTOR ; Real-time clock?
jne short HalDisableInt31 ; No -branch
mov ecx, 8 ; RTC IRQ
jmp HalDisableInt60
HalDisableInt31:
cmp ecx, APIC_FLOPPY_VECTOR ; Floppy?
jne short HalDisableInt32 ; No -branch
mov ecx, 6 ; Floppy IRQ
jmp HalDisableInt60
HalDisableInt32:
cmp ecx, APIC_IDE_VECTOR ; IDE Disk?
jne short HalDisableInt33 ; No -branch
mov ecx, 14 ; IDE Disk IRQ
jmp HalDisableInt60
HalDisableInt33:
cmp ecx, APIC_MOUSE_VECTOR ; IRQ12 vector
jne short HalDisableInt34 ; No -branch
mov ecx, 12 ; IRQ12
jmp HalDisableInt60
HalDisableInt34:
;
; --- Process other APIC vectors
;
xor eax,eax
mov al, _HalpK2Vector2RdirTabEntry[ecx] ; Get EBS RDIR entry
cmp al, 0FFH ; No RDIR entry..exit
je HalDisableInt50 ; ..exit
cmp al, 0 ; Not used vector
je HalDisableInt50 ; ..exit
btr eax, 7 ; EBS I/O APIC RDIR??
jnc HalDisableInt35 ; Yes
mov edx, _HalpIOunitTwoBase ; Boot processor I/O APIC RDIR
jmp HalDisableInt40 ; continue
HalDisableInt35:
mov edx, _HalpIOunitBase ; Address of EBS I/O APIC
HalDisableInt40:
;
; No need for a lock here since only the base manipulates these registers
;
mov [edx+IO_REGISTER_SELECT], eax ; Select register
or dword ptr [edx+IO_REGISTER_WINDOW], IOMPIC_RT_MASK ; mask it
HalDisableInt50:
cPublicFpo 2, 0
popfd
stdRET _HalDisableSystemInterrupt
;
; --- 8259 interrupt enable...
;
HalDisableInt60:
;
; --- 8259 interrupt disable...
;
mov edx, 1
shl edx, cl ; (ebx) = bit in IMR to disable
xor eax, eax
;
; Get the current interrupt mask register from the 8259
;
in al, PIC2_PORT1
shl eax, 8
in al, PIC1_PORT1
;
; Mask off the interrupt to be disabled
;
or eax, edx
;
; Write the new interrupt mask register back to the 8259
;
out PIC1_PORT1, al
shr eax, 8
out PIC2_PORT1, al
PIC2DELAY
cPublicFpo 2, 0
popfd
HalDisableInt999:
stdRET _HalDisableSystemInterrupt
stdENDP _HalDisableSystemInterrupt
;++
;
;BOOLEAN
;HalEnableSystemInterrupt(
; IN ULONG Vector,
; IN KIRQL Irql,
; IN KINTERRUPT_MODE InterruptMode
; )
;
;
;Routine Description:
;
; Enables a system interrupt via PIC or APIC hardware masks
;
;Arguments:
;
; Vector - Supplies the vector of the interrupt to be enabled
;
; Irql - Supplies the interrupt level of the interrupt to be enabled.
;
;Return Value:
;
; None.
;
;--
cPublicProc _HalEnableSystemInterrupt ,3
cPublicFpo 3, 0
;
; --- The base processor controls enabling/disabling of all ints
;
movzx ecx, byte ptr [esp+4] ; (ecx) = Vector
movzx eax, byte ptr PCR[PcHal.PcrNumber]
cmp al, 0
jne HalEnableInt999 ; Exit if not base proc
cPublicFpo 3, 1
pushfd
cli
;
; --- Enable/Disable does not get called for the interrupt vectors
; which are used for the 8259 generated interrupts. It only gets
; called for the the APIC vectors which correspond to the 8259 ints...
;
cmp ecx, APIC_DMA_VECTOR ; Is this for the 8259 DMA?
jne short HalEnableInt10 ; No - branch
mov ecx, 13 ; EISA DMA IRQ
jmp HalEnableInt60 ; Enable 8259 Int
HalEnableInt10:
cmp ecx, APIC_KBD_VECTOR ; Is this the keyboard vector?
jne short HalEnableInt20 ; No - branch
mov ecx, 1 ; Keyboard IRQ
jmp HalEnableInt60 ; Enable 8259 Int
HalEnableInt20:
cmp ecx, APIC_CLOCK_VECTOR ; 8259 clock?
jne short HalEnableInt30 ; No - branch
mov ecx, 0 ; Clock IRQ
jmp HalEnableInt60
HalEnableInt30:
cmp ecx, APIC_RTC_VECTOR ; Real-time clock?
jne short HalEnableInt31 ; No -branch
mov ecx, 8 ; RTC IRQ
jmp HalEnableInt60
HalEnableInt31:
cmp ecx, APIC_FLOPPY_VECTOR ; Floppy?
jne short HalEnableInt32 ; No -branch
mov ecx, 6 ; Floppy IRQ
jmp HalEnableInt60
HalEnableInt32:
cmp ecx, APIC_IDE_VECTOR ; IDE Disk?
jne short HalEnableInt33 ; No -branch
mov ecx, 14 ; IDE Disk IRQ
jmp HalEnableInt60
HalEnableInt33:
cmp ecx, APIC_MOUSE_VECTOR ; IRQ12 vector
jne short HalEnableInt34 ; No -branch
mov ecx, 12 ; IRQ12
jmp HalEnableInt60
HalEnableInt34:
;
; --- Process APIC vectors
;
xor eax,eax
mov al, _HalpK2Vector2RdirTabEntry[ecx] ; Get EBS RDIR entry
cmp al, 0FFH ; No RDIR entry..exit
je HalEnableInt50 ; ..exit
cmp al, 0 ; Not used vector
je HalEnableInt50 ; ..exit
btr eax, 7 ; EBS I/O APIC RDIR??
jnc HalEnableInt35 ; Yes
mov edx, _HalpIOunitTwoBase ; Boot processor I/O APIC RDIR
jmp HalEnableInt40 ; continue
HalEnableInt35:
mov edx, _HalpIOunitBase ; Address of EBS I/O APIC
HalEnableInt40:
;
; No need for a lock here since only the base manipulates these registers
;
mov [edx+IO_REGISTER_SELECT], eax ; Select register
and dword ptr [edx+IO_REGISTER_WINDOW], NOT IOMPIC_RT_MASK ; Unmask it
HalEnableInt50:
cPublicFpo 3, 0
popfd
stdRET _HalEnableSystemInterrupt
;
; --- 8259 interrupt enable...
;
HalEnableInt60:
xor eax, eax
;
; Get the current interrupt mask register from the 8259
;
in al, PIC2_PORT1
shl eax, 8
in al, PIC1_PORT1
;
; Unmask the interrupt to be enabled
;
btr eax, ecx
btr eax, 2 ; Enable cascaded IRQ2
;
; Write the new interrupt mask register back to the 8259
;
out PIC1_PORT1, al
shr eax, 8
out PIC2_PORT1, al
PIC2DELAY
cPublicFpo 3, 0
popfd
HalEnableInt999:
stdRET _HalEnableSystemInterrupt
stdENDP _HalEnableSystemInterrupt
; HalpEndSystemInterrupt
; IN KIRQL NewIrql,
; IN ULONG Vector
; )
;
; Routine Description:
;
; This routine is used to lower IRQL to the specified value just prior
; to ending interrupt processing.
;
; Arguments:
;
; NewIrql - the new irql to be set.
;
; Vector - Vector number of the interrupt
;
; Note that esp+8 is the beginning of interrupt/trap frame and upon
; entering to this routine.
;
; Return Value:
;
; None.
;
;--
HeiVector equ [esp+8]
HeiNewIrql equ [esp+4]
cPublicProc _HalEndSystemInterrupt ,2
cPublicFpo 2, 0
mov eax, HeiVector ; Get the current vector
mov edx, _HalpLocalUnitBase ; Local APIC address
if DBG
xor ecx, ecx
mov cl, byte ptr HeiNewIrql
cmp cl, PCR[PcHal.ProcIrql]
jbe short @f
push dword ptr ecx ; new irql for debugging
push dword ptr PCR[PcHal.ProcIrql] ; old irql for debugging
mov dword ptr [edx+LU_TPR], 0FFH
mov PCR[PcHal.ProcIrql], HIGH_LEVEL ; Set to avoid recursive error
stdCall _KeBugCheck, <IRQL_NOT_LESS_OR_EQUAL>
@@:
endif
;
; EOI the APIC on level EISA interrupts
;
mov al, _HalpK2Vector2EISA[eax] ; Get EISA IRQ #
mov cx, _HalpELCRImage ; Get edge/level register value
bt cx, ax ; test appropriate bit
jnc short NoEOI ; 1 means level interrupt
;
; Level interrupt so we need to determine if the source
; is the PIC or APIC. If the PIC, then we need to unmask the
; source, if the APIC, then we need to do an EOI to the APIC.
;
mov cx, _HalpMASKED ; get PIC level ints
bt cx, ax ; test appropriate bit
jnc short @f ; CF=1 means PIC level int
lock btr _HalpMASKED, ax ; atomic clear of bit
mov cx, ax
mov ax, 1
shl ax, cl
or al, ah
not al
mov cl, al
in al, PIC2_PORT1 ; unmask bit in PIC
and al, cl
out PIC2_PORT1, al
jmp short NoEOI
@@:
mov [edx+LU_EOI], eax ; EOI APIC
NoEOI:
xor eax, eax
mov al, byte ptr HeiNewIrql
;
; Write new lower priority level into the APIC Task Priority Register
;
pushfd
cli
mov PCR[PcHal.ProcIrql], al ; set new IRQL
mov al, _HalpIrql2TPR[eax] ; get new TPR
mov [edx+LU_TPR], eax ; write new TPR
mov eax, [edx+LU_TPR] ; Flush CPU write buffer
popfd
mov al, byte ptr HeiNewIrql ; get current irql
cmp al, DISPATCH_LEVEL ; SW ints possible?
jb short @f
stdRET _HalEndSystemInterrupt
;
; Check for any pending software interrupts
;
@@:
mov edx, PCR[PcIRR] ; get current IRR
and edx, FindHigherIrqlMask[eax*4]
jnz short @f
stdRET _HalEndSystemInterrupt
;
; Software interrupt(s) pending, figure out which one(s) and take it
;
@@:
cli
test dword ptr PCR[PcIRR], (1 SHL DISPATCH_LEVEL)
jz short @f
add esp, 12
jmp HalpDispatchInterrupt2ndEntry
@@:
cmp al, APC_LEVEL
jae short @f
test dword ptr PCR[PcIRR], (1 SHL APC_LEVEL)
jz short @f
add esp, 12
jmp HalpApcInterrupt2ndEntry
@@:
sti
stdRET _HalEndSystemInterrupt
stdENDP _HalEndSystemInterrupt
_TEXT ENDS
END