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