;++
;
;Copyright (c) 1991  Microsoft Corporation
;Copyright (c) 1992  Intel Corporation
;All rights reserved
;
;INTEL CORPORATION PROPRIETARY INFORMATION
;
;This software is supplied to Microsoft under the terms
;of a license agreement with Intel Corporation and may not be
;copied nor disclosed except in accordance with the terms
;of that agreement.
;
;
;Module Name:
;
;    mpsysint.asm
;
;Abstract:
;
;    This module implements the HAL routines to begin/end
;    system interrupts for a PC+MP implementation
;
;Author:
;
;    John Vert (jvert) 22-Jul-1991
;
;Environment:
;
;    Kernel Mode
;
;Revision History:
;
;    Ron Mosgrove (Intel) Aug 1993
;        Modified for PC+MP Systems
;
;--

.386p
        .xlist
include hal386.inc
include callconv.inc                ; calling convention macros
include i386\kimacro.inc
include mac386.inc
include apic.inc
include ntapic.inc
        .list

        EXTRNP  _KeBugCheck,1,IMPORT
        EXTRNP  _KiDispatchInterrupt,0,IMPORT
        extrn  _HalpVectorToIRQL:byte
        extrn  _HalpIRQLtoTPR:byte

_TEXT   SEGMENT DWORD PUBLIC 'CODE'
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING

        page ,132
        subttl  "End System Interrupt"
;++
;
; VOID
; HalpEndSystemInterrupt
;    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]
HeiVector       equ     [esp + 8]

cPublicProc _HalEndSystemInterrupt  ,2
cPublicFpo 2, 0
        xor     ecx,ecx
        mov     cl, byte ptr HeiNewIrql         ; get new IRQL
        mov     cl, _HalpIRQLtoTPR[ecx]         ; get corresponding TPR value

        mov     dword ptr APIC[LU_EOI], 0       ; send EOI to APIC local unit
        APICFIX edx

        cmp     cl, DPC_VECTOR                  ; Is new irql < DPC?
        jc      short es10                      ; Yes, go check for pending DPC

es05:   mov     dword ptr APIC[LU_TPR], ecx     ; Set new Priority

;
; We have to ensure that the requested priority is set before
; we return.  The caller is counting on it.
;
        mov     edx, dword ptr APIC[LU_TPR]
        CHECKTPR   ecx, edx
        stdRET    _HalEndSystemInterrupt

es10:   cmp     PCR[PcHal.DpcPending], 0        ; Is a DPC pending?
        mov     PCR[PcHal.ShortDpc], 0          ; Clear short dpc flag
        jz      short es05                      ; No, eoi

        mov     dword ptr APIC[LU_TPR], DPC_VECTOR  ; lower to DPC level
        APICFIX edx

        push    ebx                             ; Save EBX (used by KiDispatchInterrupt)
        push    ecx                             ; Save OldIrql
cPublicFpo 2, 2

        sti

es20:   mov     PCR[PcHal.DpcPending], 0        ; Clear pending flag

        stdCall _KiDispatchInterrupt            ; Dispatch interrupt

        cli

        pop     ecx
        pop     ebx
        jmp     short es05

stdENDP _HalEndSystemInterrupt


;++
;
;BOOLEAN
;HalBeginSystemInterrupt(
;    IN KIRQL Irql
;    IN ULONG Vector,
;    OUT PKIRQL OldIrql
;    )
;
;Routine Description:
;
;   This routine raises the IRQL to the level of the specified
;   interrupt vector.  It is called by the hardware interrupt
;   handler before any other interrupt service routine code is
;   executed.  The CPU interrupt flag is set on exit.
;
;   On APIC-based systems we do not need to check for spurious
;   interrupts since they now have their own vector.  We also
;   no longer need to check whether or not the incoming priority
;   is higher than the current priority that is guaranteed by
;   the priority mechanism of the APIC.
;
;   SO
;
;   All BeginSystemInterrupt needs to do is set the APIC TPR
;   appropriate for the IRQL, and return TRUE.  Note that to
;   use the APIC ISR priority we are not going issue EOI until
;   EndSystemInterrupt is called.
;
; Arguments:
;
;    Irql   - Supplies the IRQL to raise to
;
;    Vector - Supplies the vector of the interrupt to be
;             handled
;
;    OldIrql- Location to return OldIrql
;
; Return Value:
;
;    TRUE -  Interrupt successfully dismissed and Irql raised.
;            This routine can not fail.
;
;--


align dword
HbsiIrql        equ     byte  ptr [esp+4]
HbsiVector      equ     byte  ptr [esp+8]
HbsiOldIrql     equ     dword ptr [esp+12]

cPublicProc _HalBeginSystemInterrupt ,3
cPublicFpo 3, 0

        xor     eax, eax
        mov     al, HbsiIrql            ; (eax) = New Vector
        mov     al, _HalpIRQLtoTPR[eax]     ; get corresponding TPR value

        ;
        ; Read the TPR for the Priority (Vector) in use,
        ; and convert it to an IRQL
        ;

        mov     ecx, dword ptr APIC[LU_TPR]   ; Get the Priority
        mov     dword ptr APIC[LU_TPR], eax
        APICFIX edx

        mov     eax, HbsiOldIrql        ; return the current IRQL as OldIrql
        shr     ecx, 4
        mov     cl, byte ptr _HalpVectorToIRQL[ecx]

        mov     byte ptr [eax], cl
        mov     eax, 1                  ; return TRUE
        sti

        ;
        ; If OldIrql < DISPATCH_LEVEL and new irql >= DISPATCH_LEVEL (which
        ; is assumed), then set
        ;

        cmp     cl, DISPATCH_LEVEL
        jnc     short bs10

if DBG
        cmp     PCR[PcHal.ShortDpc], 0
        je      short @f
        int 3
@@:
endif
        mov     PCR[PcHal.ShortDpc], DISPATCH_LEVEL

bs10:
        stdRET    _HalBeginSystemInterrupt
stdENDP _HalBeginSystemInterrupt

_TEXT   ENDS

        END