4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync///** @file
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync//
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// Contains low level routines for the Virtual Machine implementation
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// on an Itanium-based platform.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync//
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// This program and the accompanying materials
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// are licensed and made available under the terms and conditions of the BSD License
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// which accompanies this distribution. The full text of the license may be found at
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// http://opensource.org/licenses/bsd-license.php
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync//
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync//
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync//**/
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync.file "EbcLowLevel.s"
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#define PROCEDURE_ENTRY(name) .##text; \
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync .##type name, @function; \
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync .##proc name; \
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncname::
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#define PROCEDURE_EXIT(name) .##endp name
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// Note: use of NESTED_SETUP requires number of locals (l) >= 3
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#define NESTED_SETUP(i,l,o,r) \
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync alloc loc1=ar##.##pfs,i,l,o,r ;\
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync mov loc0=b0
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#define NESTED_RETURN \
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync mov b0=loc0 ;\
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync mov ar##.##pfs=loc1 ;;\
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync br##.##ret##.##dpnt b0;;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync.type CopyMem, @function;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync//-----------------------------------------------------------------------------
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync//++
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// EbcAsmLLCALLEX
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync//
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// Implements the low level EBC CALLEX instruction. Sets up the
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// stack pointer, does the spill of function arguments, and
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// calls the native function. On return it restores the original
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// stack pointer and returns to the caller.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync//
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// Arguments :
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync//
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// On Entry :
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// in0 = Address of native code to call
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// in1 = New stack pointer
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync//
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// Return Value:
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync//
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// As per static calling conventions.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync//
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync//--
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync//---------------------------------------------------------------------------
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync;// void EbcAsmLLCALLEX (UINTN FunctionAddr, UINTN EbcStackPointer)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncPROCEDURE_ENTRY(EbcAsmLLCALLEX)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync NESTED_SETUP (2,6,8,0)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // NESTED_SETUP uses loc0 and loc1 for context save
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Save a copy of the EBC VM stack pointer
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync mov r8 = in1;;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Copy stack arguments from EBC stack into registers.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Assume worst case and copy 8.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync ld8 out0 = [r8], 8;;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync ld8 out1 = [r8], 8;;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync ld8 out2 = [r8], 8;;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync ld8 out3 = [r8], 8;;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync ld8 out4 = [r8], 8;;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync ld8 out5 = [r8], 8;;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync ld8 out6 = [r8], 8;;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync ld8 out7 = [r8], 8;;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Save the original stack pointer
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync mov loc2 = r12;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Save the gp
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync or loc3 = r1, r0
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Set the new aligned stack pointer. Reserve space for the required
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // 16-bytes of scratch area as well.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync add r12 = 48, in1
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Now call the function. Load up the function address from the descriptor
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // pointed to by in0. Then get the gp from the descriptor at the following
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // address in the descriptor.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync ld8 r31 = [in0], 8;;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync ld8 r30 = [in0];;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync mov b1 = r31
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync mov r1 = r30
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync (p0) br.call.dptk.many b0 = b1;;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Restore the original stack pointer and gp
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync mov r12 = loc2
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync or r1 = loc3, r0
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync // Now return
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync //
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync NESTED_RETURN
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncPROCEDURE_EXIT(EbcAsmLLCALLEX)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync//-----------------------------------------------------------------------------
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync//++
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// EbcLLCALLEXNative
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync//
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// This function is called to execute an EBC CALLEX instruction.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// This instruction requires that we thunk out to external native
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// code. On return, we restore the stack pointer to its original location.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// Destroys no working registers. For IPF, at least 8 register slots
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// must be allocated on the stack frame to support any number of
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// arguments beiung passed to the external native function. The
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// size of the stack frame is FramePtr - EbcSp. If this size is less
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// than 64-bytes, the amount of stack frame allocated is rounded up
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// to 64-bytes
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync//
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// Arguments On Entry :
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// in0 = CallAddr The function address.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// in1 = EbcSp The new EBC stack pointer.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// in2 = FramePtr The frame pointer.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync//
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// Return Value:
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// None
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync//
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// C Function Prototype:
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// VOID
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// EFIAPI
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// EbcLLCALLEXNative (
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// IN UINTN CallAddr,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// IN UINTN EbcSp,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// IN VOID *FramePtr
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// );
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync//--
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync//---------------------------------------------------------------------------
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncPROCEDURE_ENTRY(EbcLLCALLEXNative)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync NESTED_SETUP (3,6,3,0)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync mov loc2 = in2;; // loc2 = in2 = FramePtr
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync mov loc3 = in1;; // loc3 = in1 = EbcSp
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync sub loc2 = loc2, loc3;; // loc2 = loc2 - loc3 = FramePtr - EbcSp
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync mov out2 = loc2;; // out2 = loc2 = FramePtr - EbcSp
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync mov loc4 = 0x40;; // loc4 = 0x40
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync cmp.leu p6 = out2, loc4;; // IF out2 < loc4 THEN P6=1 ELSE P6=0; IF (FramePtr - EbcSp) < 0x40 THEN P6 = 1 ELSE P6=0
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync (p6) mov loc2 = loc4;; // IF P6==1 THEN loc2 = loc4 = 0x40
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync mov loc4 = r12;; // save sp
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync or loc5 = r1, r0 // save gp
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync sub r12 = r12, loc2;; // sp = sp - loc2 = sp - MAX (0x40, FramePtr - EbcSp)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync and r12 = -0x10, r12 // Round sp down to the nearest 16-byte boundary
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync mov out1 = in1;; // out1 = EbcSp
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync mov out0 = r12;; // out0 = sp
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync adds r12 = -0x8, r12
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync (p0) br.call.dptk.many b0 = CopyMem;; // CopyMem (sp, EbcSp, (FramePtr - EbcSp))
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync adds r12 = 0x8, r12
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync mov out0 = in0;; // out0 = CallAddr
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync mov out1 = r12;; // out1 = sp
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync (p0) br.call.dptk.many b0 = EbcAsmLLCALLEX;; // EbcAsmLLCALLEX (CallAddr, sp)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync mov r12 = loc4;; // restore sp
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync or r1 = loc5, r0 // restore gp
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync NESTED_RETURN
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncPROCEDURE_EXIT(EbcLLCALLEXNative)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync//
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// UINTN EbcLLGetEbcEntryPoint(VOID)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync//
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// Description:
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// Simply return, so that the caller retrieves the return register
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// contents (R8). That's where the thunk-to-ebc code stuffed the
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync// EBC entry point.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync//
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncPROCEDURE_ENTRY(EbcLLGetEbcEntryPoint)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync br.ret.sptk b0 ;;
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncPROCEDURE_EXIT(EbcLLGetEbcEntryPoint)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync