Initial import.
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
26
EdkModulePkg/Universal/Ebc/Dxe/Ebc.dxs
Normal file
26
EdkModulePkg/Universal/Ebc/Dxe/Ebc.dxs
Normal file
@@ -0,0 +1,26 @@
|
||||
/*++
|
||||
|
||||
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:
|
||||
|
||||
Ebc.dxs
|
||||
|
||||
Abstract:
|
||||
|
||||
Dependency expression file for EBC VM.
|
||||
|
||||
--*/
|
||||
#include <AutoGen.h>
|
||||
#include <DxeDepex.h>
|
||||
|
||||
DEPENDENCY_START
|
||||
TRUE
|
||||
DEPENDENCY_END
|
43
EdkModulePkg/Universal/Ebc/Dxe/Ebc.mbd
Normal file
43
EdkModulePkg/Universal/Ebc/Dxe/Ebc.mbd
Normal file
@@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<ModuleBuildDescription xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
|
||||
<MbdHeader>
|
||||
<BaseName>Ebc</BaseName>
|
||||
<Guid>13AC6DD0-73D0-11D4-B06B-00AA00BD6DE7</Guid>
|
||||
<Version>0</Version>
|
||||
<Description>FIX ME!</Description>
|
||||
<Copyright>Copyright (c) 2004-2006, 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>
|
||||
<Created>2006-03-22 14:03</Created>
|
||||
</MbdHeader>
|
||||
<Libraries>
|
||||
<Library>UefiBootServicesTableLib</Library>
|
||||
<Library>BaseLib</Library>
|
||||
<Library>UefiMemoryLib</Library>
|
||||
<Library>UefiLib</Library>
|
||||
<Library>UefiDriverEntryPoint</Library>
|
||||
<Library>DxeReportStatusCodeLib</Library>
|
||||
<Library>BaseDebugLibReportStatusCode</Library>
|
||||
<Library>EdkDxePrintLib</Library>
|
||||
<Library>DxeMemoryAllocationLib</Library>
|
||||
</Libraries>
|
||||
<BuildOptions ToolChain="MSFT">
|
||||
<ImageEntryPoint>_ModuleEntryPoint</ImageEntryPoint>
|
||||
</BuildOptions>
|
||||
</ModuleBuildDescription>
|
80
EdkModulePkg/Universal/Ebc/Dxe/Ebc.msa
Normal file
80
EdkModulePkg/Universal/Ebc/Dxe/Ebc.msa
Normal file
@@ -0,0 +1,80 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
|
||||
<MsaHeader>
|
||||
<BaseName>Ebc</BaseName>
|
||||
<ModuleType>DXE_DRIVER</ModuleType>
|
||||
<ComponentType>BS_DRIVER</ComponentType>
|
||||
<Guid>13AC6DD0-73D0-11D4-B06B-00AA00BD6DE7</Guid>
|
||||
<Version>0</Version>
|
||||
<Abstract>Component description file for DiskIo module.</Abstract>
|
||||
<Description>FIX ME!</Description>
|
||||
<Copyright>Copyright (c) 2004-2006, 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>0</Specification>
|
||||
<Created>2006-03-12 17:09</Created>
|
||||
<Updated>2006-03-22 15:19</Updated>
|
||||
</MsaHeader>
|
||||
<LibraryClassDefinitions>
|
||||
<LibraryClass Usage="ALWAYS_CONSUMED">DebugLib</LibraryClass>
|
||||
<LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverEntryPoint</LibraryClass>
|
||||
<LibraryClass Usage="ALWAYS_CONSUMED">ReportStatusCodeLib</LibraryClass>
|
||||
<LibraryClass Usage="ALWAYS_CONSUMED">UefiLib</LibraryClass>
|
||||
<LibraryClass Usage="ALWAYS_CONSUMED">BaseLib</LibraryClass>
|
||||
<LibraryClass Usage="ALWAYS_CONSUMED">BaseMemoryLib</LibraryClass>
|
||||
<LibraryClass Usage="ALWAYS_CONSUMED">MemoryAllocationLib</LibraryClass>
|
||||
<LibraryClass Usage="ALWAYS_CONSUMED">UefiBootServicesTableLib</LibraryClass>
|
||||
</LibraryClassDefinitions>
|
||||
<SourceFiles>
|
||||
<Filename>EbcInt.c</Filename>
|
||||
<Filename>EbcInt.h</Filename>
|
||||
<Filename>EbcExecute.c</Filename>
|
||||
<Filename>EbcExecute.h</Filename>
|
||||
<Filename>Ebc.dxs</Filename>
|
||||
<Arch ArchType="IA32">
|
||||
<Filename>Ia32\EbcLowLevel.asm</Filename>
|
||||
<Filename>Ia32\Ia32Math.asm</Filename>
|
||||
<Filename>Ia32\EbcSupport.c</Filename>
|
||||
</Arch>
|
||||
<Arch ArchType="X64">
|
||||
<Filename>x64\EbcLowLevel.asm</Filename>
|
||||
<Filename>x64\x64Math.c</Filename>
|
||||
<Filename>x64\EbcSupport.c</Filename>
|
||||
</Arch>
|
||||
<Arch ArchType="IPF">
|
||||
<Filename>Ipf\EbcLowLevel.s</Filename>
|
||||
<Filename>Ipf\IpfMath.c</Filename>
|
||||
<Filename>Ipf\IpfMul.s</Filename>
|
||||
<Filename>Ipf\EbcSupport.c</Filename>
|
||||
</Arch>
|
||||
</SourceFiles>
|
||||
<Includes>
|
||||
<PackageName>MdePkg</PackageName>
|
||||
<PackageName>EdkModulePkg</PackageName>
|
||||
</Includes>
|
||||
<Protocols>
|
||||
<Protocol Usage="ALWAYS_PRODUCED">Ebc</Protocol>
|
||||
<Protocol Usage="ALWAYS_PRODUCED">DebugSupport</Protocol>
|
||||
</Protocols>
|
||||
<Externs>
|
||||
<Extern>
|
||||
<ModuleEntryPoint>InitializeEbcDriver</ModuleEntryPoint>
|
||||
</Extern>
|
||||
</Externs>
|
||||
</ModuleSurfaceArea>
|
4603
EdkModulePkg/Universal/Ebc/Dxe/EbcExecute.c
Normal file
4603
EdkModulePkg/Universal/Ebc/Dxe/EbcExecute.c
Normal file
File diff suppressed because it is too large
Load Diff
383
EdkModulePkg/Universal/Ebc/Dxe/EbcExecute.h
Normal file
383
EdkModulePkg/Universal/Ebc/Dxe/EbcExecute.h
Normal file
@@ -0,0 +1,383 @@
|
||||
/*++
|
||||
|
||||
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_
|
||||
|
||||
//
|
||||
// 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
|
||||
)
|
||||
;
|
||||
|
||||
//
|
||||
// Math library routines
|
||||
//
|
||||
INT64
|
||||
DivS64x64 (
|
||||
IN INT64 Value1,
|
||||
IN INT64 Value2,
|
||||
OUT INT64 *Remainder,
|
||||
OUT UINT32 *Error
|
||||
)
|
||||
;
|
||||
#if 0
|
||||
UINT64
|
||||
DivU64x64 (
|
||||
IN UINT64 Value1,
|
||||
IN UINT64 Value2,
|
||||
OUT UINT64 *Remainder,
|
||||
OUT UINT32 *Error
|
||||
)
|
||||
;
|
||||
#endif
|
||||
|
||||
INT64
|
||||
MulS64x64 (
|
||||
IN INT64 Value1,
|
||||
IN INT64 Value2,
|
||||
OUT INT64 *ResultHigh
|
||||
)
|
||||
;
|
||||
|
||||
UINT64
|
||||
MulU64x64 (
|
||||
IN UINT64 Value1,
|
||||
IN UINT64 Value2,
|
||||
OUT UINT64 *ResultHigh
|
||||
)
|
||||
;
|
||||
|
||||
UINT64
|
||||
DivU64x64 (
|
||||
IN UINT64 Value1,
|
||||
IN UINT64 Value2,
|
||||
OUT UINT64 *Remainder,
|
||||
OUT UINT32 *Error
|
||||
)
|
||||
;
|
||||
|
||||
INT64
|
||||
ARightShift64 (
|
||||
IN INT64 Operand,
|
||||
IN INT64 Count
|
||||
)
|
||||
;
|
||||
|
||||
UINT64
|
||||
LeftShiftU64 (
|
||||
IN UINT64 Operand,
|
||||
IN UINT64 Count
|
||||
)
|
||||
;
|
||||
|
||||
UINT64
|
||||
RightShiftU64 (
|
||||
IN UINT64 Operand,
|
||||
IN UINT64 Count
|
||||
)
|
||||
;
|
||||
|
||||
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_
|
932
EdkModulePkg/Universal/Ebc/Dxe/EbcInt.c
Normal file
932
EdkModulePkg/Universal/Ebc/Dxe/EbcInt.c
Normal file
@@ -0,0 +1,932 @@
|
||||
/*++
|
||||
|
||||
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.c
|
||||
|
||||
Abstract:
|
||||
|
||||
Top level module for the EBC virtual machine implementation.
|
||||
Provides auxilliary support routines for the VM. That is, routines
|
||||
that are not particularly related to VM execution of EBC instructions.
|
||||
|
||||
--*/
|
||||
|
||||
#include "EbcInt.h"
|
||||
#include "EbcExecute.h"
|
||||
|
||||
//
|
||||
// We'll keep track of all thunks we create in a linked list. Each
|
||||
// thunk is tied to an image handle, so we have a linked list of
|
||||
// image handles, with each having a linked list of thunks allocated
|
||||
// to that image handle.
|
||||
//
|
||||
typedef struct _EBC_THUNK_LIST {
|
||||
VOID *ThunkBuffer;
|
||||
struct _EBC_THUNK_LIST *Next;
|
||||
} EBC_THUNK_LIST;
|
||||
|
||||
typedef struct _EBC_IMAGE_LIST {
|
||||
struct _EBC_IMAGE_LIST *Next;
|
||||
EFI_HANDLE ImageHandle;
|
||||
EBC_THUNK_LIST *ThunkList;
|
||||
} EBC_IMAGE_LIST;
|
||||
|
||||
//
|
||||
// Function prototypes
|
||||
//
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
InitializeEbcDriver (
|
||||
IN EFI_HANDLE ImageHandle,
|
||||
IN EFI_SYSTEM_TABLE *SystemTable
|
||||
);
|
||||
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
EbcUnloadImage (
|
||||
IN EFI_EBC_PROTOCOL *This,
|
||||
IN EFI_HANDLE ImageHandle
|
||||
);
|
||||
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
EbcCreateThunk (
|
||||
IN EFI_EBC_PROTOCOL *This,
|
||||
IN EFI_HANDLE ImageHandle,
|
||||
IN VOID *EbcEntryPoint,
|
||||
OUT VOID **Thunk
|
||||
);
|
||||
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
EbcGetVersion (
|
||||
IN EFI_EBC_PROTOCOL *This,
|
||||
IN OUT UINT64 *Version
|
||||
);
|
||||
|
||||
//
|
||||
// These two functions and the GUID are used to produce an EBC test protocol.
|
||||
// This functionality is definitely not required for execution.
|
||||
//
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
InitEbcVmTestProtocol (
|
||||
IN EFI_HANDLE *Handle
|
||||
);
|
||||
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
EbcVmTestUnsupported (
|
||||
VOID
|
||||
);
|
||||
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
EbcRegisterICacheFlush (
|
||||
IN EFI_EBC_PROTOCOL *This,
|
||||
IN EBC_ICACHE_FLUSH Flush
|
||||
);
|
||||
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
EbcDebugGetMaximumProcessorIndex (
|
||||
IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
|
||||
OUT UINTN *MaxProcessorIndex
|
||||
);
|
||||
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
EbcDebugRegisterPeriodicCallback (
|
||||
IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
|
||||
IN UINTN ProcessorIndex,
|
||||
IN EFI_PERIODIC_CALLBACK PeriodicCallback
|
||||
);
|
||||
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
EbcDebugRegisterExceptionCallback (
|
||||
IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
|
||||
IN UINTN ProcessorIndex,
|
||||
IN EFI_EXCEPTION_CALLBACK ExceptionCallback,
|
||||
IN EFI_EXCEPTION_TYPE ExceptionType
|
||||
);
|
||||
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
EbcDebugInvalidateInstructionCache (
|
||||
IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
|
||||
IN UINTN ProcessorIndex,
|
||||
IN VOID *Start,
|
||||
IN UINT64 Length
|
||||
);
|
||||
|
||||
//
|
||||
// We have one linked list of image handles for the whole world. Since
|
||||
// there should only be one interpreter, make them global. They must
|
||||
// also be global since the execution of an EBC image does not provide
|
||||
// a This pointer.
|
||||
//
|
||||
static EBC_IMAGE_LIST *mEbcImageList = NULL;
|
||||
|
||||
//
|
||||
// Callback function to flush the icache after thunk creation
|
||||
//
|
||||
static EBC_ICACHE_FLUSH mEbcICacheFlush;
|
||||
|
||||
//
|
||||
// These get set via calls by the debug agent
|
||||
//
|
||||
static EFI_PERIODIC_CALLBACK mDebugPeriodicCallback = NULL;
|
||||
static EFI_EXCEPTION_CALLBACK mDebugExceptionCallback = NULL;
|
||||
static EFI_GUID mEfiEbcVmTestProtocolGuid = EFI_EBC_VM_TEST_PROTOCOL_GUID;
|
||||
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
InitializeEbcDriver (
|
||||
IN EFI_HANDLE ImageHandle,
|
||||
IN EFI_SYSTEM_TABLE *SystemTable
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Initializes the VM EFI interface. Allocates memory for the VM interface
|
||||
and registers the VM protocol.
|
||||
|
||||
Arguments:
|
||||
|
||||
ImageHandle - EFI image handle.
|
||||
SystemTable - Pointer to the EFI system table.
|
||||
|
||||
Returns:
|
||||
Standard EFI status code.
|
||||
|
||||
--*/
|
||||
{
|
||||
EFI_EBC_PROTOCOL *EbcProtocol;
|
||||
EFI_EBC_PROTOCOL *OldEbcProtocol;
|
||||
EFI_STATUS Status;
|
||||
EFI_DEBUG_SUPPORT_PROTOCOL *EbcDebugProtocol;
|
||||
EFI_HANDLE *HandleBuffer;
|
||||
UINTN NumHandles;
|
||||
UINTN Index;
|
||||
BOOLEAN Installed;
|
||||
|
||||
//
|
||||
// Allocate memory for our protocol. Then fill in the blanks.
|
||||
//
|
||||
Status = gBS->AllocatePool (
|
||||
EfiBootServicesData,
|
||||
sizeof (EFI_EBC_PROTOCOL),
|
||||
(VOID **) &EbcProtocol
|
||||
);
|
||||
if (Status != EFI_SUCCESS) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
EbcProtocol->CreateThunk = EbcCreateThunk;
|
||||
EbcProtocol->UnloadImage = EbcUnloadImage;
|
||||
EbcProtocol->RegisterICacheFlush = EbcRegisterICacheFlush;
|
||||
EbcProtocol->GetVersion = EbcGetVersion;
|
||||
mEbcICacheFlush = NULL;
|
||||
|
||||
//
|
||||
// Find any already-installed EBC protocols and uninstall them
|
||||
//
|
||||
Installed = FALSE;
|
||||
HandleBuffer = NULL;
|
||||
Status = gBS->LocateHandleBuffer (
|
||||
ByProtocol,
|
||||
&gEfiEbcProtocolGuid,
|
||||
NULL,
|
||||
&NumHandles,
|
||||
&HandleBuffer
|
||||
);
|
||||
if (Status == EFI_SUCCESS) {
|
||||
//
|
||||
// Loop through the handles
|
||||
//
|
||||
for (Index = 0; Index < NumHandles; Index++) {
|
||||
Status = gBS->HandleProtocol (
|
||||
HandleBuffer[Index],
|
||||
&gEfiEbcProtocolGuid,
|
||||
(VOID **) &OldEbcProtocol
|
||||
);
|
||||
if (Status == EFI_SUCCESS) {
|
||||
if (gBS->ReinstallProtocolInterface (
|
||||
HandleBuffer[Index],
|
||||
&gEfiEbcProtocolGuid,
|
||||
OldEbcProtocol,
|
||||
EbcProtocol
|
||||
) == EFI_SUCCESS) {
|
||||
Installed = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (HandleBuffer != NULL) {
|
||||
gBS->FreePool (HandleBuffer);
|
||||
HandleBuffer = NULL;
|
||||
}
|
||||
//
|
||||
// Add the protocol so someone can locate us if we haven't already.
|
||||
//
|
||||
if (!Installed) {
|
||||
Status = gBS->InstallProtocolInterface (
|
||||
&ImageHandle,
|
||||
&gEfiEbcProtocolGuid,
|
||||
EFI_NATIVE_INTERFACE,
|
||||
EbcProtocol
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
gBS->FreePool (EbcProtocol);
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
//
|
||||
// Allocate memory for our debug protocol. Then fill in the blanks.
|
||||
//
|
||||
Status = gBS->AllocatePool (
|
||||
EfiBootServicesData,
|
||||
sizeof (EFI_DEBUG_SUPPORT_PROTOCOL),
|
||||
(VOID **) &EbcDebugProtocol
|
||||
);
|
||||
if (Status != EFI_SUCCESS) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
EbcDebugProtocol->Isa = IsaEbc;
|
||||
EbcDebugProtocol->GetMaximumProcessorIndex = EbcDebugGetMaximumProcessorIndex;
|
||||
EbcDebugProtocol->RegisterPeriodicCallback = EbcDebugRegisterPeriodicCallback;
|
||||
EbcDebugProtocol->RegisterExceptionCallback = EbcDebugRegisterExceptionCallback;
|
||||
EbcDebugProtocol->InvalidateInstructionCache = EbcDebugInvalidateInstructionCache;
|
||||
|
||||
//
|
||||
// Add the protocol so the debug agent can find us
|
||||
//
|
||||
Status = gBS->InstallProtocolInterface (
|
||||
&ImageHandle,
|
||||
&gEfiDebugSupportProtocolGuid,
|
||||
EFI_NATIVE_INTERFACE,
|
||||
EbcDebugProtocol
|
||||
);
|
||||
//
|
||||
// This is recoverable, so free the memory and continue.
|
||||
//
|
||||
if (EFI_ERROR (Status)) {
|
||||
gBS->FreePool (EbcDebugProtocol);
|
||||
}
|
||||
//
|
||||
// Produce a VM test interface protocol. Not required for execution.
|
||||
//
|
||||
DEBUG_CODE (
|
||||
InitEbcVmTestProtocol (&ImageHandle);
|
||||
);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
EbcCreateThunk (
|
||||
IN EFI_EBC_PROTOCOL *This,
|
||||
IN EFI_HANDLE ImageHandle,
|
||||
IN VOID *EbcEntryPoint,
|
||||
OUT VOID **Thunk
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This is the top-level routine plugged into the EBC protocol. Since thunks
|
||||
are very processor-specific, from here we dispatch directly to the very
|
||||
processor-specific routine EbcCreateThunks().
|
||||
|
||||
Arguments:
|
||||
|
||||
This - protocol instance pointer
|
||||
ImageHandle - handle to the image. The EBC interpreter may use this to keep
|
||||
track of any resource allocations performed in loading and
|
||||
executing the image.
|
||||
EbcEntryPoint - the entry point for the image (as defined in the file header)
|
||||
Thunk - pointer to thunk pointer where the address of the created
|
||||
thunk is returned.
|
||||
|
||||
Returns:
|
||||
|
||||
EFI_STATUS
|
||||
|
||||
--*/
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
Status = EbcCreateThunks (
|
||||
ImageHandle,
|
||||
EbcEntryPoint,
|
||||
Thunk,
|
||||
FLAG_THUNK_ENTRY_POINT
|
||||
);
|
||||
return Status;
|
||||
}
|
||||
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
EbcDebugGetMaximumProcessorIndex (
|
||||
IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
|
||||
OUT UINTN *MaxProcessorIndex
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This EBC debugger protocol service is called by the debug agent
|
||||
|
||||
Arguments:
|
||||
|
||||
This - pointer to the caller's debug support protocol interface
|
||||
MaxProcessorIndex - pointer to a caller allocated UINTN in which the maximum
|
||||
processor index is returned.
|
||||
|
||||
Returns:
|
||||
|
||||
Standard EFI_STATUS
|
||||
|
||||
--*/
|
||||
{
|
||||
*MaxProcessorIndex = 0;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
EbcDebugRegisterPeriodicCallback (
|
||||
IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
|
||||
IN UINTN ProcessorIndex,
|
||||
IN EFI_PERIODIC_CALLBACK PeriodicCallback
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This protocol service is called by the debug agent to register a function
|
||||
for us to call on a periodic basis.
|
||||
|
||||
|
||||
Arguments:
|
||||
|
||||
This - pointer to the caller's debug support protocol interface
|
||||
PeriodicCallback - pointer to the function to call periodically
|
||||
|
||||
Returns:
|
||||
|
||||
Always EFI_SUCCESS
|
||||
|
||||
--*/
|
||||
{
|
||||
mDebugPeriodicCallback = PeriodicCallback;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
EbcDebugRegisterExceptionCallback (
|
||||
IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
|
||||
IN UINTN ProcessorIndex,
|
||||
IN EFI_EXCEPTION_CALLBACK ExceptionCallback,
|
||||
IN EFI_EXCEPTION_TYPE ExceptionType
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This protocol service is called by the debug agent to register a function
|
||||
for us to call when we detect an exception.
|
||||
|
||||
|
||||
Arguments:
|
||||
|
||||
This - pointer to the caller's debug support protocol interface
|
||||
PeriodicCallback - pointer to the function to call periodically
|
||||
|
||||
Returns:
|
||||
|
||||
Always EFI_SUCCESS
|
||||
|
||||
--*/
|
||||
{
|
||||
mDebugExceptionCallback = ExceptionCallback;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
EbcDebugInvalidateInstructionCache (
|
||||
IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
|
||||
IN UINTN ProcessorIndex,
|
||||
IN VOID *Start,
|
||||
IN UINT64 Length
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This EBC debugger protocol service is called by the debug agent. Required
|
||||
for DebugSupport compliance but is only stubbed out for EBC.
|
||||
|
||||
Arguments:
|
||||
|
||||
Returns:
|
||||
|
||||
EFI_SUCCESS
|
||||
|
||||
--*/
|
||||
{
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
EbcDebugSignalException (
|
||||
IN EFI_EXCEPTION_TYPE ExceptionType,
|
||||
IN EXCEPTION_FLAGS ExceptionFlags,
|
||||
IN VM_CONTEXT *VmPtr
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
The VM interpreter calls this function when an exception is detected.
|
||||
|
||||
Arguments:
|
||||
|
||||
VmPtr - pointer to a VM context for passing info to the EFI debugger.
|
||||
|
||||
Returns:
|
||||
|
||||
EFI_SUCCESS if it returns at all
|
||||
|
||||
--*/
|
||||
{
|
||||
EFI_SYSTEM_CONTEXT_EBC EbcContext;
|
||||
EFI_SYSTEM_CONTEXT SystemContext;
|
||||
EFI_STATUS_CODE_VALUE StatusCodeValue;
|
||||
BOOLEAN Report;
|
||||
//
|
||||
// Save the exception in the context passed in
|
||||
//
|
||||
VmPtr->ExceptionFlags |= ExceptionFlags;
|
||||
VmPtr->LastException = ExceptionType;
|
||||
//
|
||||
// If it's a fatal exception, then flag it in the VM context in case an
|
||||
// attached debugger tries to return from it.
|
||||
//
|
||||
if (ExceptionFlags & EXCEPTION_FLAG_FATAL) {
|
||||
VmPtr->StopFlags |= STOPFLAG_APP_DONE;
|
||||
}
|
||||
//
|
||||
// Initialize the context structure
|
||||
//
|
||||
EbcContext.R0 = VmPtr->R[0];
|
||||
EbcContext.R1 = VmPtr->R[1];
|
||||
EbcContext.R2 = VmPtr->R[2];
|
||||
EbcContext.R3 = VmPtr->R[3];
|
||||
EbcContext.R4 = VmPtr->R[4];
|
||||
EbcContext.R5 = VmPtr->R[5];
|
||||
EbcContext.R6 = VmPtr->R[6];
|
||||
EbcContext.R7 = VmPtr->R[7];
|
||||
EbcContext.Ip = (UINT64) (UINTN) VmPtr->Ip;
|
||||
EbcContext.Flags = VmPtr->Flags;
|
||||
SystemContext.SystemContextEbc = &EbcContext;
|
||||
//
|
||||
// If someone's registered for exception callbacks, then call them.
|
||||
// Otherwise report the status code via the status code API
|
||||
//
|
||||
if (mDebugExceptionCallback != NULL) {
|
||||
mDebugExceptionCallback (ExceptionType, SystemContext);
|
||||
}
|
||||
//
|
||||
// Determine if we should report the exception. We report all of them by default,
|
||||
// but if a debugger is attached don't report the breakpoint, debug, and step exceptions.
|
||||
// Note that EXCEPT_EBC_OVERFLOW is never reported by this VM implementation, so is
|
||||
// not included in the switch statement.
|
||||
//
|
||||
Report = TRUE;
|
||||
switch (ExceptionType) {
|
||||
case EXCEPT_EBC_UNDEFINED:
|
||||
StatusCodeValue = EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_EBC_UNDEFINED;
|
||||
break;
|
||||
|
||||
case EXCEPT_EBC_DIVIDE_ERROR:
|
||||
StatusCodeValue = EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_EBC_DIVIDE_ERROR;
|
||||
break;
|
||||
|
||||
case EXCEPT_EBC_DEBUG:
|
||||
StatusCodeValue = EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_EBC_DEBUG;
|
||||
Report = (BOOLEAN) ((mDebugExceptionCallback == NULL) ? TRUE : FALSE);
|
||||
break;
|
||||
|
||||
case EXCEPT_EBC_BREAKPOINT:
|
||||
StatusCodeValue = EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_EBC_BREAKPOINT;
|
||||
Report = (BOOLEAN) ((mDebugExceptionCallback == NULL) ? TRUE : FALSE);
|
||||
break;
|
||||
|
||||
case EXCEPT_EBC_INVALID_OPCODE:
|
||||
StatusCodeValue = EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_EBC_INVALID_OPCODE;
|
||||
break;
|
||||
|
||||
case EXCEPT_EBC_STACK_FAULT:
|
||||
StatusCodeValue = EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_EBC_STACK_FAULT;
|
||||
break;
|
||||
|
||||
case EXCEPT_EBC_ALIGNMENT_CHECK:
|
||||
StatusCodeValue = EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_EBC_ALIGNMENT_CHECK;
|
||||
break;
|
||||
|
||||
case EXCEPT_EBC_INSTRUCTION_ENCODING:
|
||||
StatusCodeValue = EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_EBC_INSTRUCTION_ENCODING;
|
||||
break;
|
||||
|
||||
case EXCEPT_EBC_BAD_BREAK:
|
||||
StatusCodeValue = EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_EBC_BAD_BREAK;
|
||||
break;
|
||||
|
||||
case EXCEPT_EBC_STEP:
|
||||
StatusCodeValue = EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_EBC_STEP;
|
||||
Report = (BOOLEAN) ((mDebugExceptionCallback == NULL) ? TRUE : FALSE);
|
||||
break;
|
||||
|
||||
default:
|
||||
StatusCodeValue = EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_NON_SPECIFIC;
|
||||
break;
|
||||
}
|
||||
//
|
||||
// If we determined that we should report the condition, then do so now.
|
||||
//
|
||||
if (Report) {
|
||||
REPORT_STATUS_CODE (EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED, StatusCodeValue);
|
||||
}
|
||||
|
||||
switch (ExceptionType) {
|
||||
//
|
||||
// If ReportStatusCode returned, then for most exceptions we do an assert. The
|
||||
// ExceptionType++ is done simply to force the ASSERT() condition to be met.
|
||||
// For breakpoints, assume a debugger did not insert a software breakpoint
|
||||
// and skip the instruction.
|
||||
//
|
||||
case EXCEPT_EBC_BREAKPOINT:
|
||||
VmPtr->Ip += 2;
|
||||
break;
|
||||
|
||||
case EXCEPT_EBC_STEP:
|
||||
break;
|
||||
|
||||
case EXCEPT_EBC_UNDEFINED:
|
||||
ExceptionType++;
|
||||
ASSERT (ExceptionType == EXCEPT_EBC_UNDEFINED);
|
||||
break;
|
||||
|
||||
case EXCEPT_EBC_DIVIDE_ERROR:
|
||||
ExceptionType++;
|
||||
ASSERT (ExceptionType == EXCEPT_EBC_DIVIDE_ERROR);
|
||||
break;
|
||||
|
||||
case EXCEPT_EBC_DEBUG:
|
||||
ExceptionType++;
|
||||
ASSERT (ExceptionType == EXCEPT_EBC_DEBUG);
|
||||
break;
|
||||
|
||||
case EXCEPT_EBC_INVALID_OPCODE:
|
||||
ExceptionType++;
|
||||
ASSERT (ExceptionType == EXCEPT_EBC_INVALID_OPCODE);
|
||||
break;
|
||||
|
||||
case EXCEPT_EBC_STACK_FAULT:
|
||||
ExceptionType++;
|
||||
ASSERT (ExceptionType == EXCEPT_EBC_STACK_FAULT);
|
||||
break;
|
||||
|
||||
case EXCEPT_EBC_ALIGNMENT_CHECK:
|
||||
ExceptionType++;
|
||||
ASSERT (ExceptionType == EXCEPT_EBC_ALIGNMENT_CHECK);
|
||||
break;
|
||||
|
||||
case EXCEPT_EBC_INSTRUCTION_ENCODING:
|
||||
ExceptionType++;
|
||||
ASSERT (ExceptionType == EXCEPT_EBC_INSTRUCTION_ENCODING);
|
||||
break;
|
||||
|
||||
case EXCEPT_EBC_BAD_BREAK:
|
||||
ExceptionType++;
|
||||
ASSERT (ExceptionType == EXCEPT_EBC_BAD_BREAK);
|
||||
break;
|
||||
|
||||
default:
|
||||
//
|
||||
// Unknown
|
||||
//
|
||||
ASSERT (0);
|
||||
break;
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
EbcDebugPeriodic (
|
||||
IN VM_CONTEXT *VmPtr
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
The VM interpreter calls this function on a periodic basis to support
|
||||
the EFI debug support protocol.
|
||||
|
||||
Arguments:
|
||||
|
||||
VmPtr - pointer to a VM context for passing info to the debugger.
|
||||
|
||||
Returns:
|
||||
|
||||
Standard EFI status.
|
||||
|
||||
--*/
|
||||
{
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
EbcUnloadImage (
|
||||
IN EFI_EBC_PROTOCOL *This,
|
||||
IN EFI_HANDLE ImageHandle
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine is called by the core when an image is being unloaded from
|
||||
memory. Basically we now have the opportunity to do any necessary cleanup.
|
||||
Typically this will include freeing any memory allocated for thunk-creation.
|
||||
|
||||
Arguments:
|
||||
|
||||
This - protocol instance pointer
|
||||
ImageHandle - handle to the image being unloaded.
|
||||
|
||||
Returns:
|
||||
|
||||
EFI_INVALID_PARAMETER - the ImageHandle passed in was not found in
|
||||
the internal list of EBC image handles.
|
||||
EFI_STATUS - completed successfully
|
||||
|
||||
--*/
|
||||
{
|
||||
EBC_THUNK_LIST *ThunkList;
|
||||
EBC_THUNK_LIST *NextThunkList;
|
||||
EBC_IMAGE_LIST *ImageList;
|
||||
EBC_IMAGE_LIST *PrevImageList;
|
||||
//
|
||||
// First go through our list of known image handles and see if we've already
|
||||
// created an image list element for this image handle.
|
||||
//
|
||||
PrevImageList = NULL;
|
||||
for (ImageList = mEbcImageList; ImageList != NULL; ImageList = ImageList->Next) {
|
||||
if (ImageList->ImageHandle == ImageHandle) {
|
||||
break;
|
||||
}
|
||||
//
|
||||
// Save the previous so we can connect the lists when we remove this one
|
||||
//
|
||||
PrevImageList = ImageList;
|
||||
}
|
||||
|
||||
if (ImageList == NULL) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
//
|
||||
// Free up all the thunk buffers and thunks list elements for this image
|
||||
// handle.
|
||||
//
|
||||
ThunkList = ImageList->ThunkList;
|
||||
while (ThunkList != NULL) {
|
||||
NextThunkList = ThunkList->Next;
|
||||
gBS->FreePool (ThunkList->ThunkBuffer);
|
||||
gBS->FreePool (ThunkList);
|
||||
ThunkList = NextThunkList;
|
||||
}
|
||||
//
|
||||
// Now remove this image list element from the chain
|
||||
//
|
||||
if (PrevImageList == NULL) {
|
||||
//
|
||||
// Remove from head
|
||||
//
|
||||
mEbcImageList = ImageList->Next;
|
||||
} else {
|
||||
PrevImageList->Next = ImageList->Next;
|
||||
}
|
||||
//
|
||||
// Now free up the image list element
|
||||
//
|
||||
gBS->FreePool (ImageList);
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
EbcAddImageThunk (
|
||||
IN EFI_HANDLE ImageHandle,
|
||||
IN VOID *ThunkBuffer,
|
||||
IN UINT32 ThunkSize
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Add a thunk to our list of thunks for a given image handle.
|
||||
Also flush the instruction cache since we've written thunk code
|
||||
to memory that will be executed eventually.
|
||||
|
||||
Arguments:
|
||||
|
||||
ImageHandle - the image handle to which the thunk is tied
|
||||
ThunkBuffer - the buffer we've created/allocated
|
||||
ThunkSize - the size of the thunk memory allocated
|
||||
|
||||
Returns:
|
||||
|
||||
EFI_OUT_OF_RESOURCES - memory allocation failed
|
||||
EFI_SUCCESS - successful completion
|
||||
|
||||
--*/
|
||||
{
|
||||
EBC_THUNK_LIST *ThunkList;
|
||||
EBC_IMAGE_LIST *ImageList;
|
||||
EFI_STATUS Status;
|
||||
|
||||
//
|
||||
// It so far so good, then flush the instruction cache
|
||||
//
|
||||
if (mEbcICacheFlush != NULL) {
|
||||
Status = mEbcICacheFlush ((EFI_PHYSICAL_ADDRESS) (UINTN) ThunkBuffer, ThunkSize);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
//
|
||||
// Go through our list of known image handles and see if we've already
|
||||
// created a image list element for this image handle.
|
||||
//
|
||||
for (ImageList = mEbcImageList; ImageList != NULL; ImageList = ImageList->Next) {
|
||||
if (ImageList->ImageHandle == ImageHandle) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ImageList == NULL) {
|
||||
//
|
||||
// Allocate a new one
|
||||
//
|
||||
Status = gBS->AllocatePool (
|
||||
EfiBootServicesData,
|
||||
sizeof (EBC_IMAGE_LIST),
|
||||
(VOID **) &ImageList
|
||||
);
|
||||
if (Status != EFI_SUCCESS) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
ImageList->ThunkList = NULL;
|
||||
ImageList->ImageHandle = ImageHandle;
|
||||
ImageList->Next = mEbcImageList;
|
||||
mEbcImageList = ImageList;
|
||||
}
|
||||
//
|
||||
// Ok, now create a new thunk element to add to the list
|
||||
//
|
||||
Status = gBS->AllocatePool (
|
||||
EfiBootServicesData,
|
||||
sizeof (EBC_THUNK_LIST),
|
||||
(VOID **) &ThunkList
|
||||
);
|
||||
if (Status != EFI_SUCCESS) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
//
|
||||
// Add it to the head of the list
|
||||
//
|
||||
ThunkList->Next = ImageList->ThunkList;
|
||||
ThunkList->ThunkBuffer = ThunkBuffer;
|
||||
ImageList->ThunkList = ThunkList;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
EbcRegisterICacheFlush (
|
||||
IN EFI_EBC_PROTOCOL *This,
|
||||
IN EBC_ICACHE_FLUSH Flush
|
||||
)
|
||||
{
|
||||
mEbcICacheFlush = Flush;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
EbcGetVersion (
|
||||
IN EFI_EBC_PROTOCOL *This,
|
||||
IN OUT UINT64 *Version
|
||||
)
|
||||
{
|
||||
if (Version == NULL) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
*Version = GetVmVersion ();
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
InitEbcVmTestProtocol (
|
||||
IN EFI_HANDLE *IHandle
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Produce an EBC VM test protocol that can be used for regression tests.
|
||||
|
||||
Arguments:
|
||||
|
||||
IHandle - handle on which to install the protocol.
|
||||
|
||||
Returns:
|
||||
|
||||
EFI_OUT_OF_RESOURCES - memory allocation failed
|
||||
EFI_SUCCESS - successful completion
|
||||
|
||||
--*/
|
||||
{
|
||||
EFI_HANDLE Handle;
|
||||
EFI_STATUS Status;
|
||||
EFI_EBC_VM_TEST_PROTOCOL *EbcVmTestProtocol;
|
||||
|
||||
//
|
||||
// Allocate memory for the protocol, then fill in the fields
|
||||
//
|
||||
Status = gBS->AllocatePool (EfiBootServicesData, sizeof (EFI_EBC_VM_TEST_PROTOCOL), (VOID **) &EbcVmTestProtocol);
|
||||
if (Status != EFI_SUCCESS) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
EbcVmTestProtocol->Execute = (EBC_VM_TEST_EXECUTE) EbcExecuteInstructions;
|
||||
|
||||
DEBUG_CODE(
|
||||
EbcVmTestProtocol->Assemble = (EBC_VM_TEST_ASM) EbcVmTestUnsupported;
|
||||
EbcVmTestProtocol->Disassemble = (EBC_VM_TEST_DASM) EbcVmTestUnsupported;
|
||||
);
|
||||
|
||||
//
|
||||
// Publish the protocol
|
||||
//
|
||||
Handle = NULL;
|
||||
Status = gBS->InstallProtocolInterface (&Handle, &mEfiEbcVmTestProtocolGuid, EFI_NATIVE_INTERFACE, EbcVmTestProtocol);
|
||||
if (EFI_ERROR (Status)) {
|
||||
gBS->FreePool (EbcVmTestProtocol);
|
||||
}
|
||||
return Status;
|
||||
}
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
EbcVmTestUnsupported ()
|
||||
{
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
231
EdkModulePkg/Universal/Ebc/Dxe/EbcInt.h
Normal file
231
EdkModulePkg/Universal/Ebc/Dxe/EbcInt.h
Normal file
@@ -0,0 +1,231 @@
|
||||
/*++
|
||||
|
||||
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_
|
||||
|
||||
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;
|
||||
} VM_CONTEXT;
|
||||
|
||||
//
|
||||
// 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 EBC_VM_PERIODIC_CALLBACK_RATE 1000
|
||||
|
||||
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
|
||||
)
|
||||
;
|
||||
|
||||
//
|
||||
// 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_
|
148
EdkModulePkg/Universal/Ebc/Dxe/Ia32/EbcLowLevel.asm
Normal file
148
EdkModulePkg/Universal/Ebc/Dxe/Ia32/EbcLowLevel.asm
Normal file
@@ -0,0 +1,148 @@
|
||||
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 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
|
||||
;---------------------------------------------------------------------------
|
||||
|
||||
;****************************************************************************
|
||||
; 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
|
||||
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]+8
|
||||
|
||||
; Set stack pointer to new value
|
||||
; mov eax, NewStackPointer => mov eax, dword ptr [NewSp]
|
||||
mov eax, dword ptr [esp] + 0Ch
|
||||
mov esp, eax
|
||||
|
||||
; 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 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
|
482
EdkModulePkg/Universal/Ebc/Dxe/Ia32/EbcSupport.c
Normal file
482
EdkModulePkg/Universal/Ebc/Dxe/Ia32/EbcSupport.c
Normal file
@@ -0,0 +1,482 @@
|
||||
/*++
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
)
|
||||
/*++
|
||||
|
||||
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;
|
||||
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
Addr = EbcLLGetStackPointer ();
|
||||
|
||||
VmContext.R[0] = (UINT64) Addr;
|
||||
VmContext.R[0] -= VM_STACK_SIZE;
|
||||
|
||||
//
|
||||
// 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];
|
||||
VmContext.R[0] -= sizeof (UINTN);
|
||||
|
||||
//
|
||||
// For IA32, this is where we say our return address is
|
||||
//
|
||||
VmContext.StackRetAddr = (UINT64) VmContext.R[0];
|
||||
VmContext.LowStackTop = (UINTN) 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));
|
||||
//
|
||||
VmContext.HighStackBottom = (UINTN) &Arg1 - 16;
|
||||
//
|
||||
// Begin executing the EBC code
|
||||
//
|
||||
EbcExecute (&VmContext);
|
||||
|
||||
//
|
||||
// Return the value in R[7] unless there was an error
|
||||
//
|
||||
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;
|
||||
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
Addr = EbcLLGetStackPointer ();
|
||||
VmContext.R[0] = (UINT64) Addr;
|
||||
VmContext.R[0] -= VM_STACK_SIZE;
|
||||
//
|
||||
// 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.R[0] -= sizeof (UINTN);
|
||||
|
||||
//
|
||||
// Align the stack on a natural boundary
|
||||
// VmContext.R[0] &= ~(sizeof(UINTN) - 1);
|
||||
//
|
||||
VmContext.StackRetAddr = (UINT64) VmContext.R[0];
|
||||
VmContext.LowStackTop = (UINTN) VmContext.R[0];
|
||||
//
|
||||
// VM pushes 16-bytes for return address. Simulate that here.
|
||||
//
|
||||
VmContext.HighStackBottom = (UINTN) &ImageHandle - 16;
|
||||
|
||||
//
|
||||
// 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;
|
||||
EFI_STATUS Status;
|
||||
|
||||
//
|
||||
// Check alignment of pointer to EBC code
|
||||
//
|
||||
if ((UINT32) (UINTN) EbcEntryPoint & 0x01) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
Size = EBC_THUNK_SIZE;
|
||||
ThunkSize = Size;
|
||||
|
||||
Status = gBS->AllocatePool (
|
||||
EfiBootServicesData,
|
||||
Size,
|
||||
(VOID *) &Ptr
|
||||
);
|
||||
if (Status != EFI_SUCCESS) {
|
||||
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;
|
||||
}
|
622
EdkModulePkg/Universal/Ebc/Dxe/Ia32/Ia32Math.asm
Normal file
622
EdkModulePkg/Universal/Ebc/Dxe/Ia32/Ia32Math.asm
Normal file
@@ -0,0 +1,622 @@
|
||||
TITLE Ia32math.asm: Generic math routines for EBC interpreter running on IA32 processor
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
;
|
||||
; 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:
|
||||
;
|
||||
; Ia32math.asm
|
||||
;
|
||||
; Abstract:
|
||||
;
|
||||
; Generic math routines for EBC interpreter running on IA32 processor
|
||||
;
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
.686P
|
||||
.XMM
|
||||
.MODEL SMALL
|
||||
.CODE
|
||||
|
||||
LeftShiftU64 PROTO C Operand: QWORD, CountIn: QWORD
|
||||
RightShiftU64 PROTO C Operand: QWORD, CountIn: QWORD
|
||||
ARightShift64 PROTO C Operand: QWORD, CountIn: QWORD
|
||||
MulU64x64 PROTO C Value1: QWORD, Value2: QWORD, ResultHigh: DWORD
|
||||
MulS64x64 PROTO C Value1: QWORD, Value2: QWORD, ResultHigh: DWORD
|
||||
DivU64x64 PROTO C Dividend: QWORD, Divisor: QWORD, Remainder: DWORD, Error: DWORD
|
||||
DivS64x64 PROTO C Dividend: QWORD, Divisor: QWORD, Remainder: DWORD, Error: DWORD
|
||||
|
||||
|
||||
LeftShiftU64 PROC C Operand: QWORD, CountIn: QWORD
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; UINT64
|
||||
; LeftShiftU64 (
|
||||
; IN UINT64 Operand,
|
||||
; IN UINT64 CountIn
|
||||
; )
|
||||
;
|
||||
; Routine Description:
|
||||
;
|
||||
; Left-shift a 64-bit value.
|
||||
;
|
||||
; Arguments:
|
||||
;
|
||||
; Operand - the value to shift
|
||||
; Count - shift count
|
||||
;
|
||||
; Returns:
|
||||
;
|
||||
; Operand << Count
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
push ecx
|
||||
;
|
||||
; if (CountIn > 63) return 0;
|
||||
;
|
||||
cmp dword ptr CountIn[4], 0
|
||||
jne _LeftShiftU64_Overflow
|
||||
mov ecx, dword ptr CountIn[0]
|
||||
cmp ecx, 63
|
||||
jbe _LeftShiftU64_Calc
|
||||
|
||||
_LeftShiftU64_Overflow:
|
||||
xor eax, eax
|
||||
xor edx, edx
|
||||
jmp _LeftShiftU64_Done
|
||||
|
||||
_LeftShiftU64_Calc:
|
||||
mov eax, dword ptr Operand[0]
|
||||
mov edx, dword ptr Operand[4]
|
||||
|
||||
shld edx, eax, cl
|
||||
shl eax, cl
|
||||
cmp ecx, 32
|
||||
jc short _LeftShiftU64_Done
|
||||
|
||||
mov edx, eax
|
||||
xor eax, eax
|
||||
|
||||
_LeftShiftU64_Done:
|
||||
pop ecx
|
||||
ret
|
||||
|
||||
LeftShiftU64 ENDP
|
||||
|
||||
|
||||
RightShiftU64 PROC C Operand: QWORD, CountIn: QWORD
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; UINT64
|
||||
; RightShiftU64 (
|
||||
; IN UINT64 Operand,
|
||||
; IN UINT64 CountIn
|
||||
; )
|
||||
;
|
||||
; Routine Description:
|
||||
;
|
||||
; Right-shift an unsigned 64-bit value.
|
||||
;
|
||||
; Arguments:
|
||||
;
|
||||
; Operand - the value to shift
|
||||
; Count - shift count
|
||||
;
|
||||
; Returns:
|
||||
;
|
||||
; Operand >> Count
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
push ecx
|
||||
;
|
||||
; if (CountIn > 63) return 0;
|
||||
;
|
||||
cmp dword ptr CountIn[4], 0
|
||||
jne _RightShiftU64_Overflow
|
||||
mov ecx, dword ptr CountIn[0]
|
||||
cmp ecx, 63
|
||||
jbe _RightShiftU64_Calc
|
||||
|
||||
_RightShiftU64_Overflow:
|
||||
xor eax, eax
|
||||
xor edx, edx
|
||||
jmp _RightShiftU64_Done
|
||||
|
||||
_RightShiftU64_Calc:
|
||||
mov eax, dword ptr Operand[0]
|
||||
mov edx, dword ptr Operand[4]
|
||||
|
||||
shrd edx, eax, cl
|
||||
shr eax, cl
|
||||
cmp ecx, 32
|
||||
jc short _RightShiftU64_Done
|
||||
|
||||
mov eax, edx
|
||||
xor edx, edx
|
||||
|
||||
_RightShiftU64_Done:
|
||||
pop ecx
|
||||
ret
|
||||
|
||||
RightShiftU64 ENDP
|
||||
|
||||
|
||||
ARightShift64 PROC C Operand: QWORD, CountIn: QWORD
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; INT64
|
||||
; ARightShift64 (
|
||||
; IN INT64 Operand,
|
||||
; IN UINT64 CountIn
|
||||
; )
|
||||
;
|
||||
; Routine Description:
|
||||
;
|
||||
; Arithmatic shift a 64 bit signed value.
|
||||
;
|
||||
; Arguments:
|
||||
;
|
||||
; Operand - the value to shift
|
||||
; Count - shift count
|
||||
;
|
||||
; Returns:
|
||||
;
|
||||
; Operand >> Count
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
push ecx
|
||||
;
|
||||
; If they exceeded the max shift count, then return either 0 or all F's
|
||||
; depending on the sign bit.
|
||||
;
|
||||
cmp dword ptr CountIn[4], 0
|
||||
jne _ARightShiftU64_Overflow
|
||||
mov ecx, dword ptr CountIn[0]
|
||||
cmp ecx, 63
|
||||
jbe _ARightShiftU64_Calc
|
||||
|
||||
_ARightShiftU64_Overflow:
|
||||
;
|
||||
; Check the sign bit of Operand
|
||||
;
|
||||
bt dword ptr Operand[4], 31
|
||||
jnc _ARightShiftU64_Return_Zero
|
||||
;
|
||||
; return -1
|
||||
;
|
||||
or eax, 0FFFFFFFFh
|
||||
or edx, 0FFFFFFFFh
|
||||
jmp _ARightShiftU64_Done
|
||||
|
||||
_ARightShiftU64_Return_Zero:
|
||||
xor eax, eax
|
||||
xor edx, edx
|
||||
jmp _ARightShiftU64_Done
|
||||
|
||||
_ARightShiftU64_Calc:
|
||||
mov eax, dword ptr Operand[0]
|
||||
mov edx, dword ptr Operand[4]
|
||||
|
||||
shrd eax, edx, cl
|
||||
sar edx, cl
|
||||
cmp ecx, 32
|
||||
jc short _ARightShiftU64_Done
|
||||
|
||||
;
|
||||
; if ecx >= 32, then eax = edx, and edx = sign bit
|
||||
;
|
||||
mov eax, edx
|
||||
sar edx, 31
|
||||
|
||||
_ARightShiftU64_Done:
|
||||
pop ecx
|
||||
ret
|
||||
|
||||
ARightShift64 ENDP
|
||||
|
||||
|
||||
MulU64x64 PROC C Value1: QWORD, Value2: QWORD, ResultHigh: DWORD
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; UINT64
|
||||
; MulU64x64 (
|
||||
; UINT64 Value1,
|
||||
; UINT64 Value2,
|
||||
; UINT64 *ResultHigh
|
||||
; )
|
||||
;
|
||||
; Routine Description:
|
||||
;
|
||||
; Multiply two unsigned 64-bit values.
|
||||
;
|
||||
; Arguments:
|
||||
;
|
||||
; Value1 - first value to multiply
|
||||
; Value2 - value to multiply by Value1
|
||||
; ResultHigh - result to flag overflows
|
||||
;
|
||||
; Returns:
|
||||
;
|
||||
; Value1 * Value2
|
||||
; The 128-bit result is the concatenation of *ResultHigh and the return value
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
push ebx
|
||||
push ecx
|
||||
mov ebx, ResultHigh ; ebx points to the high 4 words of result
|
||||
;
|
||||
; The result consists of four double-words.
|
||||
; Here we assume their names from low to high: dw0, dw1, dw2, dw3
|
||||
;
|
||||
mov eax, dword ptr Value1[0]
|
||||
mul dword ptr Value2[0]
|
||||
push eax ; eax contains final result of dw0, push it
|
||||
mov ecx, edx ; ecx contains partial result of dw1
|
||||
|
||||
mov eax, dword ptr Value1[4]
|
||||
mul dword ptr Value2[0]
|
||||
add ecx, eax ; add eax to partial result of dw1
|
||||
adc edx, 0
|
||||
mov dword ptr [ebx], edx ; lower double-word of ResultHigh contains partial result of dw2
|
||||
|
||||
mov eax, dword ptr Value1[0]
|
||||
mul dword ptr Value2[4]
|
||||
add ecx, eax ; add eax to partial result of dw1
|
||||
push ecx ; ecx contains final result of dw1, push it
|
||||
adc edx, 0
|
||||
mov ecx, edx ; ecx contains partial result of dw2, together with ResultHigh
|
||||
|
||||
mov eax, dword ptr Value1[4]
|
||||
mul dword ptr Value2[4]
|
||||
add ecx, eax ; add eax to partial result of dw2
|
||||
adc edx, 0
|
||||
add dword ptr [ebx], ecx ; lower double-word of ResultHigh contains final result of dw2
|
||||
adc edx, 0
|
||||
mov dword ptr [ebx + 4], edx ; high double-word of ResultHigh contains final result of dw3
|
||||
|
||||
pop edx ; edx contains the final result of dw1
|
||||
pop eax ; edx contains the final result of dw0
|
||||
pop ecx
|
||||
pop ebx
|
||||
ret
|
||||
|
||||
MulU64x64 ENDP
|
||||
|
||||
|
||||
MulS64x64 PROC C Value1: QWORD, Value2: QWORD, ResultHigh: DWORD
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; INT64
|
||||
; MulS64x64 (
|
||||
; INT64 Value1,
|
||||
; INT64 Value2,
|
||||
; INT64 *ResultHigh
|
||||
; )
|
||||
;
|
||||
; Routine Description:
|
||||
;
|
||||
; Multiply two signed 64-bit values.
|
||||
;
|
||||
; Arguments:
|
||||
;
|
||||
; Value1 - first value to multiply
|
||||
; Value2 - value to multiply by Value1
|
||||
; ResultHigh - result to flag overflows
|
||||
;
|
||||
; Returns:
|
||||
;
|
||||
; Value1 * Value2
|
||||
; The 128-bit result is the concatenation of *ResultHigh and the return value
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
push ebx
|
||||
push ecx
|
||||
mov ebx, ResultHigh ; ebx points to the high 4 words of result
|
||||
xor ecx, ecx ; the lowest bit of ecx flags the sign
|
||||
|
||||
mov edx, dword ptr Value1[4]
|
||||
bt edx, 31
|
||||
jnc short _MulS64x64_A_Positive
|
||||
;
|
||||
; a is negative
|
||||
;
|
||||
mov eax, dword ptr Value1[0]
|
||||
not edx
|
||||
not eax
|
||||
add eax, 1
|
||||
adc edx, 0
|
||||
mov dword ptr Value1[0], eax
|
||||
mov dword ptr Value1[4], edx
|
||||
btc ecx, 0
|
||||
|
||||
_MulS64x64_A_Positive:
|
||||
mov edx, dword ptr Value2[4]
|
||||
bt edx, 31
|
||||
jnc short _MulS64x64_B_Positive
|
||||
;
|
||||
; b is negative
|
||||
;
|
||||
mov eax, dword ptr Value2[0]
|
||||
not edx
|
||||
not eax
|
||||
add eax, 1
|
||||
adc edx, 0
|
||||
mov dword ptr Value2[0], eax
|
||||
mov dword ptr Value2[4], edx
|
||||
btc ecx, 0
|
||||
|
||||
_MulS64x64_B_Positive:
|
||||
invoke MulU64x64, Value1, Value2, ResultHigh
|
||||
bt ecx, 0
|
||||
jnc short _MulS64x64_Done
|
||||
;
|
||||
;negate the result
|
||||
;
|
||||
not eax
|
||||
not edx
|
||||
not dword ptr [ebx]
|
||||
not dword ptr [ebx + 4]
|
||||
add eax, 1
|
||||
adc edx, 0
|
||||
adc dword ptr [ebx], 0
|
||||
adc dword ptr [ebx + 4], 0
|
||||
|
||||
_MulS64x64_Done:
|
||||
pop ecx
|
||||
pop ebx
|
||||
ret
|
||||
|
||||
MulS64x64 ENDP
|
||||
|
||||
|
||||
DivU64x64 PROC C Dividend: QWORD, Divisor: QWORD, Remainder: DWORD, Error: DWORD,
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; UINT64
|
||||
; DivU64x64 (
|
||||
; IN UINT64 Dividend,
|
||||
; IN UINT64 Divisor,
|
||||
; OUT UINT64 *Remainder OPTIONAL,
|
||||
; OUT UINT32 *Error
|
||||
; )
|
||||
;
|
||||
; Routine Description:
|
||||
;
|
||||
; This routine allows a 64 bit value to be divided with a 64 bit value returns
|
||||
; 64bit result and the Remainder
|
||||
;
|
||||
; Arguments:
|
||||
;
|
||||
; Dividend - dividend
|
||||
; Divisor - divisor
|
||||
; ResultHigh - result to flag overflows
|
||||
; Error - flag for error
|
||||
;
|
||||
; Returns:
|
||||
;
|
||||
; Dividend / Divisor
|
||||
; Remainder = Dividend mod Divisor
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
push ecx
|
||||
|
||||
mov eax, Error
|
||||
mov dword ptr [eax], 0
|
||||
|
||||
cmp dword ptr Divisor[0], 0
|
||||
jne _DivU64x64_Valid
|
||||
cmp dword ptr Divisor[4], 0
|
||||
jne _DivU64x64_Valid
|
||||
;
|
||||
; the divisor is zero
|
||||
;
|
||||
mov dword ptr [eax], 1
|
||||
cmp Remainder, 0
|
||||
je _DivU64x64_Invalid_Return
|
||||
;
|
||||
; fill the remainder if the pointer is not null
|
||||
;
|
||||
mov eax, Remainder
|
||||
mov dword ptr [eax], 0
|
||||
mov dword ptr [eax + 4], 80000000h
|
||||
|
||||
_DivU64x64_Invalid_Return:
|
||||
xor eax, eax
|
||||
mov edx, 80000000h
|
||||
jmp _DivU64x64_Done
|
||||
|
||||
_DivU64x64_Valid:
|
||||
;
|
||||
; let edx and eax contain the intermediate result of remainder
|
||||
;
|
||||
xor edx, edx
|
||||
xor eax, eax
|
||||
mov ecx, 64
|
||||
|
||||
_DivU64x64_Wend:
|
||||
;
|
||||
; shift dividend left one
|
||||
;
|
||||
shl dword ptr Dividend[0], 1
|
||||
rcl dword ptr Dividend[4], 1
|
||||
;
|
||||
; rotate intermediate result of remainder left one
|
||||
;
|
||||
rcl eax, 1
|
||||
rcl edx, 1
|
||||
|
||||
cmp edx, dword ptr Divisor[4]
|
||||
ja _DivU64x64_Sub_Divisor
|
||||
jb _DivU64x64_Cont
|
||||
cmp eax, dword ptr Divisor[0]
|
||||
jb _DivU64x64_Cont
|
||||
|
||||
_DivU64x64_Sub_Divisor:
|
||||
;
|
||||
; If intermediate result of remainder is larger than
|
||||
; or equal to divisor, then set the lowest bit of dividend,
|
||||
; and subtract divisor from intermediate remainder
|
||||
;
|
||||
bts dword ptr Dividend[0], 0
|
||||
sub eax, dword ptr Divisor[0]
|
||||
sbb edx, dword ptr Divisor[4]
|
||||
|
||||
_DivU64x64_Cont:
|
||||
loop _DivU64x64_Wend
|
||||
|
||||
cmp Remainder, 0
|
||||
je _DivU64x64_Assign
|
||||
mov ecx, Remainder
|
||||
mov dword ptr [ecx], eax
|
||||
mov dword ptr [ecx + 4], edx
|
||||
|
||||
_DivU64x64_Assign:
|
||||
mov eax, dword ptr Dividend[0]
|
||||
mov edx, dword ptr Dividend[4]
|
||||
|
||||
_DivU64x64_Done:
|
||||
pop ecx
|
||||
ret
|
||||
|
||||
DivU64x64 ENDP
|
||||
|
||||
DivS64x64 PROC C Dividend: QWORD, Divisor: QWORD, Remainder: DWORD, Error: DWORD,
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; INT64
|
||||
; DivU64x64 (
|
||||
; IN INT64 Dividend,
|
||||
; IN INT64 Divisor,
|
||||
; OUT UINT64 *Remainder OPTIONAL,
|
||||
; OUT UINT32 *Error
|
||||
; )
|
||||
;
|
||||
; Routine Description:
|
||||
;
|
||||
; This routine allows a 64 bit signed value to be divided with a 64 bit
|
||||
; signed value returns 64bit result and the Remainder.
|
||||
;
|
||||
; Arguments:
|
||||
;
|
||||
; Dividend - dividend
|
||||
; Divisor - divisor
|
||||
; ResultHigh - result to flag overflows
|
||||
; Error - flag for error
|
||||
;
|
||||
; Returns:
|
||||
;
|
||||
; Dividend / Divisor
|
||||
; Remainder = Dividend mod Divisor
|
||||
;------------------------------------------------------------------------------
|
||||
|
||||
push ecx
|
||||
|
||||
mov eax, Error
|
||||
mov dword ptr [eax], 0
|
||||
|
||||
cmp dword ptr Divisor[0], 0
|
||||
jne _DivS64x64_Valid
|
||||
cmp dword ptr Divisor[4], 0
|
||||
jne _DivS64x64_Valid
|
||||
;
|
||||
; the divisor is zero
|
||||
;
|
||||
mov dword ptr [eax], 1
|
||||
cmp Remainder, 0
|
||||
je _DivS64x64_Invalid_Return
|
||||
;
|
||||
; fill the remainder if the pointer is not null
|
||||
;
|
||||
mov eax, Remainder
|
||||
mov dword ptr [eax], 0
|
||||
mov dword ptr [eax + 4], 80000000h
|
||||
|
||||
_DivS64x64_Invalid_Return:
|
||||
xor eax, eax
|
||||
mov edx, 80000000h
|
||||
jmp _DivS64x64_Done
|
||||
|
||||
_DivS64x64_Valid:
|
||||
;
|
||||
; The lowest bit of ecx flags the sign of quotient,
|
||||
; The seconde lowest bit flags the sign of remainder
|
||||
;
|
||||
xor ecx, ecx
|
||||
|
||||
mov edx, dword ptr Dividend[4]
|
||||
bt edx, 31
|
||||
jnc short _DivS64x64_Dividend_Positive
|
||||
;
|
||||
; dividend is negative
|
||||
;
|
||||
mov eax, dword ptr Dividend[0]
|
||||
not edx
|
||||
not eax
|
||||
add eax, 1
|
||||
adc edx, 0
|
||||
mov dword ptr Dividend[0], eax
|
||||
mov dword ptr Dividend[4], edx
|
||||
;
|
||||
; set both the flags for signs of quotient and remainder
|
||||
;
|
||||
btc ecx, 0
|
||||
btc ecx, 1
|
||||
|
||||
_DivS64x64_Dividend_Positive:
|
||||
mov edx, dword ptr Divisor[4]
|
||||
bt edx, 31
|
||||
jnc short _DivS64x64_Divisor_Positive
|
||||
;
|
||||
; divisor is negative
|
||||
;
|
||||
mov eax, dword ptr Divisor[0]
|
||||
not edx
|
||||
not eax
|
||||
add eax, 1
|
||||
adc edx, 0
|
||||
mov dword ptr Divisor[0], eax
|
||||
mov dword ptr Divisor[4], edx
|
||||
;
|
||||
; just complement the flag for sign of quotient
|
||||
;
|
||||
btc ecx, 0
|
||||
|
||||
_DivS64x64_Divisor_Positive:
|
||||
invoke DivU64x64, Dividend, Divisor, Remainder, Error
|
||||
bt ecx, 0
|
||||
jnc short _DivS64x64_Remainder
|
||||
;
|
||||
; negate the quotient
|
||||
;
|
||||
not eax
|
||||
not edx
|
||||
add eax, 1
|
||||
adc edx, 0
|
||||
|
||||
_DivS64x64_Remainder:
|
||||
bt ecx, 1
|
||||
jnc short _DivS64x64_Done
|
||||
;
|
||||
; negate the remainder
|
||||
;
|
||||
mov ecx, remainder
|
||||
not dword ptr [ecx]
|
||||
not dword ptr [ecx + 4]
|
||||
add dword ptr [ecx], 1
|
||||
adc dword ptr [ecx + 4], 0
|
||||
|
||||
_DivS64x64_Done:
|
||||
pop ecx
|
||||
ret
|
||||
|
||||
DivS64x64 ENDP
|
||||
|
||||
END
|
167
EdkModulePkg/Universal/Ebc/Dxe/Ipf/EbcLowLevel.s
Normal file
167
EdkModulePkg/Universal/Ebc/Dxe/Ipf/EbcLowLevel.s
Normal file
@@ -0,0 +1,167 @@
|
||||
//++
|
||||
// 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;;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//++
|
||||
// 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)
|
||||
|
||||
//
|
||||
// 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)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
906
EdkModulePkg/Universal/Ebc/Dxe/Ipf/EbcSupport.c
Normal file
906
EdkModulePkg/Universal/Ebc/Dxe/Ipf/EbcSupport.c
Normal file
@@ -0,0 +1,906 @@
|
||||
/*++
|
||||
|
||||
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"
|
||||
|
||||
#define VM_STACK_SIZE (1024 * 32)
|
||||
|
||||
#define EBC_THUNK_SIZE 128
|
||||
|
||||
//
|
||||
// For code execution, thunks must be aligned on 16-byte boundary
|
||||
//
|
||||
#define EBC_THUNK_ALIGNMENT 16
|
||||
|
||||
//
|
||||
// Per the IA-64 Software Conventions and Runtime Architecture Guide,
|
||||
// section 3.3.4, IPF stack must always be 16-byte aligned.
|
||||
//
|
||||
#define IPF_STACK_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
|
||||
);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
UINT64
|
||||
EbcInterpret (
|
||||
UINT64 Arg1,
|
||||
...
|
||||
)
|
||||
{
|
||||
//
|
||||
// Create a new VM context on the stack
|
||||
//
|
||||
VM_CONTEXT VmContext;
|
||||
UINTN Addr;
|
||||
VA_LIST List;
|
||||
UINT64 Arg2;
|
||||
UINT64 Arg3;
|
||||
UINT64 Arg4;
|
||||
UINT64 Arg5;
|
||||
UINT64 Arg6;
|
||||
UINT64 Arg7;
|
||||
UINT64 Arg8;
|
||||
UINTN Arg9Addr;
|
||||
//
|
||||
// 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);
|
||||
Arg9Addr = (UINTN) List;
|
||||
//
|
||||
// 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 = (UINTN) Arg9Addr;
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
VmContext.HighStackBottom = (UINTN) Addr;
|
||||
//
|
||||
// Now adjust the EBC stack pointer down to leave a gap for interpreter
|
||||
// execution. Then stuff a magic value there.
|
||||
//
|
||||
VmContext.R[0] = (UINT64) Addr;
|
||||
VmContext.R[0] -= VM_STACK_SIZE;
|
||||
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, 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
|
||||
//
|
||||
return (UINT64) VmContext.R[7];
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
//
|
||||
// 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 ();
|
||||
VmContext.HighStackBottom = (UINTN) Addr;
|
||||
VmContext.R[0] = (INT64) Addr;
|
||||
|
||||
//
|
||||
// Allocate stack space for the interpreter. Then put a magic value
|
||||
// at the bottom so we can detect stack corruption.
|
||||
//
|
||||
VmContext.R[0] -= VM_STACK_SIZE;
|
||||
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
|
||||
//
|
||||
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;
|
||||
EFI_STATUS Status;
|
||||
|
||||
//
|
||||
// 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;
|
||||
Status = gBS->AllocatePool (
|
||||
EfiBootServicesData,
|
||||
Size,
|
||||
(VOID *) &Ptr
|
||||
);
|
||||
if (Status != EFI_SUCCESS) {
|
||||
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] = RightShiftU64 (Addr, 22) & 0x1ffffffffff;
|
||||
|
||||
//
|
||||
// Extract bits from the address for insertion into the instruction
|
||||
// i = Addr[63:63]
|
||||
//
|
||||
I = RightShiftU64 (Addr, 63) & 0x01;
|
||||
//
|
||||
// ic = Addr[21:21]
|
||||
//
|
||||
Ic = RightShiftU64 (Addr, 21) & 0x01;
|
||||
//
|
||||
// imm5c = Addr[20:16] for 5 bits
|
||||
//
|
||||
Imm5c = RightShiftU64 (Addr, 16) & 0x1F;
|
||||
//
|
||||
// imm9d = Addr[15:7] for 9 bits
|
||||
//
|
||||
Imm9d = RightShiftU64 (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] = LeftShiftU64 (Imm7b, 13)
|
||||
| LeftShiftU64 (0x00, 20) // vc
|
||||
| LeftShiftU64 (Ic, 21)
|
||||
| LeftShiftU64 (Imm5c, 22)
|
||||
| LeftShiftU64 (Imm9d, 27)
|
||||
| LeftShiftU64 (I, 36)
|
||||
| LeftShiftU64 ((UINT64)MOVL_OPCODE, 37)
|
||||
| LeftShiftU64 ((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] = RightShiftU64 (Addr, 22) & 0x1ffffffffff;
|
||||
|
||||
//
|
||||
// Extract bits from the address for insertion into the instruction
|
||||
// i = Addr[63:63]
|
||||
//
|
||||
I = RightShiftU64 (Addr, 63) & 0x01;
|
||||
//
|
||||
// ic = Addr[21:21]
|
||||
//
|
||||
Ic = RightShiftU64 (Addr, 21) & 0x01;
|
||||
//
|
||||
// imm5c = Addr[20:16] for 5 bits
|
||||
//
|
||||
Imm5c = RightShiftU64 (Addr, 16) & 0x1F;
|
||||
//
|
||||
// imm9d = Addr[15:7] for 9 bits
|
||||
//
|
||||
Imm9d = RightShiftU64 (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] = LeftShiftU64 (Imm7b, 13)
|
||||
| LeftShiftU64 (0x00, 20) // vc
|
||||
| LeftShiftU64 (Ic, 21)
|
||||
| LeftShiftU64 (Imm5c, 22)
|
||||
| LeftShiftU64 (Imm9d, 27)
|
||||
| LeftShiftU64 (I, 36)
|
||||
| LeftShiftU64 ((UINT64)MOVL_OPCODE, 37)
|
||||
| LeftShiftU64 ((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] = RightShiftU64 (Addr, 22) & 0x1ffffffffff;
|
||||
|
||||
//
|
||||
// Extract bits from the address for insertion into the instruction
|
||||
// i = Addr[63:63]
|
||||
//
|
||||
I = RightShiftU64 (Addr, 63) & 0x01;
|
||||
//
|
||||
// ic = Addr[21:21]
|
||||
//
|
||||
Ic = RightShiftU64 (Addr, 21) & 0x01;
|
||||
//
|
||||
// imm5c = Addr[20:16] for 5 bits
|
||||
//
|
||||
Imm5c = RightShiftU64 (Addr, 16) & 0x1F;
|
||||
//
|
||||
// imm9d = Addr[15:7] for 9 bits
|
||||
//
|
||||
Imm9d = RightShiftU64 (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] = LeftShiftU64(Imm7b, 13)
|
||||
| LeftShiftU64 (0x00, 20) // vc
|
||||
| LeftShiftU64 (Ic, 21)
|
||||
| LeftShiftU64 (Imm5c, 22)
|
||||
| LeftShiftU64 (Imm9d, 27)
|
||||
| LeftShiftU64 (I, 36)
|
||||
| LeftShiftU64 ((UINT64)MOVL_OPCODE, 37)
|
||||
| LeftShiftU64 ((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] |= LeftShiftU64 (Br, 6);
|
||||
Code[2] |= LeftShiftU64 (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] |= LeftShiftU64 (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 = LeftShiftU64 (Slot1, 46) | LeftShiftU64 (Slot0, 5) | Template;
|
||||
High64 = RightShiftU64 (Slot1, 18) | LeftShiftU64 (Slot2, 23);
|
||||
|
||||
//
|
||||
// Now write it all out
|
||||
//
|
||||
BPtr = (UINT8 *) MemPtr;
|
||||
for (Index = 0; Index < 8; Index++) {
|
||||
*BPtr = (UINT8) Low64;
|
||||
Low64 = RightShiftU64 (Low64, 8);
|
||||
BPtr++;
|
||||
}
|
||||
|
||||
for (Index = 0; Index < 8; Index++) {
|
||||
*BPtr = (UINT8) High64;
|
||||
High64 = RightShiftU64 (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 = RightShiftU64 (*((UINT64 *)CalleeAddr + 2), 46) & 0x3FFFF;
|
||||
CodeOne23 = (*((UINT64 *)CalleeAddr + 3)) & 0x7FFFFF;
|
||||
CodeTwoI = RightShiftU64 (*((UINT64 *)CalleeAddr + 3), 59) & 0x1;
|
||||
CodeTwoIc = RightShiftU64 (*((UINT64 *)CalleeAddr + 3), 44) & 0x1;
|
||||
CodeTwo7b = RightShiftU64 (*((UINT64 *)CalleeAddr + 3), 36) & 0x7F;
|
||||
CodeTwo5c = RightShiftU64 (*((UINT64 *)CalleeAddr + 3), 45) & 0x1F;
|
||||
CodeTwo9d = RightShiftU64 (*((UINT64 *)CalleeAddr + 3), 50) & 0x1FF;
|
||||
|
||||
TargetEbcAddr = CodeTwo7b
|
||||
| LeftShiftU64 (CodeTwo9d, 7)
|
||||
| LeftShiftU64 (CodeTwo5c, 16)
|
||||
| LeftShiftU64 (CodeTwoIc, 21)
|
||||
| LeftShiftU64 (CodeOne18, 22)
|
||||
| LeftShiftU64 (CodeOne23, 40)
|
||||
| LeftShiftU64 (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;
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
EbcLLCALLEXNative (
|
||||
IN UINTN CallAddr,
|
||||
IN UINTN EbcSp,
|
||||
IN VOID *FramePtr
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
Implements the EBC CALLEX instruction to call an external function, which
|
||||
seems to be native code.
|
||||
|
||||
We'll copy the entire EBC stack frame down below itself in memory and use
|
||||
that copy for passing parameters.
|
||||
|
||||
Arguments:
|
||||
CallAddr - address (function pointer) of function to call
|
||||
EbcSp - current EBC stack pointer
|
||||
FramePtr - current EBC frame pointer.
|
||||
|
||||
Returns:
|
||||
NA
|
||||
|
||||
--*/
|
||||
{
|
||||
UINTN FrameSize;
|
||||
VOID *Destination;
|
||||
VOID *Source;
|
||||
//
|
||||
// The stack for an EBC function looks like this:
|
||||
// FramePtr (8)
|
||||
// RetAddr (8)
|
||||
// Locals (n)
|
||||
// Stack for passing args (m)
|
||||
//
|
||||
// Pad the frame size with 64 bytes because the low-level code we call
|
||||
// will move the stack pointer up assuming worst-case 8 args in registers.
|
||||
//
|
||||
FrameSize = (UINTN) FramePtr - (UINTN) EbcSp + 64;
|
||||
Source = (VOID *) EbcSp;
|
||||
Destination = (VOID *) ((UINT8 *) EbcSp - FrameSize - IPF_STACK_ALIGNMENT);
|
||||
Destination = (VOID *) ((UINTN) ((UINTN) Destination + IPF_STACK_ALIGNMENT - 1) &~((UINTN) IPF_STACK_ALIGNMENT - 1));
|
||||
gBS->CopyMem (Destination, Source, FrameSize);
|
||||
EbcAsmLLCALLEX ((UINTN) CallAddr, (UINTN) Destination);
|
||||
}
|
375
EdkModulePkg/Universal/Ebc/Dxe/Ipf/IpfMath.c
Normal file
375
EdkModulePkg/Universal/Ebc/Dxe/Ipf/IpfMath.c
Normal file
@@ -0,0 +1,375 @@
|
||||
/*++
|
||||
|
||||
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:
|
||||
|
||||
Ipfmath.c
|
||||
|
||||
Abstract:
|
||||
|
||||
Math routines for IPF.
|
||||
|
||||
--*/
|
||||
|
||||
UINT64
|
||||
LeftShiftU64 (
|
||||
IN UINT64 Operand,
|
||||
IN UINT64 Count
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Left-shift a 64 bit value.
|
||||
|
||||
Arguments:
|
||||
|
||||
Operand - 64-bit value to shift
|
||||
Count - shift count
|
||||
|
||||
Returns:
|
||||
|
||||
Operand << Count
|
||||
|
||||
--*/
|
||||
{
|
||||
if (Count > 63) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Operand << Count;
|
||||
}
|
||||
|
||||
UINT64
|
||||
RightShiftU64 (
|
||||
IN UINT64 Operand,
|
||||
IN UINT64 Count
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Right-shift a 64 bit value.
|
||||
|
||||
Arguments:
|
||||
|
||||
Operand - 64-bit value to shift
|
||||
Count - shift count
|
||||
|
||||
Returns:
|
||||
|
||||
Operand >> Count
|
||||
|
||||
--*/
|
||||
{
|
||||
if (Count > 63) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Operand >> Count;
|
||||
}
|
||||
|
||||
INT64
|
||||
ARightShift64 (
|
||||
IN INT64 Operand,
|
||||
IN UINT64 Count
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Right-shift a 64 bit signed value.
|
||||
|
||||
Arguments:
|
||||
|
||||
Operand - 64-bit value to shift
|
||||
Count - shift count
|
||||
|
||||
Returns:
|
||||
|
||||
Operand >> Count
|
||||
|
||||
--*/
|
||||
{
|
||||
if (Count > 63) {
|
||||
|
||||
if (Operand & (0x01 << 63)) {
|
||||
return (INT64)~0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Operand >> Count;
|
||||
}
|
||||
|
||||
#if 0
|
||||
//
|
||||
// The compiler generates true assembly for these, so we don't need them.
|
||||
//
|
||||
INT32
|
||||
ARightShift32 (
|
||||
IN INT32 Operand,
|
||||
IN UINTN Count
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Right shift a 32-bit value
|
||||
|
||||
Arguments:
|
||||
|
||||
Operand - value to shift
|
||||
Count - shift count
|
||||
|
||||
Returns:
|
||||
|
||||
Operand >> Count
|
||||
|
||||
--*/
|
||||
{
|
||||
return Operand >> (Count & 0x1f);
|
||||
}
|
||||
|
||||
INT32
|
||||
MulS32x32 (
|
||||
INT32 Value1,
|
||||
INT32 Value2,
|
||||
INT32 *ResultHigh
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Multiply two signed 32-bit numbers.
|
||||
|
||||
Arguments:
|
||||
|
||||
Value1 - first value to multiply
|
||||
Value2 - value to multiply Value1 by
|
||||
ResultHigh - overflow
|
||||
|
||||
Returns:
|
||||
|
||||
Value1 * Value2
|
||||
|
||||
Notes:
|
||||
|
||||
The 64-bit result is the concatenation of *ResultHigh and the return value
|
||||
|
||||
The product fits in 32 bits if
|
||||
(*ResultHigh == 0x00000000 AND *ResultLow_bit31 == 0)
|
||||
OR
|
||||
(*ResultHigh == 0xffffffff AND *ResultLow_bit31 == 1)
|
||||
|
||||
--*/
|
||||
{
|
||||
INT64 Rres64;
|
||||
INT32 Result;
|
||||
|
||||
Res64 = (INT64) Value1 * (INT64) Value2;
|
||||
*ResultHigh = (Res64 >> 32) & 0xffffffff;
|
||||
Result = Res64 & 0xffffffff;
|
||||
return Result;
|
||||
}
|
||||
|
||||
UINT32
|
||||
MulU32x32 (
|
||||
UINT32 Value1,
|
||||
UINT32 Value2,
|
||||
UINT32 *ResultHigh
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Multiply two unsigned 32-bit values.
|
||||
|
||||
Arguments:
|
||||
|
||||
Value1 - first number
|
||||
Value2 - number to multiply by Value1
|
||||
ResultHigh - overflow
|
||||
|
||||
Returns:
|
||||
|
||||
Value1 * Value2
|
||||
|
||||
Notes:
|
||||
|
||||
The 64-bit result is the concatenation of *ResultHigh and the return value.
|
||||
The product fits in 32 bits if *ResultHigh == 0x00000000
|
||||
|
||||
--*/
|
||||
{
|
||||
UINT64 Res64;
|
||||
UINT32 Result;
|
||||
|
||||
Res64 = (INT64) Value1 * (INT64) Value2;
|
||||
*ResultHigh = (Res64 >> 32) & 0xffffffff;
|
||||
Result = Res64 & 0xffffffff;
|
||||
return Result;
|
||||
}
|
||||
|
||||
INT32
|
||||
DivS32x32 (
|
||||
INT32 Value1,
|
||||
INT32 Value2,
|
||||
INT32 *Remainder,
|
||||
UINTN *error
|
||||
)
|
||||
//
|
||||
// signed 32-bit by signed 32-bit divide; the 32-bit remainder is
|
||||
// in *Remainder and the quotient is the return value; *error = 1 if the
|
||||
// divisor is 0, and it is 1 otherwise
|
||||
//
|
||||
{
|
||||
INT32 Result;
|
||||
|
||||
*error = 0;
|
||||
|
||||
if (Value2 == 0x0) {
|
||||
*error = 1;
|
||||
Result = 0x80000000;
|
||||
*Remainder = 0x80000000;
|
||||
} else {
|
||||
Result = Value1 / Value2;
|
||||
*Remainder = Value1 - Result * Value2;
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
UINT32
|
||||
DivU32x32 (
|
||||
UINT32 Value1,
|
||||
UINT32 Value2,
|
||||
UINT32 *Remainder,
|
||||
UINTN *Error
|
||||
)
|
||||
//
|
||||
// unsigned 32-bit by unsigned 32-bit divide; the 32-bit remainder is
|
||||
// in *Remainder and the quotient is the return value; *error = 1 if the
|
||||
// divisor is 0, and it is 1 otherwise
|
||||
//
|
||||
{
|
||||
UINT32 Result;
|
||||
|
||||
*Error = 0;
|
||||
|
||||
if (Value2 == 0x0) {
|
||||
*Error = 1;
|
||||
Result = 0x80000000;
|
||||
*Remainder = 0x80000000;
|
||||
} else {
|
||||
Result = Value1 / Value2;
|
||||
*Remainder = Value1 - Result * Value2;
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
INT64
|
||||
DivS64x64 (
|
||||
INT64 Value1,
|
||||
INT64 Value2,
|
||||
INT64 *Remainder,
|
||||
UINTN *Error
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Divide two 64-bit signed values.
|
||||
|
||||
Arguments:
|
||||
|
||||
Value1 - dividend
|
||||
Value2 - divisor
|
||||
Remainder - remainder of Value1/Value2
|
||||
Error - to flag errors (divide-by-0)
|
||||
|
||||
Returns:
|
||||
|
||||
Value1 / Valu2
|
||||
|
||||
Note:
|
||||
|
||||
The 64-bit remainder is in *Remainder and the quotient is the return value.
|
||||
*Error = 1 if the divisor is 0, and it is 1 otherwise
|
||||
|
||||
--*/
|
||||
{
|
||||
INT64 Result;
|
||||
|
||||
*Error = 0;
|
||||
|
||||
if (Value2 == 0x0) {
|
||||
*Error = 1;
|
||||
Result = 0x8000000000000000;
|
||||
*Remainder = 0x8000000000000000;
|
||||
} else {
|
||||
Result = Value1 / Value2;
|
||||
*Remainder = Value1 - Result * Value2;
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
UINT64
|
||||
DivU64x64 (
|
||||
UINT64 Value1,
|
||||
UINT64 Value2,
|
||||
UINT64 *Remainder,
|
||||
UINTN *Error
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Divide two 64-bit unsigned values.
|
||||
|
||||
Arguments:
|
||||
|
||||
Value1 - dividend
|
||||
Value2 - divisor
|
||||
Remainder - remainder of Value1/Value2
|
||||
Error - to flag errors (divide-by-0)
|
||||
|
||||
Returns:
|
||||
|
||||
Value1 / Valu2
|
||||
|
||||
Note:
|
||||
|
||||
The 64-bit remainder is in *Remainder and the quotient is the return value.
|
||||
*Error = 1 if the divisor is 0, and it is 1 otherwise
|
||||
|
||||
--*/
|
||||
{
|
||||
UINT64 Result;
|
||||
|
||||
*Error = 0;
|
||||
|
||||
if (Value2 == 0x0) {
|
||||
*Error = 1;
|
||||
Result = 0x8000000000000000;
|
||||
*Remainder = 0x8000000000000000;
|
||||
} else {
|
||||
Result = Value1 / Value2;
|
||||
*Remainder = Value1 - Result * Value2;
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
144
EdkModulePkg/Universal/Ebc/Dxe/Ipf/IpfMul.s
Normal file
144
EdkModulePkg/Universal/Ebc/Dxe/Ipf/IpfMul.s
Normal file
@@ -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.
|
||||
//
|
||||
//Module Name:
|
||||
//
|
||||
// IpfMul.s
|
||||
//
|
||||
//Abstract:
|
||||
//
|
||||
// Low level routines for IPF multiply support
|
||||
//
|
||||
//--*/
|
||||
|
||||
.file "IpfMul.s"
|
||||
.section .text
|
||||
|
||||
.proc MulS64x64#
|
||||
.align 32
|
||||
.global MulS64x64#
|
||||
.align 32
|
||||
|
||||
///*++
|
||||
//
|
||||
//Routine Description:
|
||||
//
|
||||
// Multiply two 64-bit signed numbers.
|
||||
//
|
||||
//
|
||||
//Arguments:
|
||||
//
|
||||
// INT64
|
||||
// MulS64x64 (
|
||||
// IN INT64 Value1,
|
||||
// IN INT64 Value2,
|
||||
// OUT INT64 *ResultHigh);
|
||||
//
|
||||
//Returns:
|
||||
//
|
||||
// 64-bit signed result
|
||||
//
|
||||
//--*/
|
||||
|
||||
MulS64x64:
|
||||
// signed 64x64->128-bit multiply
|
||||
// A in r32, B in r33, Q_hi stored in [r34], Q_lo returned in r8
|
||||
{ .mfi
|
||||
alloc r31=ar.pfs,3,0,0,0 // r32-r34
|
||||
nop.f 0
|
||||
nop.i 0;;
|
||||
}
|
||||
{.mmi
|
||||
setf.sig f6=r32
|
||||
setf.sig f7=r33
|
||||
nop.i 0;;
|
||||
}
|
||||
|
||||
{.mfi
|
||||
nop.m 0
|
||||
xma.h f8=f6,f7,f0
|
||||
nop.i 0
|
||||
}
|
||||
{.mfi
|
||||
nop.m 0
|
||||
xma.l f6=f6,f7,f0
|
||||
nop.i 0;;
|
||||
}
|
||||
|
||||
|
||||
{.mmb
|
||||
stf8 [r34]=f8
|
||||
getf.sig r8=f6
|
||||
br.ret.sptk b0;;
|
||||
}
|
||||
|
||||
.endp MulS64x64
|
||||
|
||||
.proc MulU64x64#
|
||||
.align 32
|
||||
.global MulU64x64#
|
||||
.align 32
|
||||
|
||||
|
||||
///*++
|
||||
//
|
||||
//Routine Description:
|
||||
//
|
||||
// Multiply two 64-bit unsigned numbers.
|
||||
//
|
||||
//
|
||||
//Arguments:
|
||||
//
|
||||
// UINT64
|
||||
// MulU64x64 (
|
||||
// IN UINT64 Value1,
|
||||
// IN UINT64 Value2,
|
||||
// OUT UINT64 *ResultHigh);
|
||||
//
|
||||
//Returns:
|
||||
//
|
||||
// 64-bit unsigned result
|
||||
//
|
||||
//--*/
|
||||
MulU64x64:
|
||||
// A in r32, B in r33, Q_hi stored in [r34], Q_lo returned in r8
|
||||
{ .mfi
|
||||
alloc r31=ar.pfs,3,0,0,0 // r32-r34
|
||||
nop.f 0
|
||||
nop.i 0;;
|
||||
}
|
||||
{.mmi
|
||||
setf.sig f6=r32
|
||||
setf.sig f7=r33
|
||||
nop.i 0;;
|
||||
}
|
||||
|
||||
{.mfi
|
||||
nop.m 0
|
||||
xma.hu f8=f6,f7,f0
|
||||
nop.i 0
|
||||
}
|
||||
{.mfi
|
||||
nop.m 0
|
||||
xma.l f6=f6,f7,f0
|
||||
nop.i 0;;
|
||||
}
|
||||
|
||||
|
||||
{.mmb
|
||||
stf8 [r34]=f8
|
||||
getf.sig r8=f6
|
||||
br.ret.sptk b0;;
|
||||
}
|
||||
|
||||
.endp MulU64x64
|
||||
|
||||
|
47
EdkModulePkg/Universal/Ebc/Dxe/build.xml
Normal file
47
EdkModulePkg/Universal/Ebc/Dxe/build.xml
Normal file
@@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><!-- 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.-->
|
||||
<project basedir="." default="Ebc"><!--Apply external ANT tasks-->
|
||||
<taskdef resource="GenBuild.tasks"/>
|
||||
<taskdef resource="net/sf/antcontrib/antlib.xml"/>
|
||||
<property environment="env"/>
|
||||
<property name="WORKSPACE_DIR" value="${env.WORKSPACE}"/>
|
||||
<import file="${WORKSPACE_DIR}\Tools\Conf\BuildMacro.xml"/><!--MODULE_RELATIVE PATH is relative to PACKAGE_DIR-->
|
||||
<property name="MODULE_RELATIVE_PATH" value="Universal\Ebc\Dxe"/>
|
||||
<property name="MODULE_DIR" value="${PACKAGE_DIR}\${MODULE_RELATIVE_PATH}"/>
|
||||
<property name="COMMON_FILE" value="${WORKSPACE_DIR}\Tools\Conf\Common.xml"/>
|
||||
<target name="Ebc">
|
||||
<GenBuild baseName="Ebc" mbdFilename="${MODULE_DIR}\Ebc.mbd" msaFilename="${MODULE_DIR}\Ebc.msa"/>
|
||||
</target>
|
||||
<target depends="Ebc_clean" name="clean"/>
|
||||
<target depends="Ebc_cleanall" name="cleanall"/>
|
||||
<target name="Ebc_clean">
|
||||
<OutputDirSetup baseName="Ebc" mbdFilename="${MODULE_DIR}\Ebc.mbd" msaFilename="${MODULE_DIR}\Ebc.msa"/>
|
||||
<if>
|
||||
<available file="${DEST_DIR_OUTPUT}\Ebc_build.xml"/>
|
||||
<then>
|
||||
<ant antfile="${DEST_DIR_OUTPUT}\Ebc_build.xml" target="clean"/>
|
||||
</then>
|
||||
</if>
|
||||
<delete dir="${DEST_DIR_OUTPUT}" excludes="*.xml"/>
|
||||
</target>
|
||||
<target name="Ebc_cleanall">
|
||||
<OutputDirSetup baseName="Ebc" mbdFilename="${MODULE_DIR}\Ebc.mbd" msaFilename="${MODULE_DIR}\Ebc.msa"/>
|
||||
<if>
|
||||
<available file="${DEST_DIR_OUTPUT}\Ebc_build.xml"/>
|
||||
<then>
|
||||
<ant antfile="${DEST_DIR_OUTPUT}\Ebc_build.xml" target="cleanall"/>
|
||||
</then>
|
||||
</if>
|
||||
<delete dir="${DEST_DIR_OUTPUT}"/>
|
||||
<delete dir="${DEST_DIR_DEBUG}"/>
|
||||
<delete>
|
||||
<fileset dir="${BIN_DIR}" includes="**Ebc*"/>
|
||||
</delete>
|
||||
</target>
|
||||
</project>
|
145
EdkModulePkg/Universal/Ebc/Dxe/x64/EbcLowLevel.asm
Normal file
145
EdkModulePkg/Universal/Ebc/Dxe/x64/EbcLowLevel.asm
Normal file
@@ -0,0 +1,145 @@
|
||||
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)
|
||||
EbcLLCALLEXNative PROC
|
||||
push rbp
|
||||
push rbx
|
||||
mov rbp, rsp
|
||||
; Function prolog
|
||||
|
||||
; Copy FuncAddr to a preserved register.
|
||||
mov rbx, rcx
|
||||
|
||||
; Set stack pointer to new value
|
||||
mov rsp, rdx
|
||||
|
||||
; 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
|
||||
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
|
||||
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
|
||||
ret
|
||||
EbcLLGetReturnValue ENDP
|
||||
|
||||
text ENDS
|
||||
END
|
||||
|
579
EdkModulePkg/Universal/Ebc/Dxe/x64/EbcSupport.c
Normal file
579
EdkModulePkg/Universal/Ebc/Dxe/x64/EbcSupport.c
Normal file
@@ -0,0 +1,579 @@
|
||||
/*++
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
)
|
||||
/*++
|
||||
|
||||
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;
|
||||
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
VmContext.R[0] = (UINT64) Addr;
|
||||
VmContext.R[0] -= VM_STACK_SIZE;
|
||||
|
||||
//
|
||||
// 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) 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) 0x1234567887654321);
|
||||
|
||||
//
|
||||
// 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));
|
||||
//
|
||||
VmContext.HighStackBottom = (UINTN) &Arg5;
|
||||
|
||||
//
|
||||
// Begin executing the EBC code
|
||||
//
|
||||
EbcExecute (&VmContext);
|
||||
|
||||
//
|
||||
// Return the value in R[7] unless there was an error
|
||||
//
|
||||
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;
|
||||
|
||||
//
|
||||
// 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 ();
|
||||
VmContext.R[0] = (UINT64) Addr;
|
||||
VmContext.R[0] -= VM_STACK_SIZE;
|
||||
|
||||
//
|
||||
// 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) 0x1234567887654321);
|
||||
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
VmContext.HighStackBottom = (UINTN) Addr;
|
||||
|
||||
//
|
||||
// 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;
|
||||
UINT64 Addr;
|
||||
INT32 Size;
|
||||
INT32 ThunkSize;
|
||||
EFI_STATUS Status;
|
||||
|
||||
//
|
||||
// Check alignment of pointer to EBC code
|
||||
//
|
||||
if ((UINT32) (UINTN) EbcEntryPoint & 0x01) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
Size = EBC_THUNK_SIZE;
|
||||
ThunkSize = Size;
|
||||
|
||||
Status = gBS->AllocatePool (
|
||||
EfiBootServicesData,
|
||||
Size,
|
||||
(VOID *) &Ptr
|
||||
);
|
||||
if (Status != EFI_SUCCESS) {
|
||||
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) 0xCA112EBCCA112EBC;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
451
EdkModulePkg/Universal/Ebc/Dxe/x64/x64Math.c
Normal file
451
EdkModulePkg/Universal/Ebc/Dxe/x64/x64Math.c
Normal file
@@ -0,0 +1,451 @@
|
||||
/*++
|
||||
|
||||
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:
|
||||
|
||||
x64math.c
|
||||
|
||||
Abstract:
|
||||
|
||||
Math routines for x64.
|
||||
|
||||
--*/
|
||||
|
||||
UINT64
|
||||
LeftShiftU64 (
|
||||
IN UINT64 Operand,
|
||||
IN UINT64 Count
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Left-shift a 64 bit value.
|
||||
|
||||
Arguments:
|
||||
|
||||
Operand - 64-bit value to shift
|
||||
Count - shift count
|
||||
|
||||
Returns:
|
||||
|
||||
Operand << Count
|
||||
|
||||
--*/
|
||||
{
|
||||
if (Count > 63) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Operand << Count;
|
||||
}
|
||||
|
||||
UINT64
|
||||
RightShiftU64 (
|
||||
IN UINT64 Operand,
|
||||
IN UINT64 Count
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Right-shift a 64 bit value.
|
||||
|
||||
Arguments:
|
||||
|
||||
Operand - 64-bit value to shift
|
||||
Count - shift count
|
||||
|
||||
Returns:
|
||||
|
||||
Operand >> Count
|
||||
|
||||
--*/
|
||||
{
|
||||
if (Count > 63) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Operand >> Count;
|
||||
}
|
||||
|
||||
INT64
|
||||
ARightShift64 (
|
||||
IN INT64 Operand,
|
||||
IN UINT64 Count
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Right-shift a 64 bit signed value.
|
||||
|
||||
Arguments:
|
||||
|
||||
Operand - 64-bit value to shift
|
||||
Count - shift count
|
||||
|
||||
Returns:
|
||||
|
||||
Operand >> Count
|
||||
|
||||
--*/
|
||||
{
|
||||
if (Count > 63) {
|
||||
|
||||
if (Operand & 0x8000000000000000ULL) {
|
||||
return (INT64)~0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Operand >> Count;
|
||||
}
|
||||
|
||||
#if 0
|
||||
//
|
||||
// The compiler generates true assembly for these, so we don't need them.
|
||||
//
|
||||
INT32
|
||||
ARightShift32 (
|
||||
IN INT32 Operand,
|
||||
IN UINTN Count
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Right shift a 32-bit value
|
||||
|
||||
Arguments:
|
||||
|
||||
Operand - value to shift
|
||||
Count - shift count
|
||||
|
||||
Returns:
|
||||
|
||||
Operand >> Count
|
||||
|
||||
--*/
|
||||
{
|
||||
return Operand >> (Count & 0x1f);
|
||||
}
|
||||
|
||||
INT32
|
||||
MulS32x32 (
|
||||
INT32 Value1,
|
||||
INT32 Value2,
|
||||
INT32 *ResultHigh
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Multiply two signed 32-bit numbers.
|
||||
|
||||
Arguments:
|
||||
|
||||
Value1 - first value to multiply
|
||||
Value2 - value to multiply Value1 by
|
||||
ResultHigh - overflow
|
||||
|
||||
Returns:
|
||||
|
||||
Value1 * Value2
|
||||
|
||||
Notes:
|
||||
|
||||
The 64-bit result is the concatenation of *ResultHigh and the return value
|
||||
|
||||
The product fits in 32 bits if
|
||||
(*ResultHigh == 0x00000000 AND *ResultLow_bit31 == 0)
|
||||
OR
|
||||
(*ResultHigh == 0xffffffff AND *ResultLow_bit31 == 1)
|
||||
|
||||
--*/
|
||||
{
|
||||
INT64 Rres64;
|
||||
INT32 Result;
|
||||
|
||||
Res64 = (INT64) Value1 * (INT64) Value2;
|
||||
*ResultHigh = (Res64 >> 32) & 0xffffffff;
|
||||
Result = Res64 & 0xffffffff;
|
||||
return Result;
|
||||
}
|
||||
|
||||
UINT32
|
||||
MulU32x32 (
|
||||
UINT32 Value1,
|
||||
UINT32 Value2,
|
||||
UINT32 *ResultHigh
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Multiply two unsigned 32-bit values.
|
||||
|
||||
Arguments:
|
||||
|
||||
Value1 - first number
|
||||
Value2 - number to multiply by Value1
|
||||
ResultHigh - overflow
|
||||
|
||||
Returns:
|
||||
|
||||
Value1 * Value2
|
||||
|
||||
Notes:
|
||||
|
||||
The 64-bit result is the concatenation of *ResultHigh and the return value.
|
||||
The product fits in 32 bits if *ResultHigh == 0x00000000
|
||||
|
||||
--*/
|
||||
{
|
||||
UINT64 Res64;
|
||||
UINT32 Result;
|
||||
|
||||
Res64 = (INT64) Value1 * (INT64) Value2;
|
||||
*ResultHigh = (Res64 >> 32) & 0xffffffff;
|
||||
Result = Res64 & 0xffffffff;
|
||||
return Result;
|
||||
}
|
||||
|
||||
INT32
|
||||
DivS32x32 (
|
||||
INT32 Value1,
|
||||
INT32 Value2,
|
||||
INT32 *Remainder,
|
||||
UINTN *error
|
||||
)
|
||||
//
|
||||
// signed 32-bit by signed 32-bit divide; the 32-bit remainder is
|
||||
// in *Remainder and the quotient is the return value; *error = 1 if the
|
||||
// divisor is 0, and it is 1 otherwise
|
||||
//
|
||||
{
|
||||
INT32 Result;
|
||||
|
||||
*error = 0;
|
||||
|
||||
if (Value2 == 0x0) {
|
||||
*error = 1;
|
||||
Result = 0x80000000;
|
||||
*Remainder = 0x80000000;
|
||||
} else {
|
||||
Result = Value1 / Value2;
|
||||
*Remainder = Value1 - Result * Value2;
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
UINT32
|
||||
DivU32x32 (
|
||||
UINT32 Value1,
|
||||
UINT32 Value2,
|
||||
UINT32 *Remainder,
|
||||
UINTN *Error
|
||||
)
|
||||
//
|
||||
// unsigned 32-bit by unsigned 32-bit divide; the 32-bit remainder is
|
||||
// in *Remainder and the quotient is the return value; *error = 1 if the
|
||||
// divisor is 0, and it is 1 otherwise
|
||||
//
|
||||
{
|
||||
UINT32 Result;
|
||||
|
||||
*Error = 0;
|
||||
|
||||
if (Value2 == 0x0) {
|
||||
*Error = 1;
|
||||
Result = 0x80000000;
|
||||
*Remainder = 0x80000000;
|
||||
} else {
|
||||
Result = Value1 / Value2;
|
||||
*Remainder = Value1 - Result * Value2;
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
INT64
|
||||
MulS64x64 (
|
||||
INT64 Value1,
|
||||
INT64 Value2,
|
||||
INT64 *ResultHigh
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Multiply two signed 32-bit numbers.
|
||||
|
||||
Arguments:
|
||||
|
||||
Value1 - first value to multiply
|
||||
Value2 - value to multiply Value1 by
|
||||
ResultHigh - overflow
|
||||
|
||||
Returns:
|
||||
|
||||
Value1 * Value2
|
||||
|
||||
Notes:
|
||||
|
||||
The 64-bit result is the concatenation of *ResultHigh and the return value
|
||||
|
||||
The product fits in 32 bits if
|
||||
(*ResultHigh == 0x00000000 AND *ResultLow_bit31 == 0)
|
||||
OR
|
||||
(*ResultHigh == 0xffffffff AND *ResultLow_bit31 == 1)
|
||||
|
||||
--*/
|
||||
{
|
||||
INT64 Result;
|
||||
|
||||
Result = Value1 * Value2;
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
UINT64
|
||||
MulU64x64 (
|
||||
UINT64 Value1,
|
||||
UINT64 Value2,
|
||||
UINT64 *ResultHigh
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Multiply two unsigned 32-bit values.
|
||||
|
||||
Arguments:
|
||||
|
||||
Value1 - first number
|
||||
Value2 - number to multiply by Value1
|
||||
ResultHigh - overflow
|
||||
|
||||
Returns:
|
||||
|
||||
Value1 * Value2
|
||||
|
||||
Notes:
|
||||
|
||||
The 64-bit result is the concatenation of *ResultHigh and the return value.
|
||||
The product fits in 32 bits if *ResultHigh == 0x00000000
|
||||
|
||||
--*/
|
||||
{
|
||||
UINT64 Result;
|
||||
|
||||
Result = Value1 * Value2;
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
INT64
|
||||
DivS64x64 (
|
||||
INT64 Value1,
|
||||
INT64 Value2,
|
||||
INT64 *Remainder,
|
||||
UINTN *Error
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Divide two 64-bit signed values.
|
||||
|
||||
Arguments:
|
||||
|
||||
Value1 - dividend
|
||||
Value2 - divisor
|
||||
Remainder - remainder of Value1/Value2
|
||||
Error - to flag errors (divide-by-0)
|
||||
|
||||
Returns:
|
||||
|
||||
Value1 / Valu2
|
||||
|
||||
Note:
|
||||
|
||||
The 64-bit remainder is in *Remainder and the quotient is the return value.
|
||||
*Error = 1 if the divisor is 0, and it is 1 otherwise
|
||||
|
||||
--*/
|
||||
{
|
||||
INT64 Result;
|
||||
|
||||
*Error = 0;
|
||||
|
||||
if (Value2 == 0x0) {
|
||||
*Error = 1;
|
||||
Result = 0x8000000000000000;
|
||||
*Remainder = 0x8000000000000000;
|
||||
} else {
|
||||
Result = Value1 / Value2;
|
||||
*Remainder = Value1 - Result * Value2;
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
UINT64
|
||||
DivU64x64 (
|
||||
UINT64 Value1,
|
||||
UINT64 Value2,
|
||||
UINT64 *Remainder,
|
||||
UINTN *Error
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Divide two 64-bit unsigned values.
|
||||
|
||||
Arguments:
|
||||
|
||||
Value1 - dividend
|
||||
Value2 - divisor
|
||||
Remainder - remainder of Value1/Value2
|
||||
Error - to flag errors (divide-by-0)
|
||||
|
||||
Returns:
|
||||
|
||||
Value1 / Valu2
|
||||
|
||||
Note:
|
||||
|
||||
The 64-bit remainder is in *Remainder and the quotient is the return value.
|
||||
*Error = 1 if the divisor is 0, and it is 1 otherwise
|
||||
|
||||
--*/
|
||||
{
|
||||
UINT64 Result;
|
||||
|
||||
*Error = 0;
|
||||
|
||||
if (Value2 == 0x0) {
|
||||
*Error = 1;
|
||||
Result = 0x8000000000000000;
|
||||
*Remainder = 0x8000000000000000;
|
||||
} else {
|
||||
Result = Value1 / Value2;
|
||||
*Remainder = Value1 - Result * Value2;
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
Reference in New Issue
Block a user