1#/** @file
2#
3#    This code provides low level routines that support the Virtual Machine
4#   for option ROMs.
5#
6#  Copyright (c) 2007 - 2014, 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#---------------------------------------------------------------------------
18# Equate files needed.
19#---------------------------------------------------------------------------
20
21ASM_GLOBAL ASM_PFX(CopyMem);
22ASM_GLOBAL ASM_PFX(EbcInterpret);
23ASM_GLOBAL ASM_PFX(ExecuteEbcImageEntryPoint);
24
25#****************************************************************************
26# EbcLLCALLEX
27#
28# This function is called to execute an EBC CALLEX instruction.
29# This instruction requires that we thunk out to external native
30# code. For x64, we switch stacks, copy the arguments to the stack
31# and jump to the specified function.
32# On return, we restore the stack pointer to its original location.
33#
34# Destroys no working registers.
35#****************************************************************************
36# VOID EbcLLCALLEXNative(UINTN FuncAddr, UINTN NewStackPointer, VOID *FramePtr)
37ASM_GLOBAL ASM_PFX(EbcLLCALLEXNative);
38ASM_PFX(EbcLLCALLEXNative):
39      push   %rbp
40      push   %rbx
41      mov    %rsp, %rbp
42      # Function prolog
43
44      # Copy FuncAddr to a preserved register.
45      mov    %rcx, %rbx
46
47      # Set stack pointer to new value
48      sub    %rdx, %r8
49
50      #
51      # Fix X64 native function call prolog. Prepare space for at least 4 arguments,
52      # even if the native function's arguments are less than 4.
53      #
54      # From MSDN x64 Software Conventions, Overview of x64 Calling Conventions:
55      #   "The caller is responsible for allocating space for parameters to the
56      #   callee, and must always allocate sufficient space for the 4 register
57      #   parameters, even if the callee doesn't have that many parameters.
58      #   This aids in the simplicity of supporting C unprototyped functions,
59      #   and vararg C/C++ functions."
60      #
61      cmp    $0x20, %r8
62      jae    skip_expansion
63      mov    $0x20, %r8
64skip_expansion:
65
66      sub    %r8,  %rsp
67
68      #
69      # Fix X64 native function call 16-byte alignment.
70      #
71      # From MSDN x64 Software Conventions, Stack Usage:
72      #   "The stack will always be maintained 16-byte aligned, except within
73      #   the prolog (for example, after the return address is pushed)."
74      #
75      and    $0xFFFFFFFFFFFFFFF0, %rsp
76
77      mov    %rsp, %rcx
78      sub    $0x20, %rsp
79      call   ASM_PFX(CopyMem)
80      add    $0x20, %rsp
81
82      # Considering the worst case, load 4 potiential arguments
83      # into registers.
84      mov    (%rsp), %rcx
85      mov    0x8(%rsp), %rdx
86      mov    0x10(%rsp), %r8
87      mov    0x18(%rsp), %r9
88
89      # Now call the external routine
90      call  *%rbx
91
92      # Function epilog
93      mov      %rbp, %rsp
94      pop      %rbx
95      pop      %rbp
96      ret
97
98ASM_GLOBAL ASM_PFX(EbcLLEbcInterpret);
99ASM_PFX(EbcLLEbcInterpret):
100    # save old parameter to stack
101    mov  %rcx, 0x8(%rsp)
102    mov  %rdx, 0x10(%rsp)
103    mov  %r8, 0x18(%rsp)
104    mov  %r9, 0x20(%rsp)
105
106    # Construct new stack
107    push %rbp
108    mov  %rsp, %rbp
109    push %rsi
110    push %rdi
111    push %rbx
112    sub  $0x80, %rsp
113    push %r10
114    mov  %rbp, %rsi
115    add  $0x10, %rsi
116    mov  %rsp, %rdi
117    add  $0x8, %rdi
118    mov  $0x10, %rcx
119    rep  movsq
120
121    # build new paramater calling convention
122    mov  0x18(%rsp), %r9
123    mov  0x10(%rsp), %r8
124    mov  0x8(%rsp), %rdx
125    mov  %r10, %rcx
126
127    # call C-code
128    call ASM_PFX(EbcInterpret)
129    add  $0x88, %esp
130    pop  %rbx
131    pop  %rdi
132    pop  %rsi
133    pop  %rbp
134    ret
135
136ASM_GLOBAL ASM_PFX(EbcLLExecuteEbcImageEntryPoint);
137ASM_PFX(EbcLLExecuteEbcImageEntryPoint):
138    # build new paramater calling convention
139    mov  %rdx, %r8
140    mov  %rcx, %rdx
141    mov  %r10, %rcx
142
143    # call C-code
144    sub  $0x28, %rsp
145    call ASM_PFX(ExecuteEbcImageEntryPoint)
146    add  $0x28, %rsp
147    ret
148