/** This function is called to execute an EBC CALLEX instruction. The function check the callee's content to see whether it is common native code or a thunk to another piece of EBC code. If the callee is common native code, use EbcLLCAllEXASM to manipulate, otherwise, set the VM->IP to target EBC code directly to avoid another VM be startup which cost time and stack space. @param VmPtr Pointer to a VM context. @param FuncAddr Callee's address @param NewStackPointer New stack pointer after the call @param FramePtr New frame pointer after the call @param Size The size of call instruction **/ VOID EbcLLCALLEX ( IN VM_CONTEXT *VmPtr, IN UINTN FuncAddr, IN UINTN NewStackPointer, IN VOID *FramePtr, IN UINT8 Size ) { CONST EBC_INSTRUCTION_BUFFER *InstructionBuffer; // // Processor specific code to check whether the callee is a thunk to EBC. // InstructionBuffer = (EBC_INSTRUCTION_BUFFER *)FuncAddr; if (CompareMem (InstructionBuffer, &mEbcInstructionBufferTemplate, sizeof(EBC_INSTRUCTION_BUFFER) - 2 * sizeof (UINT64)) == 0) { // // The callee is a thunk to EBC, adjust the stack pointer down 16 bytes and // put our return address and frame pointer on the VM stack. // Then set the VM's IP to new EBC code. // VmPtr->Gpr[0] -= 8; VmWriteMemN (VmPtr, (UINTN) VmPtr->Gpr[0], (UINTN) FramePtr); VmPtr->FramePtr = (VOID *) (UINTN) VmPtr->Gpr[0]; VmPtr->Gpr[0] -= 8; VmWriteMem64 (VmPtr, (UINTN) VmPtr->Gpr[0], (UINT64) (UINTN) (VmPtr->Ip + Size)); VmPtr->Ip = (VMIP) InstructionBuffer->EbcEntryPoint; } else { // // The callee is not a thunk to EBC, call native code, // and get return value. // VmPtr->Gpr[7] = EbcLLCALLEXNative (FuncAddr, NewStackPointer, FramePtr); // // Advance the IP. // VmPtr->Ip += Size; } }
/** This function is called to execute an EBC CALLEX instruction. The function check the callee's content to see whether it is common native code or a thunk to another piece of EBC code. If the callee is common native code, use EbcLLCAllEXASM to manipulate, otherwise, set the VM->IP to target EBC code directly to avoid another VM be startup which cost time and stack space. @param VmPtr Pointer to a VM context. @param FuncAddr Callee's address @param NewStackPointer New stack pointer after the call @param FramePtr New frame pointer after the call @param Size The size of call instruction **/ VOID EbcLLCALLEX ( IN VM_CONTEXT *VmPtr, IN UINTN FuncAddr, IN UINTN NewStackPointer, IN VOID *FramePtr, IN UINT8 Size ) { UINTN IsThunk; UINTN TargetEbcAddr; UINT8 InstructionBuffer[sizeof(mInstructionBufferTemplate)]; UINTN Index; UINTN IndexOfEbcEntrypoint; IsThunk = 1; TargetEbcAddr = 0; IndexOfEbcEntrypoint = 0; // // Processor specific code to check whether the callee is a thunk to EBC. // CopyMem (InstructionBuffer, (VOID *)FuncAddr, sizeof(InstructionBuffer)); // // Fill the signature according to mInstructionBufferTemplate // for (Index = 0; Index < sizeof(mInstructionBufferTemplate) - sizeof(UINTN); Index++) { if (*(UINTN *)&mInstructionBufferTemplate[Index] == EBC_ENTRYPOINT_SIGNATURE) { *(UINTN *)&InstructionBuffer[Index] = EBC_ENTRYPOINT_SIGNATURE; IndexOfEbcEntrypoint = Index; } if (*(UINTN *)&mInstructionBufferTemplate[Index] == EBC_LL_EBC_ENTRYPOINT_SIGNATURE) { *(UINTN *)&InstructionBuffer[Index] = EBC_LL_EBC_ENTRYPOINT_SIGNATURE; } } // // Check if we need thunk to native // if (CompareMem (InstructionBuffer, mInstructionBufferTemplate, sizeof(mInstructionBufferTemplate)) != 0) { IsThunk = 0; } if (IsThunk == 1){ // // The callee is a thunk to EBC, adjust the stack pointer down 16 bytes and // put our return address and frame pointer on the VM stack. // Then set the VM's IP to new EBC code. // VmPtr->Gpr[0] -= 8; VmWriteMemN (VmPtr, (UINTN) VmPtr->Gpr[0], (UINTN) FramePtr); VmPtr->FramePtr = (VOID *) (UINTN) VmPtr->Gpr[0]; VmPtr->Gpr[0] -= 8; VmWriteMem64 (VmPtr, (UINTN) VmPtr->Gpr[0], (UINT64) (UINTN) (VmPtr->Ip + Size)); CopyMem (&TargetEbcAddr, (UINT8 *)FuncAddr + IndexOfEbcEntrypoint, sizeof(UINTN)); VmPtr->Ip = (VMIP) (UINTN) TargetEbcAddr; } else { // // The callee is not a thunk to EBC, call native code, // and get return value. // VmPtr->Gpr[7] = EbcLLCALLEXNative (FuncAddr, NewStackPointer, FramePtr); // // Advance the IP. // VmPtr->Ip += Size; } }
/** This function is called to execute an EBC CALLEX instruction. The function check the callee's content to see whether it is common native code or a thunk to another piece of EBC code. If the callee is common native code, use EbcLLCAllEXASM to manipulate, otherwise, set the VM->IP to target EBC code directly to avoid another VM be startup which cost time and stack space. @param VmPtr Pointer to a VM context. @param FuncAddr Callee's address @param NewStackPointer New stack pointer after the call @param FramePtr New frame pointer after the call @param Size The size of call instruction **/ VOID EbcLLCALLEX ( IN VM_CONTEXT *VmPtr, IN UINTN FuncAddr, IN UINTN NewStackPointer, IN VOID *FramePtr, IN UINT8 Size ) { UINTN IsThunk; UINTN TargetEbcAddr; IsThunk = 1; TargetEbcAddr = 0; // // Processor specific code to check whether the callee is a thunk to EBC. // if (*((UINT8 *)FuncAddr) != 0xB8) { IsThunk = 0; goto Action; } if (*((UINT8 *)FuncAddr + 1) != 0xBC) { IsThunk = 0; goto Action; } if (*((UINT8 *)FuncAddr + 2) != 0x2E) { IsThunk = 0; goto Action; } if (*((UINT8 *)FuncAddr + 3) != 0x11) { IsThunk = 0; goto Action; } if (*((UINT8 *)FuncAddr + 4) != 0xCA) { IsThunk = 0; goto Action; } if (*((UINT8 *)FuncAddr + 5) != 0xB8) { IsThunk = 0; goto Action; } if (*((UINT8 *)FuncAddr + 10) != 0xB9) { IsThunk = 0; goto Action; } if (*((UINT8 *)FuncAddr + 15) != 0xFF) { IsThunk = 0; goto Action; } if (*((UINT8 *)FuncAddr + 16) != 0xE1) { IsThunk = 0; goto Action; } TargetEbcAddr = ((UINTN)(*((UINT8 *)FuncAddr + 9)) << 24) + ((UINTN)(*((UINT8 *)FuncAddr + 8)) << 16) + ((UINTN)(*((UINT8 *)FuncAddr + 7)) << 8) + ((UINTN)(*((UINT8 *)FuncAddr + 6))); Action: if (IsThunk == 1){ // // The callee is a thunk to EBC, adjust the stack pointer down 16 bytes and // put our return address and frame pointer on the VM stack. // Then set the VM's IP to new EBC code. // VmPtr->Gpr[0] -= 8; VmWriteMemN (VmPtr, (UINTN) VmPtr->Gpr[0], (UINTN) FramePtr); VmPtr->FramePtr = (VOID *) (UINTN) VmPtr->Gpr[0]; VmPtr->Gpr[0] -= 8; VmWriteMem64 (VmPtr, (UINTN) VmPtr->Gpr[0], (UINT64) (UINTN) (VmPtr->Ip + Size)); VmPtr->Ip = (VMIP) (UINTN) TargetEbcAddr; } else { // // The callee is not a thunk to EBC, call native code. // EbcLLCALLEXNative (FuncAddr, NewStackPointer, FramePtr); // // Get return value and advance the IP. // VmPtr->Gpr[7] = EbcLLGetReturnValue (); VmPtr->Ip += Size; } }