summaryrefslogtreecommitdiffstats
path: root/MdeModulePkg/Universal/EbcDxe/Ipf/EbcLowLevel.s
blob: e329b68e66eb8d5942b175adf99fc9b9522fba0b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
//++
// Copyright (c) 2006, Intel Corporation                                                         
// All rights reserved. This program and the accompanying materials                          
// are licensed and made available under the terms and conditions of the BSD License         
// which accompanies this distribution.  The full text of the license may be found at        
// http://opensource.org/licenses/bsd-license.php                                            
//                                                                                           
// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     
// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             
// 
// Module Name:
//
//   EbcLowLevel.s
//
// Abstract:
//
//   Contains low level routines for the Virtual Machine implementation
//   on an Itanium-based platform.
//
//
//--

.file  "EbcLowLevel.s"

#define PROCEDURE_ENTRY(name)   .##text;            \
                                .##type name, @function;    \
                                .##proc name;           \
name::

#define PROCEDURE_EXIT(name)    .##endp name

// Note: use of NESTED_SETUP requires number of locals (l) >= 3

#define NESTED_SETUP(i,l,o,r) \
         alloc loc1=ar##.##pfs,i,l,o,r ;\
         mov loc0=b0

#define NESTED_RETURN \
         mov b0=loc0 ;\
         mov ar##.##pfs=loc1 ;;\
         br##.##ret##.##dpnt  b0;;

.type CopyMem, @function;  

//-----------------------------------------------------------------------------
//++
// EbcAsmLLCALLEX
//
//  Implements the low level EBC CALLEX instruction. Sets up the
//  stack pointer, does the spill of function arguments, and
//  calls the native function. On return it restores the original
//  stack pointer and returns to the caller.
//
// Arguments : 
//
// On Entry :
//    in0 = Address of native code to call
//    in1 = New stack pointer
//
// Return Value: 
// 
// As per static calling conventions. 
// 
//--
//---------------------------------------------------------------------------
;// void EbcAsmLLCALLEX (UINTN FunctionAddr, UINTN EbcStackPointer)
PROCEDURE_ENTRY(EbcAsmLLCALLEX)
  NESTED_SETUP (2,6,8,0)

  // NESTED_SETUP uses loc0 and loc1 for context save

  //
  // Save a copy of the EBC VM stack pointer
  //
  mov r8 = in1;;

  //
  // Copy stack arguments from EBC stack into registers. 
  // Assume worst case and copy 8.
  //
  ld8   out0 = [r8], 8;;
  ld8   out1 = [r8], 8;;
  ld8   out2 = [r8], 8;;
  ld8   out3 = [r8], 8;;
  ld8   out4 = [r8], 8;;
  ld8   out5 = [r8], 8;;
  ld8   out6 = [r8], 8;;
  ld8   out7 = [r8], 8;;

  //
  // Save the original stack pointer
  //
  mov   loc2 = r12;

  //
  // Save the gp
  //
  or    loc3 = r1, r0

  //
  // Set the new aligned stack pointer. Reserve space for the required 
  // 16-bytes of scratch area as well.
  //
  add  r12 = 48, in1

  //
  // Now call the function. Load up the function address from the descriptor
  // pointed to by in0. Then get the gp from the descriptor at the following
  // address in the descriptor.
  //
  ld8   r31 = [in0], 8;;
  ld8   r30 = [in0];;
  mov   b1 = r31
  mov   r1 = r30
  (p0) br.call.dptk.many b0 = b1;;

  //
  // Restore the original stack pointer and gp
  //
  mov   r12 = loc2
  or    r1 = loc3, r0

  //
  // Now return
  //
  NESTED_RETURN

PROCEDURE_EXIT(EbcAsmLLCALLEX)

PROCEDURE_ENTRY(EbcLLCALLEXNative)
  NESTED_SETUP (3,6,3,0)
  
  mov   loc2 = in2;;
  mov   loc3 = in1;;
  sub   loc2 = loc2, loc3
  mov   loc4 = r12;;
  or    loc5 = r1, r0
  
  sub   r12 = r12, loc2
  mov   out2 = loc2;;

  and   r12 = -0x10, r12
  mov   out1 = in1;;
  mov   out0 = r12;;
  adds  r12 = -0x8, r12
  (p0) br.call.dptk.many b0 = CopyMem;;
  adds  r12 = 0x8, r12
 
  mov   out0 = in0;;
  mov   out1 = r12;;
  (p0) br.call.dptk.many b0 = EbcAsmLLCALLEX;;
  mov   r12 = loc4;;
  or    r1 = loc5, r0
  
  NESTED_RETURN
PROCEDURE_EXIT(EbcLLCALLEXNative)


//
// UINTN EbcLLGetEbcEntryPoint(VOID)
//
// Description:
//    Simply return, so that the caller retrieves the return register
//    contents (R8). That's where the thunk-to-ebc code stuffed the
//    EBC entry point.
//
PROCEDURE_ENTRY(EbcLLGetEbcEntryPoint)
    br.ret.sptk  b0 ;;
PROCEDURE_EXIT(EbcLLGetEbcEntryPoint)

//
// INT64 EbcLLGetReturnValue(VOID)
//
// Description:
//    This function is called to get the value returned by native code
//     to EBC. It simply returns because the return value should still
//    be in the register, so the caller just gets the unmodified value.
//
PROCEDURE_ENTRY(EbcLLGetReturnValue)
    br.ret.sptk  b0 ;;
PROCEDURE_EXIT(EbcLLGetReturnValue)

//
// UINTN EbcLLGetStackPointer(VOID)
//
PROCEDURE_ENTRY(EbcLLGetStackPointer)
    mov    r8 = r12 ;;
    br.ret.sptk  b0 ;;
    br.sptk.few b6 
PROCEDURE_EXIT(EbcLLGetStackPointer)