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; \ 22name:: 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) 61PROCEDURE_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 122PROCEDURE_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 157PROCEDURE_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 186PROCEDURE_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// 197PROCEDURE_ENTRY(EbcLLGetEbcEntryPoint) 198 br.ret.sptk b0 ;; 199PROCEDURE_EXIT(EbcLLGetEbcEntryPoint) 200 201 202 203 204 205 206 207