mirror of https://github.com/acidanthera/audk.git
Adjust directory structures.
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3325 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
parent
7fb66a6dff
commit
53c71d097b
|
@ -21,7 +21,7 @@
|
|||
################################################################################
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010005
|
||||
BASE_NAME = DebugSupport
|
||||
BASE_NAME = DebugSupportDxe
|
||||
FILE_GUID = 911D584C-35F7-4955-BEF9-B452769DDC3A
|
||||
MODULE_TYPE = DXE_DRIVER
|
||||
VERSION_STRING = 1.0
|
|
@ -0,0 +1,115 @@
|
|||
#/** @file
|
||||
# Component description file for Ebc module.
|
||||
#
|
||||
# This module for the EBC virtual machine implementation produces
|
||||
# EBC and EBC debug support protocols.
|
||||
# Copyright (c) 2006 - 2007, 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.
|
||||
#
|
||||
#
|
||||
#**/
|
||||
|
||||
################################################################################
|
||||
#
|
||||
# Defines Section - statements that will be processed to create a Makefile.
|
||||
#
|
||||
################################################################################
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010005
|
||||
BASE_NAME = EbcDxe
|
||||
FILE_GUID = 13AC6DD0-73D0-11D4-B06B-00AA00BD6DE7
|
||||
MODULE_TYPE = DXE_DRIVER
|
||||
VERSION_STRING = 1.0
|
||||
EDK_RELEASE_VERSION = 0x00020000
|
||||
EFI_SPECIFICATION_VERSION = 0x00020000
|
||||
|
||||
ENTRY_POINT = InitializeEbcDriver
|
||||
|
||||
#
|
||||
# The following information is for reference only and not required by the build tools.
|
||||
#
|
||||
# VALID_ARCHITECTURES = IA32 X64 IPF
|
||||
#
|
||||
|
||||
################################################################################
|
||||
#
|
||||
# Sources Section - list of files that are required for the build to succeed.
|
||||
#
|
||||
################################################################################
|
||||
|
||||
[Sources.common]
|
||||
EbcExecute.h
|
||||
EbcExecute.c
|
||||
EbcInt.h
|
||||
EbcInt.c
|
||||
|
||||
[Sources.Ia32]
|
||||
Ia32/EbcSupport.c
|
||||
Ia32/EbcLowLevel.S
|
||||
Ia32/EbcLowLevel.asm
|
||||
|
||||
[Sources.X64]
|
||||
x64/EbcSupport.c
|
||||
x64/EbcLowLevel.S
|
||||
x64/EbcLowLevel.asm
|
||||
|
||||
[Sources.IPF]
|
||||
Ipf/EbcSupport.h
|
||||
Ipf/EbcSupport.c
|
||||
Ipf/EbcLowLevel.s
|
||||
|
||||
|
||||
################################################################################
|
||||
#
|
||||
# Package Dependency Section - list of Package files that are required for
|
||||
# this module.
|
||||
#
|
||||
################################################################################
|
||||
|
||||
[Packages]
|
||||
MdePkg/MdePkg.dec
|
||||
|
||||
|
||||
|
||||
################################################################################
|
||||
#
|
||||
# Library Class Section - list of Library Classes that are required for
|
||||
# this module.
|
||||
#
|
||||
################################################################################
|
||||
|
||||
[LibraryClasses]
|
||||
MemoryAllocationLib
|
||||
UefiBootServicesTableLib
|
||||
BaseMemoryLib
|
||||
UefiDriverEntryPoint
|
||||
DebugLib
|
||||
BaseLib
|
||||
|
||||
|
||||
################################################################################
|
||||
#
|
||||
# Protocol C Name Section - list of Protocol and Protocol Notify C Names
|
||||
# that this module uses or produces.
|
||||
#
|
||||
################################################################################
|
||||
|
||||
[Protocols]
|
||||
gEfiDebugSupportProtocolGuid # PROTOCOL ALWAYS_PRODUCED
|
||||
gEfiEbcProtocolGuid # PROTOCOL ALWAYS_PRODUCED
|
||||
|
||||
################################################################################
|
||||
#
|
||||
# Dependency Expression Section - list of Dependency expressions that are required for
|
||||
# this module.
|
||||
#
|
||||
################################################################################
|
||||
|
||||
[Depex]
|
||||
TRUE
|
|
@ -0,0 +1,80 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<MsaHeader>
|
||||
<ModuleName>Ebc</ModuleName>
|
||||
<ModuleType>DXE_DRIVER</ModuleType>
|
||||
<GuidValue>13AC6DD0-73D0-11D4-B06B-00AA00BD6DE7</GuidValue>
|
||||
<Version>1.0</Version>
|
||||
<Abstract>Component description file for Ebc module.</Abstract>
|
||||
<Description>This module for the EBC virtual machine implementation produces
|
||||
EBC and EBC debug support protocols.</Description>
|
||||
<Copyright>Copyright (c) 2006 - 2007, Intel Corporation</Copyright>
|
||||
<License>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.</License>
|
||||
<Specification>FRAMEWORK_BUILD_PACKAGING_SPECIFICATION 0x00000052</Specification>
|
||||
</MsaHeader>
|
||||
<ModuleDefinitions>
|
||||
<SupportedArchitectures>IA32 X64 IPF</SupportedArchitectures>
|
||||
<BinaryModule>false</BinaryModule>
|
||||
<OutputFileBasename>Ebc</OutputFileBasename>
|
||||
</ModuleDefinitions>
|
||||
<LibraryClassDefinitions>
|
||||
<LibraryClass Usage="ALWAYS_CONSUMED">
|
||||
<Keyword>BaseLib</Keyword>
|
||||
</LibraryClass>
|
||||
<LibraryClass Usage="ALWAYS_CONSUMED">
|
||||
<Keyword>DebugLib</Keyword>
|
||||
</LibraryClass>
|
||||
<LibraryClass Usage="ALWAYS_CONSUMED">
|
||||
<Keyword>UefiDriverEntryPoint</Keyword>
|
||||
</LibraryClass>
|
||||
<LibraryClass Usage="ALWAYS_CONSUMED">
|
||||
<Keyword>BaseMemoryLib</Keyword>
|
||||
</LibraryClass>
|
||||
<LibraryClass Usage="ALWAYS_CONSUMED">
|
||||
<Keyword>UefiBootServicesTableLib</Keyword>
|
||||
</LibraryClass>
|
||||
<LibraryClass Usage="ALWAYS_CONSUMED">
|
||||
<Keyword>MemoryAllocationLib</Keyword>
|
||||
</LibraryClass>
|
||||
</LibraryClassDefinitions>
|
||||
<SourceFiles>
|
||||
<Filename>EbcInt.c</Filename>
|
||||
<Filename>EbcInt.h</Filename>
|
||||
<Filename>EbcExecute.c</Filename>
|
||||
<Filename>EbcExecute.h</Filename>
|
||||
<Filename>Ebc.dxs</Filename>
|
||||
<Filename SupArchList="IA32" ToolChainFamily="MSFT">Ia32/EbcLowLevel.asm</Filename>
|
||||
<Filename SupArchList="IA32" ToolChainFamily="GCC">Ia32/EbcLowLevel.S</Filename>
|
||||
<Filename SupArchList="IA32">Ia32/EbcSupport.c</Filename>
|
||||
<Filename SupArchList="X64" ToolChainFamily="MSFT">x64/EbcLowLevel.asm</Filename>
|
||||
<Filename SupArchList="X64" ToolChainFamily="GCC">x64/EbcLowLevel.S</Filename>
|
||||
<Filename SupArchList="X64">x64/EbcSupport.c</Filename>
|
||||
<Filename SupArchList="IPF">Ipf/EbcLowLevel.s</Filename>
|
||||
<Filename SupArchList="IPF">Ipf/EbcSupport.c</Filename>
|
||||
<Filename SupArchList="IPF">Ipf/EbcSupport.h</Filename>
|
||||
</SourceFiles>
|
||||
<PackageDependencies>
|
||||
<Package PackageGuid="1E73767F-8F52-4603-AEB4-F29B510B6766"/>
|
||||
<Package PackageGuid="2759ded5-bb57-4b06-af4f-c398fa552719"/>
|
||||
</PackageDependencies>
|
||||
<Protocols>
|
||||
<Protocol Usage="ALWAYS_PRODUCED">
|
||||
<ProtocolCName>gEfiEbcProtocolGuid</ProtocolCName>
|
||||
</Protocol>
|
||||
<Protocol Usage="ALWAYS_PRODUCED">
|
||||
<ProtocolCName>gEfiDebugSupportProtocolGuid</ProtocolCName>
|
||||
</Protocol>
|
||||
</Protocols>
|
||||
<Externs>
|
||||
<Specification>EFI_SPECIFICATION_VERSION 0x00020000</Specification>
|
||||
<Specification>EDK_RELEASE_VERSION 0x00020000</Specification>
|
||||
<Extern>
|
||||
<ModuleEntryPoint>InitializeEbcDriver</ModuleEntryPoint>
|
||||
</Extern>
|
||||
</Externs>
|
||||
</ModuleSurfaceArea>
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,323 @@
|
|||
/*++
|
||||
|
||||
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:
|
||||
|
||||
EbcExecute.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Header file for Virtual Machine support. Contains EBC defines that can
|
||||
be of use to a disassembler for the most part. Also provides function
|
||||
prototypes for VM functions.
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef _EBC_EXECUTE_H_
|
||||
#define _EBC_EXECUTE_H_
|
||||
|
||||
//
|
||||
// VM major/minor version
|
||||
//
|
||||
#define VM_MAJOR_VERSION 1
|
||||
#define VM_MINOR_VERSION 0
|
||||
|
||||
//
|
||||
// Macros to check and set alignment
|
||||
//
|
||||
#define ASSERT_ALIGNED(addr, size) ASSERT (!((UINT32) (addr) & (size - 1)))
|
||||
#define IS_ALIGNED(addr, size) !((UINT32) (addr) & (size - 1))
|
||||
|
||||
//
|
||||
// Define a macro to get the operand. Then we can change it to be either a
|
||||
// direct read or have it call a function to read memory.
|
||||
//
|
||||
#define GETOPERANDS(pVM) (UINT8) (*(UINT8 *) (pVM->Ip + 1))
|
||||
#define GETOPCODE(pVM) (UINT8) (*(UINT8 *) pVM->Ip)
|
||||
|
||||
//
|
||||
// Bit masks for opcode encodings
|
||||
//
|
||||
#define OPCODE_M_OPCODE 0x3F // bits of interest for first level decode
|
||||
#define OPCODE_M_IMMDATA 0x80
|
||||
#define OPCODE_M_IMMDATA64 0x40
|
||||
#define OPCODE_M_64BIT 0x40 // for CMP
|
||||
#define OPCODE_M_RELADDR 0x10 // for CALL instruction
|
||||
#define OPCODE_M_CMPI32_DATA 0x80 // for CMPI
|
||||
#define OPCODE_M_CMPI64 0x40 // for CMPI 32 or 64 bit comparison
|
||||
#define OPERAND_M_MOVIN_N 0x80
|
||||
#define OPERAND_M_CMPI_INDEX 0x10
|
||||
|
||||
//
|
||||
// Masks for instructions that encode presence of indexes for operand1 and/or
|
||||
// operand2.
|
||||
//
|
||||
#define OPCODE_M_IMMED_OP1 0x80
|
||||
#define OPCODE_M_IMMED_OP2 0x40
|
||||
|
||||
//
|
||||
// Bit masks for operand encodings
|
||||
//
|
||||
#define OPERAND_M_INDIRECT1 0x08
|
||||
#define OPERAND_M_INDIRECT2 0x80
|
||||
#define OPERAND_M_OP1 0x07
|
||||
#define OPERAND_M_OP2 0x70
|
||||
|
||||
//
|
||||
// Masks for data manipulation instructions
|
||||
//
|
||||
#define DATAMANIP_M_64 0x40 // 64-bit width operation
|
||||
#define DATAMANIP_M_IMMDATA 0x80
|
||||
|
||||
//
|
||||
// For MOV instructions, need a mask for the opcode when immediate
|
||||
// data applies to R2.
|
||||
//
|
||||
#define OPCODE_M_IMMED_OP2 0x40
|
||||
|
||||
//
|
||||
// The MOVI/MOVIn instructions use bit 6 of operands byte to indicate
|
||||
// if an index is present. Then bits 4 and 5 are used to indicate the width
|
||||
// of the move.
|
||||
//
|
||||
#define MOVI_M_IMMDATA 0x40
|
||||
#define MOVI_M_DATAWIDTH 0xC0
|
||||
#define MOVI_DATAWIDTH16 0x40
|
||||
#define MOVI_DATAWIDTH32 0x80
|
||||
#define MOVI_DATAWIDTH64 0xC0
|
||||
#define MOVI_M_MOVEWIDTH 0x30
|
||||
#define MOVI_MOVEWIDTH8 0x00
|
||||
#define MOVI_MOVEWIDTH16 0x10
|
||||
#define MOVI_MOVEWIDTH32 0x20
|
||||
#define MOVI_MOVEWIDTH64 0x30
|
||||
|
||||
//
|
||||
// Masks for CALL instruction encodings
|
||||
//
|
||||
#define OPERAND_M_RELATIVE_ADDR 0x10
|
||||
#define OPERAND_M_NATIVE_CALL 0x20
|
||||
|
||||
//
|
||||
// Masks for decoding push/pop instructions
|
||||
//
|
||||
#define PUSHPOP_M_IMMDATA 0x80 // opcode bit indicating immediate data
|
||||
#define PUSHPOP_M_64 0x40 // opcode bit indicating 64-bit operation
|
||||
//
|
||||
// Mask for operand of JMP instruction
|
||||
//
|
||||
#define JMP_M_RELATIVE 0x10
|
||||
#define JMP_M_CONDITIONAL 0x80
|
||||
#define JMP_M_CS 0x40
|
||||
|
||||
//
|
||||
// Macros to determine if a given operand is indirect
|
||||
//
|
||||
#define OPERAND1_INDIRECT(op) ((op) & OPERAND_M_INDIRECT1)
|
||||
#define OPERAND2_INDIRECT(op) ((op) & OPERAND_M_INDIRECT2)
|
||||
|
||||
//
|
||||
// Macros to extract the operands from second byte of instructions
|
||||
//
|
||||
#define OPERAND1_REGNUM(op) ((op) & OPERAND_M_OP1)
|
||||
#define OPERAND2_REGNUM(op) (((op) & OPERAND_M_OP2) >> 4)
|
||||
|
||||
#define OPERAND1_CHAR(op) ('0' + OPERAND1_REGNUM (op))
|
||||
#define OPERAND2_CHAR(op) ('0' + OPERAND2_REGNUM (op))
|
||||
|
||||
#define OPERAND1_REGDATA(pvm, op) pvm->R[OPERAND1_REGNUM (op)]
|
||||
#define OPERAND2_REGDATA(pvm, op) pvm->R[OPERAND2_REGNUM (op)]
|
||||
|
||||
//
|
||||
// Condition masks usually for byte 1 encodings of code
|
||||
//
|
||||
#define CONDITION_M_CONDITIONAL 0x80
|
||||
#define CONDITION_M_CS 0x40
|
||||
|
||||
//
|
||||
// Bits in the VM->StopFlags field
|
||||
//
|
||||
#define STOPFLAG_APP_DONE 0x0001
|
||||
#define STOPFLAG_BREAKPOINT 0x0002
|
||||
#define STOPFLAG_INVALID_BREAK 0x0004
|
||||
#define STOPFLAG_BREAK_ON_CALLEX 0x0008
|
||||
|
||||
//
|
||||
// Masks for working with the VM flags register
|
||||
//
|
||||
#define VMFLAGS_CC 0x0001 // condition flag
|
||||
#define VMFLAGS_STEP 0x0002 // step instruction mode
|
||||
#define VMFLAGS_ALL_VALID (VMFLAGS_CC | VMFLAGS_STEP)
|
||||
|
||||
//
|
||||
// Macros for operating on the VM flags register
|
||||
//
|
||||
#define VMFLAG_SET(pVM, Flag) (pVM->Flags |= (Flag))
|
||||
#define VMFLAG_ISSET(pVM, Flag) ((pVM->Flags & (Flag)) ? 1 : 0)
|
||||
#define VMFLAG_CLEAR(pVM, Flag) (pVM->Flags &= ~(Flag))
|
||||
|
||||
//
|
||||
// Debug macro
|
||||
//
|
||||
#define EBCMSG(s) gST->ConOut->OutputString (gST->ConOut, s)
|
||||
|
||||
//
|
||||
// Define OPCODES
|
||||
//
|
||||
#define OPCODE_BREAK 0x00
|
||||
#define OPCODE_JMP 0x01
|
||||
#define OPCODE_JMP8 0x02
|
||||
#define OPCODE_CALL 0x03
|
||||
#define OPCODE_RET 0x04
|
||||
#define OPCODE_CMPEQ 0x05
|
||||
#define OPCODE_CMPLTE 0x06
|
||||
#define OPCODE_CMPGTE 0x07
|
||||
#define OPCODE_CMPULTE 0x08
|
||||
#define OPCODE_CMPUGTE 0x09
|
||||
#define OPCODE_NOT 0x0A
|
||||
#define OPCODE_NEG 0x0B
|
||||
#define OPCODE_ADD 0x0C
|
||||
#define OPCODE_SUB 0x0D
|
||||
#define OPCODE_MUL 0x0E
|
||||
#define OPCODE_MULU 0x0F
|
||||
#define OPCODE_DIV 0x10
|
||||
#define OPCODE_DIVU 0x11
|
||||
#define OPCODE_MOD 0x12
|
||||
#define OPCODE_MODU 0x13
|
||||
#define OPCODE_AND 0x14
|
||||
#define OPCODE_OR 0x15
|
||||
#define OPCODE_XOR 0x16
|
||||
#define OPCODE_SHL 0x17
|
||||
#define OPCODE_SHR 0x18
|
||||
#define OPCODE_ASHR 0x19
|
||||
#define OPCODE_EXTNDB 0x1A
|
||||
#define OPCODE_EXTNDW 0x1B
|
||||
#define OPCODE_EXTNDD 0x1C
|
||||
#define OPCODE_MOVBW 0x1D
|
||||
#define OPCODE_MOVWW 0x1E
|
||||
#define OPCODE_MOVDW 0x1F
|
||||
#define OPCODE_MOVQW 0x20
|
||||
#define OPCODE_MOVBD 0x21
|
||||
#define OPCODE_MOVWD 0x22
|
||||
#define OPCODE_MOVDD 0x23
|
||||
#define OPCODE_MOVQD 0x24
|
||||
#define OPCODE_MOVSNW 0x25 // Move signed natural with word index
|
||||
#define OPCODE_MOVSND 0x26 // Move signed natural with dword index
|
||||
//
|
||||
// #define OPCODE_27 0x27
|
||||
//
|
||||
#define OPCODE_MOVQQ 0x28 // Does this go away?
|
||||
#define OPCODE_LOADSP 0x29
|
||||
#define OPCODE_STORESP 0x2A
|
||||
#define OPCODE_PUSH 0x2B
|
||||
#define OPCODE_POP 0x2C
|
||||
#define OPCODE_CMPIEQ 0x2D
|
||||
#define OPCODE_CMPILTE 0x2E
|
||||
#define OPCODE_CMPIGTE 0x2F
|
||||
#define OPCODE_CMPIULTE 0x30
|
||||
#define OPCODE_CMPIUGTE 0x31
|
||||
#define OPCODE_MOVNW 0x32
|
||||
#define OPCODE_MOVND 0x33
|
||||
//
|
||||
// #define OPCODE_34 0x34
|
||||
//
|
||||
#define OPCODE_PUSHN 0x35
|
||||
#define OPCODE_POPN 0x36
|
||||
#define OPCODE_MOVI 0x37
|
||||
#define OPCODE_MOVIN 0x38
|
||||
#define OPCODE_MOVREL 0x39
|
||||
|
||||
EFI_STATUS
|
||||
EbcExecute (
|
||||
IN VM_CONTEXT *VmPtr
|
||||
)
|
||||
;
|
||||
|
||||
|
||||
|
||||
UINT64
|
||||
GetVmVersion (
|
||||
VOID
|
||||
)
|
||||
;
|
||||
|
||||
EFI_STATUS
|
||||
VmWriteMemN (
|
||||
IN VM_CONTEXT *VmPtr,
|
||||
IN UINTN Addr,
|
||||
IN UINTN Data
|
||||
)
|
||||
;
|
||||
|
||||
EFI_STATUS
|
||||
VmWriteMem64 (
|
||||
IN VM_CONTEXT *VmPtr,
|
||||
UINTN Addr,
|
||||
IN UINT64 Data
|
||||
)
|
||||
;
|
||||
|
||||
//
|
||||
// Define a protocol for an EBC VM test interface.
|
||||
//
|
||||
#define EFI_EBC_VM_TEST_PROTOCOL_GUID \
|
||||
{ \
|
||||
0xAAEACCFDL, 0xF27B, 0x4C17, { 0xB6, 0x10, 0x75, 0xCA, 0x1F, 0x2D, 0xFB, 0x52 } \
|
||||
}
|
||||
|
||||
//
|
||||
// Define for forward reference.
|
||||
//
|
||||
typedef struct _EFI_EBC_VM_TEST_PROTOCOL EFI_EBC_VM_TEST_PROTOCOL;
|
||||
|
||||
typedef
|
||||
EFI_STATUS
|
||||
(*EBC_VM_TEST_EXECUTE) (
|
||||
IN EFI_EBC_VM_TEST_PROTOCOL * This,
|
||||
IN VM_CONTEXT * VmPtr,
|
||||
IN OUT UINTN *InstructionCount
|
||||
);
|
||||
|
||||
typedef
|
||||
EFI_STATUS
|
||||
(*EBC_VM_TEST_ASM) (
|
||||
IN EFI_EBC_VM_TEST_PROTOCOL * This,
|
||||
IN CHAR16 *AsmText,
|
||||
IN OUT INT8 *Buffer,
|
||||
IN OUT UINTN *BufferLen
|
||||
);
|
||||
|
||||
typedef
|
||||
EFI_STATUS
|
||||
(*EBC_VM_TEST_DASM) (
|
||||
IN EFI_EBC_VM_TEST_PROTOCOL * This,
|
||||
IN OUT CHAR16 *AsmText,
|
||||
IN OUT INT8 *Buffer,
|
||||
IN OUT UINTN *Len
|
||||
);
|
||||
|
||||
//
|
||||
// Prototype for the actual EBC test protocol interface
|
||||
//
|
||||
struct _EFI_EBC_VM_TEST_PROTOCOL {
|
||||
EBC_VM_TEST_EXECUTE Execute;
|
||||
EBC_VM_TEST_ASM Assemble;
|
||||
EBC_VM_TEST_DASM Disassemble;
|
||||
};
|
||||
|
||||
EFI_STATUS
|
||||
EbcExecuteInstructions (
|
||||
IN EFI_EBC_VM_TEST_PROTOCOL *This,
|
||||
IN VM_CONTEXT *VmPtr,
|
||||
IN OUT UINTN *InstructionCount
|
||||
)
|
||||
;
|
||||
|
||||
#endif // ifndef _EBC_EXECUTE_H_
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,283 @@
|
|||
/*++
|
||||
|
||||
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:
|
||||
|
||||
EbcInt.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Main routines for the EBC interpreter. Includes the initialization and
|
||||
main interpreter routines.
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef _EBC_INT_H_
|
||||
#define _EBC_INT_H_
|
||||
|
||||
//
|
||||
// The package level header files this module uses
|
||||
//
|
||||
#include <PiDxe.h>
|
||||
//
|
||||
// The protocols, PPI and GUID defintions for this module
|
||||
//
|
||||
#include <Protocol/DebugSupport.h>
|
||||
#include <Protocol/Ebc.h>
|
||||
//
|
||||
// The Library classes this module consumes
|
||||
//
|
||||
#include <Library/BaseLib.h>
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/UefiDriverEntryPoint.h>
|
||||
#include <Library/BaseMemoryLib.h>
|
||||
#include <Library/UefiBootServicesTableLib.h>
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
|
||||
typedef INT64 VM_REGISTER;
|
||||
typedef UINT8 *VMIP; // instruction pointer for the VM
|
||||
typedef UINT32 EXCEPTION_FLAGS;
|
||||
|
||||
typedef struct {
|
||||
VM_REGISTER R[8]; // General purpose registers.
|
||||
UINT64 Flags; // Flags register:
|
||||
// 0 Set to 1 if the result of the last compare was true
|
||||
// 1 Set to 1 if stepping
|
||||
// 2..63 Reserved.
|
||||
VMIP Ip; // Instruction pointer.
|
||||
UINTN LastException; //
|
||||
EXCEPTION_FLAGS ExceptionFlags; // to keep track of exceptions
|
||||
UINT32 StopFlags;
|
||||
UINT32 CompilerVersion; // via break(6)
|
||||
UINTN HighStackBottom; // bottom of the upper stack
|
||||
UINTN LowStackTop; // top of the lower stack
|
||||
UINT64 StackRetAddr; // location of final return address on stack
|
||||
UINTN *StackMagicPtr; // pointer to magic value on stack to detect corruption
|
||||
EFI_HANDLE ImageHandle; // for this EBC driver
|
||||
EFI_SYSTEM_TABLE *SystemTable; // for debugging only
|
||||
UINTN LastAddrConverted; // for debug
|
||||
UINTN LastAddrConvertedValue; // for debug
|
||||
VOID *FramePtr;
|
||||
VOID *EntryPoint; // entry point of EBC image
|
||||
UINTN ImageBase;
|
||||
VOID *StackPool;
|
||||
VOID *StackTop;
|
||||
} VM_CONTEXT;
|
||||
|
||||
extern VM_CONTEXT *mVmPtr;
|
||||
|
||||
//
|
||||
// Bits of exception flags field of VM context
|
||||
//
|
||||
#define EXCEPTION_FLAG_FATAL 0x80000000 // can't continue
|
||||
#define EXCEPTION_FLAG_ERROR 0x40000000 // bad, but try to continue
|
||||
#define EXCEPTION_FLAG_WARNING 0x20000000 // harmless problem
|
||||
#define EXCEPTION_FLAG_NONE 0x00000000 // for normal return
|
||||
//
|
||||
// Flags passed to the internal create-thunks function.
|
||||
//
|
||||
#define FLAG_THUNK_ENTRY_POINT 0x01 // thunk for an image entry point
|
||||
#define FLAG_THUNK_PROTOCOL 0x00 // thunk for an EBC protocol service
|
||||
//
|
||||
// Put this value at the bottom of the VM's stack gap so we can check it on
|
||||
// occasion to make sure the stack has not been corrupted.
|
||||
//
|
||||
#define VM_STACK_KEY_VALUE 0xDEADBEEF
|
||||
|
||||
EFI_STATUS
|
||||
EbcCreateThunks (
|
||||
IN EFI_HANDLE ImageHandle,
|
||||
IN VOID *EbcEntryPoint,
|
||||
OUT VOID **Thunk,
|
||||
IN UINT32 Flags
|
||||
)
|
||||
;
|
||||
|
||||
EFI_STATUS
|
||||
EbcAddImageThunk (
|
||||
IN EFI_HANDLE ImageHandle,
|
||||
IN VOID *ThunkBuffer,
|
||||
IN UINT32 ThunkSize
|
||||
)
|
||||
;
|
||||
|
||||
//
|
||||
// The interpreter calls these when an exception is detected,
|
||||
// or as a periodic callback.
|
||||
//
|
||||
EFI_STATUS
|
||||
EbcDebugSignalException (
|
||||
IN EFI_EXCEPTION_TYPE ExceptionType,
|
||||
IN EXCEPTION_FLAGS ExceptionFlags,
|
||||
IN VM_CONTEXT *VmPtr
|
||||
)
|
||||
;
|
||||
|
||||
//
|
||||
// Define a constant of how often to call the debugger periodic callback
|
||||
// function.
|
||||
//
|
||||
#define EFI_TIMER_UNIT_1MS (1000 * 10)
|
||||
#define EBC_VM_PERIODIC_CALLBACK_RATE (1000 * EFI_TIMER_UNIT_1MS)
|
||||
#define STACK_POOL_SIZE (1024 * 1020)
|
||||
#define MAX_STACK_NUM 4
|
||||
|
||||
EFI_STATUS
|
||||
EbcDebugSignalPeriodic (
|
||||
IN VM_CONTEXT *VmPtr
|
||||
)
|
||||
;
|
||||
|
||||
//
|
||||
// External low level functions that are native-processor dependent
|
||||
//
|
||||
UINTN
|
||||
EbcLLGetEbcEntryPoint (
|
||||
VOID
|
||||
)
|
||||
;
|
||||
|
||||
UINTN
|
||||
EbcLLGetStackPointer (
|
||||
VOID
|
||||
)
|
||||
;
|
||||
|
||||
VOID
|
||||
EbcLLCALLEXNative (
|
||||
IN UINTN CallAddr,
|
||||
IN UINTN EbcSp,
|
||||
IN VOID *FramePtr
|
||||
)
|
||||
;
|
||||
|
||||
VOID
|
||||
EbcLLCALLEX (
|
||||
IN VM_CONTEXT *VmPtr,
|
||||
IN UINTN CallAddr,
|
||||
IN UINTN EbcSp,
|
||||
IN VOID *FramePtr,
|
||||
IN UINT8 Size
|
||||
)
|
||||
;
|
||||
|
||||
INT64
|
||||
EbcLLGetReturnValue (
|
||||
VOID
|
||||
)
|
||||
;
|
||||
|
||||
EFI_STATUS
|
||||
GetEBCStack(
|
||||
EFI_HANDLE Handle,
|
||||
VOID **StackBuffer,
|
||||
UINTN *BufferIndex
|
||||
);
|
||||
|
||||
EFI_STATUS
|
||||
ReturnEBCStack(
|
||||
UINTN Index
|
||||
);
|
||||
|
||||
EFI_STATUS
|
||||
InitEBCStack (
|
||||
VOID
|
||||
);
|
||||
|
||||
EFI_STATUS
|
||||
FreeEBCStack(
|
||||
VOID
|
||||
);
|
||||
|
||||
EFI_STATUS
|
||||
ReturnEBCStackByHandle(
|
||||
EFI_HANDLE Handle
|
||||
);
|
||||
//
|
||||
// Defines for a simple EBC debugger interface
|
||||
//
|
||||
typedef struct _EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL;
|
||||
|
||||
#define EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL_GUID \
|
||||
{ \
|
||||
0x2a72d11e, 0x7376, 0x40f6, { 0x9c, 0x68, 0x23, 0xfa, 0x2f, 0xe3, 0x63, 0xf1 } \
|
||||
}
|
||||
|
||||
typedef
|
||||
EFI_STATUS
|
||||
(*EBC_DEBUGGER_SIGNAL_EXCEPTION) (
|
||||
IN EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL * This,
|
||||
IN VM_CONTEXT * VmPtr,
|
||||
IN EFI_EXCEPTION_TYPE ExceptionType
|
||||
);
|
||||
|
||||
typedef
|
||||
VOID
|
||||
(*EBC_DEBUGGER_DEBUG) (
|
||||
IN EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL * This,
|
||||
IN VM_CONTEXT * VmPtr
|
||||
);
|
||||
|
||||
typedef
|
||||
UINT32
|
||||
(*EBC_DEBUGGER_DASM) (
|
||||
IN EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL * This,
|
||||
IN VM_CONTEXT * VmPtr,
|
||||
IN UINT16 *DasmString OPTIONAL,
|
||||
IN UINT32 DasmStringSize
|
||||
);
|
||||
|
||||
//
|
||||
// This interface allows you to configure the EBC debug support
|
||||
// driver. For example, turn on or off saving and printing of
|
||||
// delta VM even if called. Or to even disable the entire interface,
|
||||
// in which case all functions become no-ops.
|
||||
//
|
||||
typedef
|
||||
EFI_STATUS
|
||||
(*EBC_DEBUGGER_CONFIGURE) (
|
||||
IN EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL * This,
|
||||
IN UINT32 ConfigId,
|
||||
IN UINTN ConfigValue
|
||||
);
|
||||
|
||||
//
|
||||
// Prototype for the actual EBC debug support protocol interface
|
||||
//
|
||||
struct _EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL {
|
||||
EBC_DEBUGGER_DEBUG Debugger;
|
||||
EBC_DEBUGGER_SIGNAL_EXCEPTION SignalException;
|
||||
EBC_DEBUGGER_DASM Dasm;
|
||||
EBC_DEBUGGER_CONFIGURE Configure;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
EFI_EBC_PROTOCOL *This;
|
||||
VOID *EntryPoint;
|
||||
EFI_HANDLE ImageHandle;
|
||||
VM_CONTEXT VmContext;
|
||||
} EFI_EBC_THUNK_DATA;
|
||||
|
||||
#define EBC_PROTOCOL_PRIVATE_DATA_SIGNATURE EFI_SIGNATURE_32 ('e', 'b', 'c', 'p')
|
||||
|
||||
struct _EBC_PROTOCOL_PRIVATE_DATA {
|
||||
UINT32 Signature;
|
||||
EFI_EBC_PROTOCOL EbcProtocol;
|
||||
UINTN StackBase;
|
||||
UINTN StackTop;
|
||||
UINTN StackSize;
|
||||
} ;
|
||||
|
||||
#define EBC_PROTOCOL_PRIVATE_DATA_FROM_THIS(a) \
|
||||
CR(a, EBC_PROTOCOL_PRIVATE_DATA, EbcProtocol, EBC_PROTOCOL_PRIVATE_DATA_SIGNATURE)
|
||||
|
||||
|
||||
#endif // #ifndef _EBC_INT_H_
|
|
@ -0,0 +1,54 @@
|
|||
#****************************************************************************
|
||||
#*
|
||||
#* 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.
|
||||
#*
|
||||
#****************************************************************************
|
||||
.globl ASM_PFX(CopyMem)
|
||||
|
||||
.globl ASM_PFX(EbcLLCALLEXNative)
|
||||
ASM_PFX(EbcLLCALLEXNative):
|
||||
push %ebp
|
||||
push %ebx
|
||||
mov %esp,%ebp
|
||||
mov 0xc(%esp),%ecx
|
||||
mov 0x14(%esp),%eax
|
||||
mov 0x10(%esp),%edx
|
||||
sub %edx,%eax
|
||||
sub %eax,%esp
|
||||
mov %esp,%ebx
|
||||
push %ecx
|
||||
push %eax
|
||||
push %edx
|
||||
push %ebx
|
||||
call ASM_PFX(CopyMem)
|
||||
pop %eax
|
||||
pop %eax
|
||||
pop %eax
|
||||
pop %ecx
|
||||
call *%ecx
|
||||
mov %ebp,%esp
|
||||
mov %ebp,%esp
|
||||
pop %ebx
|
||||
pop %ebp
|
||||
ret
|
||||
|
||||
.globl ASM_PFX(EbcLLGetEbcEntryPoint)
|
||||
ASM_PFX(EbcLLGetEbcEntryPoint):
|
||||
ret
|
||||
|
||||
.globl ASM_PFX(EbcLLGetStackPointer)
|
||||
ASM_PFX(EbcLLGetStackPointer):
|
||||
mov %esp,%eax
|
||||
add $0x4,%eax
|
||||
ret
|
||||
|
||||
.globl ASM_PFX(EbcLLGetReturnValue)
|
||||
ASM_PFX(EbcLLGetReturnValue):
|
||||
ret
|
|
@ -0,0 +1,163 @@
|
|||
page ,132
|
||||
title VM ASSEMBLY LANGUAGE ROUTINES
|
||||
;****************************************************************************
|
||||
;*
|
||||
;* Copyright (c) 2006 - 2007, 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.
|
||||
;*
|
||||
;****************************************************************************
|
||||
;****************************************************************************
|
||||
; REV 1.0
|
||||
;****************************************************************************
|
||||
;
|
||||
; Rev Date Description
|
||||
; --- -------- ------------------------------------------------------------
|
||||
; 1.0 03/14/01 Initial creation of file.
|
||||
;
|
||||
;****************************************************************************
|
||||
|
||||
;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
; This code provides low level routines that support the Virtual Machine
|
||||
; for option ROMs.
|
||||
;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
|
||||
;---------------------------------------------------------------------------
|
||||
; Equate files needed.
|
||||
;---------------------------------------------------------------------------
|
||||
|
||||
.XLIST
|
||||
|
||||
.LIST
|
||||
|
||||
;---------------------------------------------------------------------------
|
||||
; Assembler options
|
||||
;---------------------------------------------------------------------------
|
||||
|
||||
.686p
|
||||
.model flat
|
||||
.code
|
||||
;---------------------------------------------------------------------------
|
||||
;;GenericPostSegment SEGMENT USE16
|
||||
;---------------------------------------------------------------------------
|
||||
CopyMem PROTO C Destination:PTR DWORD, Source:PTR DWORD, Count:DWORD
|
||||
|
||||
;****************************************************************************
|
||||
; EbcLLCALLEXNative
|
||||
;
|
||||
; This function is called to execute an EBC CALLEX instruction
|
||||
; to native code.
|
||||
; This instruction requires that we thunk out to external native
|
||||
; code. For IA32, we simply switch stacks and jump to the
|
||||
; specified function. On return, we restore the stack pointer
|
||||
; to its original location.
|
||||
;
|
||||
; Destroys no working registers.
|
||||
;****************************************************************************
|
||||
; VOID EbcLLCALLEXNative(UINTN FuncAddr, UINTN NewStackPointer, VOID *FramePtr)
|
||||
_EbcLLCALLEXNative PROC NEAR PUBLIC
|
||||
push ebp
|
||||
push ebx
|
||||
mov ebp, esp ; standard function prolog
|
||||
|
||||
; Get function address in a register
|
||||
; mov ecx, FuncAddr => mov ecx, dword ptr [FuncAddr]
|
||||
mov ecx, dword ptr [esp]+0Ch
|
||||
|
||||
; Set stack pointer to new value
|
||||
; mov eax, NewStackPointer => mov eax, dword ptr [NewSp]
|
||||
mov eax, dword ptr [esp] + 14h
|
||||
mov edx, dword ptr [esp] + 10h
|
||||
sub eax, edx
|
||||
sub esp, eax
|
||||
mov ebx, esp
|
||||
push ecx
|
||||
push eax
|
||||
push edx
|
||||
push ebx
|
||||
call CopyMem
|
||||
pop eax
|
||||
pop eax
|
||||
pop eax
|
||||
pop ecx
|
||||
|
||||
; Now call the external routine
|
||||
call ecx
|
||||
|
||||
; ebp is preserved by the callee. In this function it
|
||||
; equals the original esp, so set them equal
|
||||
mov esp, ebp
|
||||
|
||||
; Standard function epilog
|
||||
mov esp, ebp
|
||||
pop ebx
|
||||
pop ebp
|
||||
ret
|
||||
_EbcLLCALLEXNative ENDP
|
||||
|
||||
|
||||
; UINTN EbcLLGetEbcEntryPoint(VOID);
|
||||
; Routine Description:
|
||||
; The VM thunk code stuffs an EBC entry point into a processor
|
||||
; register. Since we can't use inline assembly to get it from
|
||||
; the interpreter C code, stuff it into the return value
|
||||
; register and return.
|
||||
;
|
||||
; Arguments:
|
||||
; None.
|
||||
;
|
||||
; Returns:
|
||||
; The contents of the register in which the entry point is passed.
|
||||
;
|
||||
_EbcLLGetEbcEntryPoint PROC NEAR PUBLIC
|
||||
ret
|
||||
_EbcLLGetEbcEntryPoint ENDP
|
||||
|
||||
;/*++
|
||||
;
|
||||
;Routine Description:
|
||||
;
|
||||
; Return the caller's value of the stack pointer.
|
||||
;
|
||||
;Arguments:
|
||||
;
|
||||
; None.
|
||||
;
|
||||
;Returns:
|
||||
;
|
||||
; The current value of the stack pointer for the caller. We
|
||||
; adjust it by 4 here because when they called us, the return address
|
||||
; is put on the stack, thereby lowering it by 4 bytes.
|
||||
;
|
||||
;--*/
|
||||
|
||||
; UINTN EbcLLGetStackPointer()
|
||||
_EbcLLGetStackPointer PROC NEAR PUBLIC
|
||||
mov eax, esp ; get current stack pointer
|
||||
add eax, 4 ; stack adjusted by this much when we were called
|
||||
ret
|
||||
_EbcLLGetStackPointer ENDP
|
||||
|
||||
; UINT64 EbcLLGetReturnValue(VOID);
|
||||
; Routine Description:
|
||||
; When EBC calls native, on return the VM has to stuff the return
|
||||
; value into a VM register. It's assumed here that the value is still
|
||||
; in the register, so simply return and the caller should get the
|
||||
; return result properly.
|
||||
;
|
||||
; Arguments:
|
||||
; None.
|
||||
;
|
||||
; Returns:
|
||||
; The unmodified value returned by the native code.
|
||||
;
|
||||
_EbcLLGetReturnValue PROC NEAR PUBLIC
|
||||
ret
|
||||
_EbcLLGetReturnValue ENDP
|
||||
|
||||
END
|
|
@ -0,0 +1,545 @@
|
|||
/*++
|
||||
|
||||
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:
|
||||
|
||||
EbcSupport.c
|
||||
|
||||
Abstract:
|
||||
|
||||
This module contains EBC support routines that are customized based on
|
||||
the target processor.
|
||||
|
||||
--*/
|
||||
|
||||
#include "EbcInt.h"
|
||||
#include "EbcExecute.h"
|
||||
|
||||
//
|
||||
// NOTE: This is the stack size allocated for the interpreter
|
||||
// when it executes an EBC image. The requirements can change
|
||||
// based on whether or not a debugger is present, and other
|
||||
// platform-specific configurations.
|
||||
//
|
||||
#define VM_STACK_SIZE (1024 * 4)
|
||||
#define EBC_THUNK_SIZE 32
|
||||
|
||||
#define STACK_REMAIN_SIZE (1024 * 4)
|
||||
VOID
|
||||
EbcLLCALLEX (
|
||||
IN VM_CONTEXT *VmPtr,
|
||||
IN UINTN FuncAddr,
|
||||
IN UINTN NewStackPointer,
|
||||
IN VOID *FramePtr,
|
||||
IN UINT8 Size
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
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.
|
||||
|
||||
Arguments:
|
||||
|
||||
VmPtr - Pointer to a VM context.
|
||||
FuncAddr - Callee's address
|
||||
NewStackPointer - New stack pointer after the call
|
||||
FramePtr - New frame pointer after the call
|
||||
Size - The size of call instruction
|
||||
|
||||
Returns:
|
||||
|
||||
None.
|
||||
|
||||
--*/
|
||||
{
|
||||
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->R[0] -= 8;
|
||||
VmWriteMemN (VmPtr, (UINTN) VmPtr->R[0], (UINTN) FramePtr);
|
||||
VmPtr->FramePtr = (VOID *) (UINTN) VmPtr->R[0];
|
||||
VmPtr->R[0] -= 8;
|
||||
VmWriteMem64 (VmPtr, (UINTN) VmPtr->R[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->R[7] = EbcLLGetReturnValue ();
|
||||
VmPtr->Ip += Size;
|
||||
}
|
||||
}
|
||||
|
||||
STATIC
|
||||
UINT64
|
||||
EbcInterpret (
|
||||
IN OUT UINTN Arg1,
|
||||
IN OUT UINTN Arg2,
|
||||
IN OUT UINTN Arg3,
|
||||
IN OUT UINTN Arg4,
|
||||
IN OUT UINTN Arg5,
|
||||
IN OUT UINTN Arg6,
|
||||
IN OUT UINTN Arg7,
|
||||
IN OUT UINTN Arg8,
|
||||
IN OUT UINTN Arg9,
|
||||
IN OUT UINTN Arg10,
|
||||
IN OUT UINTN Arg11,
|
||||
IN OUT UINTN Arg12,
|
||||
IN OUT UINTN Arg13,
|
||||
IN OUT UINTN Arg14,
|
||||
IN OUT UINTN Arg15,
|
||||
IN OUT UINTN Arg16
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Begin executing an EBC image. The address of the entry point is passed
|
||||
in via a processor register, so we'll need to make a call to get the
|
||||
value.
|
||||
|
||||
Arguments:
|
||||
|
||||
None. Since we're called from a fixed up thunk (which we want to keep
|
||||
small), our only so-called argument is the EBC entry point passed in
|
||||
to us in a processor register.
|
||||
|
||||
Returns:
|
||||
|
||||
The value returned by the EBC application we're going to run.
|
||||
|
||||
--*/
|
||||
{
|
||||
//
|
||||
// Create a new VM context on the stack
|
||||
//
|
||||
VM_CONTEXT VmContext;
|
||||
UINTN Addr;
|
||||
EFI_STATUS Status;
|
||||
UINTN StackIndex;
|
||||
|
||||
//
|
||||
// Get the EBC entry point from the processor register.
|
||||
//
|
||||
Addr = EbcLLGetEbcEntryPoint ();
|
||||
|
||||
//
|
||||
// Now clear out our context
|
||||
//
|
||||
ZeroMem ((VOID *) &VmContext, sizeof (VM_CONTEXT));
|
||||
|
||||
//
|
||||
// Set the VM instruction pointer to the correct location in memory.
|
||||
//
|
||||
VmContext.Ip = (VMIP) Addr;
|
||||
//
|
||||
// Initialize the stack pointer for the EBC. Get the current system stack
|
||||
// pointer and adjust it down by the max needed for the interpreter.
|
||||
//
|
||||
|
||||
//
|
||||
// Align the stack on a natural boundary
|
||||
//
|
||||
|
||||
//
|
||||
// Allocate stack pool
|
||||
//
|
||||
Status = GetEBCStack((EFI_HANDLE)-1, &VmContext.StackPool, &StackIndex);
|
||||
if (EFI_ERROR(Status)) {
|
||||
return Status;
|
||||
}
|
||||
VmContext.StackTop = (UINT8*)VmContext.StackPool + (STACK_REMAIN_SIZE);
|
||||
VmContext.R[0] = (UINT64)(UINTN) ((UINT8*)VmContext.StackPool + STACK_POOL_SIZE);
|
||||
VmContext.HighStackBottom = (UINTN)VmContext.R[0];
|
||||
VmContext.R[0] &= ~(sizeof (UINTN) - 1);
|
||||
VmContext.R[0] -= sizeof (UINTN);
|
||||
|
||||
//
|
||||
// Put a magic value in the stack gap, then adjust down again
|
||||
//
|
||||
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) VM_STACK_KEY_VALUE;
|
||||
VmContext.StackMagicPtr = (UINTN *) (UINTN) VmContext.R[0];
|
||||
VmContext.LowStackTop = (UINTN) VmContext.R[0];
|
||||
|
||||
//
|
||||
// For IA32, this is where we say our return address is
|
||||
//
|
||||
VmContext.R[0] -= sizeof (UINTN);
|
||||
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) Arg16;
|
||||
VmContext.R[0] -= sizeof (UINTN);
|
||||
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) Arg15;
|
||||
VmContext.R[0] -= sizeof (UINTN);
|
||||
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) Arg14;
|
||||
VmContext.R[0] -= sizeof (UINTN);
|
||||
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) Arg13;
|
||||
VmContext.R[0] -= sizeof (UINTN);
|
||||
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) Arg12;
|
||||
VmContext.R[0] -= sizeof (UINTN);
|
||||
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) Arg11;
|
||||
VmContext.R[0] -= sizeof (UINTN);
|
||||
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) Arg10;
|
||||
VmContext.R[0] -= sizeof (UINTN);
|
||||
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) Arg9;
|
||||
VmContext.R[0] -= sizeof (UINTN);
|
||||
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) Arg8;
|
||||
VmContext.R[0] -= sizeof (UINTN);
|
||||
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) Arg7;
|
||||
VmContext.R[0] -= sizeof (UINTN);
|
||||
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) Arg6;
|
||||
VmContext.R[0] -= sizeof (UINTN);
|
||||
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) Arg5;
|
||||
VmContext.R[0] -= sizeof (UINTN);
|
||||
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) Arg4;
|
||||
VmContext.R[0] -= sizeof (UINTN);
|
||||
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) Arg3;
|
||||
VmContext.R[0] -= sizeof (UINTN);
|
||||
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) Arg2;
|
||||
VmContext.R[0] -= sizeof (UINTN);
|
||||
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) Arg1;
|
||||
VmContext.R[0] -= 16;
|
||||
VmContext.StackRetAddr = (UINT64) VmContext.R[0];
|
||||
|
||||
//
|
||||
// We need to keep track of where the EBC stack starts. This way, if the EBC
|
||||
// accesses any stack variables above its initial stack setting, then we know
|
||||
// it's accessing variables passed into it, which means the data is on the
|
||||
// VM's stack.
|
||||
// When we're called, on the stack (high to low) we have the parameters, the
|
||||
// return address, then the saved ebp. Save the pointer to the return address.
|
||||
// EBC code knows that's there, so should look above it for function parameters.
|
||||
// The offset is the size of locals (VMContext + Addr + saved ebp).
|
||||
// Note that the interpreter assumes there is a 16 bytes of return address on
|
||||
// the stack too, so adjust accordingly.
|
||||
// VmContext.HighStackBottom = (UINTN)(Addr + sizeof (VmContext) + sizeof (Addr));
|
||||
//
|
||||
|
||||
//
|
||||
// Begin executing the EBC code
|
||||
//
|
||||
EbcExecute (&VmContext);
|
||||
|
||||
//
|
||||
// Return the value in R[7] unless there was an error
|
||||
//
|
||||
ReturnEBCStack(StackIndex);
|
||||
return (UINT64) VmContext.R[7];
|
||||
}
|
||||
|
||||
STATIC
|
||||
UINT64
|
||||
ExecuteEbcImageEntryPoint (
|
||||
IN EFI_HANDLE ImageHandle,
|
||||
IN EFI_SYSTEM_TABLE *SystemTable
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Begin executing an EBC image. The address of the entry point is passed
|
||||
in via a processor register, so we'll need to make a call to get the
|
||||
value.
|
||||
|
||||
Arguments:
|
||||
|
||||
ImageHandle - image handle for the EBC application we're executing
|
||||
SystemTable - standard system table passed into an driver's entry point
|
||||
|
||||
Returns:
|
||||
|
||||
The value returned by the EBC application we're going to run.
|
||||
|
||||
--*/
|
||||
{
|
||||
//
|
||||
// Create a new VM context on the stack
|
||||
//
|
||||
VM_CONTEXT VmContext;
|
||||
UINTN Addr;
|
||||
EFI_STATUS Status;
|
||||
UINTN StackIndex;
|
||||
|
||||
//
|
||||
// Get the EBC entry point from the processor register. Make sure you don't
|
||||
// call any functions before this or you could mess up the register the
|
||||
// entry point is passed in.
|
||||
//
|
||||
Addr = EbcLLGetEbcEntryPoint ();
|
||||
|
||||
//
|
||||
// Print(L"*** Thunked into EBC entry point - ImageHandle = 0x%X\n", (UINTN)ImageHandle);
|
||||
// Print(L"EBC entry point is 0x%X\n", (UINT32)(UINTN)Addr);
|
||||
//
|
||||
// Now clear out our context
|
||||
//
|
||||
ZeroMem ((VOID *) &VmContext, sizeof (VM_CONTEXT));
|
||||
|
||||
//
|
||||
// Save the image handle so we can track the thunks created for this image
|
||||
//
|
||||
VmContext.ImageHandle = ImageHandle;
|
||||
VmContext.SystemTable = SystemTable;
|
||||
|
||||
//
|
||||
// Set the VM instruction pointer to the correct location in memory.
|
||||
//
|
||||
VmContext.Ip = (VMIP) Addr;
|
||||
|
||||
//
|
||||
// Initialize the stack pointer for the EBC. Get the current system stack
|
||||
// pointer and adjust it down by the max needed for the interpreter.
|
||||
//
|
||||
|
||||
//
|
||||
// Allocate stack pool
|
||||
//
|
||||
Status = GetEBCStack(ImageHandle, &VmContext.StackPool, &StackIndex);
|
||||
if (EFI_ERROR(Status)) {
|
||||
return Status;
|
||||
}
|
||||
VmContext.StackTop = (UINT8*)VmContext.StackPool + (STACK_REMAIN_SIZE);
|
||||
VmContext.R[0] = (UINT64)(UINTN) ((UINT8*)VmContext.StackPool + STACK_POOL_SIZE);
|
||||
VmContext.HighStackBottom = (UINTN)VmContext.R[0];
|
||||
VmContext.R[0] -= sizeof (UINTN);
|
||||
|
||||
//
|
||||
// Put a magic value in the stack gap, then adjust down again
|
||||
//
|
||||
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) VM_STACK_KEY_VALUE;
|
||||
VmContext.StackMagicPtr = (UINTN *) (UINTN) VmContext.R[0];
|
||||
|
||||
//
|
||||
// Align the stack on a natural boundary
|
||||
// VmContext.R[0] &= ~(sizeof(UINTN) - 1);
|
||||
//
|
||||
VmContext.LowStackTop = (UINTN) VmContext.R[0];
|
||||
VmContext.R[0] -= sizeof (UINTN);
|
||||
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) SystemTable;
|
||||
VmContext.R[0] -= sizeof (UINTN);
|
||||
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) ImageHandle;
|
||||
|
||||
VmContext.R[0] -= 16;
|
||||
VmContext.StackRetAddr = (UINT64) VmContext.R[0];
|
||||
//
|
||||
// VM pushes 16-bytes for return address. Simulate that here.
|
||||
//
|
||||
|
||||
//
|
||||
// Begin executing the EBC code
|
||||
//
|
||||
EbcExecute (&VmContext);
|
||||
|
||||
//
|
||||
// Return the value in R[7] unless there was an error
|
||||
//
|
||||
return (UINT64) VmContext.R[7];
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
EbcCreateThunks (
|
||||
IN EFI_HANDLE ImageHandle,
|
||||
IN VOID *EbcEntryPoint,
|
||||
OUT VOID **Thunk,
|
||||
IN UINT32 Flags
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Create an IA32 thunk for the given EBC entry point.
|
||||
|
||||
Arguments:
|
||||
|
||||
ImageHandle - Handle of image for which this thunk is being created
|
||||
EbcEntryPoint - Address of the EBC code that the thunk is to call
|
||||
Thunk - Returned thunk we create here
|
||||
|
||||
Returns:
|
||||
|
||||
Standard EFI status.
|
||||
|
||||
--*/
|
||||
{
|
||||
UINT8 *Ptr;
|
||||
UINT8 *ThunkBase;
|
||||
UINT32 I;
|
||||
UINT32 Addr;
|
||||
INT32 Size;
|
||||
INT32 ThunkSize;
|
||||
|
||||
//
|
||||
// Check alignment of pointer to EBC code
|
||||
//
|
||||
if ((UINT32) (UINTN) EbcEntryPoint & 0x01) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
Size = EBC_THUNK_SIZE;
|
||||
ThunkSize = Size;
|
||||
|
||||
Ptr = AllocatePool (Size);
|
||||
|
||||
if (Ptr == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
//
|
||||
// Print(L"Allocate TH: 0x%X\n", (UINT32)Ptr);
|
||||
//
|
||||
// Save the start address so we can add a pointer to it to a list later.
|
||||
//
|
||||
ThunkBase = Ptr;
|
||||
|
||||
//
|
||||
// Give them the address of our buffer we're going to fix up
|
||||
//
|
||||
*Thunk = (VOID *) Ptr;
|
||||
|
||||
//
|
||||
// Add a magic code here to help the VM recognize the thunk..
|
||||
// mov eax, 0xca112ebc => B8 BC 2E 11 CA
|
||||
//
|
||||
*Ptr = 0xB8;
|
||||
Ptr++;
|
||||
Size--;
|
||||
Addr = (UINT32) 0xCA112EBC;
|
||||
for (I = 0; I < sizeof (Addr); I++) {
|
||||
*Ptr = (UINT8) (UINTN) Addr;
|
||||
Addr >>= 8;
|
||||
Ptr++;
|
||||
Size--;
|
||||
}
|
||||
|
||||
//
|
||||
// Add code bytes to load up a processor register with the EBC entry point.
|
||||
// mov eax, 0xaa55aa55 => B8 55 AA 55 AA
|
||||
// The first 8 bytes of the thunk entry is the address of the EBC
|
||||
// entry point.
|
||||
//
|
||||
*Ptr = 0xB8;
|
||||
Ptr++;
|
||||
Size--;
|
||||
Addr = (UINT32) EbcEntryPoint;
|
||||
for (I = 0; I < sizeof (Addr); I++) {
|
||||
*Ptr = (UINT8) (UINTN) Addr;
|
||||
Addr >>= 8;
|
||||
Ptr++;
|
||||
Size--;
|
||||
}
|
||||
//
|
||||
// Stick in a load of ecx with the address of appropriate VM function.
|
||||
// mov ecx 12345678h => 0xB9 0x78 0x56 0x34 0x12
|
||||
//
|
||||
if (Flags & FLAG_THUNK_ENTRY_POINT) {
|
||||
Addr = (UINT32) (UINTN) ExecuteEbcImageEntryPoint;
|
||||
} else {
|
||||
Addr = (UINT32) (UINTN) EbcInterpret;
|
||||
}
|
||||
|
||||
//
|
||||
// MOV ecx
|
||||
//
|
||||
*Ptr = 0xB9;
|
||||
Ptr++;
|
||||
Size--;
|
||||
for (I = 0; I < sizeof (Addr); I++) {
|
||||
*Ptr = (UINT8) Addr;
|
||||
Addr >>= 8;
|
||||
Ptr++;
|
||||
Size--;
|
||||
}
|
||||
//
|
||||
// Stick in jump opcode bytes for jmp ecx => 0xFF 0xE1
|
||||
//
|
||||
*Ptr = 0xFF;
|
||||
Ptr++;
|
||||
Size--;
|
||||
*Ptr = 0xE1;
|
||||
Size--;
|
||||
|
||||
//
|
||||
// Double check that our defined size is ok (application error)
|
||||
//
|
||||
if (Size < 0) {
|
||||
ASSERT (FALSE);
|
||||
return EFI_BUFFER_TOO_SMALL;
|
||||
}
|
||||
//
|
||||
// Add the thunk to the list for this image. Do this last since the add
|
||||
// function flushes the cache for us.
|
||||
//
|
||||
EbcAddImageThunk (ImageHandle, (VOID *) ThunkBase, ThunkSize);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
|
@ -0,0 +1,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)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,869 @@
|
|||
/*++
|
||||
|
||||
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:
|
||||
|
||||
EbcSupport.c
|
||||
|
||||
Abstract:
|
||||
|
||||
This module contains EBC support routines that are customized based on
|
||||
the target processor.
|
||||
|
||||
--*/
|
||||
|
||||
#include "EbcInt.h"
|
||||
#include "EbcExecute.h"
|
||||
#include "EbcSupport.h"
|
||||
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
WriteBundle (
|
||||
IN VOID *MemPtr,
|
||||
IN UINT8 Template,
|
||||
IN UINT64 Slot0,
|
||||
IN UINT64 Slot1,
|
||||
IN UINT64 Slot2
|
||||
);
|
||||
|
||||
STATIC
|
||||
VOID
|
||||
PushU64 (
|
||||
VM_CONTEXT *VmPtr,
|
||||
UINT64 Arg
|
||||
)
|
||||
{
|
||||
//
|
||||
// Advance the VM stack down, and then copy the argument to the stack.
|
||||
// Hope it's aligned.
|
||||
//
|
||||
VmPtr->R[0] -= sizeof (UINT64);
|
||||
*(UINT64 *) VmPtr->R[0] = Arg;
|
||||
}
|
||||
|
||||
STATIC
|
||||
UINT64
|
||||
EbcInterpret (
|
||||
UINT64 Arg1,
|
||||
...
|
||||
)
|
||||
{
|
||||
//
|
||||
// Create a new VM context on the stack
|
||||
//
|
||||
VM_CONTEXT VmContext;
|
||||
UINTN Addr;
|
||||
EFI_STATUS Status;
|
||||
UINTN StackIndex;
|
||||
VA_LIST List;
|
||||
UINT64 Arg2;
|
||||
UINT64 Arg3;
|
||||
UINT64 Arg4;
|
||||
UINT64 Arg5;
|
||||
UINT64 Arg6;
|
||||
UINT64 Arg7;
|
||||
UINT64 Arg8;
|
||||
UINT64 Arg9;
|
||||
UINT64 Arg10;
|
||||
UINT64 Arg11;
|
||||
UINT64 Arg12;
|
||||
UINT64 Arg13;
|
||||
UINT64 Arg14;
|
||||
UINT64 Arg15;
|
||||
UINT64 Arg16;
|
||||
//
|
||||
// Get the EBC entry point from the processor register. Make sure you don't
|
||||
// call any functions before this or you could mess up the register the
|
||||
// entry point is passed in.
|
||||
//
|
||||
Addr = EbcLLGetEbcEntryPoint ();
|
||||
//
|
||||
// Need the args off the stack.
|
||||
//
|
||||
VA_START (List, Arg1);
|
||||
Arg2 = VA_ARG (List, UINT64);
|
||||
Arg3 = VA_ARG (List, UINT64);
|
||||
Arg4 = VA_ARG (List, UINT64);
|
||||
Arg5 = VA_ARG (List, UINT64);
|
||||
Arg6 = VA_ARG (List, UINT64);
|
||||
Arg7 = VA_ARG (List, UINT64);
|
||||
Arg8 = VA_ARG (List, UINT64);
|
||||
Arg9 = VA_ARG (List, UINT64);
|
||||
Arg10 = VA_ARG (List, UINT64);
|
||||
Arg11 = VA_ARG (List, UINT64);
|
||||
Arg12 = VA_ARG (List, UINT64);
|
||||
Arg13 = VA_ARG (List, UINT64);
|
||||
Arg14 = VA_ARG (List, UINT64);
|
||||
Arg15 = VA_ARG (List, UINT64);
|
||||
Arg16 = VA_ARG (List, UINT64);
|
||||
//
|
||||
// Now clear out our context
|
||||
//
|
||||
ZeroMem ((VOID *) &VmContext, sizeof (VM_CONTEXT));
|
||||
//
|
||||
// Set the VM instruction pointer to the correct location in memory.
|
||||
//
|
||||
VmContext.Ip = (VMIP) Addr;
|
||||
//
|
||||
// Initialize the stack pointer for the EBC. Get the current system stack
|
||||
// pointer and adjust it down by the max needed for the interpreter.
|
||||
//
|
||||
//
|
||||
// NOTE: Eventually we should have the interpreter allocate memory
|
||||
// for stack space which it will use during its execution. This
|
||||
// would likely improve performance because the interpreter would
|
||||
// no longer be required to test each memory access and adjust
|
||||
// those reading from the stack gap.
|
||||
//
|
||||
// For IPF, the stack looks like (assuming 10 args passed)
|
||||
// arg10
|
||||
// arg9 (Bottom of high stack)
|
||||
// [ stack gap for interpreter execution ]
|
||||
// [ magic value for detection of stack corruption ]
|
||||
// arg8 (Top of low stack)
|
||||
// arg7....
|
||||
// arg1
|
||||
// [ 64-bit return address ]
|
||||
// [ ebc stack ]
|
||||
// If the EBC accesses memory in the stack gap, then we assume that it's
|
||||
// actually trying to access args9 and greater. Therefore we need to
|
||||
// adjust memory accesses in this region to point above the stack gap.
|
||||
//
|
||||
//
|
||||
// Now adjust the EBC stack pointer down to leave a gap for interpreter
|
||||
// execution. Then stuff a magic value there.
|
||||
//
|
||||
|
||||
Status = GetEBCStack((EFI_HANDLE)(UINTN)-1, &VmContext.StackPool, &StackIndex);
|
||||
if (EFI_ERROR(Status)) {
|
||||
return Status;
|
||||
}
|
||||
VmContext.StackTop = (UINT8*)VmContext.StackPool + (STACK_REMAIN_SIZE);
|
||||
VmContext.R[0] = (UINT64) ((UINT8*)VmContext.StackPool + STACK_POOL_SIZE);
|
||||
VmContext.HighStackBottom = (UINTN) VmContext.R[0];
|
||||
VmContext.R[0] -= sizeof (UINTN);
|
||||
|
||||
|
||||
PushU64 (&VmContext, (UINT64) VM_STACK_KEY_VALUE);
|
||||
VmContext.StackMagicPtr = (UINTN *) VmContext.R[0];
|
||||
VmContext.LowStackTop = (UINTN) VmContext.R[0];
|
||||
//
|
||||
// Push the EBC arguments on the stack. Does not matter that they may not
|
||||
// all be valid.
|
||||
//
|
||||
PushU64 (&VmContext, Arg16);
|
||||
PushU64 (&VmContext, Arg15);
|
||||
PushU64 (&VmContext, Arg14);
|
||||
PushU64 (&VmContext, Arg13);
|
||||
PushU64 (&VmContext, Arg12);
|
||||
PushU64 (&VmContext, Arg11);
|
||||
PushU64 (&VmContext, Arg10);
|
||||
PushU64 (&VmContext, Arg9);
|
||||
PushU64 (&VmContext, Arg8);
|
||||
PushU64 (&VmContext, Arg7);
|
||||
PushU64 (&VmContext, Arg6);
|
||||
PushU64 (&VmContext, Arg5);
|
||||
PushU64 (&VmContext, Arg4);
|
||||
PushU64 (&VmContext, Arg3);
|
||||
PushU64 (&VmContext, Arg2);
|
||||
PushU64 (&VmContext, Arg1);
|
||||
//
|
||||
// Push a bogus return address on the EBC stack because the
|
||||
// interpreter expects one there. For stack alignment purposes on IPF,
|
||||
// EBC return addresses are always 16 bytes. Push a bogus value as well.
|
||||
//
|
||||
PushU64 (&VmContext, 0);
|
||||
PushU64 (&VmContext, 0xDEADBEEFDEADBEEF);
|
||||
VmContext.StackRetAddr = (UINT64) VmContext.R[0];
|
||||
//
|
||||
// Begin executing the EBC code
|
||||
//
|
||||
EbcExecute (&VmContext);
|
||||
//
|
||||
// Return the value in R[7] unless there was an error
|
||||
//
|
||||
ReturnEBCStack(StackIndex);
|
||||
return (UINT64) VmContext.R[7];
|
||||
}
|
||||
|
||||
STATIC
|
||||
UINT64
|
||||
ExecuteEbcImageEntryPoint (
|
||||
IN EFI_HANDLE ImageHandle,
|
||||
IN EFI_SYSTEM_TABLE *SystemTable
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
IPF implementation.
|
||||
|
||||
Begin executing an EBC image. The address of the entry point is passed
|
||||
in via a processor register, so we'll need to make a call to get the
|
||||
value.
|
||||
|
||||
Arguments:
|
||||
|
||||
ImageHandle - image handle for the EBC application we're executing
|
||||
SystemTable - standard system table passed into an driver's entry point
|
||||
|
||||
Returns:
|
||||
|
||||
The value returned by the EBC application we're going to run.
|
||||
|
||||
--*/
|
||||
{
|
||||
//
|
||||
// Create a new VM context on the stack
|
||||
//
|
||||
VM_CONTEXT VmContext;
|
||||
UINTN Addr;
|
||||
EFI_STATUS Status;
|
||||
UINTN StackIndex;
|
||||
|
||||
//
|
||||
// Get the EBC entry point from the processor register. Make sure you don't
|
||||
// call any functions before this or you could mess up the register the
|
||||
// entry point is passed in.
|
||||
//
|
||||
Addr = EbcLLGetEbcEntryPoint ();
|
||||
|
||||
//
|
||||
// Now clear out our context
|
||||
//
|
||||
ZeroMem ((VOID *) &VmContext, sizeof (VM_CONTEXT));
|
||||
|
||||
//
|
||||
// Save the image handle so we can track the thunks created for this image
|
||||
//
|
||||
VmContext.ImageHandle = ImageHandle;
|
||||
VmContext.SystemTable = SystemTable;
|
||||
|
||||
//
|
||||
// Set the VM instruction pointer to the correct location in memory.
|
||||
//
|
||||
VmContext.Ip = (VMIP) Addr;
|
||||
|
||||
//
|
||||
// Get the stack pointer. This is the bottom of the upper stack.
|
||||
//
|
||||
Addr = EbcLLGetStackPointer ();
|
||||
|
||||
Status = GetEBCStack(ImageHandle, &VmContext.StackPool, &StackIndex);
|
||||
if (EFI_ERROR(Status)) {
|
||||
return Status;
|
||||
}
|
||||
VmContext.StackTop = (UINT8*)VmContext.StackPool + (STACK_REMAIN_SIZE);
|
||||
VmContext.R[0] = (UINT64) ((UINT8*)VmContext.StackPool + STACK_POOL_SIZE);
|
||||
VmContext.HighStackBottom = (UINTN) VmContext.R[0];
|
||||
VmContext.R[0] -= sizeof (UINTN);
|
||||
|
||||
|
||||
//
|
||||
// Allocate stack space for the interpreter. Then put a magic value
|
||||
// at the bottom so we can detect stack corruption.
|
||||
//
|
||||
PushU64 (&VmContext, (UINT64) VM_STACK_KEY_VALUE);
|
||||
VmContext.StackMagicPtr = (UINTN *) (UINTN) VmContext.R[0];
|
||||
|
||||
//
|
||||
// When we thunk to external native code, we copy the last 8 qwords from
|
||||
// the EBC stack into the processor registers, and adjust the stack pointer
|
||||
// up. If the caller is not passing 8 parameters, then we've moved the
|
||||
// stack pointer up into the stack gap. If this happens, then the caller
|
||||
// can mess up the stack gap contents (in particular our magic value).
|
||||
// Therefore, leave another gap below the magic value. Pick 10 qwords down,
|
||||
// just as a starting point.
|
||||
//
|
||||
VmContext.R[0] -= 10 * sizeof (UINT64);
|
||||
|
||||
//
|
||||
// Align the stack pointer such that after pushing the system table,
|
||||
// image handle, and return address on the stack, it's aligned on a 16-byte
|
||||
// boundary as required for IPF.
|
||||
//
|
||||
VmContext.R[0] &= (INT64)~0x0f;
|
||||
VmContext.LowStackTop = (UINTN) VmContext.R[0];
|
||||
//
|
||||
// Simply copy the image handle and system table onto the EBC stack.
|
||||
// Greatly simplifies things by not having to spill the args
|
||||
//
|
||||
PushU64 (&VmContext, (UINT64) SystemTable);
|
||||
PushU64 (&VmContext, (UINT64) ImageHandle);
|
||||
|
||||
//
|
||||
// Interpreter assumes 64-bit return address is pushed on the stack.
|
||||
// IPF does not do this so pad the stack accordingly. Also, a
|
||||
// "return address" is 16 bytes as required for IPF stack alignments.
|
||||
//
|
||||
PushU64 (&VmContext, (UINT64) 0);
|
||||
PushU64 (&VmContext, (UINT64) 0x1234567887654321);
|
||||
VmContext.StackRetAddr = (UINT64) VmContext.R[0];
|
||||
|
||||
//
|
||||
// Begin executing the EBC code
|
||||
//
|
||||
EbcExecute (&VmContext);
|
||||
|
||||
//
|
||||
// Return the value in R[7] unless there was an error
|
||||
//
|
||||
ReturnEBCStack(StackIndex);
|
||||
return (UINT64) VmContext.R[7];
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
EbcCreateThunks (
|
||||
IN EFI_HANDLE ImageHandle,
|
||||
IN VOID *EbcEntryPoint,
|
||||
OUT VOID **Thunk,
|
||||
IN UINT32 Flags
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Create thunks for an EBC image entry point, or an EBC protocol service.
|
||||
|
||||
Arguments:
|
||||
|
||||
ImageHandle - Image handle for the EBC image. If not null, then we're
|
||||
creating a thunk for an image entry point.
|
||||
EbcEntryPoint - Address of the EBC code that the thunk is to call
|
||||
Thunk - Returned thunk we create here
|
||||
Flags - Flags indicating options for creating the thunk
|
||||
|
||||
Returns:
|
||||
|
||||
Standard EFI status.
|
||||
|
||||
--*/
|
||||
{
|
||||
UINT8 *Ptr;
|
||||
UINT8 *ThunkBase;
|
||||
UINT64 Addr;
|
||||
UINT64 Code[3]; // Code in a bundle
|
||||
UINT64 RegNum; // register number for MOVL
|
||||
UINT64 I; // bits of MOVL immediate data
|
||||
UINT64 Ic; // bits of MOVL immediate data
|
||||
UINT64 Imm5c; // bits of MOVL immediate data
|
||||
UINT64 Imm9d; // bits of MOVL immediate data
|
||||
UINT64 Imm7b; // bits of MOVL immediate data
|
||||
UINT64 Br; // branch register for loading and jumping
|
||||
UINT64 *Data64Ptr;
|
||||
UINT32 ThunkSize;
|
||||
UINT32 Size;
|
||||
|
||||
//
|
||||
// Check alignment of pointer to EBC code, which must always be aligned
|
||||
// on a 2-byte boundary.
|
||||
//
|
||||
if ((UINT32) (UINTN) EbcEntryPoint & 0x01) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
//
|
||||
// Allocate memory for the thunk. Make the (most likely incorrect) assumption
|
||||
// that the returned buffer is not aligned, so round up to the next
|
||||
// alignment size.
|
||||
//
|
||||
Size = EBC_THUNK_SIZE + EBC_THUNK_ALIGNMENT - 1;
|
||||
ThunkSize = Size;
|
||||
Ptr = AllocatePool (Size);
|
||||
|
||||
if (Ptr == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
//
|
||||
// Save the start address of the buffer.
|
||||
//
|
||||
ThunkBase = Ptr;
|
||||
|
||||
//
|
||||
// Make sure it's aligned for code execution. If not, then
|
||||
// round up.
|
||||
//
|
||||
if ((UINT32) (UINTN) Ptr & (EBC_THUNK_ALIGNMENT - 1)) {
|
||||
Ptr = (UINT8 *) (((UINTN) Ptr + (EBC_THUNK_ALIGNMENT - 1)) &~ (UINT64) (EBC_THUNK_ALIGNMENT - 1));
|
||||
}
|
||||
//
|
||||
// Return the pointer to the thunk to the caller to user as the
|
||||
// image entry point.
|
||||
//
|
||||
*Thunk = (VOID *) Ptr;
|
||||
|
||||
//
|
||||
// Clear out the thunk entry
|
||||
// ZeroMem(Ptr, Size);
|
||||
//
|
||||
// For IPF, when you do a call via a function pointer, the function pointer
|
||||
// actually points to a function descriptor which consists of a 64-bit
|
||||
// address of the function, followed by a 64-bit gp for the function being
|
||||
// called. See the the Software Conventions and Runtime Architecture Guide
|
||||
// for details.
|
||||
// So first off in our thunk, create a descriptor for our actual thunk code.
|
||||
// This means we need to create a pointer to the thunk code (which follows
|
||||
// the descriptor we're going to create), followed by the gp of the Vm
|
||||
// interpret function we're going to eventually execute.
|
||||
//
|
||||
Data64Ptr = (UINT64 *) Ptr;
|
||||
|
||||
//
|
||||
// Write the function's entry point (which is our thunk code that follows
|
||||
// this descriptor we're creating).
|
||||
//
|
||||
*Data64Ptr = (UINT64) (Data64Ptr + 2);
|
||||
//
|
||||
// Get the gp from the descriptor for EbcInterpret and stuff it in our thunk
|
||||
// descriptor.
|
||||
//
|
||||
*(Data64Ptr + 1) = *(UINT64 *) ((UINT64 *) (UINTN) EbcInterpret + 1);
|
||||
//
|
||||
// Advance our thunk data pointer past the descriptor. Since the
|
||||
// descriptor consists of 16 bytes, the pointer is still aligned for
|
||||
// IPF code execution (on 16-byte boundary).
|
||||
//
|
||||
Ptr += sizeof (UINT64) * 2;
|
||||
|
||||
//
|
||||
// *************************** MAGIC BUNDLE ********************************
|
||||
//
|
||||
// Write magic code bundle for: movl r8 = 0xca112ebcca112ebc to help the VM
|
||||
// to recognize it is a thunk.
|
||||
//
|
||||
Addr = (UINT64) 0xCA112EBCCA112EBC;
|
||||
|
||||
//
|
||||
// Now generate the code bytes. First is nop.m 0x0
|
||||
//
|
||||
Code[0] = OPCODE_NOP;
|
||||
|
||||
//
|
||||
// Next is simply Addr[62:22] (41 bits) of the address
|
||||
//
|
||||
Code[1] = RShiftU64 (Addr, 22) & 0x1ffffffffff;
|
||||
|
||||
//
|
||||
// Extract bits from the address for insertion into the instruction
|
||||
// i = Addr[63:63]
|
||||
//
|
||||
I = RShiftU64 (Addr, 63) & 0x01;
|
||||
//
|
||||
// ic = Addr[21:21]
|
||||
//
|
||||
Ic = RShiftU64 (Addr, 21) & 0x01;
|
||||
//
|
||||
// imm5c = Addr[20:16] for 5 bits
|
||||
//
|
||||
Imm5c = RShiftU64 (Addr, 16) & 0x1F;
|
||||
//
|
||||
// imm9d = Addr[15:7] for 9 bits
|
||||
//
|
||||
Imm9d = RShiftU64 (Addr, 7) & 0x1FF;
|
||||
//
|
||||
// imm7b = Addr[6:0] for 7 bits
|
||||
//
|
||||
Imm7b = Addr & 0x7F;
|
||||
|
||||
//
|
||||
// The EBC entry point will be put into r8, so r8 can be used here
|
||||
// temporary. R8 is general register and is auto-serialized.
|
||||
//
|
||||
RegNum = 8;
|
||||
|
||||
//
|
||||
// Next is jumbled data, including opcode and rest of address
|
||||
//
|
||||
Code[2] = LShiftU64 (Imm7b, 13);
|
||||
Code[2] = Code[2] | LShiftU64 (0x00, 20); // vc
|
||||
Code[2] = Code[2] | LShiftU64 (Ic, 21);
|
||||
Code[2] = Code[2] | LShiftU64 (Imm5c, 22);
|
||||
Code[2] = Code[2] | LShiftU64 (Imm9d, 27);
|
||||
Code[2] = Code[2] | LShiftU64 (I, 36);
|
||||
Code[2] = Code[2] | LShiftU64 ((UINT64)MOVL_OPCODE, 37);
|
||||
Code[2] = Code[2] | LShiftU64 ((RegNum & 0x7F), 6);
|
||||
|
||||
WriteBundle ((VOID *) Ptr, 0x05, Code[0], Code[1], Code[2]);
|
||||
|
||||
//
|
||||
// *************************** FIRST BUNDLE ********************************
|
||||
//
|
||||
// Write code bundle for: movl r8 = EBC_ENTRY_POINT so we pass
|
||||
// the ebc entry point in to the interpreter function via a processor
|
||||
// register.
|
||||
// Note -- we could easily change this to pass in a pointer to a structure
|
||||
// that contained, among other things, the EBC image's entry point. But
|
||||
// for now pass it directly.
|
||||
//
|
||||
Ptr += 16;
|
||||
Addr = (UINT64) EbcEntryPoint;
|
||||
|
||||
//
|
||||
// Now generate the code bytes. First is nop.m 0x0
|
||||
//
|
||||
Code[0] = OPCODE_NOP;
|
||||
|
||||
//
|
||||
// Next is simply Addr[62:22] (41 bits) of the address
|
||||
//
|
||||
Code[1] = RShiftU64 (Addr, 22) & 0x1ffffffffff;
|
||||
|
||||
//
|
||||
// Extract bits from the address for insertion into the instruction
|
||||
// i = Addr[63:63]
|
||||
//
|
||||
I = RShiftU64 (Addr, 63) & 0x01;
|
||||
//
|
||||
// ic = Addr[21:21]
|
||||
//
|
||||
Ic = RShiftU64 (Addr, 21) & 0x01;
|
||||
//
|
||||
// imm5c = Addr[20:16] for 5 bits
|
||||
//
|
||||
Imm5c = RShiftU64 (Addr, 16) & 0x1F;
|
||||
//
|
||||
// imm9d = Addr[15:7] for 9 bits
|
||||
//
|
||||
Imm9d = RShiftU64 (Addr, 7) & 0x1FF;
|
||||
//
|
||||
// imm7b = Addr[6:0] for 7 bits
|
||||
//
|
||||
Imm7b = Addr & 0x7F;
|
||||
|
||||
//
|
||||
// Put the EBC entry point in r8, which is the location of the return value
|
||||
// for functions.
|
||||
//
|
||||
RegNum = 8;
|
||||
|
||||
//
|
||||
// Next is jumbled data, including opcode and rest of address
|
||||
//
|
||||
Code[2] = LShiftU64 (Imm7b, 13);
|
||||
Code[2] = Code[2] | LShiftU64 (0x00, 20); // vc
|
||||
Code[2] = Code[2] | LShiftU64 (Ic, 21);
|
||||
Code[2] = Code[2] | LShiftU64 (Imm5c, 22);
|
||||
Code[2] = Code[2] | LShiftU64 (Imm9d, 27);
|
||||
Code[2] = Code[2] | LShiftU64 (I, 36);
|
||||
Code[2] = Code[2] | LShiftU64 ((UINT64)MOVL_OPCODE, 37);
|
||||
Code[2] = Code[2] | LShiftU64 ((RegNum & 0x7F), 6);
|
||||
|
||||
WriteBundle ((VOID *) Ptr, 0x05, Code[0], Code[1], Code[2]);
|
||||
|
||||
//
|
||||
// *************************** NEXT BUNDLE *********************************
|
||||
//
|
||||
// Write code bundle for:
|
||||
// movl rx = offset_of(EbcInterpret|ExecuteEbcImageEntryPoint)
|
||||
//
|
||||
// Advance pointer to next bundle, then compute the offset from this bundle
|
||||
// to the address of the entry point of the interpreter.
|
||||
//
|
||||
Ptr += 16;
|
||||
if (Flags & FLAG_THUNK_ENTRY_POINT) {
|
||||
Addr = (UINT64) ExecuteEbcImageEntryPoint;
|
||||
} else {
|
||||
Addr = (UINT64) EbcInterpret;
|
||||
}
|
||||
//
|
||||
// Indirection on Itanium-based systems
|
||||
//
|
||||
Addr = *(UINT64 *) Addr;
|
||||
|
||||
//
|
||||
// Now write the code to load the offset into a register
|
||||
//
|
||||
Code[0] = OPCODE_NOP;
|
||||
|
||||
//
|
||||
// Next is simply Addr[62:22] (41 bits) of the address
|
||||
//
|
||||
Code[1] = RShiftU64 (Addr, 22) & 0x1ffffffffff;
|
||||
|
||||
//
|
||||
// Extract bits from the address for insertion into the instruction
|
||||
// i = Addr[63:63]
|
||||
//
|
||||
I = RShiftU64 (Addr, 63) & 0x01;
|
||||
//
|
||||
// ic = Addr[21:21]
|
||||
//
|
||||
Ic = RShiftU64 (Addr, 21) & 0x01;
|
||||
//
|
||||
// imm5c = Addr[20:16] for 5 bits
|
||||
//
|
||||
Imm5c = RShiftU64 (Addr, 16) & 0x1F;
|
||||
//
|
||||
// imm9d = Addr[15:7] for 9 bits
|
||||
//
|
||||
Imm9d = RShiftU64 (Addr, 7) & 0x1FF;
|
||||
//
|
||||
// imm7b = Addr[6:0] for 7 bits
|
||||
//
|
||||
Imm7b = Addr & 0x7F;
|
||||
|
||||
//
|
||||
// Put it in r31, a scratch register
|
||||
//
|
||||
RegNum = 31;
|
||||
|
||||
//
|
||||
// Next is jumbled data, including opcode and rest of address
|
||||
//
|
||||
Code[2] = LShiftU64(Imm7b, 13);
|
||||
Code[2] = Code[2] | LShiftU64 (0x00, 20); // vc
|
||||
Code[2] = Code[2] | LShiftU64 (Ic, 21);
|
||||
Code[2] = Code[2] | LShiftU64 (Imm5c, 22);
|
||||
Code[2] = Code[2] | LShiftU64 (Imm9d, 27);
|
||||
Code[2] = Code[2] | LShiftU64 (I, 36);
|
||||
Code[2] = Code[2] | LShiftU64 ((UINT64)MOVL_OPCODE, 37);
|
||||
Code[2] = Code[2] | LShiftU64 ((RegNum & 0x7F), 6);
|
||||
|
||||
WriteBundle ((VOID *) Ptr, 0x05, Code[0], Code[1], Code[2]);
|
||||
|
||||
//
|
||||
// *************************** NEXT BUNDLE *********************************
|
||||
//
|
||||
// Load branch register with EbcInterpret() function offset from the bundle
|
||||
// address: mov b6 = RegNum
|
||||
//
|
||||
// See volume 3 page 4-29 of the Arch. Software Developer's Manual.
|
||||
//
|
||||
// Advance pointer to next bundle
|
||||
//
|
||||
Ptr += 16;
|
||||
Code[0] = OPCODE_NOP;
|
||||
Code[1] = OPCODE_NOP;
|
||||
Code[2] = OPCODE_MOV_BX_RX;
|
||||
|
||||
//
|
||||
// Pick a branch register to use. Then fill in the bits for the branch
|
||||
// register and user register (same user register as previous bundle).
|
||||
//
|
||||
Br = 6;
|
||||
Code[2] |= LShiftU64 (Br, 6);
|
||||
Code[2] |= LShiftU64 (RegNum, 13);
|
||||
WriteBundle ((VOID *) Ptr, 0x0d, Code[0], Code[1], Code[2]);
|
||||
|
||||
//
|
||||
// *************************** NEXT BUNDLE *********************************
|
||||
//
|
||||
// Now do the branch: (p0) br.cond.sptk.few b6
|
||||
//
|
||||
// Advance pointer to next bundle.
|
||||
// Fill in the bits for the branch register (same reg as previous bundle)
|
||||
//
|
||||
Ptr += 16;
|
||||
Code[0] = OPCODE_NOP;
|
||||
Code[1] = OPCODE_NOP;
|
||||
Code[2] = OPCODE_BR_COND_SPTK_FEW;
|
||||
Code[2] |= LShiftU64 (Br, 13);
|
||||
WriteBundle ((VOID *) Ptr, 0x1d, Code[0], Code[1], Code[2]);
|
||||
|
||||
//
|
||||
// Add the thunk to our list of allocated thunks so we can do some cleanup
|
||||
// when the image is unloaded. Do this last since the Add function flushes
|
||||
// the instruction cache for us.
|
||||
//
|
||||
EbcAddImageThunk (ImageHandle, (VOID *) ThunkBase, ThunkSize);
|
||||
|
||||
//
|
||||
// Done
|
||||
//
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
WriteBundle (
|
||||
IN VOID *MemPtr,
|
||||
IN UINT8 Template,
|
||||
IN UINT64 Slot0,
|
||||
IN UINT64 Slot1,
|
||||
IN UINT64 Slot2
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Given raw bytes of Itanium based code, format them into a bundle and
|
||||
write them out.
|
||||
|
||||
Arguments:
|
||||
|
||||
MemPtr - pointer to memory location to write the bundles to
|
||||
Template - 5-bit template
|
||||
Slot0-2 - instruction slot data for the bundle
|
||||
|
||||
Returns:
|
||||
|
||||
EFI_INVALID_PARAMETER - Pointer is not aligned
|
||||
- No more than 5 bits in template
|
||||
- More than 41 bits used in code
|
||||
EFI_SUCCESS - All data is written.
|
||||
|
||||
--*/
|
||||
{
|
||||
UINT8 *BPtr;
|
||||
UINT32 Index;
|
||||
UINT64 Low64;
|
||||
UINT64 High64;
|
||||
|
||||
//
|
||||
// Verify pointer is aligned
|
||||
//
|
||||
if ((UINT64) MemPtr & 0xF) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
//
|
||||
// Verify no more than 5 bits in template
|
||||
//
|
||||
if (Template &~0x1F) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
//
|
||||
// Verify max of 41 bits used in code
|
||||
//
|
||||
if ((Slot0 | Slot1 | Slot2) &~0x1ffffffffff) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
Low64 = LShiftU64 (Slot1, 46);
|
||||
Low64 = Low64 | LShiftU64 (Slot0, 5) | Template;
|
||||
|
||||
High64 = RShiftU64 (Slot1, 18);
|
||||
High64 = High64 | LShiftU64 (Slot2, 23);
|
||||
|
||||
//
|
||||
// Now write it all out
|
||||
//
|
||||
BPtr = (UINT8 *) MemPtr;
|
||||
for (Index = 0; Index < 8; Index++) {
|
||||
*BPtr = (UINT8) Low64;
|
||||
Low64 = RShiftU64 (Low64, 8);
|
||||
BPtr++;
|
||||
}
|
||||
|
||||
for (Index = 0; Index < 8; Index++) {
|
||||
*BPtr = (UINT8) High64;
|
||||
High64 = RShiftU64 (High64, 8);
|
||||
BPtr++;
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
VOID
|
||||
EbcLLCALLEX (
|
||||
IN VM_CONTEXT *VmPtr,
|
||||
IN UINTN FuncAddr,
|
||||
IN UINTN NewStackPointer,
|
||||
IN VOID *FramePtr,
|
||||
IN UINT8 Size
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
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.
|
||||
|
||||
Arguments:
|
||||
|
||||
VmPtr - Pointer to a VM context.
|
||||
FuncAddr - Callee's address
|
||||
NewStackPointer - New stack pointer after the call
|
||||
FramePtr - New frame pointer after the call
|
||||
Size - The size of call instruction
|
||||
|
||||
Returns:
|
||||
|
||||
None.
|
||||
|
||||
--*/
|
||||
{
|
||||
UINTN IsThunk;
|
||||
UINTN TargetEbcAddr;
|
||||
UINTN CodeOne18;
|
||||
UINTN CodeOne23;
|
||||
UINTN CodeTwoI;
|
||||
UINTN CodeTwoIc;
|
||||
UINTN CodeTwo7b;
|
||||
UINTN CodeTwo5c;
|
||||
UINTN CodeTwo9d;
|
||||
UINTN CalleeAddr;
|
||||
|
||||
IsThunk = 1;
|
||||
TargetEbcAddr = 0;
|
||||
|
||||
//
|
||||
// FuncAddr points to the descriptor of the target instructions.
|
||||
//
|
||||
CalleeAddr = *((UINT64 *)FuncAddr);
|
||||
|
||||
//
|
||||
// Processor specific code to check whether the callee is a thunk to EBC.
|
||||
//
|
||||
if (*((UINT64 *)CalleeAddr) != 0xBCCA000100000005) {
|
||||
IsThunk = 0;
|
||||
goto Action;
|
||||
}
|
||||
if (*((UINT64 *)CalleeAddr + 1) != 0x697623C1004A112E) {
|
||||
IsThunk = 0;
|
||||
goto Action;
|
||||
}
|
||||
|
||||
CodeOne18 = RShiftU64 (*((UINT64 *)CalleeAddr + 2), 46) & 0x3FFFF;
|
||||
CodeOne23 = (*((UINT64 *)CalleeAddr + 3)) & 0x7FFFFF;
|
||||
CodeTwoI = RShiftU64 (*((UINT64 *)CalleeAddr + 3), 59) & 0x1;
|
||||
CodeTwoIc = RShiftU64 (*((UINT64 *)CalleeAddr + 3), 44) & 0x1;
|
||||
CodeTwo7b = RShiftU64 (*((UINT64 *)CalleeAddr + 3), 36) & 0x7F;
|
||||
CodeTwo5c = RShiftU64 (*((UINT64 *)CalleeAddr + 3), 45) & 0x1F;
|
||||
CodeTwo9d = RShiftU64 (*((UINT64 *)CalleeAddr + 3), 50) & 0x1FF;
|
||||
|
||||
TargetEbcAddr = CodeTwo7b;
|
||||
TargetEbcAddr = TargetEbcAddr | LShiftU64 (CodeTwo9d, 7);
|
||||
TargetEbcAddr = TargetEbcAddr | LShiftU64 (CodeTwo5c, 16);
|
||||
TargetEbcAddr = TargetEbcAddr | LShiftU64 (CodeTwoIc, 21);
|
||||
TargetEbcAddr = TargetEbcAddr | LShiftU64 (CodeOne18, 22);
|
||||
TargetEbcAddr = TargetEbcAddr | LShiftU64 (CodeOne23, 40);
|
||||
TargetEbcAddr = TargetEbcAddr | LShiftU64 (CodeTwoI, 63);
|
||||
|
||||
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->R[0] -= 8;
|
||||
VmWriteMemN (VmPtr, (UINTN) VmPtr->R[0], (UINTN) FramePtr);
|
||||
VmPtr->FramePtr = (VOID *) (UINTN) VmPtr->R[0];
|
||||
VmPtr->R[0] -= 8;
|
||||
VmWriteMem64 (VmPtr, (UINTN) VmPtr->R[0], (UINT64) (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->R[7] = EbcLLGetReturnValue ();
|
||||
VmPtr->Ip += Size;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/*++
|
||||
|
||||
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:
|
||||
|
||||
EbcSupport.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Definition of EBC Support function
|
||||
|
||||
Revision History
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef _IPF_EBC_SUPPORT_H_
|
||||
#define _IPF_EBC_SUPPORT_H_
|
||||
|
||||
#define VM_STACK_SIZE (1024 * 32)
|
||||
|
||||
#define EBC_THUNK_SIZE 128
|
||||
#define STACK_REMAIN_SIZE (1024 * 4)
|
||||
|
||||
//
|
||||
// For code execution, thunks must be aligned on 16-byte boundary
|
||||
//
|
||||
#define EBC_THUNK_ALIGNMENT 16
|
||||
|
||||
//
|
||||
// Opcodes for IPF instructions. We'll need to hand-create thunk code (stuffing
|
||||
// bits) to insert a jump to the interpreter.
|
||||
//
|
||||
#define OPCODE_NOP (UINT64) 0x00008000000
|
||||
#define OPCODE_BR_COND_SPTK_FEW (UINT64) 0x00100000000
|
||||
#define OPCODE_MOV_BX_RX (UINT64) 0x00E00100000
|
||||
|
||||
//
|
||||
// Opcode for MOVL instruction
|
||||
//
|
||||
#define MOVL_OPCODE 0x06
|
||||
|
||||
VOID
|
||||
EbcAsmLLCALLEX (
|
||||
IN UINTN CallAddr,
|
||||
IN UINTN EbcSp
|
||||
);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,144 @@
|
|||
#****************************************************************************
|
||||
#*
|
||||
#* 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.
|
||||
#*
|
||||
#****************************************************************************
|
||||
#****************************************************************************
|
||||
# REV 1.0
|
||||
#****************************************************************************
|
||||
#
|
||||
# Rev Date Description
|
||||
# --- -------- ------------------------------------------------------------
|
||||
# 1.0 05/09/12 Initial creation of file.
|
||||
#
|
||||
#****************************************************************************
|
||||
|
||||
#* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
# This code provides low level routines that support the Virtual Machine
|
||||
# for option ROMs.
|
||||
#* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Equate files needed.
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
##GenericPostSegment SEGMENT USE16
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
#****************************************************************************
|
||||
# EbcLLCALLEX
|
||||
#
|
||||
# This function is called to execute an EBC CALLEX instruction.
|
||||
# This instruction requires that we thunk out to external native
|
||||
# code. For x64, we switch stacks, copy the arguments to the stack
|
||||
# and jump to the specified function.
|
||||
# On return, we restore the stack pointer to its original location.
|
||||
#
|
||||
# Destroys no working registers.
|
||||
#****************************************************************************
|
||||
.global _CopyMem;
|
||||
|
||||
# VOID EbcLLCALLEXNative(UINTN FuncAddr, UINTN NewStackPointer, VOID *FramePtr)
|
||||
.global _EbcLLCALLEXNative;
|
||||
_EbcLLCALLEXNative:
|
||||
push %rbp
|
||||
push %rbx
|
||||
mov %rsp, %rbp
|
||||
# Function prolog
|
||||
|
||||
# Copy FuncAddr to a preserved register.
|
||||
mov %rcx, %rbx
|
||||
|
||||
# Set stack pointer to new value
|
||||
sub %r8, %rdx
|
||||
sub %rsp, %r8
|
||||
mov %rsp, %rcx
|
||||
sub %rsp, 0x20
|
||||
call _CopyMem
|
||||
add %rsp, 0x20
|
||||
|
||||
# Considering the worst case, load 4 potiential arguments
|
||||
# into registers.
|
||||
mov (%rsp), %rcx
|
||||
mov 8(%rsp), %rdx
|
||||
mov 10(%rsp), %r8
|
||||
mov 18(%rsp), %r9
|
||||
|
||||
# Now call the external routine
|
||||
call *%rbx
|
||||
|
||||
# Function epilog
|
||||
mov %rbp, %rsp
|
||||
pop %rbx
|
||||
pop %rbp
|
||||
ret
|
||||
|
||||
|
||||
# UINTN EbcLLGetEbcEntryPoint(VOID);
|
||||
# Routine Description:
|
||||
# The VM thunk code stuffs an EBC entry point into a processor
|
||||
# register. Since we can't use inline assembly to get it from
|
||||
# the interpreter C code, stuff it into the return value
|
||||
# register and return.
|
||||
#
|
||||
# Arguments:
|
||||
# None.
|
||||
#
|
||||
# Returns:
|
||||
# The contents of the register in which the entry point is passed.
|
||||
#
|
||||
.global _EbcLLGetEbcEntryPoint;
|
||||
_EbcLLGetEbcEntryPoint:
|
||||
ret
|
||||
|
||||
#/*++
|
||||
#
|
||||
#Routine Description:
|
||||
#
|
||||
# Return the caller's value of the stack pointer.
|
||||
#
|
||||
#Arguments:
|
||||
#
|
||||
# None.
|
||||
#
|
||||
#Returns:
|
||||
#
|
||||
# The current value of the stack pointer for the caller. We
|
||||
# adjust it by 4 here because when they called us, the return address
|
||||
# is put on the stack, thereby lowering it by 4 bytes.
|
||||
#
|
||||
#--*/
|
||||
|
||||
# UINTN EbcLLGetStackPointer()
|
||||
.global _EbcLLGetStackPointer;
|
||||
_EbcLLGetStackPointer:
|
||||
mov %rsp, %rax
|
||||
# Stack adjusted by this much when we were called,
|
||||
# For this function, it's 4.
|
||||
add $4, %rax
|
||||
ret
|
||||
|
||||
.global _EbcLLGetReturnValue;
|
||||
_EbcLLGetReturnValue:
|
||||
# UINT64 EbcLLGetReturnValue(VOID);
|
||||
# Routine Description:
|
||||
# When EBC calls native, on return the VM has to stuff the return
|
||||
# value into a VM register. It's assumed here that the value is still
|
||||
# in the register, so simply return and the caller should get the
|
||||
# return result properly.
|
||||
#
|
||||
# Arguments:
|
||||
# None.
|
||||
#
|
||||
# Returns:
|
||||
# The unmodified value returned by the native code.
|
||||
#
|
||||
ret
|
|
@ -0,0 +1,154 @@
|
|||
page ,132
|
||||
title VM ASSEMBLY LANGUAGE ROUTINES
|
||||
;****************************************************************************
|
||||
;*
|
||||
;* 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.
|
||||
;*
|
||||
;****************************************************************************
|
||||
;****************************************************************************
|
||||
; REV 1.0
|
||||
;****************************************************************************
|
||||
;
|
||||
; Rev Date Description
|
||||
; --- -------- ------------------------------------------------------------
|
||||
; 1.0 05/09/12 Initial creation of file.
|
||||
;
|
||||
;****************************************************************************
|
||||
|
||||
;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
; This code provides low level routines that support the Virtual Machine
|
||||
; for option ROMs.
|
||||
;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
|
||||
;---------------------------------------------------------------------------
|
||||
; Equate files needed.
|
||||
;---------------------------------------------------------------------------
|
||||
|
||||
text SEGMENT
|
||||
|
||||
;---------------------------------------------------------------------------
|
||||
;;GenericPostSegment SEGMENT USE16
|
||||
;---------------------------------------------------------------------------
|
||||
|
||||
;****************************************************************************
|
||||
; EbcLLCALLEX
|
||||
;
|
||||
; This function is called to execute an EBC CALLEX instruction.
|
||||
; This instruction requires that we thunk out to external native
|
||||
; code. For x64, we switch stacks, copy the arguments to the stack
|
||||
; and jump to the specified function.
|
||||
; On return, we restore the stack pointer to its original location.
|
||||
;
|
||||
; Destroys no working registers.
|
||||
;****************************************************************************
|
||||
; VOID EbcLLCALLEXNative(UINTN FuncAddr, UINTN NewStackPointer, VOID *FramePtr)
|
||||
|
||||
CopyMem PROTO Destination:PTR DWORD, Source:PTR DWORD, Count:DWORD
|
||||
|
||||
|
||||
EbcLLCALLEXNative PROC NEAR PUBLIC
|
||||
push rbp
|
||||
push rbx
|
||||
mov rbp, rsp
|
||||
; Function prolog
|
||||
|
||||
; Copy FuncAddr to a preserved register.
|
||||
mov rbx, rcx
|
||||
|
||||
; Set stack pointer to new value
|
||||
sub r8, rdx
|
||||
sub rsp, r8
|
||||
mov rcx, rsp
|
||||
sub rsp, 20h
|
||||
call CopyMem
|
||||
add rsp, 20h
|
||||
|
||||
; Considering the worst case, load 4 potiential arguments
|
||||
; into registers.
|
||||
mov rcx, qword ptr [rsp]
|
||||
mov rdx, qword ptr [rsp+8h]
|
||||
mov r8, qword ptr [rsp+10h]
|
||||
mov r9, qword ptr [rsp+18h]
|
||||
|
||||
; Now call the external routine
|
||||
call rbx
|
||||
|
||||
; Function epilog
|
||||
mov rsp, rbp
|
||||
pop rbx
|
||||
pop rbp
|
||||
ret
|
||||
EbcLLCALLEXNative ENDP
|
||||
|
||||
|
||||
; UINTN EbcLLGetEbcEntryPoint(VOID);
|
||||
; Routine Description:
|
||||
; The VM thunk code stuffs an EBC entry point into a processor
|
||||
; register. Since we can't use inline assembly to get it from
|
||||
; the interpreter C code, stuff it into the return value
|
||||
; register and return.
|
||||
;
|
||||
; Arguments:
|
||||
; None.
|
||||
;
|
||||
; Returns:
|
||||
; The contents of the register in which the entry point is passed.
|
||||
;
|
||||
EbcLLGetEbcEntryPoint PROC NEAR PUBLIC
|
||||
ret
|
||||
EbcLLGetEbcEntryPoint ENDP
|
||||
|
||||
;/*++
|
||||
;
|
||||
;Routine Description:
|
||||
;
|
||||
; Return the caller's value of the stack pointer.
|
||||
;
|
||||
;Arguments:
|
||||
;
|
||||
; None.
|
||||
;
|
||||
;Returns:
|
||||
;
|
||||
; The current value of the stack pointer for the caller. We
|
||||
; adjust it by 4 here because when they called us, the return address
|
||||
; is put on the stack, thereby lowering it by 4 bytes.
|
||||
;
|
||||
;--*/
|
||||
|
||||
; UINTN EbcLLGetStackPointer()
|
||||
EbcLLGetStackPointer PROC NEAR PUBLIC
|
||||
mov rax, rsp ; get current stack pointer
|
||||
; Stack adjusted by this much when we were called,
|
||||
; For this function, it's 4.
|
||||
add rax, 4
|
||||
ret
|
||||
EbcLLGetStackPointer ENDP
|
||||
|
||||
; UINT64 EbcLLGetReturnValue(VOID);
|
||||
; Routine Description:
|
||||
; When EBC calls native, on return the VM has to stuff the return
|
||||
; value into a VM register. It's assumed here that the value is still
|
||||
; in the register, so simply return and the caller should get the
|
||||
; return result properly.
|
||||
;
|
||||
; Arguments:
|
||||
; None.
|
||||
;
|
||||
; Returns:
|
||||
; The unmodified value returned by the native code.
|
||||
;
|
||||
EbcLLGetReturnValue PROC NEAR PUBLIC
|
||||
ret
|
||||
EbcLLGetReturnValue ENDP
|
||||
|
||||
text ENDS
|
||||
END
|
||||
|
|
@ -0,0 +1,619 @@
|
|||
/*++
|
||||
|
||||
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:
|
||||
|
||||
EbcSupport.c
|
||||
|
||||
Abstract:
|
||||
|
||||
This module contains EBC support routines that are customized based on
|
||||
the target x64 processor.
|
||||
|
||||
--*/
|
||||
|
||||
#include "EbcInt.h"
|
||||
#include "EbcExecute.h"
|
||||
|
||||
//
|
||||
// NOTE: This is the stack size allocated for the interpreter
|
||||
// when it executes an EBC image. The requirements can change
|
||||
// based on whether or not a debugger is present, and other
|
||||
// platform-specific configurations.
|
||||
//
|
||||
#define VM_STACK_SIZE (1024 * 8)
|
||||
#define EBC_THUNK_SIZE 64
|
||||
|
||||
#define STACK_REMAIN_SIZE (1024 * 4)
|
||||
|
||||
STATIC
|
||||
VOID
|
||||
PushU64 (
|
||||
VM_CONTEXT *VmPtr,
|
||||
UINT64 Arg
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Push a 64 bit unsigned value to the VM stack.
|
||||
|
||||
Arguments:
|
||||
|
||||
VmPtr - The pointer to current VM context.
|
||||
Arg - The value to be pushed
|
||||
|
||||
Returns:
|
||||
|
||||
VOID
|
||||
|
||||
--*/
|
||||
{
|
||||
//
|
||||
// Advance the VM stack down, and then copy the argument to the stack.
|
||||
// Hope it's aligned.
|
||||
//
|
||||
VmPtr->R[0] -= sizeof (UINT64);
|
||||
*(UINT64 *) VmPtr->R[0] = Arg;
|
||||
return;
|
||||
}
|
||||
|
||||
STATIC
|
||||
UINT64
|
||||
EbcInterpret (
|
||||
UINTN Arg1,
|
||||
UINTN Arg2,
|
||||
UINTN Arg3,
|
||||
UINTN Arg4,
|
||||
UINTN Arg5,
|
||||
UINTN Arg6,
|
||||
UINTN Arg7,
|
||||
UINTN Arg8,
|
||||
UINTN Arg9,
|
||||
UINTN Arg10,
|
||||
UINTN Arg11,
|
||||
UINTN Arg12,
|
||||
UINTN Arg13,
|
||||
UINTN Arg14,
|
||||
UINTN Arg15,
|
||||
UINTN Arg16
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Begin executing an EBC image. The address of the entry point is passed
|
||||
in via a processor register, so we'll need to make a call to get the
|
||||
value.
|
||||
|
||||
Arguments:
|
||||
|
||||
This is a thunk function. Microsoft x64 compiler only provide fast_call
|
||||
calling convention, so the first four arguments are passed by rcx, rdx,
|
||||
r8, and r9, while other arguments are passed in stack.
|
||||
|
||||
Returns:
|
||||
|
||||
The value returned by the EBC application we're going to run.
|
||||
|
||||
--*/
|
||||
{
|
||||
//
|
||||
// Create a new VM context on the stack
|
||||
//
|
||||
VM_CONTEXT VmContext;
|
||||
UINTN Addr;
|
||||
EFI_STATUS Status;
|
||||
UINTN StackIndex;
|
||||
|
||||
//
|
||||
// Get the EBC entry point from the processor register.
|
||||
// Don't call any function before getting the EBC entry
|
||||
// point because this will collab the return register.
|
||||
//
|
||||
Addr = EbcLLGetEbcEntryPoint ();
|
||||
|
||||
//
|
||||
// Now clear out our context
|
||||
//
|
||||
ZeroMem ((VOID *) &VmContext, sizeof (VM_CONTEXT));
|
||||
|
||||
//
|
||||
// Set the VM instruction pointer to the correct location in memory.
|
||||
//
|
||||
VmContext.Ip = (VMIP) Addr;
|
||||
|
||||
//
|
||||
// Initialize the stack pointer for the EBC. Get the current system stack
|
||||
// pointer and adjust it down by the max needed for the interpreter.
|
||||
//
|
||||
Addr = EbcLLGetStackPointer ();
|
||||
|
||||
//
|
||||
// Adjust the VM's stack pointer down.
|
||||
//
|
||||
|
||||
Status = GetEBCStack((EFI_HANDLE)(UINTN)-1, &VmContext.StackPool, &StackIndex);
|
||||
if (EFI_ERROR(Status)) {
|
||||
return Status;
|
||||
}
|
||||
VmContext.StackTop = (UINT8*)VmContext.StackPool + (STACK_REMAIN_SIZE);
|
||||
VmContext.R[0] = (UINT64) ((UINT8*)VmContext.StackPool + STACK_POOL_SIZE);
|
||||
VmContext.HighStackBottom = (UINTN) VmContext.R[0];
|
||||
VmContext.R[0] -= sizeof (UINTN);
|
||||
|
||||
//
|
||||
// Align the stack on a natural boundary.
|
||||
//
|
||||
VmContext.R[0] &= ~(sizeof (UINTN) - 1);
|
||||
|
||||
//
|
||||
// Put a magic value in the stack gap, then adjust down again.
|
||||
//
|
||||
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) VM_STACK_KEY_VALUE;
|
||||
VmContext.StackMagicPtr = (UINTN *) (UINTN) VmContext.R[0];
|
||||
|
||||
//
|
||||
// The stack upper to LowStackTop is belong to the VM.
|
||||
//
|
||||
VmContext.LowStackTop = (UINTN) VmContext.R[0];
|
||||
|
||||
//
|
||||
// For the worst case, assume there are 4 arguments passed in registers, store
|
||||
// them to VM's stack.
|
||||
//
|
||||
PushU64 (&VmContext, (UINT64) Arg16);
|
||||
PushU64 (&VmContext, (UINT64) Arg15);
|
||||
PushU64 (&VmContext, (UINT64) Arg14);
|
||||
PushU64 (&VmContext, (UINT64) Arg13);
|
||||
PushU64 (&VmContext, (UINT64) Arg12);
|
||||
PushU64 (&VmContext, (UINT64) Arg11);
|
||||
PushU64 (&VmContext, (UINT64) Arg10);
|
||||
PushU64 (&VmContext, (UINT64) Arg9);
|
||||
PushU64 (&VmContext, (UINT64) Arg8);
|
||||
PushU64 (&VmContext, (UINT64) Arg7);
|
||||
PushU64 (&VmContext, (UINT64) Arg6);
|
||||
PushU64 (&VmContext, (UINT64) Arg5);
|
||||
PushU64 (&VmContext, (UINT64) Arg4);
|
||||
PushU64 (&VmContext, (UINT64) Arg3);
|
||||
PushU64 (&VmContext, (UINT64) Arg2);
|
||||
PushU64 (&VmContext, (UINT64) Arg1);
|
||||
|
||||
//
|
||||
// Interpreter assumes 64-bit return address is pushed on the stack.
|
||||
// The x64 does not do this so pad the stack accordingly.
|
||||
//
|
||||
PushU64 (&VmContext, (UINT64) 0);
|
||||
PushU64 (&VmContext, (UINT64) 0x1234567887654321ULL);
|
||||
|
||||
//
|
||||
// For x64, this is where we say our return address is
|
||||
//
|
||||
VmContext.StackRetAddr = (UINT64) VmContext.R[0];
|
||||
|
||||
//
|
||||
// We need to keep track of where the EBC stack starts. This way, if the EBC
|
||||
// accesses any stack variables above its initial stack setting, then we know
|
||||
// it's accessing variables passed into it, which means the data is on the
|
||||
// VM's stack.
|
||||
// When we're called, on the stack (high to low) we have the parameters, the
|
||||
// return address, then the saved ebp. Save the pointer to the return address.
|
||||
// EBC code knows that's there, so should look above it for function parameters.
|
||||
// The offset is the size of locals (VMContext + Addr + saved ebp).
|
||||
// Note that the interpreter assumes there is a 16 bytes of return address on
|
||||
// the stack too, so adjust accordingly.
|
||||
// VmContext.HighStackBottom = (UINTN)(Addr + sizeof (VmContext) + sizeof (Addr));
|
||||
//
|
||||
|
||||
//
|
||||
// Begin executing the EBC code
|
||||
//
|
||||
EbcExecute (&VmContext);
|
||||
|
||||
//
|
||||
// Return the value in R[7] unless there was an error
|
||||
//
|
||||
ReturnEBCStack(StackIndex);
|
||||
return (UINT64) VmContext.R[7];
|
||||
}
|
||||
|
||||
STATIC
|
||||
UINT64
|
||||
ExecuteEbcImageEntryPoint (
|
||||
IN EFI_HANDLE ImageHandle,
|
||||
IN EFI_SYSTEM_TABLE *SystemTable
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Begin executing an EBC image. The address of the entry point is passed
|
||||
in via a processor register, so we'll need to make a call to get the
|
||||
value.
|
||||
|
||||
Arguments:
|
||||
|
||||
ImageHandle - image handle for the EBC application we're executing
|
||||
SystemTable - standard system table passed into an driver's entry point
|
||||
|
||||
Returns:
|
||||
|
||||
The value returned by the EBC application we're going to run.
|
||||
|
||||
--*/
|
||||
{
|
||||
//
|
||||
// Create a new VM context on the stack
|
||||
//
|
||||
VM_CONTEXT VmContext;
|
||||
UINTN Addr;
|
||||
EFI_STATUS Status;
|
||||
UINTN StackIndex;
|
||||
|
||||
//
|
||||
// Get the EBC entry point from the processor register. Make sure you don't
|
||||
// call any functions before this or you could mess up the register the
|
||||
// entry point is passed in.
|
||||
//
|
||||
Addr = EbcLLGetEbcEntryPoint ();
|
||||
|
||||
//
|
||||
// Now clear out our context
|
||||
//
|
||||
ZeroMem ((VOID *) &VmContext, sizeof (VM_CONTEXT));
|
||||
|
||||
//
|
||||
// Save the image handle so we can track the thunks created for this image
|
||||
//
|
||||
VmContext.ImageHandle = ImageHandle;
|
||||
VmContext.SystemTable = SystemTable;
|
||||
|
||||
//
|
||||
// Set the VM instruction pointer to the correct location in memory.
|
||||
//
|
||||
VmContext.Ip = (VMIP) Addr;
|
||||
|
||||
//
|
||||
// Initialize the stack pointer for the EBC. Get the current system stack
|
||||
// pointer and adjust it down by the max needed for the interpreter.
|
||||
//
|
||||
Addr = EbcLLGetStackPointer ();
|
||||
|
||||
Status = GetEBCStack(ImageHandle, &VmContext.StackPool, &StackIndex);
|
||||
if (EFI_ERROR(Status)) {
|
||||
return Status;
|
||||
}
|
||||
VmContext.StackTop = (UINT8*)VmContext.StackPool + (STACK_REMAIN_SIZE);
|
||||
VmContext.R[0] = (UINT64) ((UINT8*)VmContext.StackPool + STACK_POOL_SIZE);
|
||||
VmContext.HighStackBottom = (UINTN) VmContext.R[0];
|
||||
VmContext.R[0] -= sizeof (UINTN);
|
||||
|
||||
|
||||
//
|
||||
// Put a magic value in the stack gap, then adjust down again
|
||||
//
|
||||
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) VM_STACK_KEY_VALUE;
|
||||
VmContext.StackMagicPtr = (UINTN *) (UINTN) VmContext.R[0];
|
||||
|
||||
//
|
||||
// Align the stack on a natural boundary
|
||||
VmContext.R[0] &= ~(sizeof(UINTN) - 1);
|
||||
//
|
||||
VmContext.LowStackTop = (UINTN) VmContext.R[0];
|
||||
|
||||
//
|
||||
// Simply copy the image handle and system table onto the EBC stack.
|
||||
// Greatly simplifies things by not having to spill the args.
|
||||
//
|
||||
PushU64 (&VmContext, (UINT64) SystemTable);
|
||||
PushU64 (&VmContext, (UINT64) ImageHandle);
|
||||
|
||||
//
|
||||
// VM pushes 16-bytes for return address. Simulate that here.
|
||||
//
|
||||
PushU64 (&VmContext, (UINT64) 0);
|
||||
PushU64 (&VmContext, (UINT64) 0x1234567887654321ULL);
|
||||
|
||||
//
|
||||
// For x64, this is where we say our return address is
|
||||
//
|
||||
VmContext.StackRetAddr = (UINT64) VmContext.R[0];
|
||||
|
||||
//
|
||||
// Entry function needn't access high stack context, simply
|
||||
// put the stack pointer here.
|
||||
//
|
||||
|
||||
//
|
||||
// Begin executing the EBC code
|
||||
//
|
||||
EbcExecute (&VmContext);
|
||||
|
||||
//
|
||||
// Return the value in R[7] unless there was an error
|
||||
//
|
||||
ReturnEBCStack(StackIndex);
|
||||
return (UINT64) VmContext.R[7];
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
EbcCreateThunks (
|
||||
IN EFI_HANDLE ImageHandle,
|
||||
IN VOID *EbcEntryPoint,
|
||||
OUT VOID **Thunk,
|
||||
IN UINT32 Flags
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Create an IA32 thunk for the given EBC entry point.
|
||||
|
||||
Arguments:
|
||||
|
||||
ImageHandle - Handle of image for which this thunk is being created
|
||||
EbcEntryPoint - Address of the EBC code that the thunk is to call
|
||||
Thunk - Returned thunk we create here
|
||||
|
||||
Returns:
|
||||
|
||||
Standard EFI status.
|
||||
|
||||
--*/
|
||||
{
|
||||
UINT8 *Ptr;
|
||||
UINT8 *ThunkBase;
|
||||
UINT32 I;
|
||||
UINT64 Addr;
|
||||
INT32 Size;
|
||||
INT32 ThunkSize;
|
||||
|
||||
//
|
||||
// Check alignment of pointer to EBC code
|
||||
//
|
||||
if ((UINT32) (UINTN) EbcEntryPoint & 0x01) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
Size = EBC_THUNK_SIZE;
|
||||
ThunkSize = Size;
|
||||
|
||||
Ptr = AllocatePool (Size);
|
||||
|
||||
if (Ptr == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
//
|
||||
// Print(L"Allocate TH: 0x%X\n", (UINT32)Ptr);
|
||||
//
|
||||
// Save the start address so we can add a pointer to it to a list later.
|
||||
//
|
||||
ThunkBase = Ptr;
|
||||
|
||||
//
|
||||
// Give them the address of our buffer we're going to fix up
|
||||
//
|
||||
*Thunk = (VOID *) Ptr;
|
||||
|
||||
//
|
||||
// Add a magic code here to help the VM recognize the thunk..
|
||||
// mov rax, ca112ebccall2ebch => 48 B8 BC 2E 11 CA BC 2E 11 CA
|
||||
//
|
||||
*Ptr = 0x48;
|
||||
Ptr++;
|
||||
Size--;
|
||||
*Ptr = 0xB8;
|
||||
Ptr++;
|
||||
Size--;
|
||||
Addr = (UINT64) 0xCA112EBCCA112EBCULL;
|
||||
for (I = 0; I < sizeof (Addr); I++) {
|
||||
*Ptr = (UINT8) (UINTN) Addr;
|
||||
Addr >>= 8;
|
||||
Ptr++;
|
||||
Size--;
|
||||
}
|
||||
|
||||
//
|
||||
// Add code bytes to load up a processor register with the EBC entry point.
|
||||
// mov rax, 123456789abcdef0h => 48 B8 F0 DE BC 9A 78 56 34 12
|
||||
// The first 8 bytes of the thunk entry is the address of the EBC
|
||||
// entry point.
|
||||
//
|
||||
*Ptr = 0x48;
|
||||
Ptr++;
|
||||
Size--;
|
||||
*Ptr = 0xB8;
|
||||
Ptr++;
|
||||
Size--;
|
||||
Addr = (UINT64) EbcEntryPoint;
|
||||
for (I = 0; I < sizeof (Addr); I++) {
|
||||
*Ptr = (UINT8) (UINTN) Addr;
|
||||
Addr >>= 8;
|
||||
Ptr++;
|
||||
Size--;
|
||||
}
|
||||
|
||||
//
|
||||
// Stick in a load of ecx with the address of appropriate VM function.
|
||||
// Using r11 because it's a volatile register and won't be used in this
|
||||
// point.
|
||||
// mov r11 123456789abcdef0h => 49 BB F0 DE BC 9A 78 56 34 12
|
||||
//
|
||||
if (Flags & FLAG_THUNK_ENTRY_POINT) {
|
||||
Addr = (UINTN) ExecuteEbcImageEntryPoint;
|
||||
} else {
|
||||
Addr = (UINTN) EbcInterpret;
|
||||
}
|
||||
|
||||
//
|
||||
// mov r11 Addr => 0x49 0xBB
|
||||
//
|
||||
*Ptr = 0x49;
|
||||
Ptr++;
|
||||
Size--;
|
||||
*Ptr = 0xBB;
|
||||
Ptr++;
|
||||
Size--;
|
||||
for (I = 0; I < sizeof (Addr); I++) {
|
||||
*Ptr = (UINT8) Addr;
|
||||
Addr >>= 8;
|
||||
Ptr++;
|
||||
Size--;
|
||||
}
|
||||
//
|
||||
// Stick in jump opcode bytes for jmp r11 => 0x41 0xFF 0xE3
|
||||
//
|
||||
*Ptr = 0x41;
|
||||
Ptr++;
|
||||
Size--;
|
||||
*Ptr = 0xFF;
|
||||
Ptr++;
|
||||
Size--;
|
||||
*Ptr = 0xE3;
|
||||
Size--;
|
||||
|
||||
//
|
||||
// Double check that our defined size is ok (application error)
|
||||
//
|
||||
if (Size < 0) {
|
||||
ASSERT (FALSE);
|
||||
return EFI_BUFFER_TOO_SMALL;
|
||||
}
|
||||
//
|
||||
// Add the thunk to the list for this image. Do this last since the add
|
||||
// function flushes the cache for us.
|
||||
//
|
||||
EbcAddImageThunk (ImageHandle, (VOID *) ThunkBase, ThunkSize);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
VOID
|
||||
EbcLLCALLEX (
|
||||
IN VM_CONTEXT *VmPtr,
|
||||
IN UINTN FuncAddr,
|
||||
IN UINTN NewStackPointer,
|
||||
IN VOID *FramePtr,
|
||||
IN UINT8 Size
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
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.
|
||||
|
||||
Arguments:
|
||||
|
||||
VmPtr - Pointer to a VM context.
|
||||
FuncAddr - Callee's address
|
||||
NewStackPointer - New stack pointer after the call
|
||||
FramePtr - New frame pointer after the call
|
||||
Size - The size of call instruction
|
||||
|
||||
Returns:
|
||||
|
||||
None.
|
||||
|
||||
--*/
|
||||
{
|
||||
UINTN IsThunk;
|
||||
UINTN TargetEbcAddr;
|
||||
|
||||
IsThunk = 1;
|
||||
TargetEbcAddr = 0;
|
||||
|
||||
//
|
||||
// Processor specific code to check whether the callee is a thunk to EBC.
|
||||
//
|
||||
if (*((UINT8 *)FuncAddr) != 0x48) {
|
||||
IsThunk = 0;
|
||||
goto Action;
|
||||
}
|
||||
if (*((UINT8 *)FuncAddr + 1) != 0xB8) {
|
||||
IsThunk = 0;
|
||||
goto Action;
|
||||
}
|
||||
if (*((UINT8 *)FuncAddr + 2) != 0xBC) {
|
||||
IsThunk = 0;
|
||||
goto Action;
|
||||
}
|
||||
if (*((UINT8 *)FuncAddr + 3) != 0x2E) {
|
||||
IsThunk = 0;
|
||||
goto Action;
|
||||
}
|
||||
if (*((UINT8 *)FuncAddr + 4) != 0x11) {
|
||||
IsThunk = 0;
|
||||
goto Action;
|
||||
}
|
||||
if (*((UINT8 *)FuncAddr + 5) != 0xCA) {
|
||||
IsThunk = 0;
|
||||
goto Action;
|
||||
}
|
||||
if (*((UINT8 *)FuncAddr + 6) != 0xBC) {
|
||||
IsThunk = 0;
|
||||
goto Action;
|
||||
}
|
||||
if (*((UINT8 *)FuncAddr + 7) != 0x2E) {
|
||||
IsThunk = 0;
|
||||
goto Action;
|
||||
}
|
||||
if (*((UINT8 *)FuncAddr + 8) != 0x11) {
|
||||
IsThunk = 0;
|
||||
goto Action;
|
||||
}
|
||||
if (*((UINT8 *)FuncAddr + 9) != 0xCA) {
|
||||
IsThunk = 0;
|
||||
goto Action;
|
||||
}
|
||||
if (*((UINT8 *)FuncAddr + 10) != 0x48) {
|
||||
IsThunk = 0;
|
||||
goto Action;
|
||||
}
|
||||
if (*((UINT8 *)FuncAddr + 11) != 0xB8) {
|
||||
IsThunk = 0;
|
||||
goto Action;
|
||||
}
|
||||
|
||||
CopyMem (&TargetEbcAddr, (UINT8 *)FuncAddr + 12, 8);
|
||||
|
||||
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->R[0] -= 8;
|
||||
VmWriteMemN (VmPtr, (UINTN) VmPtr->R[0], (UINTN) FramePtr);
|
||||
VmPtr->FramePtr = (VOID *) (UINTN) VmPtr->R[0];
|
||||
VmPtr->R[0] -= 8;
|
||||
VmWriteMem64 (VmPtr, (UINTN) VmPtr->R[0], (UINT64) (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->R[7] = EbcLLGetReturnValue ();
|
||||
VmPtr->Ip += Size;
|
||||
}
|
||||
}
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010005
|
||||
BASE_NAME = Crc32SectionExtract
|
||||
BASE_NAME = Crc32SectionExtractDxe
|
||||
FILE_GUID = 51C9F40C-5243-4473-B265-B3C8FFAFF9FA
|
||||
MODULE_TYPE = DXE_DRIVER
|
||||
VERSION_STRING = 1.0
|
|
@ -1,27 +0,0 @@
|
|||
/*++
|
||||
|
||||
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:
|
||||
|
||||
FtwLite.dxs
|
||||
|
||||
Abstract:
|
||||
|
||||
Dependency expression source file.
|
||||
|
||||
--*/
|
||||
#include <DxeDepex.h>
|
||||
|
||||
|
||||
DEPENDENCY_START
|
||||
EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL_GUID AND EFI_ALTERNATE_FV_BLOCK_GUID
|
||||
DEPENDENCY_END
|
|
@ -1,26 +0,0 @@
|
|||
/*++
|
||||
|
||||
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:
|
||||
|
||||
Crc32SectionExtraction.dxs
|
||||
|
||||
Abstract:
|
||||
|
||||
Dependency expression file.
|
||||
|
||||
--*/
|
||||
#include "DxeDepex.h"
|
||||
|
||||
DEPENDENCY_START
|
||||
EFI_RUNTIME_ARCH_PROTOCOL_GUID
|
||||
DEPENDENCY_END
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
/*++
|
||||
|
||||
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:
|
||||
|
||||
NullMemoryTest.dxs
|
||||
|
||||
Abstract:
|
||||
|
||||
Dependency expression source file.
|
||||
|
||||
--*/
|
||||
#include <DxeDepex.h>
|
||||
|
||||
DEPENDENCY_START
|
||||
TRUE
|
||||
DEPENDENCY_END
|
|
@ -22,7 +22,7 @@
|
|||
################################################################################
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010005
|
||||
BASE_NAME = NullMemoryTest
|
||||
BASE_NAME = NullMemoryTestDxe
|
||||
FILE_GUID = 96B5C032-DF4C-4b6e-8232-438DCF448D0E
|
||||
MODULE_TYPE = DXE_DRIVER
|
||||
VERSION_STRING = 1.0
|
|
@ -21,7 +21,7 @@
|
|||
################################################################################
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010005
|
||||
BASE_NAME = MonotonicCounter
|
||||
BASE_NAME = MonotonicCounterRuntimeDxe
|
||||
FILE_GUID = AD608272-D07F-4964-801E-7BD3B7888652
|
||||
MODULE_TYPE = DXE_RUNTIME_DRIVER
|
||||
VERSION_STRING = 1.0
|
Loading…
Reference in New Issue