//
///////////////////////////////////////////////////////////////////////////////
//
// Module Name:  EFIASM.S - IA64 EFI Physical Mode Calls //
// Description:
// Target Platform:  Merced
//
// Reuse: None
//
///////////////////////////////////////////////////////////////////////////////

#include "regia64.h"
#include "kxia64.h"

        .global HalpCallEfiPhysical
        .global HalpPhysBSPointer
        .global HalpPhysStackPointer
        .text

//++
// Name: HalpCallEfiPhysical()
// 
// Routine Description:
//
// Arguments:
//
//      Arg 0 to Arg 5
//      EntryPoint
//      GlobalPointer
//
// Return Value: EFI_STATUS
//
//--


        NESTED_ENTRY(HalpCallEfiPhysical)
        NESTED_SETUP(8,2,0,0)

//
//      Aliases
//
        rSaveEP     = t22
        rSaveGP     = t21
        rSaveA5     = t20
        rSaveA4     = t19
        rSaveA3     = t18
        rSaveA2     = t17
        rSaveA1     = t16
        rSaveA0     = t15

        rSaveSp     = t14
        rSaveBSP    = t13
        rSavePfs    = t12
        rSaveBrp    = t11
        rSaveRSC    = t10
        rSaveRNAT   = t9
        rSavePSR    = t8

        rNewSp      = t7
        rNewBSP     = t6

        rT1         = t1
        rT2         = t2
        rT3         = t3
                
// Save Arguements in static Registers
   
        mov         rSaveA0  = a0
        mov         rSaveA1  = a1
        mov         rSaveA2  = a2
        mov         rSaveA3  = a3
        mov         rSaveA4  = a4
        mov         rSaveA5  = a5
        mov         rSaveEP  = a6
        mov         rSaveGP  = a7

        mov         rSaveSp = sp
        mov         rSavePfs = ar.pfs
        mov         rSaveBrp = brp
        
//
// Setup Physical sp, bsp
//

        add          rT1 = @gprel(HalpPhysStackPointer), gp
        add          rT2 = @gprel(HalpPhysBSPointer), gp
        ;;
        ld8          rNewSp = [rT1]
        ld8          rNewBSP = [rT2]

// Allocate 0
        ;;
        alloc       rT1 = 0,0,0,0

// Flush RSE 
        ;;
        flushrs
        ;;
        mov         rSavePSR = psr
        movl        rT2 = (1 << PSR_BN)
        ;;
        or          rSavePSR = rT2, rSavePSR    // psr.bn stays on
        rsm         (1 << PSR_I)        
        
        mov         rSaveRSC = ar.rsc

// Flush RSE to enforced lazy mode by clearing both RSC.mode bits

        mov         rT1 = RSC_KERNEL_DISABLED
        ;;
        mov         ar.rsc = rT1
        ;;
//
// save RSC, RNAT, BSP, PSR, SP in the allocated space during initialization 
//
        mov         rSaveBSP = ar.bsp
        mov         rSaveRNAT = ar.rnat
//
// IC = 0; I = 0; 
//
        ;;
        rsm         (1 << PSR_IC)
        ;;
//        
// IIP = HceContinuePhysical:  IPSR is physical
//        
        movl        rT1 = (1 << PSR_IT) | (1 << PSR_RT) | (1 << PSR_DT) | (1 << PSR_I)
        movl        rT2 = 0xffffffffffffffff
        ;;
        xor         rT1 = rT1, rT2
        ;;
        and         rT1 = rT1, rSavePSR         // rT1 = old PSR & zero it, dt, rt, i
        srlz.i
        ;;
        mov         cr.ipsr = rT1
        mov         cr.ifs = zero
        ;;
        movl        rT2 = HceContinuePhysical
        movl        rT3 = 0xe0000000ffffffff
        ;;
        and         rT2 = rT2, rT3
        ;;
        tpa         rT2 = rT2                   // phys address of new ip
        ;;
        mov         cr.iip = rT2
        ;;
        rfi
        ;;
      
//
// Now in physical mode, ic = 1, i = 0
//

HceContinuePhysical::

//
// Switch to new bsp, sp
//
        mov         sp = rNewSp
        mov         ar.bspstore = rNewBSP
        ;;        
        mov         ar.rnat = zero
        ;;
//
// Enable RSC
//
        mov         ar.rsc = RSC_KERNEL

//
// Allocate frame on new bsp
//
        ;;
        alloc       rT1 = ar.pfs,0,7,6,0

//
// Save caller's state in register stack
//

        mov         loc0 = rSaveRNAT
        mov         loc1 = rSaveSp
        mov         loc2 = rSaveBSP
        mov         loc3 = rSaveRSC
        mov         loc4 = rSaveBrp
        mov         loc5 = rSavePfs
        mov         loc6 = rSavePSR
        ;;
// Setup Arguements

        mov         out0 = rSaveA0
        mov         out1 = rSaveA1
        mov         out2 = rSaveA2
        mov         out3 = rSaveA3
        mov         out4 = rSaveA4
        mov         out5 = rSaveA5

        movl        rT1 = HceEfiReturnAddress
        movl        rT2 = 0xe0000000FFFFFFFF
        ;;
        and         rT2 = rT2, rT1
        ;;
        tpa         rT2 = rT2
        ;;
        mov         brp = rT2
        mov         gp = rSaveGP
        mov         bt0 = rSaveEP        
        ;;
        br.call.sptk brp = bt0
        ;;

HceEfiReturnAddress::
//
// In physical mode: switch to virtual
//

//
// Restore saved state
//
        mov         rSaveRNAT = loc0
        mov         rSaveSp  = loc1
        mov         rSaveBSP = loc2
        mov         rSaveRSC = loc3
        mov         rSaveBrp = loc4
        mov         rSavePfs = loc5
        mov         rSavePSR = loc6
        ;;
//
// Restore BSP, SP
//
        ;;
        mov         ar.rsc = RSC_KERNEL_DISABLED
        ;;
        alloc       rT1 = 0,0,0,0
        ;;
        mov         ar.bspstore = rSaveBSP
        ;;
        mov         ar.rnat = rSaveRNAT
        mov         sp = rSaveSp
        ;;
        rsm         (1 << PSR_IC)
        ;;
        
        movl        rT1 = HceContinueVirtual
        movl        rT2 = 0xe0000000ffffffff
        ;;
        and         rT1 = rT2, rT1
        ;;
        srlz.i
        ;;
        mov         cr.iip = rT1
        mov         cr.ipsr = rSavePSR
        mov         cr.ifs = zero
        ;;
        rfi
        ;;
//
// Now in virtual mode, ic = 1, i = 1
//
HceContinueVirtual::

//
// Restore psf, brp and return
//
        mov         ar.rsc = rSaveRSC
        ;;
        mov         ar.pfs = rSavePfs
        mov         brp = rSaveBrp
        ;;
        br.ret.sptk brp
        NESTED_EXIT(HalpCallEfiPhysical)      





//++
//
//  VOID
//  HalpCallEfiVirtual(
//      ULONGLONG a0,  /* Arg 1 */
//      ULONGLONG a1,  /* Arg 2 */
//      ULONGLONG a2, /*  Arg 3 */
//      ULONGLONG a3, /*  Arg 4 */
//      ULONGLONG a4, /*  Arg 5 */
//      ULONGLONG a5, /*  Arg 6 */
//      ULONGLONG a6, /*  Entry Point */
//      ULONGLONG a7  /*  GP    */
//      );
//
//  Routine Description:
//
//  Return Values:
//      r8->r11 contain the 4 64-bit return values, r8 is the status
//--

        NESTED_ENTRY(HalpCallEfiVirtual)
        
        NESTED_SETUP(8,2,8,0)
        
        // copy args to outs
        mov         out0 = a0
        mov         out1 = a1
        mov         out2 = a2
        mov         out3 = a3
        mov         out4 = a4
        mov         out5 = a5
        mov         out6 = a6
        mov         out7 = a7
        ;;
        
        // Simply load the address and branch to it

        
        mov         gp   = a7
        ;;
        mov         bt0 =  a6
        ;;
        br.call.sptk brp = bt0
        ;;
        NESTED_RETURN
        
        NESTED_EXIT(HalpCallEfiVirtual)