Home | History | Annotate | Download | only in Ipf
      1 ///** @file
      2 //
      3 //  Contains low level routines for the Virtual Machine implementation
      4 //  on an Itanium-based platform.
      5 //
      6 //  Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
      7 //  This program and the accompanying materials
      8 //  are licensed and made available under the terms and conditions of the BSD License
      9 //  which accompanies this distribution.  The full text of the license may be found at
     10 //  http://opensource.org/licenses/bsd-license.php
     11 //
     12 //  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     13 //  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     14 //
     15 //**/
     16 
     17 .file  "EbcLowLevel.s"
     18 
     19 #define PROCEDURE_ENTRY(name)   .##text;            \
     20                                 .##type name, @function;    \
     21                                 .##proc name;           \
     22 name::
     23 
     24 #define PROCEDURE_EXIT(name)    .##endp name
     25 
     26 // Note: use of NESTED_SETUP requires number of locals (l) >= 3
     27 
     28 #define NESTED_SETUP(i,l,o,r) \
     29          alloc loc1=ar##.##pfs,i,l,o,r ;\
     30          mov loc0=b0
     31 
     32 #define NESTED_RETURN \
     33          mov b0=loc0 ;\
     34          mov ar##.##pfs=loc1 ;;\
     35          br##.##ret##.##dpnt  b0;;
     36 
     37 .type CopyMem, @function;
     38 
     39 //-----------------------------------------------------------------------------
     40 //++
     41 // EbcAsmLLCALLEX
     42 //
     43 //  Implements the low level EBC CALLEX instruction. Sets up the
     44 //  stack pointer, does the spill of function arguments, and
     45 //  calls the native function. On return it restores the original
     46 //  stack pointer and returns to the caller.
     47 //
     48 // Arguments :
     49 //
     50 // On Entry :
     51 //    in0 = Address of native code to call
     52 //    in1 = New stack pointer
     53 //
     54 // Return Value:
     55 //
     56 // As per static calling conventions.
     57 //
     58 //--
     59 //---------------------------------------------------------------------------
     60 ;// void EbcAsmLLCALLEX (UINTN FunctionAddr, UINTN EbcStackPointer)
     61 PROCEDURE_ENTRY(EbcAsmLLCALLEX)
     62   NESTED_SETUP (2,6,8,0)
     63 
     64   // NESTED_SETUP uses loc0 and loc1 for context save
     65 
     66   //
     67   // Save a copy of the EBC VM stack pointer
     68   //
     69   mov r8 = in1;;
     70 
     71   //
     72   // Copy stack arguments from EBC stack into registers.
     73   // Assume worst case and copy 8.
     74   //
     75   ld8   out0 = [r8], 8;;
     76   ld8   out1 = [r8], 8;;
     77   ld8   out2 = [r8], 8;;
     78   ld8   out3 = [r8], 8;;
     79   ld8   out4 = [r8], 8;;
     80   ld8   out5 = [r8], 8;;
     81   ld8   out6 = [r8], 8;;
     82   ld8   out7 = [r8], 8;;
     83 
     84   //
     85   // Save the original stack pointer
     86   //
     87   mov   loc2 = r12;
     88 
     89   //
     90   // Save the gp
     91   //
     92   or    loc3 = r1, r0
     93 
     94   //
     95   // Set the new aligned stack pointer. Reserve space for the required
     96   // 16-bytes of scratch area as well.
     97   //
     98   add  r12 = 48, in1
     99 
    100   //
    101   // Now call the function. Load up the function address from the descriptor
    102   // pointed to by in0. Then get the gp from the descriptor at the following
    103   // address in the descriptor.
    104   //
    105   ld8   r31 = [in0], 8;;
    106   ld8   r30 = [in0];;
    107   mov   b1 = r31
    108   mov   r1 = r30
    109   (p0) br.call.dptk.many b0 = b1;;
    110 
    111   //
    112   // Restore the original stack pointer and gp
    113   //
    114   mov   r12 = loc2
    115   or    r1 = loc3, r0
    116 
    117   //
    118   // Now return
    119   //
    120   NESTED_RETURN
    121 
    122 PROCEDURE_EXIT(EbcAsmLLCALLEX)
    123 
    124 //-----------------------------------------------------------------------------
    125 //++
    126 // EbcLLCALLEXNative
    127 //
    128 //  This function is called to execute an EBC CALLEX instruction.
    129 //  This instruction requires that we thunk out to external native
    130 //  code. On return, we restore the stack pointer to its original location.
    131 //  Destroys no working registers.  For IPF, at least 8 register slots
    132 //  must be allocated on the stack frame to support any number of
    133 //  arguments beiung passed to the external native function.  The
    134 //  size of the stack frame is FramePtr - EbcSp.  If this size is less
    135 //  than 64-bytes, the amount of stack frame allocated is rounded up
    136 //  to 64-bytes
    137 //
    138 // Arguments On Entry :
    139 //    in0 = CallAddr     The function address.
    140 //    in1 = EbcSp        The new EBC stack pointer.
    141 //    in2 = FramePtr     The frame pointer.
    142 //
    143 // Return Value:
    144 //    None
    145 //
    146 // C Function Prototype:
    147 //    VOID
    148 //    EFIAPI
    149 //    EbcLLCALLEXNative (
    150 //      IN UINTN        CallAddr,
    151 //      IN UINTN        EbcSp,
    152 //      IN VOID         *FramePtr
    153 //      );
    154 //--
    155 //---------------------------------------------------------------------------
    156 
    157 PROCEDURE_ENTRY(EbcLLCALLEXNative)
    158   NESTED_SETUP (3,6,3,0)
    159 
    160   mov   loc2 = in2;;              // loc2 = in2 = FramePtr
    161   mov   loc3 = in1;;              // loc3 = in1 = EbcSp
    162   sub   loc2 = loc2, loc3;;       // loc2 = loc2 - loc3 = FramePtr - EbcSp
    163   mov   out2 = loc2;;             // out2 = loc2 = FramePtr - EbcSp
    164   mov   loc4 = 0x40;;             // loc4 = 0x40
    165   cmp.leu p6  = out2, loc4;;      // IF out2 < loc4 THEN P6=1 ELSE P6=0; IF (FramePtr - EbcSp) < 0x40 THEN P6 = 1 ELSE P6=0
    166   (p6) mov   loc2 = loc4;;        // IF P6==1 THEN loc2 = loc4 = 0x40
    167   mov   loc4 = r12;;              // save sp
    168   or    loc5 = r1, r0             // save gp
    169 
    170   sub   r12 = r12, loc2;;         // sp = sp - loc2 = sp - MAX (0x40, FramePtr - EbcSp)
    171 
    172   and   r12 = -0x10, r12          // Round sp down to the nearest 16-byte boundary
    173   mov   out1 = in1;;              // out1 = EbcSp
    174   mov   out0 = r12;;              // out0 = sp
    175   adds  r12 = -0x8, r12
    176   (p0) br.call.dptk.many b0 = CopyMem;;      // CopyMem (sp, EbcSp, (FramePtr - EbcSp))
    177   adds  r12 = 0x8, r12
    178 
    179   mov   out0 = in0;;              // out0 = CallAddr
    180   mov   out1 = r12;;              // out1 = sp
    181   (p0) br.call.dptk.many b0 = EbcAsmLLCALLEX;;    // EbcAsmLLCALLEX (CallAddr, sp)
    182   mov   r12 = loc4;;              // restore sp
    183   or    r1 = loc5, r0             // restore gp
    184 
    185   NESTED_RETURN
    186 PROCEDURE_EXIT(EbcLLCALLEXNative)
    187 
    188 
    189 //
    190 // UINTN EbcLLGetEbcEntryPoint(VOID)
    191 //
    192 // Description:
    193 //    Simply return, so that the caller retrieves the return register
    194 //    contents (R8). That's where the thunk-to-ebc code stuffed the
    195 //    EBC entry point.
    196 //
    197 PROCEDURE_ENTRY(EbcLLGetEbcEntryPoint)
    198     br.ret.sptk  b0 ;;
    199 PROCEDURE_EXIT(EbcLLGetEbcEntryPoint)
    200 
    201 
    202 
    203 
    204 
    205 
    206 
    207