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