Home | History | Annotate | Download | only in AArch64
      1 ///** @file
      2 //
      3 //  This code provides low level routines that support the Virtual Machine
      4 //  for option ROMs.
      5 //
      6 //  Copyright (c) 2016, Linaro, Ltd. All rights reserved.<BR>
      7 //  Copyright (c) 2015, The Linux Foundation. All rights reserved.<BR>
      8 //  Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
      9 //
     10 //  This program and the accompanying materials
     11 //  are licensed and made available under the terms and conditions of the BSD License
     12 //  which accompanies this distribution.  The full text of the license may be found at
     13 //  http://opensource.org/licenses/bsd-license.php
     14 //
     15 //  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     16 //  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     17 //
     18 //**/
     19 
     20 ASM_GLOBAL ASM_PFX(EbcLLCALLEXNative)
     21 ASM_GLOBAL ASM_PFX(EbcLLEbcInterpret)
     22 ASM_GLOBAL ASM_PFX(EbcLLExecuteEbcImageEntryPoint)
     23 
     24 ASM_GLOBAL ASM_PFX(mEbcInstructionBufferTemplate)
     25 
     26 //****************************************************************************
     27 // EbcLLCALLEX
     28 //
     29 // This function is called to execute an EBC CALLEX instruction.
     30 // This instruction requires that we thunk out to external native
     31 // code. For AArch64, we copy the VM stack into the main stack and then pop
     32 // the first 8 arguments off according to the AArch64 Procedure Call Standard
     33 // On return, we restore the stack pointer to its original location.
     34 //
     35 //****************************************************************************
     36 // UINTN EbcLLCALLEXNative(UINTN FuncAddr, UINTN NewStackPointer, VOID *FramePtr)
     37 ASM_PFX(EbcLLCALLEXNative):
     38     mov     x8, x0                 // Preserve x0
     39     mov     x9, x1                 // Preserve x1
     40 
     41     //
     42     // If the EBC stack frame is smaller than or equal to 64 bytes, we know there
     43     // are no stacked arguments #9 and beyond that we need to copy to the native
     44     // stack. In this case, we can perform a tail call which is much more
     45     // efficient, since there is no need to touch the native stack at all.
     46     //
     47     sub     x3, x2, x1              // Length = NewStackPointer - FramePtr
     48     cmp     x3, #64
     49     b.gt    1f
     50 
     51     //
     52     // While probably harmless in practice, we should not access the VM stack
     53     // outside of the interval [NewStackPointer, FramePtr), which means we
     54     // should not blindly fill all 8 argument registers with VM stack data.
     55     // So instead, calculate how many argument registers we can fill based on
     56     // the size of the VM stack frame, and skip the remaining ones.
     57     //
     58     adr     x0, 0f                  // Take address of 'br' instruction below
     59     bic     x3, x3, #7              // Ensure correct alignment
     60     sub     x0, x0, x3, lsr #1      // Subtract 4 bytes for each arg to unstack
     61     br      x0                      // Skip remaining argument registers
     62 
     63     ldr     x7, [x9, #56]           // Call with 8 arguments
     64     ldr     x6, [x9, #48]           //  |
     65     ldr     x5, [x9, #40]           //  |
     66     ldr     x4, [x9, #32]           //  |
     67     ldr     x3, [x9, #24]           //  |
     68     ldr     x2, [x9, #16]           //  |
     69     ldr     x1, [x9, #8]            //  V
     70     ldr     x0, [x9]                // Call with 1 argument
     71 
     72 0:  br      x8                      // Call with no arguments
     73 
     74     //
     75     // More than 64 bytes: we need to build the full native stack frame and copy
     76     // the part of the VM stack exceeding 64 bytes (which may contain stacked
     77     // arguments) to the native stack
     78     //
     79 1:  stp     x29, x30, [sp, #-16]!
     80     mov     x29, sp
     81 
     82     //
     83     // Ensure that the stack pointer remains 16 byte aligned,
     84     // even if the size of the VM stack frame is not a multiple of 16
     85     //
     86     add     x1, x1, #64             // Skip over [potential] reg params
     87     tbz     x3, #3, 2f              // Multiple of 16?
     88     ldr     x4, [x2, #-8]!          // No? Then push one word
     89     str     x4, [sp, #-16]!         // ... but use two slots
     90     b       3f
     91 
     92 2:  ldp     x4, x5, [x2, #-16]!
     93     stp     x4, x5, [sp, #-16]!
     94 3:  cmp     x2, x1
     95     b.gt    2b
     96 
     97     ldp     x0, x1, [x9]
     98     ldp     x2, x3, [x9, #16]
     99     ldp     x4, x5, [x9, #32]
    100     ldp     x6, x7, [x9, #48]
    101 
    102     blr     x8
    103 
    104     mov     sp, x29
    105     ldp     x29, x30, [sp], #16
    106     ret
    107 
    108 //****************************************************************************
    109 // EbcLLEbcInterpret
    110 //
    111 // This function is called by the thunk code to handle an Native to EBC call
    112 // This can handle up to 16 arguments (1-8 on in x0-x7, 9-16 are on the stack)
    113 // x16 contains the Entry point that will be the first stacked argument when
    114 // EBCInterpret is called.
    115 //
    116 //****************************************************************************
    117 ASM_PFX(EbcLLEbcInterpret):
    118     stp     x29, x30, [sp, #-16]!
    119     mov     x29, sp
    120 
    121     // push the entry point and the address of args #9 - #16 onto the stack
    122     add     x17, sp, #16
    123     stp     x16, x17, [sp, #-16]!
    124 
    125     // call C-code
    126     bl      ASM_PFX(EbcInterpret)
    127 
    128     add     sp, sp, #16
    129     ldp     x29, x30, [sp], #16
    130     ret
    131 
    132 //****************************************************************************
    133 // EbcLLExecuteEbcImageEntryPoint
    134 //
    135 // This function is called by the thunk code to handle the image entry point
    136 // x16 contains the Entry point that will be the third argument when
    137 // ExecuteEbcImageEntryPoint is called.
    138 //
    139 //****************************************************************************
    140 ASM_PFX(EbcLLExecuteEbcImageEntryPoint):
    141     mov     x2, x16
    142 
    143     // tail call to C code
    144     b       ASM_PFX(ExecuteEbcImageEntryPoint)
    145 
    146 //****************************************************************************
    147 // mEbcInstructionBufferTemplate
    148 //****************************************************************************
    149     .section    ".rodata", "a"
    150     .align      3
    151 ASM_PFX(mEbcInstructionBufferTemplate):
    152     adr     x17, 0f
    153     ldp     x16, x17, [x17]
    154     br      x17
    155 
    156     //
    157     // Add a magic code here to help the VM recognize the thunk.
    158     //
    159     hlt     #0xEBC
    160 
    161 0:  .quad   0   // EBC_ENTRYPOINT_SIGNATURE
    162     .quad   0   // EBC_LL_EBC_ENTRYPOINT_SIGNATURE
    163