//      TITLE("Miscellaneous Kernel Functions")
//++
//
// Copyright (c) 1990  Microsoft Corporation
//
// Module Name:
//
//    miscs.s
//
// Abstract:
//
//    This module implements machine dependent miscellaneous kernel functions.
//    Functions are provided to request a software interrupt, continue thread
//    execution, and perform last chance exception processing.
//
// Author:
//
//    David N. Cutler (davec) 31-Mar-1990
//
// Environment:
//
//    Kernel mode only.
//
// Revision History:
//
//    Thomas Van Baak (tvb) 29-Jul-1992
//
//        Adapted for Alpha AXP.
//
//--

#include "ksalpha.h"

        SBTTL("Request Software Interrupt")
//++
//
// VOID
// KiRequestSoftwareInterrupt (
//    KIRQL RequestIrql
//    )
//
// Routine Description:
//
//    This function requests a software interrupt at the specified IRQL
//    level.
//
// Arguments:
//
//    RequestIrql (a0) - Supplies the requested IRQL value.
//
// Return Value:
//
//    None.
//
//--

        LEAF_ENTRY(KiRequestSoftwareInterrupt)

//
// If an interrupt routine is active, do not request an interrupt from the
// PAL. Indicate the interrupt has been requested in the PRCB. The interrupt
// exit code will dispatch the software interrupt directly.
//

        GET_PROCESSOR_CONTROL_BLOCK_BASE // get current prcb address

        LDP     t0, PbInterruptTrapFrame(v0) // get interrupt trap frame
        beq     t0, 10f                 // if eq, no interrupt active
        blbs    a0, 10f                 // if lbs, APC interrupt requested
        stl     a0, PbSoftwareInterrupts(v0) // set interrupt request bit in PRCB
        ret     zero, (ra)              //

//
// Request software interrupt.
//

10:     REQUEST_SOFTWARE_INTERRUPT      // request software interrupt

        ret     zero, (ra)              // return

        .end    KiRequestSoftwareInterrupt

        SBTTL("Continue Execution System Service")
//++
//
// NTSTATUS
// NtContinue (
//    IN PCONTEXT ContextRecord,
//    IN BOOLEAN TestAlert
//    )
//
// Routine Description:
//
//    This routine is called as a system service to continue execution after
//    an exception has occurred. Its function is to transfer information from
//    the specified context record into the trap frame that was built when the
//    system service was executed, and then exit the system as if an exception
//    had occurred.
//
// Arguments:
//
//    ContextRecord (a0) - Supplies a pointer to a context record.
//
//    TestAlert (a1) - Supplies a boolean value that specifies whether alert
//       should be tested for the previous processor mode.
//
//    N.B. Register fp is assumed to contain the address of a trap frame.
//
// Return Value:
//
//    Normally there is no return from this routine. However, if the specified
//    context record is misaligned or is not accessible, then the appropriate
//    status code is returned.
//
//--

        NESTED_ENTRY(NtContinue, ExceptionFrameLength, zero)

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

        PROLOGUE_END

//
// Save the nonvolatile machine state so that it can be restored by exception
// exit if it is not overwritten by the specified context record.
//

        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)         //

        stt     f2, ExFltF2(sp)         // save nonvolatile floating state
        stt     f3, ExFltF3(sp)         //
        stt     f4, ExFltF4(sp)         //
        stt     f5, ExFltF5(sp)         //
        stt     f6, ExFltF6(sp)         //
        stt     f7, ExFltF7(sp)         //
        stt     f8, ExFltF8(sp)         //
        stt     f9, ExFltF9(sp)         //

//
// Transfer information from the context frame to the exception and trap
// frames.
//

        mov     a1, s0                  // preserve test alert argument in s0
        mov     sp, a1                  // set address of exception frame
        mov     fp, a2                  // set address of trap frame
        bsr     ra, KiContinue          // transfer context to kernel frames

//
// If the kernel continuation routine returns success, then exit via the
// exception exit code. Otherwise return to the system service dispatcher.
//

        bne     v0, 20f                 // if ne, transfer failed

//
// Check to determine if alert should be tested for the previous processor
// mode and restore the previous mode in the thread object.
//

        GET_CURRENT_THREAD              // get current thread address

        LDP     t3, TrTrapFrame(fp)     // get old trap frame address
        ldl     t2, TrPreviousMode(fp)  // get old previous mode
        LoadByte(a0, ThPreviousMode(v0)) // get current previous mode
        STP     t3, ThTrapFrame(v0)     // restore old trap frame address
        StoreByte(t2, ThPreviousMode(v0)) // restore old previous mode
        beq     s0, 10f                 // if eq, don't test for alert
        bsr     ra, KeTestAlertThread   // test alert for current thread

//
// Exit the system via exception exit which will restore the nonvolatile
// machine state.
//

10:     br      zero, KiExceptionExit   // finish in exception exit

//
// Context record is misaligned or not accessible.
//

20:     ldq     ra, ExIntRa(sp)         // restore return address
        lda     sp, ExceptionFrameLength(sp) // deallocate stack frame
        ret     zero, (ra)              // return

        .end    NtContinue

        SBTTL("Raise Exception System Service")
//++
//
// NTSTATUS
// NtRaiseException (
//    IN PEXCEPTION_RECORD ExceptionRecord,
//    IN PCONTEXT ContextRecord,
//    IN BOOLEAN FirstChance
//    )
//
// Routine Description:
//
//    This routine is called as a system service to raise an exception.
//    The exception can be raised as a first or second chance exception.
//
// Arguments:
//
//    ExceptionRecord (a0) - Supplies a pointer to an exception record.
//
//    ContextRecord (a1) - Supplies a pointer to a context record.
//
//    FirstChance (a2) - Supplies a boolean value that determines whether
//       this is the first (TRUE) or second (FALSE) chance for dispatching
//       the exception.
//
//    N.B. Register fp is assumed to contain the address of a trap frame.
//
// Return Value:
//
//    Normally there is no return from this routine. However, if the specified
//    context record or exception record is misaligned or is not accessible,
//    then the appropriate status code is returned.
//
//--

        NESTED_ENTRY(NtRaiseException, ExceptionFrameLength, zero)

        lda     sp, -ExceptionFrameLength(sp) // allocate exception frame
        stq     ra, ExIntRa(sp)         // save return address
        stq     s0, ExIntS0(sp)         // save S0 and S1 in the prologue
        stq     s1, ExIntS1(sp)         // so that Get/SetContext can find
                                        // the right ones.
        PROLOGUE_END

//
// Save the nonvolatile machine state so that it can be restored by exception
// exit if it is not overwritten by the specified context record.
//

        stq     s2, ExIntS2(sp)         //
        stq     s3, ExIntS3(sp)         //
        stq     s4, ExIntS4(sp)         //
        stq     s5, ExIntS5(sp)         //

        stt     f2, ExFltF2(sp)         // save nonvolatile floating state
        stt     f3, ExFltF3(sp)         //
        stt     f4, ExFltF4(sp)         //
        stt     f5, ExFltF5(sp)         //
        stt     f6, ExFltF6(sp)         //
        stt     f7, ExFltF7(sp)         //
        stt     f8, ExFltF8(sp)         //
        stt     f9, ExFltF9(sp)         //

//
// Call the raise exception kernel routine which will marshall the arguments
// and then call the exception dispatcher.
//
// KiRaiseException requires five arguments: the first two are the same as
// the first two of this function and the other three are set here.
//

        mov     a2, a4                  // set first chance argument
        mov     sp, a2                  // set address of exception frame
        mov     fp, a3                  // set address of trap frame
        bsr     ra, KiRaiseException    // call raise exception routine

//
// If the raise exception routine returns success, then exit via the exception
// exit code. Otherwise return to the system service dispatcher.
//

        bis     v0, zero, t0            // save return status
        LDP     t1, TrTrapFrame(fp)     // get old trap frame address

        GET_CURRENT_THREAD              // get current thread address

        bne     t0, 10f                 // if ne, dispatch not successful
        STP     t1, ThTrapFrame(v0)     // restore old trap frame address

//
// Exit the system via exception exit which will restore the nonvolatile
// machine state.
//

        br      zero, KiExceptionExit   // finish in exception exit

//
// The context or exception record is misaligned or not accessible, or the
// exception was not handled.
//

10:     ldq     ra, ExIntRa(sp)         // restore return address
        lda     sp, ExceptionFrameLength(sp) // deallocate stack frame
        ret     zero, (ra)              // return

        .end    NtRaiseException

        SBTTL("Instruction Memory Barrier")
//++
//
// VOID
// KiImb (
//     VOID
//     )
//
// Routine Description:
//
//    This routine is called to flush the instruction cache on the
//    current processor.
//
// Arguments:
//
//    None.
//
// Return Value:
//
//    None.
//
//--

        LEAF_ENTRY(KiImb)

        IMB                     // flush the icache via PALcode

        ret     zero, (ra)      // return

        .end    KiImb

        SBTTL("Memory Barrier")
//++
//
// VOID
// KiImb (
//     VOID
//     )
//
// Routine Description:
//
//    This routine is called to issue a memory barrier on the current
//    processor.
//
// Arguments:
//
//    None.
//
// Return Value:
//
//    None.
//
//--

        LEAF_ENTRY(KiMb)

        mb                      // memory barrier

        ret     zero, (ra)      // return

        .end    KiMb

//++
//
// VOID
// KiEnablePALAlignmentFixups(
//     VOID	
//     )
//
// Routine Description:
//
//     Enable PAL fixups and PAL counting of alignment faults.
//
// Arguments:
//
//     None
//
// Return Value:
//
//     None.
//
//--

	LEAF_ENTRY(KiEnablePALAlignmentFixups)


	ENABLE_ALIGNMENT_FIXUPS         // enable alignment fixups

	ret	zero, (ra)		// return

	.end	KiEnablePALAlignmentFixups

//++
//
// VOID
// KiDisablePALAlignmentFixups(
//     VOID	
//     )
//
// Routine Description:
//
//     Disable PAL fixups and force all alignment faults to
//     the kernel.
//
// Arguments:
//
//     None
//
// Return Value:
//
//     None.
//
//--

	LEAF_ENTRY(KiDisablePALAlignmentFixups)

	DISABLE_ALIGNMENT_FIXUPS        // disable alignment fixups

	ret	zero, (ra)		// return

	.end	KiDisablePALAlignmentFixups