//      TITLE("Asynchronous Procedure Call (APC) Interrupt")
//++
//
// Copyright (c) 1990  Microsoft Corporation
//
// Module Name:
//
//    apcint.s
//
// Abstract:
//
//    This module implements the code necessary to field and process the
//    Asynchronous Procedure Call (APC) interrupt.
//
// Author:
//
//    David N. Cutler (davec) 3-Apr-1990
//    Joe Notarangelo 15-Jul-1992  alpha version
//
// Environment:
//
//    Kernel mode only, IRQL APC_LEVEL.
//
// Revision History:
//
//--

#include "ksalpha.h"

        SBTTL("Asynchronous Procedure Call Interrupt")
//++
//
// Routine Description:
//
//    This routine is entered as the result of a software interrupt generated
//    at APC_LEVEL. Its function is to allocate an exception frame and call
//    the kernel APC delivery routine to deliver kernel mode APCs and to check
//    if a user mode APC should be delivered. If a user mode APC should be
//    delivered, then the kernel APC delivery routine constructs a context
//    frame on the user stack and alters the exception and trap frames so that
//    control will be transfered to the user APC dispatcher on return from the
//    interrupt.
//
//    N.B. On entry to this routine only the volatile integer registers have
//       been saved. The remainder of the machine state is saved if and only
//       if the previous mode was user mode. It is assumed that none of the
//       APC delivery code, nor any of the kernel mode APC routines themselves
//       use any floating point instructions.
//
// Arguments:
//
//    s6/fp - Supplies a pointer to a trap frame.
//
// Return Value:
//
//    None.
//
//--

        NESTED_ENTRY(KiApcInterrupt, ExceptionFrameLength, zero)

	lda	sp, -ExceptionFrameLength(sp) // allocate exception frame
	stq	ra, ExIntRa(sp)		// save return address

        PROLOGUE_END

//
// Save the volatile floating state and determine the previous mode.
//

	bsr	ra, KiSaveVolatileFloatState // save volatile floats
	ldl	t0, TrPsr(fp)		// get saved processor status
	and	t0, PSR_MODE_MASK, a0	// isolate previous mode
        beq     a0, 10f			// if eq, kernel mode

//
// The previous mode was user.
//
// Save the nonvolatile machine state so a context record can be
// properly constructed to deliver an APC to user mode if required.
// It is also necessary to save the volatile floating state for
// suspend/resume operations.
//

	stq	s0, ExIntS0(sp)		// save nonvolatile integer state
	stq	s1, ExIntS1(sp)		//
	stq	s2, ExIntS2(sp)		//
	stq	s3, ExIntS3(sp)		//
	stq	s4, ExIntS4(sp)		//
	stq	s5, ExIntS5(sp)		//
	bsr	ra, KiSaveNonVolatileFloatState // save floating state

//
// Attempt to deliver an APC.
//

10:     bis	sp, zero, a1		// set address of exception frame
	bis	fp, zero, a2		// set address of trap frame
	bsr	ra, KiDeliverApc	// call APC delivery routine

//
// Restore the volatile floating state and return from the interrupt.
//

	bsr	ra, KiRestoreVolatileFloatState // restore floating state
	ldq	ra, ExIntRa(sp)		// restore return address
	lda	sp, ExceptionFrameLength(sp) // deallocate exception frame
	ret	zero, (ra)		// return

        .end    KiApcInterrupt
