Add EBC, FTW, Crc32SectionExtract, NullMemoryTest modules.

CrcSectionExtract cannot build for now for some missing definitions. 

git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@2813 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
qhuang8 2007-06-27 14:52:40 +00:00
parent eb5f1a7fc7
commit d7dec593ea
40 changed files with 14183 additions and 3 deletions

View File

@ -289,6 +289,10 @@
PcdUefiLibMaxPrintBufferSize|gEfiMdePkgTokenSpaceGuid|320 PcdUefiLibMaxPrintBufferSize|gEfiMdePkgTokenSpaceGuid|320
PcdMaxSizeNonPopulateCapsule|gEfiEdkModulePkgTokenSpaceGuid|0x0 PcdMaxSizeNonPopulateCapsule|gEfiEdkModulePkgTokenSpaceGuid|0x0
PcdMaxSizePopulateCapsule|gEfiEdkModulePkgTokenSpaceGuid|0x0 PcdMaxSizePopulateCapsule|gEfiEdkModulePkgTokenSpaceGuid|0x0
PcdFlashNvStorageFtwSpareBase|gEfiGenericPlatformTokenSpaceGuid|0x0
PcdFlashNvStorageFtwSpareSize|gEfiGenericPlatformTokenSpaceGuid|0x0
PcdFlashNvStorageFtwWorkingBase|gEfiGenericPlatformTokenSpaceGuid|0x0
PcdFlashNvStorageFtwWorkingSize|gEfiGenericPlatformTokenSpaceGuid|0x0
[PcdsPatchableInModule.common] [PcdsPatchableInModule.common]
PcdDebugPrintErrorLevel|gEfiMdePkgTokenSpaceGuid|0x80000000 PcdDebugPrintErrorLevel|gEfiMdePkgTokenSpaceGuid|0x80000000
@ -309,4 +313,8 @@
${WORKSPACE}/MdeModulePkg/Universal/Disk/Partition/Dxe/Partition.inf ${WORKSPACE}/MdeModulePkg/Universal/Disk/Partition/Dxe/Partition.inf
${WORKSPACE}/MdeModulePkg/Universal/Security/SecurityStub/Dxe/SecurityStub.inf ${WORKSPACE}/MdeModulePkg/Universal/Security/SecurityStub/Dxe/SecurityStub.inf
${WORKSPACE}/MdeModulePkg/Universal/Capsule/RuntimeDxe/CapsuleRuntime.inf ${WORKSPACE}/MdeModulePkg/Universal/Capsule/RuntimeDxe/CapsuleRuntime.inf
${WORKSPACE}/MdeModulePkg/Universal/Ebc/Dxe/Ebc.inf
${WORKSPACE}/MdeModulePkg/Universal/GenericMemoryTest/Dxe/NullMemoryTest.inf
${WORKSPACE}/MdeModulePkg/Universal/FirmwareVolume/FaultTolerantWriteLite/Dxe/FtwLite.inf
#${WORKSPACE}/MdeModulePkg/Universal/FirmwareVolume/GuidedSectionExtraction/Crc32SectionExtract/Dxe/Crc32SectionExtract.inf
${WORKSPACE}/MdeModulePkg/Bus/Pci/AtapiPassThru/Dxe/AtapiPassThru.inf ${WORKSPACE}/MdeModulePkg/Bus/Pci/AtapiPassThru/Dxe/AtapiPassThru.inf

View File

@ -57,10 +57,8 @@
################################################################################ ################################################################################
[Packages] [Packages]
MdeModulePkg/MdeModulePkg.dec
IntelFrameworkPkg/IntelFrameworkPkg.dec
MdePkg/MdePkg.dec MdePkg/MdePkg.dec
IntelFrameworkPkg/IntelFrameworkPkg.dec
################################################################################ ################################################################################
# #

View File

@ -0,0 +1,25 @@
/*++
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 <DxeDepex.h>
DEPENDENCY_START
TRUE
DEPENDENCY_END

View File

@ -0,0 +1,108 @@
#/** @file
# Component description file for Ebc module.
#
# This module for the EBC virtual machine implementation produces
# EBC and EBC debug support protocols.
# Copyright (c) 2006 - 2007, Intel Corporation
#
# All rights reserved. This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
#
#**/
################################################################################
#
# Defines Section - statements that will be processed to create a Makefile.
#
################################################################################
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = Ebc
FILE_GUID = 13AC6DD0-73D0-11D4-B06B-00AA00BD6DE7
MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.0
EDK_RELEASE_VERSION = 0x00020000
EFI_SPECIFICATION_VERSION = 0x00020000
ENTRY_POINT = InitializeEbcDriver
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64 IPF
#
################################################################################
#
# Sources Section - list of files that are required for the build to succeed.
#
################################################################################
[Sources.common]
Ebc.dxs
EbcExecute.h
EbcExecute.c
EbcInt.h
EbcInt.c
[Sources.Ia32]
Ia32/EbcSupport.c
Ia32/EbcLowLevel.S
Ia32/EbcLowLevel.asm
[Sources.X64]
x64/EbcSupport.c
x64/EbcLowLevel.S
x64/EbcLowLevel.asm
[Sources.IPF]
Ipf/EbcSupport.h
Ipf/EbcSupport.c
Ipf/EbcLowLevel.s
################################################################################
#
# Package Dependency Section - list of Package files that are required for
# this module.
#
################################################################################
[Packages]
MdePkg/MdePkg.dec
IntelFrameworkPkg/IntelFrameworkPkg.dec
################################################################################
#
# Library Class Section - list of Library Classes that are required for
# this module.
#
################################################################################
[LibraryClasses]
MemoryAllocationLib
UefiBootServicesTableLib
BaseMemoryLib
UefiDriverEntryPoint
DebugLib
BaseLib
################################################################################
#
# Protocol C Name Section - list of Protocol and Protocol Notify C Names
# that this module uses or produces.
#
################################################################################
[Protocols]
gEfiDebugSupportProtocolGuid # PROTOCOL ALWAYS_PRODUCED
gEfiEbcProtocolGuid # PROTOCOL ALWAYS_PRODUCED

View File

@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<MsaHeader>
<ModuleName>Ebc</ModuleName>
<ModuleType>DXE_DRIVER</ModuleType>
<GuidValue>13AC6DD0-73D0-11D4-B06B-00AA00BD6DE7</GuidValue>
<Version>1.0</Version>
<Abstract>Component description file for Ebc module.</Abstract>
<Description>This module for the EBC virtual machine implementation produces
EBC and EBC debug support protocols.</Description>
<Copyright>Copyright (c) 2006 - 2007, Intel Corporation</Copyright>
<License>All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.</License>
<Specification>FRAMEWORK_BUILD_PACKAGING_SPECIFICATION 0x00000052</Specification>
</MsaHeader>
<ModuleDefinitions>
<SupportedArchitectures>IA32 X64 IPF</SupportedArchitectures>
<BinaryModule>false</BinaryModule>
<OutputFileBasename>Ebc</OutputFileBasename>
</ModuleDefinitions>
<LibraryClassDefinitions>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>BaseLib</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>DebugLib</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>UefiDriverEntryPoint</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>BaseMemoryLib</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>UefiBootServicesTableLib</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>MemoryAllocationLib</Keyword>
</LibraryClass>
</LibraryClassDefinitions>
<SourceFiles>
<Filename>EbcInt.c</Filename>
<Filename>EbcInt.h</Filename>
<Filename>EbcExecute.c</Filename>
<Filename>EbcExecute.h</Filename>
<Filename>Ebc.dxs</Filename>
<Filename SupArchList="IA32" ToolChainFamily="MSFT">Ia32/EbcLowLevel.asm</Filename>
<Filename SupArchList="IA32" ToolChainFamily="GCC">Ia32/EbcLowLevel.S</Filename>
<Filename SupArchList="IA32">Ia32/EbcSupport.c</Filename>
<Filename SupArchList="X64" ToolChainFamily="MSFT">x64/EbcLowLevel.asm</Filename>
<Filename SupArchList="X64" ToolChainFamily="GCC">x64/EbcLowLevel.S</Filename>
<Filename SupArchList="X64">x64/EbcSupport.c</Filename>
<Filename SupArchList="IPF">Ipf/EbcLowLevel.s</Filename>
<Filename SupArchList="IPF">Ipf/EbcSupport.c</Filename>
<Filename SupArchList="IPF">Ipf/EbcSupport.h</Filename>
</SourceFiles>
<PackageDependencies>
<Package PackageGuid="1E73767F-8F52-4603-AEB4-F29B510B6766"/>
<Package PackageGuid="2759ded5-bb57-4b06-af4f-c398fa552719"/>
</PackageDependencies>
<Protocols>
<Protocol Usage="ALWAYS_PRODUCED">
<ProtocolCName>gEfiEbcProtocolGuid</ProtocolCName>
</Protocol>
<Protocol Usage="ALWAYS_PRODUCED">
<ProtocolCName>gEfiDebugSupportProtocolGuid</ProtocolCName>
</Protocol>
</Protocols>
<Externs>
<Specification>EFI_SPECIFICATION_VERSION 0x00020000</Specification>
<Specification>EDK_RELEASE_VERSION 0x00020000</Specification>
<Extern>
<ModuleEntryPoint>InitializeEbcDriver</ModuleEntryPoint>
</Extern>
</Externs>
</ModuleSurfaceArea>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,323 @@
/*++
Copyright (c) 2006, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
EbcExecute.h
Abstract:
Header file for Virtual Machine support. Contains EBC defines that can
be of use to a disassembler for the most part. Also provides function
prototypes for VM functions.
--*/
#ifndef _EBC_EXECUTE_H_
#define _EBC_EXECUTE_H_
//
// VM major/minor version
//
#define VM_MAJOR_VERSION 1
#define VM_MINOR_VERSION 0
//
// Macros to check and set alignment
//
#define ASSERT_ALIGNED(addr, size) ASSERT (!((UINT32) (addr) & (size - 1)))
#define IS_ALIGNED(addr, size) !((UINT32) (addr) & (size - 1))
//
// Define a macro to get the operand. Then we can change it to be either a
// direct read or have it call a function to read memory.
//
#define GETOPERANDS(pVM) (UINT8) (*(UINT8 *) (pVM->Ip + 1))
#define GETOPCODE(pVM) (UINT8) (*(UINT8 *) pVM->Ip)
//
// Bit masks for opcode encodings
//
#define OPCODE_M_OPCODE 0x3F // bits of interest for first level decode
#define OPCODE_M_IMMDATA 0x80
#define OPCODE_M_IMMDATA64 0x40
#define OPCODE_M_64BIT 0x40 // for CMP
#define OPCODE_M_RELADDR 0x10 // for CALL instruction
#define OPCODE_M_CMPI32_DATA 0x80 // for CMPI
#define OPCODE_M_CMPI64 0x40 // for CMPI 32 or 64 bit comparison
#define OPERAND_M_MOVIN_N 0x80
#define OPERAND_M_CMPI_INDEX 0x10
//
// Masks for instructions that encode presence of indexes for operand1 and/or
// operand2.
//
#define OPCODE_M_IMMED_OP1 0x80
#define OPCODE_M_IMMED_OP2 0x40
//
// Bit masks for operand encodings
//
#define OPERAND_M_INDIRECT1 0x08
#define OPERAND_M_INDIRECT2 0x80
#define OPERAND_M_OP1 0x07
#define OPERAND_M_OP2 0x70
//
// Masks for data manipulation instructions
//
#define DATAMANIP_M_64 0x40 // 64-bit width operation
#define DATAMANIP_M_IMMDATA 0x80
//
// For MOV instructions, need a mask for the opcode when immediate
// data applies to R2.
//
#define OPCODE_M_IMMED_OP2 0x40
//
// The MOVI/MOVIn instructions use bit 6 of operands byte to indicate
// if an index is present. Then bits 4 and 5 are used to indicate the width
// of the move.
//
#define MOVI_M_IMMDATA 0x40
#define MOVI_M_DATAWIDTH 0xC0
#define MOVI_DATAWIDTH16 0x40
#define MOVI_DATAWIDTH32 0x80
#define MOVI_DATAWIDTH64 0xC0
#define MOVI_M_MOVEWIDTH 0x30
#define MOVI_MOVEWIDTH8 0x00
#define MOVI_MOVEWIDTH16 0x10
#define MOVI_MOVEWIDTH32 0x20
#define MOVI_MOVEWIDTH64 0x30
//
// Masks for CALL instruction encodings
//
#define OPERAND_M_RELATIVE_ADDR 0x10
#define OPERAND_M_NATIVE_CALL 0x20
//
// Masks for decoding push/pop instructions
//
#define PUSHPOP_M_IMMDATA 0x80 // opcode bit indicating immediate data
#define PUSHPOP_M_64 0x40 // opcode bit indicating 64-bit operation
//
// Mask for operand of JMP instruction
//
#define JMP_M_RELATIVE 0x10
#define JMP_M_CONDITIONAL 0x80
#define JMP_M_CS 0x40
//
// Macros to determine if a given operand is indirect
//
#define OPERAND1_INDIRECT(op) ((op) & OPERAND_M_INDIRECT1)
#define OPERAND2_INDIRECT(op) ((op) & OPERAND_M_INDIRECT2)
//
// Macros to extract the operands from second byte of instructions
//
#define OPERAND1_REGNUM(op) ((op) & OPERAND_M_OP1)
#define OPERAND2_REGNUM(op) (((op) & OPERAND_M_OP2) >> 4)
#define OPERAND1_CHAR(op) ('0' + OPERAND1_REGNUM (op))
#define OPERAND2_CHAR(op) ('0' + OPERAND2_REGNUM (op))
#define OPERAND1_REGDATA(pvm, op) pvm->R[OPERAND1_REGNUM (op)]
#define OPERAND2_REGDATA(pvm, op) pvm->R[OPERAND2_REGNUM (op)]
//
// Condition masks usually for byte 1 encodings of code
//
#define CONDITION_M_CONDITIONAL 0x80
#define CONDITION_M_CS 0x40
//
// Bits in the VM->StopFlags field
//
#define STOPFLAG_APP_DONE 0x0001
#define STOPFLAG_BREAKPOINT 0x0002
#define STOPFLAG_INVALID_BREAK 0x0004
#define STOPFLAG_BREAK_ON_CALLEX 0x0008
//
// Masks for working with the VM flags register
//
#define VMFLAGS_CC 0x0001 // condition flag
#define VMFLAGS_STEP 0x0002 // step instruction mode
#define VMFLAGS_ALL_VALID (VMFLAGS_CC | VMFLAGS_STEP)
//
// Macros for operating on the VM flags register
//
#define VMFLAG_SET(pVM, Flag) (pVM->Flags |= (Flag))
#define VMFLAG_ISSET(pVM, Flag) ((pVM->Flags & (Flag)) ? 1 : 0)
#define VMFLAG_CLEAR(pVM, Flag) (pVM->Flags &= ~(Flag))
//
// Debug macro
//
#define EBCMSG(s) gST->ConOut->OutputString (gST->ConOut, s)
//
// Define OPCODES
//
#define OPCODE_BREAK 0x00
#define OPCODE_JMP 0x01
#define OPCODE_JMP8 0x02
#define OPCODE_CALL 0x03
#define OPCODE_RET 0x04
#define OPCODE_CMPEQ 0x05
#define OPCODE_CMPLTE 0x06
#define OPCODE_CMPGTE 0x07
#define OPCODE_CMPULTE 0x08
#define OPCODE_CMPUGTE 0x09
#define OPCODE_NOT 0x0A
#define OPCODE_NEG 0x0B
#define OPCODE_ADD 0x0C
#define OPCODE_SUB 0x0D
#define OPCODE_MUL 0x0E
#define OPCODE_MULU 0x0F
#define OPCODE_DIV 0x10
#define OPCODE_DIVU 0x11
#define OPCODE_MOD 0x12
#define OPCODE_MODU 0x13
#define OPCODE_AND 0x14
#define OPCODE_OR 0x15
#define OPCODE_XOR 0x16
#define OPCODE_SHL 0x17
#define OPCODE_SHR 0x18
#define OPCODE_ASHR 0x19
#define OPCODE_EXTNDB 0x1A
#define OPCODE_EXTNDW 0x1B
#define OPCODE_EXTNDD 0x1C
#define OPCODE_MOVBW 0x1D
#define OPCODE_MOVWW 0x1E
#define OPCODE_MOVDW 0x1F
#define OPCODE_MOVQW 0x20
#define OPCODE_MOVBD 0x21
#define OPCODE_MOVWD 0x22
#define OPCODE_MOVDD 0x23
#define OPCODE_MOVQD 0x24
#define OPCODE_MOVSNW 0x25 // Move signed natural with word index
#define OPCODE_MOVSND 0x26 // Move signed natural with dword index
//
// #define OPCODE_27 0x27
//
#define OPCODE_MOVQQ 0x28 // Does this go away?
#define OPCODE_LOADSP 0x29
#define OPCODE_STORESP 0x2A
#define OPCODE_PUSH 0x2B
#define OPCODE_POP 0x2C
#define OPCODE_CMPIEQ 0x2D
#define OPCODE_CMPILTE 0x2E
#define OPCODE_CMPIGTE 0x2F
#define OPCODE_CMPIULTE 0x30
#define OPCODE_CMPIUGTE 0x31
#define OPCODE_MOVNW 0x32
#define OPCODE_MOVND 0x33
//
// #define OPCODE_34 0x34
//
#define OPCODE_PUSHN 0x35
#define OPCODE_POPN 0x36
#define OPCODE_MOVI 0x37
#define OPCODE_MOVIN 0x38
#define OPCODE_MOVREL 0x39
EFI_STATUS
EbcExecute (
IN VM_CONTEXT *VmPtr
)
;
UINT64
GetVmVersion (
VOID
)
;
EFI_STATUS
VmWriteMemN (
IN VM_CONTEXT *VmPtr,
IN UINTN Addr,
IN UINTN Data
)
;
EFI_STATUS
VmWriteMem64 (
IN VM_CONTEXT *VmPtr,
UINTN Addr,
IN UINT64 Data
)
;
//
// Define a protocol for an EBC VM test interface.
//
#define EFI_EBC_VM_TEST_PROTOCOL_GUID \
{ \
0xAAEACCFDL, 0xF27B, 0x4C17, { 0xB6, 0x10, 0x75, 0xCA, 0x1F, 0x2D, 0xFB, 0x52 } \
}
//
// Define for forward reference.
//
typedef struct _EFI_EBC_VM_TEST_PROTOCOL EFI_EBC_VM_TEST_PROTOCOL;
typedef
EFI_STATUS
(*EBC_VM_TEST_EXECUTE) (
IN EFI_EBC_VM_TEST_PROTOCOL * This,
IN VM_CONTEXT * VmPtr,
IN OUT UINTN *InstructionCount
);
typedef
EFI_STATUS
(*EBC_VM_TEST_ASM) (
IN EFI_EBC_VM_TEST_PROTOCOL * This,
IN CHAR16 *AsmText,
IN OUT INT8 *Buffer,
IN OUT UINTN *BufferLen
);
typedef
EFI_STATUS
(*EBC_VM_TEST_DASM) (
IN EFI_EBC_VM_TEST_PROTOCOL * This,
IN OUT CHAR16 *AsmText,
IN OUT INT8 *Buffer,
IN OUT UINTN *Len
);
//
// Prototype for the actual EBC test protocol interface
//
struct _EFI_EBC_VM_TEST_PROTOCOL {
EBC_VM_TEST_EXECUTE Execute;
EBC_VM_TEST_ASM Assemble;
EBC_VM_TEST_DASM Disassemble;
};
EFI_STATUS
EbcExecuteInstructions (
IN EFI_EBC_VM_TEST_PROTOCOL *This,
IN VM_CONTEXT *VmPtr,
IN OUT UINTN *InstructionCount
)
;
#endif // ifndef _EBC_EXECUTE_H_

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,283 @@
/*++
Copyright (c) 2006, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
EbcInt.h
Abstract:
Main routines for the EBC interpreter. Includes the initialization and
main interpreter routines.
--*/
#ifndef _EBC_INT_H_
#define _EBC_INT_H_
//
// The package level header files this module uses
//
#include <PiDxe.h>
//
// The protocols, PPI and GUID defintions for this module
//
#include <Protocol/DebugSupport.h>
#include <Protocol/Ebc.h>
//
// The Library classes this module consumes
//
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
#include <Library/UefiDriverEntryPoint.h>
#include <Library/BaseMemoryLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/MemoryAllocationLib.h>
typedef INT64 VM_REGISTER;
typedef UINT8 *VMIP; // instruction pointer for the VM
typedef UINT32 EXCEPTION_FLAGS;
typedef struct {
VM_REGISTER R[8]; // General purpose registers.
UINT64 Flags; // Flags register:
// 0 Set to 1 if the result of the last compare was true
// 1 Set to 1 if stepping
// 2..63 Reserved.
VMIP Ip; // Instruction pointer.
UINTN LastException; //
EXCEPTION_FLAGS ExceptionFlags; // to keep track of exceptions
UINT32 StopFlags;
UINT32 CompilerVersion; // via break(6)
UINTN HighStackBottom; // bottom of the upper stack
UINTN LowStackTop; // top of the lower stack
UINT64 StackRetAddr; // location of final return address on stack
UINTN *StackMagicPtr; // pointer to magic value on stack to detect corruption
EFI_HANDLE ImageHandle; // for this EBC driver
EFI_SYSTEM_TABLE *SystemTable; // for debugging only
UINTN LastAddrConverted; // for debug
UINTN LastAddrConvertedValue; // for debug
VOID *FramePtr;
VOID *EntryPoint; // entry point of EBC image
UINTN ImageBase;
VOID *StackPool;
VOID *StackTop;
} VM_CONTEXT;
extern VM_CONTEXT *mVmPtr;
//
// Bits of exception flags field of VM context
//
#define EXCEPTION_FLAG_FATAL 0x80000000 // can't continue
#define EXCEPTION_FLAG_ERROR 0x40000000 // bad, but try to continue
#define EXCEPTION_FLAG_WARNING 0x20000000 // harmless problem
#define EXCEPTION_FLAG_NONE 0x00000000 // for normal return
//
// Flags passed to the internal create-thunks function.
//
#define FLAG_THUNK_ENTRY_POINT 0x01 // thunk for an image entry point
#define FLAG_THUNK_PROTOCOL 0x00 // thunk for an EBC protocol service
//
// Put this value at the bottom of the VM's stack gap so we can check it on
// occasion to make sure the stack has not been corrupted.
//
#define VM_STACK_KEY_VALUE 0xDEADBEEF
EFI_STATUS
EbcCreateThunks (
IN EFI_HANDLE ImageHandle,
IN VOID *EbcEntryPoint,
OUT VOID **Thunk,
IN UINT32 Flags
)
;
EFI_STATUS
EbcAddImageThunk (
IN EFI_HANDLE ImageHandle,
IN VOID *ThunkBuffer,
IN UINT32 ThunkSize
)
;
//
// The interpreter calls these when an exception is detected,
// or as a periodic callback.
//
EFI_STATUS
EbcDebugSignalException (
IN EFI_EXCEPTION_TYPE ExceptionType,
IN EXCEPTION_FLAGS ExceptionFlags,
IN VM_CONTEXT *VmPtr
)
;
//
// Define a constant of how often to call the debugger periodic callback
// function.
//
#define EFI_TIMER_UNIT_1MS (1000 * 10)
#define EBC_VM_PERIODIC_CALLBACK_RATE (1000 * EFI_TIMER_UNIT_1MS)
#define STACK_POOL_SIZE (1024 * 1020)
#define MAX_STACK_NUM 4
EFI_STATUS
EbcDebugSignalPeriodic (
IN VM_CONTEXT *VmPtr
)
;
//
// External low level functions that are native-processor dependent
//
UINTN
EbcLLGetEbcEntryPoint (
VOID
)
;
UINTN
EbcLLGetStackPointer (
VOID
)
;
VOID
EbcLLCALLEXNative (
IN UINTN CallAddr,
IN UINTN EbcSp,
IN VOID *FramePtr
)
;
VOID
EbcLLCALLEX (
IN VM_CONTEXT *VmPtr,
IN UINTN CallAddr,
IN UINTN EbcSp,
IN VOID *FramePtr,
IN UINT8 Size
)
;
INT64
EbcLLGetReturnValue (
VOID
)
;
EFI_STATUS
GetEBCStack(
EFI_HANDLE Handle,
VOID **StackBuffer,
UINTN *BufferIndex
);
EFI_STATUS
ReturnEBCStack(
UINTN Index
);
EFI_STATUS
InitEBCStack (
VOID
);
EFI_STATUS
FreeEBCStack(
VOID
);
EFI_STATUS
ReturnEBCStackByHandle(
EFI_HANDLE Handle
);
//
// Defines for a simple EBC debugger interface
//
typedef struct _EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL;
#define EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL_GUID \
{ \
0x2a72d11e, 0x7376, 0x40f6, { 0x9c, 0x68, 0x23, 0xfa, 0x2f, 0xe3, 0x63, 0xf1 } \
}
typedef
EFI_STATUS
(*EBC_DEBUGGER_SIGNAL_EXCEPTION) (
IN EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL * This,
IN VM_CONTEXT * VmPtr,
IN EFI_EXCEPTION_TYPE ExceptionType
);
typedef
VOID
(*EBC_DEBUGGER_DEBUG) (
IN EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL * This,
IN VM_CONTEXT * VmPtr
);
typedef
UINT32
(*EBC_DEBUGGER_DASM) (
IN EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL * This,
IN VM_CONTEXT * VmPtr,
IN UINT16 *DasmString OPTIONAL,
IN UINT32 DasmStringSize
);
//
// This interface allows you to configure the EBC debug support
// driver. For example, turn on or off saving and printing of
// delta VM even if called. Or to even disable the entire interface,
// in which case all functions become no-ops.
//
typedef
EFI_STATUS
(*EBC_DEBUGGER_CONFIGURE) (
IN EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL * This,
IN UINT32 ConfigId,
IN UINTN ConfigValue
);
//
// Prototype for the actual EBC debug support protocol interface
//
struct _EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL {
EBC_DEBUGGER_DEBUG Debugger;
EBC_DEBUGGER_SIGNAL_EXCEPTION SignalException;
EBC_DEBUGGER_DASM Dasm;
EBC_DEBUGGER_CONFIGURE Configure;
};
typedef struct {
EFI_EBC_PROTOCOL *This;
VOID *EntryPoint;
EFI_HANDLE ImageHandle;
VM_CONTEXT VmContext;
} EFI_EBC_THUNK_DATA;
#define EBC_PROTOCOL_PRIVATE_DATA_SIGNATURE EFI_SIGNATURE_32 ('e', 'b', 'c', 'p')
struct _EBC_PROTOCOL_PRIVATE_DATA {
UINT32 Signature;
EFI_EBC_PROTOCOL EbcProtocol;
UINTN StackBase;
UINTN StackTop;
UINTN StackSize;
} ;
#define EBC_PROTOCOL_PRIVATE_DATA_FROM_THIS(a) \
CR(a, EBC_PROTOCOL_PRIVATE_DATA, EbcProtocol, EBC_PROTOCOL_PRIVATE_DATA_SIGNATURE)
#endif // #ifndef _EBC_INT_H_

View File

@ -0,0 +1,54 @@
#****************************************************************************
#*
#* Copyright (c) 2006, Intel Corporation
#* All rights reserved. This program and the accompanying materials
#* are licensed and made available under the terms and conditions of the BSD License
#* which accompanies this distribution. The full text of the license may be found at
#* http://opensource.org/licenses/bsd-license.php
#*
#* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
#* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#*
#****************************************************************************
.globl ASM_PFX(CopyMem)
.globl ASM_PFX(EbcLLCALLEXNative)
ASM_PFX(EbcLLCALLEXNative):
push %ebp
push %ebx
mov %esp,%ebp
mov 0xc(%esp),%ecx
mov 0x14(%esp),%eax
mov 0x10(%esp),%edx
sub %edx,%eax
sub %eax,%esp
mov %esp,%ebx
push %ecx
push %eax
push %edx
push %ebx
call ASM_PFX(CopyMem)
pop %eax
pop %eax
pop %eax
pop %ecx
call *%ecx
mov %ebp,%esp
mov %ebp,%esp
pop %ebx
pop %ebp
ret
.globl ASM_PFX(EbcLLGetEbcEntryPoint)
ASM_PFX(EbcLLGetEbcEntryPoint):
ret
.globl ASM_PFX(EbcLLGetStackPointer)
ASM_PFX(EbcLLGetStackPointer):
mov %esp,%eax
add $0x4,%eax
ret
.globl ASM_PFX(EbcLLGetReturnValue)
ASM_PFX(EbcLLGetReturnValue):
ret

View File

@ -0,0 +1,163 @@
page ,132
title VM ASSEMBLY LANGUAGE ROUTINES
;****************************************************************************
;*
;* Copyright (c) 2006 - 2007, Intel Corporation
;* All rights reserved. This program and the accompanying materials
;* are licensed and made available under the terms and conditions of the BSD License
;* which accompanies this distribution. The full text of the license may be found at
;* http://opensource.org/licenses/bsd-license.php
;*
;* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
;* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
;*
;****************************************************************************
;****************************************************************************
; REV 1.0
;****************************************************************************
;
; Rev Date Description
; --- -------- ------------------------------------------------------------
; 1.0 03/14/01 Initial creation of file.
;
;****************************************************************************
;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; This code provides low level routines that support the Virtual Machine
; for option ROMs.
;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;---------------------------------------------------------------------------
; Equate files needed.
;---------------------------------------------------------------------------
.XLIST
.LIST
;---------------------------------------------------------------------------
; Assembler options
;---------------------------------------------------------------------------
.686p
.model flat
.code
;---------------------------------------------------------------------------
;;GenericPostSegment SEGMENT USE16
;---------------------------------------------------------------------------
CopyMem PROTO C Destination:PTR DWORD, Source:PTR DWORD, Count:DWORD
;****************************************************************************
; EbcLLCALLEXNative
;
; This function is called to execute an EBC CALLEX instruction
; to native code.
; This instruction requires that we thunk out to external native
; code. For IA32, we simply switch stacks and jump to the
; specified function. On return, we restore the stack pointer
; to its original location.
;
; Destroys no working registers.
;****************************************************************************
; VOID EbcLLCALLEXNative(UINTN FuncAddr, UINTN NewStackPointer, VOID *FramePtr)
_EbcLLCALLEXNative PROC NEAR PUBLIC
push ebp
push ebx
mov ebp, esp ; standard function prolog
; Get function address in a register
; mov ecx, FuncAddr => mov ecx, dword ptr [FuncAddr]
mov ecx, dword ptr [esp]+0Ch
; Set stack pointer to new value
; mov eax, NewStackPointer => mov eax, dword ptr [NewSp]
mov eax, dword ptr [esp] + 14h
mov edx, dword ptr [esp] + 10h
sub eax, edx
sub esp, eax
mov ebx, esp
push ecx
push eax
push edx
push ebx
call CopyMem
pop eax
pop eax
pop eax
pop ecx
; Now call the external routine
call ecx
; ebp is preserved by the callee. In this function it
; equals the original esp, so set them equal
mov esp, ebp
; Standard function epilog
mov esp, ebp
pop ebx
pop ebp
ret
_EbcLLCALLEXNative ENDP
; UINTN EbcLLGetEbcEntryPoint(VOID);
; Routine Description:
; The VM thunk code stuffs an EBC entry point into a processor
; register. Since we can't use inline assembly to get it from
; the interpreter C code, stuff it into the return value
; register and return.
;
; Arguments:
; None.
;
; Returns:
; The contents of the register in which the entry point is passed.
;
_EbcLLGetEbcEntryPoint PROC NEAR PUBLIC
ret
_EbcLLGetEbcEntryPoint ENDP
;/*++
;
;Routine Description:
;
; Return the caller's value of the stack pointer.
;
;Arguments:
;
; None.
;
;Returns:
;
; The current value of the stack pointer for the caller. We
; adjust it by 4 here because when they called us, the return address
; is put on the stack, thereby lowering it by 4 bytes.
;
;--*/
; UINTN EbcLLGetStackPointer()
_EbcLLGetStackPointer PROC NEAR PUBLIC
mov eax, esp ; get current stack pointer
add eax, 4 ; stack adjusted by this much when we were called
ret
_EbcLLGetStackPointer ENDP
; UINT64 EbcLLGetReturnValue(VOID);
; Routine Description:
; When EBC calls native, on return the VM has to stuff the return
; value into a VM register. It's assumed here that the value is still
; in the register, so simply return and the caller should get the
; return result properly.
;
; Arguments:
; None.
;
; Returns:
; The unmodified value returned by the native code.
;
_EbcLLGetReturnValue PROC NEAR PUBLIC
ret
_EbcLLGetReturnValue ENDP
END

View File

@ -0,0 +1,545 @@
/*++
Copyright (c) 2006, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
EbcSupport.c
Abstract:
This module contains EBC support routines that are customized based on
the target processor.
--*/
#include "EbcInt.h"
#include "EbcExecute.h"
//
// NOTE: This is the stack size allocated for the interpreter
// when it executes an EBC image. The requirements can change
// based on whether or not a debugger is present, and other
// platform-specific configurations.
//
#define VM_STACK_SIZE (1024 * 4)
#define EBC_THUNK_SIZE 32
#define STACK_REMAIN_SIZE (1024 * 4)
VOID
EbcLLCALLEX (
IN VM_CONTEXT *VmPtr,
IN UINTN FuncAddr,
IN UINTN NewStackPointer,
IN VOID *FramePtr,
IN UINT8 Size
)
/*++
Routine Description:
This function is called to execute an EBC CALLEX instruction.
The function check the callee's content to see whether it is common native
code or a thunk to another piece of EBC code.
If the callee is common native code, use EbcLLCAllEXASM to manipulate,
otherwise, set the VM->IP to target EBC code directly to avoid another VM
be startup which cost time and stack space.
Arguments:
VmPtr - Pointer to a VM context.
FuncAddr - Callee's address
NewStackPointer - New stack pointer after the call
FramePtr - New frame pointer after the call
Size - The size of call instruction
Returns:
None.
--*/
{
UINTN IsThunk;
UINTN TargetEbcAddr;
IsThunk = 1;
TargetEbcAddr = 0;
//
// Processor specific code to check whether the callee is a thunk to EBC.
//
if (*((UINT8 *)FuncAddr) != 0xB8) {
IsThunk = 0;
goto Action;
}
if (*((UINT8 *)FuncAddr + 1) != 0xBC) {
IsThunk = 0;
goto Action;
}
if (*((UINT8 *)FuncAddr + 2) != 0x2E) {
IsThunk = 0;
goto Action;
}
if (*((UINT8 *)FuncAddr + 3) != 0x11) {
IsThunk = 0;
goto Action;
}
if (*((UINT8 *)FuncAddr + 4) != 0xCA) {
IsThunk = 0;
goto Action;
}
if (*((UINT8 *)FuncAddr + 5) != 0xB8) {
IsThunk = 0;
goto Action;
}
if (*((UINT8 *)FuncAddr + 10) != 0xB9) {
IsThunk = 0;
goto Action;
}
if (*((UINT8 *)FuncAddr + 15) != 0xFF) {
IsThunk = 0;
goto Action;
}
if (*((UINT8 *)FuncAddr + 16) != 0xE1) {
IsThunk = 0;
goto Action;
}
TargetEbcAddr = ((UINTN)(*((UINT8 *)FuncAddr + 9)) << 24) + ((UINTN)(*((UINT8 *)FuncAddr + 8)) << 16) +
((UINTN)(*((UINT8 *)FuncAddr + 7)) << 8) + ((UINTN)(*((UINT8 *)FuncAddr + 6)));
Action:
if (IsThunk == 1){
//
// The callee is a thunk to EBC, adjust the stack pointer down 16 bytes and
// put our return address and frame pointer on the VM stack.
// Then set the VM's IP to new EBC code.
//
VmPtr->R[0] -= 8;
VmWriteMemN (VmPtr, (UINTN) VmPtr->R[0], (UINTN) FramePtr);
VmPtr->FramePtr = (VOID *) (UINTN) VmPtr->R[0];
VmPtr->R[0] -= 8;
VmWriteMem64 (VmPtr, (UINTN) VmPtr->R[0], (UINT64) (UINTN) (VmPtr->Ip + Size));
VmPtr->Ip = (VMIP) (UINTN) TargetEbcAddr;
} else {
//
// The callee is not a thunk to EBC, call native code.
//
EbcLLCALLEXNative (FuncAddr, NewStackPointer, FramePtr);
//
// Get return value and advance the IP.
//
VmPtr->R[7] = EbcLLGetReturnValue ();
VmPtr->Ip += Size;
}
}
STATIC
UINT64
EbcInterpret (
IN OUT UINTN Arg1,
IN OUT UINTN Arg2,
IN OUT UINTN Arg3,
IN OUT UINTN Arg4,
IN OUT UINTN Arg5,
IN OUT UINTN Arg6,
IN OUT UINTN Arg7,
IN OUT UINTN Arg8,
IN OUT UINTN Arg9,
IN OUT UINTN Arg10,
IN OUT UINTN Arg11,
IN OUT UINTN Arg12,
IN OUT UINTN Arg13,
IN OUT UINTN Arg14,
IN OUT UINTN Arg15,
IN OUT UINTN Arg16
)
/*++
Routine Description:
Begin executing an EBC image. The address of the entry point is passed
in via a processor register, so we'll need to make a call to get the
value.
Arguments:
None. Since we're called from a fixed up thunk (which we want to keep
small), our only so-called argument is the EBC entry point passed in
to us in a processor register.
Returns:
The value returned by the EBC application we're going to run.
--*/
{
//
// Create a new VM context on the stack
//
VM_CONTEXT VmContext;
UINTN Addr;
EFI_STATUS Status;
UINTN StackIndex;
//
// Get the EBC entry point from the processor register.
//
Addr = EbcLLGetEbcEntryPoint ();
//
// Now clear out our context
//
ZeroMem ((VOID *) &VmContext, sizeof (VM_CONTEXT));
//
// Set the VM instruction pointer to the correct location in memory.
//
VmContext.Ip = (VMIP) Addr;
//
// Initialize the stack pointer for the EBC. Get the current system stack
// pointer and adjust it down by the max needed for the interpreter.
//
//
// Align the stack on a natural boundary
//
//
// Allocate stack pool
//
Status = GetEBCStack((EFI_HANDLE)-1, &VmContext.StackPool, &StackIndex);
if (EFI_ERROR(Status)) {
return Status;
}
VmContext.StackTop = (UINT8*)VmContext.StackPool + (STACK_REMAIN_SIZE);
VmContext.R[0] = (UINT64)(UINTN) ((UINT8*)VmContext.StackPool + STACK_POOL_SIZE);
VmContext.HighStackBottom = (UINTN)VmContext.R[0];
VmContext.R[0] &= ~(sizeof (UINTN) - 1);
VmContext.R[0] -= sizeof (UINTN);
//
// Put a magic value in the stack gap, then adjust down again
//
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) VM_STACK_KEY_VALUE;
VmContext.StackMagicPtr = (UINTN *) (UINTN) VmContext.R[0];
VmContext.LowStackTop = (UINTN) VmContext.R[0];
//
// For IA32, this is where we say our return address is
//
VmContext.R[0] -= sizeof (UINTN);
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) Arg16;
VmContext.R[0] -= sizeof (UINTN);
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) Arg15;
VmContext.R[0] -= sizeof (UINTN);
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) Arg14;
VmContext.R[0] -= sizeof (UINTN);
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) Arg13;
VmContext.R[0] -= sizeof (UINTN);
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) Arg12;
VmContext.R[0] -= sizeof (UINTN);
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) Arg11;
VmContext.R[0] -= sizeof (UINTN);
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) Arg10;
VmContext.R[0] -= sizeof (UINTN);
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) Arg9;
VmContext.R[0] -= sizeof (UINTN);
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) Arg8;
VmContext.R[0] -= sizeof (UINTN);
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) Arg7;
VmContext.R[0] -= sizeof (UINTN);
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) Arg6;
VmContext.R[0] -= sizeof (UINTN);
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) Arg5;
VmContext.R[0] -= sizeof (UINTN);
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) Arg4;
VmContext.R[0] -= sizeof (UINTN);
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) Arg3;
VmContext.R[0] -= sizeof (UINTN);
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) Arg2;
VmContext.R[0] -= sizeof (UINTN);
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) Arg1;
VmContext.R[0] -= 16;
VmContext.StackRetAddr = (UINT64) VmContext.R[0];
//
// We need to keep track of where the EBC stack starts. This way, if the EBC
// accesses any stack variables above its initial stack setting, then we know
// it's accessing variables passed into it, which means the data is on the
// VM's stack.
// When we're called, on the stack (high to low) we have the parameters, the
// return address, then the saved ebp. Save the pointer to the return address.
// EBC code knows that's there, so should look above it for function parameters.
// The offset is the size of locals (VMContext + Addr + saved ebp).
// Note that the interpreter assumes there is a 16 bytes of return address on
// the stack too, so adjust accordingly.
// VmContext.HighStackBottom = (UINTN)(Addr + sizeof (VmContext) + sizeof (Addr));
//
//
// Begin executing the EBC code
//
EbcExecute (&VmContext);
//
// Return the value in R[7] unless there was an error
//
ReturnEBCStack(StackIndex);
return (UINT64) VmContext.R[7];
}
STATIC
UINT64
ExecuteEbcImageEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
/*++
Routine Description:
Begin executing an EBC image. The address of the entry point is passed
in via a processor register, so we'll need to make a call to get the
value.
Arguments:
ImageHandle - image handle for the EBC application we're executing
SystemTable - standard system table passed into an driver's entry point
Returns:
The value returned by the EBC application we're going to run.
--*/
{
//
// Create a new VM context on the stack
//
VM_CONTEXT VmContext;
UINTN Addr;
EFI_STATUS Status;
UINTN StackIndex;
//
// Get the EBC entry point from the processor register. Make sure you don't
// call any functions before this or you could mess up the register the
// entry point is passed in.
//
Addr = EbcLLGetEbcEntryPoint ();
//
// Print(L"*** Thunked into EBC entry point - ImageHandle = 0x%X\n", (UINTN)ImageHandle);
// Print(L"EBC entry point is 0x%X\n", (UINT32)(UINTN)Addr);
//
// Now clear out our context
//
ZeroMem ((VOID *) &VmContext, sizeof (VM_CONTEXT));
//
// Save the image handle so we can track the thunks created for this image
//
VmContext.ImageHandle = ImageHandle;
VmContext.SystemTable = SystemTable;
//
// Set the VM instruction pointer to the correct location in memory.
//
VmContext.Ip = (VMIP) Addr;
//
// Initialize the stack pointer for the EBC. Get the current system stack
// pointer and adjust it down by the max needed for the interpreter.
//
//
// Allocate stack pool
//
Status = GetEBCStack(ImageHandle, &VmContext.StackPool, &StackIndex);
if (EFI_ERROR(Status)) {
return Status;
}
VmContext.StackTop = (UINT8*)VmContext.StackPool + (STACK_REMAIN_SIZE);
VmContext.R[0] = (UINT64)(UINTN) ((UINT8*)VmContext.StackPool + STACK_POOL_SIZE);
VmContext.HighStackBottom = (UINTN)VmContext.R[0];
VmContext.R[0] -= sizeof (UINTN);
//
// Put a magic value in the stack gap, then adjust down again
//
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) VM_STACK_KEY_VALUE;
VmContext.StackMagicPtr = (UINTN *) (UINTN) VmContext.R[0];
//
// Align the stack on a natural boundary
// VmContext.R[0] &= ~(sizeof(UINTN) - 1);
//
VmContext.LowStackTop = (UINTN) VmContext.R[0];
VmContext.R[0] -= sizeof (UINTN);
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) SystemTable;
VmContext.R[0] -= sizeof (UINTN);
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) ImageHandle;
VmContext.R[0] -= 16;
VmContext.StackRetAddr = (UINT64) VmContext.R[0];
//
// VM pushes 16-bytes for return address. Simulate that here.
//
//
// Begin executing the EBC code
//
EbcExecute (&VmContext);
//
// Return the value in R[7] unless there was an error
//
return (UINT64) VmContext.R[7];
}
EFI_STATUS
EbcCreateThunks (
IN EFI_HANDLE ImageHandle,
IN VOID *EbcEntryPoint,
OUT VOID **Thunk,
IN UINT32 Flags
)
/*++
Routine Description:
Create an IA32 thunk for the given EBC entry point.
Arguments:
ImageHandle - Handle of image for which this thunk is being created
EbcEntryPoint - Address of the EBC code that the thunk is to call
Thunk - Returned thunk we create here
Returns:
Standard EFI status.
--*/
{
UINT8 *Ptr;
UINT8 *ThunkBase;
UINT32 I;
UINT32 Addr;
INT32 Size;
INT32 ThunkSize;
//
// Check alignment of pointer to EBC code
//
if ((UINT32) (UINTN) EbcEntryPoint & 0x01) {
return EFI_INVALID_PARAMETER;
}
Size = EBC_THUNK_SIZE;
ThunkSize = Size;
Ptr = AllocatePool (Size);
if (Ptr == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// Print(L"Allocate TH: 0x%X\n", (UINT32)Ptr);
//
// Save the start address so we can add a pointer to it to a list later.
//
ThunkBase = Ptr;
//
// Give them the address of our buffer we're going to fix up
//
*Thunk = (VOID *) Ptr;
//
// Add a magic code here to help the VM recognize the thunk..
// mov eax, 0xca112ebc => B8 BC 2E 11 CA
//
*Ptr = 0xB8;
Ptr++;
Size--;
Addr = (UINT32) 0xCA112EBC;
for (I = 0; I < sizeof (Addr); I++) {
*Ptr = (UINT8) (UINTN) Addr;
Addr >>= 8;
Ptr++;
Size--;
}
//
// Add code bytes to load up a processor register with the EBC entry point.
// mov eax, 0xaa55aa55 => B8 55 AA 55 AA
// The first 8 bytes of the thunk entry is the address of the EBC
// entry point.
//
*Ptr = 0xB8;
Ptr++;
Size--;
Addr = (UINT32) EbcEntryPoint;
for (I = 0; I < sizeof (Addr); I++) {
*Ptr = (UINT8) (UINTN) Addr;
Addr >>= 8;
Ptr++;
Size--;
}
//
// Stick in a load of ecx with the address of appropriate VM function.
// mov ecx 12345678h => 0xB9 0x78 0x56 0x34 0x12
//
if (Flags & FLAG_THUNK_ENTRY_POINT) {
Addr = (UINT32) (UINTN) ExecuteEbcImageEntryPoint;
} else {
Addr = (UINT32) (UINTN) EbcInterpret;
}
//
// MOV ecx
//
*Ptr = 0xB9;
Ptr++;
Size--;
for (I = 0; I < sizeof (Addr); I++) {
*Ptr = (UINT8) Addr;
Addr >>= 8;
Ptr++;
Size--;
}
//
// Stick in jump opcode bytes for jmp ecx => 0xFF 0xE1
//
*Ptr = 0xFF;
Ptr++;
Size--;
*Ptr = 0xE1;
Size--;
//
// Double check that our defined size is ok (application error)
//
if (Size < 0) {
ASSERT (FALSE);
return EFI_BUFFER_TOO_SMALL;
}
//
// Add the thunk to the list for this image. Do this last since the add
// function flushes the cache for us.
//
EbcAddImageThunk (ImageHandle, (VOID *) ThunkBase, ThunkSize);
return EFI_SUCCESS;
}

View File

@ -0,0 +1,197 @@
//++
// Copyright (c) 2006, Intel Corporation
// All rights reserved. This program and the accompanying materials
// are licensed and made available under the terms and conditions of the BSD License
// which accompanies this distribution. The full text of the license may be found at
// http://opensource.org/licenses/bsd-license.php
//
// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
//
// Module Name:
//
// EbcLowLevel.s
//
// Abstract:
//
// Contains low level routines for the Virtual Machine implementation
// on an Itanium-based platform.
//
//
//--
.file "EbcLowLevel.s"
#define PROCEDURE_ENTRY(name) .##text; \
.##type name, @function; \
.##proc name; \
name::
#define PROCEDURE_EXIT(name) .##endp name
// Note: use of NESTED_SETUP requires number of locals (l) >= 3
#define NESTED_SETUP(i,l,o,r) \
alloc loc1=ar##.##pfs,i,l,o,r ;\
mov loc0=b0
#define NESTED_RETURN \
mov b0=loc0 ;\
mov ar##.##pfs=loc1 ;;\
br##.##ret##.##dpnt b0;;
.type CopyMem, @function;
//-----------------------------------------------------------------------------
//++
// EbcAsmLLCALLEX
//
// Implements the low level EBC CALLEX instruction. Sets up the
// stack pointer, does the spill of function arguments, and
// calls the native function. On return it restores the original
// stack pointer and returns to the caller.
//
// Arguments :
//
// On Entry :
// in0 = Address of native code to call
// in1 = New stack pointer
//
// Return Value:
//
// As per static calling conventions.
//
//--
//---------------------------------------------------------------------------
;// void EbcAsmLLCALLEX (UINTN FunctionAddr, UINTN EbcStackPointer)
PROCEDURE_ENTRY(EbcAsmLLCALLEX)
NESTED_SETUP (2,6,8,0)
// NESTED_SETUP uses loc0 and loc1 for context save
//
// Save a copy of the EBC VM stack pointer
//
mov r8 = in1;;
//
// Copy stack arguments from EBC stack into registers.
// Assume worst case and copy 8.
//
ld8 out0 = [r8], 8;;
ld8 out1 = [r8], 8;;
ld8 out2 = [r8], 8;;
ld8 out3 = [r8], 8;;
ld8 out4 = [r8], 8;;
ld8 out5 = [r8], 8;;
ld8 out6 = [r8], 8;;
ld8 out7 = [r8], 8;;
//
// Save the original stack pointer
//
mov loc2 = r12;
//
// Save the gp
//
or loc3 = r1, r0
//
// Set the new aligned stack pointer. Reserve space for the required
// 16-bytes of scratch area as well.
//
add r12 = 48, in1
//
// Now call the function. Load up the function address from the descriptor
// pointed to by in0. Then get the gp from the descriptor at the following
// address in the descriptor.
//
ld8 r31 = [in0], 8;;
ld8 r30 = [in0];;
mov b1 = r31
mov r1 = r30
(p0) br.call.dptk.many b0 = b1;;
//
// Restore the original stack pointer and gp
//
mov r12 = loc2
or r1 = loc3, r0
//
// Now return
//
NESTED_RETURN
PROCEDURE_EXIT(EbcAsmLLCALLEX)
PROCEDURE_ENTRY(EbcLLCALLEXNative)
NESTED_SETUP (3,6,3,0)
mov loc2 = in2;;
mov loc3 = in1;;
sub loc2 = loc2, loc3
mov loc4 = r12;;
or loc5 = r1, r0
sub r12 = r12, loc2
mov out2 = loc2;;
and r12 = -0x10, r12
mov out1 = in1;;
mov out0 = r12;;
adds r12 = -0x8, r12
(p0) br.call.dptk.many b0 = CopyMem;;
adds r12 = 0x8, r12
mov out0 = in0;;
mov out1 = r12;;
(p0) br.call.dptk.many b0 = EbcAsmLLCALLEX;;
mov r12 = loc4;;
or r1 = loc5, r0
NESTED_RETURN
PROCEDURE_EXIT(EbcLLCALLEXNative)
//
// UINTN EbcLLGetEbcEntryPoint(VOID)
//
// Description:
// Simply return, so that the caller retrieves the return register
// contents (R8). That's where the thunk-to-ebc code stuffed the
// EBC entry point.
//
PROCEDURE_ENTRY(EbcLLGetEbcEntryPoint)
br.ret.sptk b0 ;;
PROCEDURE_EXIT(EbcLLGetEbcEntryPoint)
//
// INT64 EbcLLGetReturnValue(VOID)
//
// Description:
// This function is called to get the value returned by native code
// to EBC. It simply returns because the return value should still
// be in the register, so the caller just gets the unmodified value.
//
PROCEDURE_ENTRY(EbcLLGetReturnValue)
br.ret.sptk b0 ;;
PROCEDURE_EXIT(EbcLLGetReturnValue)
//
// UINTN EbcLLGetStackPointer(VOID)
//
PROCEDURE_ENTRY(EbcLLGetStackPointer)
mov r8 = r12 ;;
br.ret.sptk b0 ;;
br.sptk.few b6
PROCEDURE_EXIT(EbcLLGetStackPointer)

View File

@ -0,0 +1,869 @@
/*++
Copyright (c) 2006, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
EbcSupport.c
Abstract:
This module contains EBC support routines that are customized based on
the target processor.
--*/
#include "EbcInt.h"
#include "EbcExecute.h"
#include "EbcSupport.h"
STATIC
EFI_STATUS
WriteBundle (
IN VOID *MemPtr,
IN UINT8 Template,
IN UINT64 Slot0,
IN UINT64 Slot1,
IN UINT64 Slot2
);
STATIC
VOID
PushU64 (
VM_CONTEXT *VmPtr,
UINT64 Arg
)
{
//
// Advance the VM stack down, and then copy the argument to the stack.
// Hope it's aligned.
//
VmPtr->R[0] -= sizeof (UINT64);
*(UINT64 *) VmPtr->R[0] = Arg;
}
STATIC
UINT64
EbcInterpret (
UINT64 Arg1,
...
)
{
//
// Create a new VM context on the stack
//
VM_CONTEXT VmContext;
UINTN Addr;
EFI_STATUS Status;
UINTN StackIndex;
VA_LIST List;
UINT64 Arg2;
UINT64 Arg3;
UINT64 Arg4;
UINT64 Arg5;
UINT64 Arg6;
UINT64 Arg7;
UINT64 Arg8;
UINT64 Arg9;
UINT64 Arg10;
UINT64 Arg11;
UINT64 Arg12;
UINT64 Arg13;
UINT64 Arg14;
UINT64 Arg15;
UINT64 Arg16;
//
// Get the EBC entry point from the processor register. Make sure you don't
// call any functions before this or you could mess up the register the
// entry point is passed in.
//
Addr = EbcLLGetEbcEntryPoint ();
//
// Need the args off the stack.
//
VA_START (List, Arg1);
Arg2 = VA_ARG (List, UINT64);
Arg3 = VA_ARG (List, UINT64);
Arg4 = VA_ARG (List, UINT64);
Arg5 = VA_ARG (List, UINT64);
Arg6 = VA_ARG (List, UINT64);
Arg7 = VA_ARG (List, UINT64);
Arg8 = VA_ARG (List, UINT64);
Arg9 = VA_ARG (List, UINT64);
Arg10 = VA_ARG (List, UINT64);
Arg11 = VA_ARG (List, UINT64);
Arg12 = VA_ARG (List, UINT64);
Arg13 = VA_ARG (List, UINT64);
Arg14 = VA_ARG (List, UINT64);
Arg15 = VA_ARG (List, UINT64);
Arg16 = VA_ARG (List, UINT64);
//
// Now clear out our context
//
ZeroMem ((VOID *) &VmContext, sizeof (VM_CONTEXT));
//
// Set the VM instruction pointer to the correct location in memory.
//
VmContext.Ip = (VMIP) Addr;
//
// Initialize the stack pointer for the EBC. Get the current system stack
// pointer and adjust it down by the max needed for the interpreter.
//
//
// NOTE: Eventually we should have the interpreter allocate memory
// for stack space which it will use during its execution. This
// would likely improve performance because the interpreter would
// no longer be required to test each memory access and adjust
// those reading from the stack gap.
//
// For IPF, the stack looks like (assuming 10 args passed)
// arg10
// arg9 (Bottom of high stack)
// [ stack gap for interpreter execution ]
// [ magic value for detection of stack corruption ]
// arg8 (Top of low stack)
// arg7....
// arg1
// [ 64-bit return address ]
// [ ebc stack ]
// If the EBC accesses memory in the stack gap, then we assume that it's
// actually trying to access args9 and greater. Therefore we need to
// adjust memory accesses in this region to point above the stack gap.
//
//
// Now adjust the EBC stack pointer down to leave a gap for interpreter
// execution. Then stuff a magic value there.
//
Status = GetEBCStack((EFI_HANDLE)(UINTN)-1, &VmContext.StackPool, &StackIndex);
if (EFI_ERROR(Status)) {
return Status;
}
VmContext.StackTop = (UINT8*)VmContext.StackPool + (STACK_REMAIN_SIZE);
VmContext.R[0] = (UINT64) ((UINT8*)VmContext.StackPool + STACK_POOL_SIZE);
VmContext.HighStackBottom = (UINTN) VmContext.R[0];
VmContext.R[0] -= sizeof (UINTN);
PushU64 (&VmContext, (UINT64) VM_STACK_KEY_VALUE);
VmContext.StackMagicPtr = (UINTN *) VmContext.R[0];
VmContext.LowStackTop = (UINTN) VmContext.R[0];
//
// Push the EBC arguments on the stack. Does not matter that they may not
// all be valid.
//
PushU64 (&VmContext, Arg16);
PushU64 (&VmContext, Arg15);
PushU64 (&VmContext, Arg14);
PushU64 (&VmContext, Arg13);
PushU64 (&VmContext, Arg12);
PushU64 (&VmContext, Arg11);
PushU64 (&VmContext, Arg10);
PushU64 (&VmContext, Arg9);
PushU64 (&VmContext, Arg8);
PushU64 (&VmContext, Arg7);
PushU64 (&VmContext, Arg6);
PushU64 (&VmContext, Arg5);
PushU64 (&VmContext, Arg4);
PushU64 (&VmContext, Arg3);
PushU64 (&VmContext, Arg2);
PushU64 (&VmContext, Arg1);
//
// Push a bogus return address on the EBC stack because the
// interpreter expects one there. For stack alignment purposes on IPF,
// EBC return addresses are always 16 bytes. Push a bogus value as well.
//
PushU64 (&VmContext, 0);
PushU64 (&VmContext, 0xDEADBEEFDEADBEEF);
VmContext.StackRetAddr = (UINT64) VmContext.R[0];
//
// Begin executing the EBC code
//
EbcExecute (&VmContext);
//
// Return the value in R[7] unless there was an error
//
ReturnEBCStack(StackIndex);
return (UINT64) VmContext.R[7];
}
STATIC
UINT64
ExecuteEbcImageEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
/*++
Routine Description:
IPF implementation.
Begin executing an EBC image. The address of the entry point is passed
in via a processor register, so we'll need to make a call to get the
value.
Arguments:
ImageHandle - image handle for the EBC application we're executing
SystemTable - standard system table passed into an driver's entry point
Returns:
The value returned by the EBC application we're going to run.
--*/
{
//
// Create a new VM context on the stack
//
VM_CONTEXT VmContext;
UINTN Addr;
EFI_STATUS Status;
UINTN StackIndex;
//
// Get the EBC entry point from the processor register. Make sure you don't
// call any functions before this or you could mess up the register the
// entry point is passed in.
//
Addr = EbcLLGetEbcEntryPoint ();
//
// Now clear out our context
//
ZeroMem ((VOID *) &VmContext, sizeof (VM_CONTEXT));
//
// Save the image handle so we can track the thunks created for this image
//
VmContext.ImageHandle = ImageHandle;
VmContext.SystemTable = SystemTable;
//
// Set the VM instruction pointer to the correct location in memory.
//
VmContext.Ip = (VMIP) Addr;
//
// Get the stack pointer. This is the bottom of the upper stack.
//
Addr = EbcLLGetStackPointer ();
Status = GetEBCStack(ImageHandle, &VmContext.StackPool, &StackIndex);
if (EFI_ERROR(Status)) {
return Status;
}
VmContext.StackTop = (UINT8*)VmContext.StackPool + (STACK_REMAIN_SIZE);
VmContext.R[0] = (UINT64) ((UINT8*)VmContext.StackPool + STACK_POOL_SIZE);
VmContext.HighStackBottom = (UINTN) VmContext.R[0];
VmContext.R[0] -= sizeof (UINTN);
//
// Allocate stack space for the interpreter. Then put a magic value
// at the bottom so we can detect stack corruption.
//
PushU64 (&VmContext, (UINT64) VM_STACK_KEY_VALUE);
VmContext.StackMagicPtr = (UINTN *) (UINTN) VmContext.R[0];
//
// When we thunk to external native code, we copy the last 8 qwords from
// the EBC stack into the processor registers, and adjust the stack pointer
// up. If the caller is not passing 8 parameters, then we've moved the
// stack pointer up into the stack gap. If this happens, then the caller
// can mess up the stack gap contents (in particular our magic value).
// Therefore, leave another gap below the magic value. Pick 10 qwords down,
// just as a starting point.
//
VmContext.R[0] -= 10 * sizeof (UINT64);
//
// Align the stack pointer such that after pushing the system table,
// image handle, and return address on the stack, it's aligned on a 16-byte
// boundary as required for IPF.
//
VmContext.R[0] &= (INT64)~0x0f;
VmContext.LowStackTop = (UINTN) VmContext.R[0];
//
// Simply copy the image handle and system table onto the EBC stack.
// Greatly simplifies things by not having to spill the args
//
PushU64 (&VmContext, (UINT64) SystemTable);
PushU64 (&VmContext, (UINT64) ImageHandle);
//
// Interpreter assumes 64-bit return address is pushed on the stack.
// IPF does not do this so pad the stack accordingly. Also, a
// "return address" is 16 bytes as required for IPF stack alignments.
//
PushU64 (&VmContext, (UINT64) 0);
PushU64 (&VmContext, (UINT64) 0x1234567887654321);
VmContext.StackRetAddr = (UINT64) VmContext.R[0];
//
// Begin executing the EBC code
//
EbcExecute (&VmContext);
//
// Return the value in R[7] unless there was an error
//
ReturnEBCStack(StackIndex);
return (UINT64) VmContext.R[7];
}
EFI_STATUS
EbcCreateThunks (
IN EFI_HANDLE ImageHandle,
IN VOID *EbcEntryPoint,
OUT VOID **Thunk,
IN UINT32 Flags
)
/*++
Routine Description:
Create thunks for an EBC image entry point, or an EBC protocol service.
Arguments:
ImageHandle - Image handle for the EBC image. If not null, then we're
creating a thunk for an image entry point.
EbcEntryPoint - Address of the EBC code that the thunk is to call
Thunk - Returned thunk we create here
Flags - Flags indicating options for creating the thunk
Returns:
Standard EFI status.
--*/
{
UINT8 *Ptr;
UINT8 *ThunkBase;
UINT64 Addr;
UINT64 Code[3]; // Code in a bundle
UINT64 RegNum; // register number for MOVL
UINT64 I; // bits of MOVL immediate data
UINT64 Ic; // bits of MOVL immediate data
UINT64 Imm5c; // bits of MOVL immediate data
UINT64 Imm9d; // bits of MOVL immediate data
UINT64 Imm7b; // bits of MOVL immediate data
UINT64 Br; // branch register for loading and jumping
UINT64 *Data64Ptr;
UINT32 ThunkSize;
UINT32 Size;
//
// Check alignment of pointer to EBC code, which must always be aligned
// on a 2-byte boundary.
//
if ((UINT32) (UINTN) EbcEntryPoint & 0x01) {
return EFI_INVALID_PARAMETER;
}
//
// Allocate memory for the thunk. Make the (most likely incorrect) assumption
// that the returned buffer is not aligned, so round up to the next
// alignment size.
//
Size = EBC_THUNK_SIZE + EBC_THUNK_ALIGNMENT - 1;
ThunkSize = Size;
Ptr = AllocatePool (Size);
if (Ptr == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// Save the start address of the buffer.
//
ThunkBase = Ptr;
//
// Make sure it's aligned for code execution. If not, then
// round up.
//
if ((UINT32) (UINTN) Ptr & (EBC_THUNK_ALIGNMENT - 1)) {
Ptr = (UINT8 *) (((UINTN) Ptr + (EBC_THUNK_ALIGNMENT - 1)) &~ (UINT64) (EBC_THUNK_ALIGNMENT - 1));
}
//
// Return the pointer to the thunk to the caller to user as the
// image entry point.
//
*Thunk = (VOID *) Ptr;
//
// Clear out the thunk entry
// ZeroMem(Ptr, Size);
//
// For IPF, when you do a call via a function pointer, the function pointer
// actually points to a function descriptor which consists of a 64-bit
// address of the function, followed by a 64-bit gp for the function being
// called. See the the Software Conventions and Runtime Architecture Guide
// for details.
// So first off in our thunk, create a descriptor for our actual thunk code.
// This means we need to create a pointer to the thunk code (which follows
// the descriptor we're going to create), followed by the gp of the Vm
// interpret function we're going to eventually execute.
//
Data64Ptr = (UINT64 *) Ptr;
//
// Write the function's entry point (which is our thunk code that follows
// this descriptor we're creating).
//
*Data64Ptr = (UINT64) (Data64Ptr + 2);
//
// Get the gp from the descriptor for EbcInterpret and stuff it in our thunk
// descriptor.
//
*(Data64Ptr + 1) = *(UINT64 *) ((UINT64 *) (UINTN) EbcInterpret + 1);
//
// Advance our thunk data pointer past the descriptor. Since the
// descriptor consists of 16 bytes, the pointer is still aligned for
// IPF code execution (on 16-byte boundary).
//
Ptr += sizeof (UINT64) * 2;
//
// *************************** MAGIC BUNDLE ********************************
//
// Write magic code bundle for: movl r8 = 0xca112ebcca112ebc to help the VM
// to recognize it is a thunk.
//
Addr = (UINT64) 0xCA112EBCCA112EBC;
//
// Now generate the code bytes. First is nop.m 0x0
//
Code[0] = OPCODE_NOP;
//
// Next is simply Addr[62:22] (41 bits) of the address
//
Code[1] = RShiftU64 (Addr, 22) & 0x1ffffffffff;
//
// Extract bits from the address for insertion into the instruction
// i = Addr[63:63]
//
I = RShiftU64 (Addr, 63) & 0x01;
//
// ic = Addr[21:21]
//
Ic = RShiftU64 (Addr, 21) & 0x01;
//
// imm5c = Addr[20:16] for 5 bits
//
Imm5c = RShiftU64 (Addr, 16) & 0x1F;
//
// imm9d = Addr[15:7] for 9 bits
//
Imm9d = RShiftU64 (Addr, 7) & 0x1FF;
//
// imm7b = Addr[6:0] for 7 bits
//
Imm7b = Addr & 0x7F;
//
// The EBC entry point will be put into r8, so r8 can be used here
// temporary. R8 is general register and is auto-serialized.
//
RegNum = 8;
//
// Next is jumbled data, including opcode and rest of address
//
Code[2] = LShiftU64 (Imm7b, 13);
Code[2] = Code[2] | LShiftU64 (0x00, 20); // vc
Code[2] = Code[2] | LShiftU64 (Ic, 21);
Code[2] = Code[2] | LShiftU64 (Imm5c, 22);
Code[2] = Code[2] | LShiftU64 (Imm9d, 27);
Code[2] = Code[2] | LShiftU64 (I, 36);
Code[2] = Code[2] | LShiftU64 ((UINT64)MOVL_OPCODE, 37);
Code[2] = Code[2] | LShiftU64 ((RegNum & 0x7F), 6);
WriteBundle ((VOID *) Ptr, 0x05, Code[0], Code[1], Code[2]);
//
// *************************** FIRST BUNDLE ********************************
//
// Write code bundle for: movl r8 = EBC_ENTRY_POINT so we pass
// the ebc entry point in to the interpreter function via a processor
// register.
// Note -- we could easily change this to pass in a pointer to a structure
// that contained, among other things, the EBC image's entry point. But
// for now pass it directly.
//
Ptr += 16;
Addr = (UINT64) EbcEntryPoint;
//
// Now generate the code bytes. First is nop.m 0x0
//
Code[0] = OPCODE_NOP;
//
// Next is simply Addr[62:22] (41 bits) of the address
//
Code[1] = RShiftU64 (Addr, 22) & 0x1ffffffffff;
//
// Extract bits from the address for insertion into the instruction
// i = Addr[63:63]
//
I = RShiftU64 (Addr, 63) & 0x01;
//
// ic = Addr[21:21]
//
Ic = RShiftU64 (Addr, 21) & 0x01;
//
// imm5c = Addr[20:16] for 5 bits
//
Imm5c = RShiftU64 (Addr, 16) & 0x1F;
//
// imm9d = Addr[15:7] for 9 bits
//
Imm9d = RShiftU64 (Addr, 7) & 0x1FF;
//
// imm7b = Addr[6:0] for 7 bits
//
Imm7b = Addr & 0x7F;
//
// Put the EBC entry point in r8, which is the location of the return value
// for functions.
//
RegNum = 8;
//
// Next is jumbled data, including opcode and rest of address
//
Code[2] = LShiftU64 (Imm7b, 13);
Code[2] = Code[2] | LShiftU64 (0x00, 20); // vc
Code[2] = Code[2] | LShiftU64 (Ic, 21);
Code[2] = Code[2] | LShiftU64 (Imm5c, 22);
Code[2] = Code[2] | LShiftU64 (Imm9d, 27);
Code[2] = Code[2] | LShiftU64 (I, 36);
Code[2] = Code[2] | LShiftU64 ((UINT64)MOVL_OPCODE, 37);
Code[2] = Code[2] | LShiftU64 ((RegNum & 0x7F), 6);
WriteBundle ((VOID *) Ptr, 0x05, Code[0], Code[1], Code[2]);
//
// *************************** NEXT BUNDLE *********************************
//
// Write code bundle for:
// movl rx = offset_of(EbcInterpret|ExecuteEbcImageEntryPoint)
//
// Advance pointer to next bundle, then compute the offset from this bundle
// to the address of the entry point of the interpreter.
//
Ptr += 16;
if (Flags & FLAG_THUNK_ENTRY_POINT) {
Addr = (UINT64) ExecuteEbcImageEntryPoint;
} else {
Addr = (UINT64) EbcInterpret;
}
//
// Indirection on Itanium-based systems
//
Addr = *(UINT64 *) Addr;
//
// Now write the code to load the offset into a register
//
Code[0] = OPCODE_NOP;
//
// Next is simply Addr[62:22] (41 bits) of the address
//
Code[1] = RShiftU64 (Addr, 22) & 0x1ffffffffff;
//
// Extract bits from the address for insertion into the instruction
// i = Addr[63:63]
//
I = RShiftU64 (Addr, 63) & 0x01;
//
// ic = Addr[21:21]
//
Ic = RShiftU64 (Addr, 21) & 0x01;
//
// imm5c = Addr[20:16] for 5 bits
//
Imm5c = RShiftU64 (Addr, 16) & 0x1F;
//
// imm9d = Addr[15:7] for 9 bits
//
Imm9d = RShiftU64 (Addr, 7) & 0x1FF;
//
// imm7b = Addr[6:0] for 7 bits
//
Imm7b = Addr & 0x7F;
//
// Put it in r31, a scratch register
//
RegNum = 31;
//
// Next is jumbled data, including opcode and rest of address
//
Code[2] = LShiftU64(Imm7b, 13);
Code[2] = Code[2] | LShiftU64 (0x00, 20); // vc
Code[2] = Code[2] | LShiftU64 (Ic, 21);
Code[2] = Code[2] | LShiftU64 (Imm5c, 22);
Code[2] = Code[2] | LShiftU64 (Imm9d, 27);
Code[2] = Code[2] | LShiftU64 (I, 36);
Code[2] = Code[2] | LShiftU64 ((UINT64)MOVL_OPCODE, 37);
Code[2] = Code[2] | LShiftU64 ((RegNum & 0x7F), 6);
WriteBundle ((VOID *) Ptr, 0x05, Code[0], Code[1], Code[2]);
//
// *************************** NEXT BUNDLE *********************************
//
// Load branch register with EbcInterpret() function offset from the bundle
// address: mov b6 = RegNum
//
// See volume 3 page 4-29 of the Arch. Software Developer's Manual.
//
// Advance pointer to next bundle
//
Ptr += 16;
Code[0] = OPCODE_NOP;
Code[1] = OPCODE_NOP;
Code[2] = OPCODE_MOV_BX_RX;
//
// Pick a branch register to use. Then fill in the bits for the branch
// register and user register (same user register as previous bundle).
//
Br = 6;
Code[2] |= LShiftU64 (Br, 6);
Code[2] |= LShiftU64 (RegNum, 13);
WriteBundle ((VOID *) Ptr, 0x0d, Code[0], Code[1], Code[2]);
//
// *************************** NEXT BUNDLE *********************************
//
// Now do the branch: (p0) br.cond.sptk.few b6
//
// Advance pointer to next bundle.
// Fill in the bits for the branch register (same reg as previous bundle)
//
Ptr += 16;
Code[0] = OPCODE_NOP;
Code[1] = OPCODE_NOP;
Code[2] = OPCODE_BR_COND_SPTK_FEW;
Code[2] |= LShiftU64 (Br, 13);
WriteBundle ((VOID *) Ptr, 0x1d, Code[0], Code[1], Code[2]);
//
// Add the thunk to our list of allocated thunks so we can do some cleanup
// when the image is unloaded. Do this last since the Add function flushes
// the instruction cache for us.
//
EbcAddImageThunk (ImageHandle, (VOID *) ThunkBase, ThunkSize);
//
// Done
//
return EFI_SUCCESS;
}
STATIC
EFI_STATUS
WriteBundle (
IN VOID *MemPtr,
IN UINT8 Template,
IN UINT64 Slot0,
IN UINT64 Slot1,
IN UINT64 Slot2
)
/*++
Routine Description:
Given raw bytes of Itanium based code, format them into a bundle and
write them out.
Arguments:
MemPtr - pointer to memory location to write the bundles to
Template - 5-bit template
Slot0-2 - instruction slot data for the bundle
Returns:
EFI_INVALID_PARAMETER - Pointer is not aligned
- No more than 5 bits in template
- More than 41 bits used in code
EFI_SUCCESS - All data is written.
--*/
{
UINT8 *BPtr;
UINT32 Index;
UINT64 Low64;
UINT64 High64;
//
// Verify pointer is aligned
//
if ((UINT64) MemPtr & 0xF) {
return EFI_INVALID_PARAMETER;
}
//
// Verify no more than 5 bits in template
//
if (Template &~0x1F) {
return EFI_INVALID_PARAMETER;
}
//
// Verify max of 41 bits used in code
//
if ((Slot0 | Slot1 | Slot2) &~0x1ffffffffff) {
return EFI_INVALID_PARAMETER;
}
Low64 = LShiftU64 (Slot1, 46);
Low64 = Low64 | LShiftU64 (Slot0, 5) | Template;
High64 = RShiftU64 (Slot1, 18);
High64 = High64 | LShiftU64 (Slot2, 23);
//
// Now write it all out
//
BPtr = (UINT8 *) MemPtr;
for (Index = 0; Index < 8; Index++) {
*BPtr = (UINT8) Low64;
Low64 = RShiftU64 (Low64, 8);
BPtr++;
}
for (Index = 0; Index < 8; Index++) {
*BPtr = (UINT8) High64;
High64 = RShiftU64 (High64, 8);
BPtr++;
}
return EFI_SUCCESS;
}
VOID
EbcLLCALLEX (
IN VM_CONTEXT *VmPtr,
IN UINTN FuncAddr,
IN UINTN NewStackPointer,
IN VOID *FramePtr,
IN UINT8 Size
)
/*++
Routine Description:
This function is called to execute an EBC CALLEX instruction.
The function check the callee's content to see whether it is common native
code or a thunk to another piece of EBC code.
If the callee is common native code, use EbcLLCAllEXASM to manipulate,
otherwise, set the VM->IP to target EBC code directly to avoid another VM
be startup which cost time and stack space.
Arguments:
VmPtr - Pointer to a VM context.
FuncAddr - Callee's address
NewStackPointer - New stack pointer after the call
FramePtr - New frame pointer after the call
Size - The size of call instruction
Returns:
None.
--*/
{
UINTN IsThunk;
UINTN TargetEbcAddr;
UINTN CodeOne18;
UINTN CodeOne23;
UINTN CodeTwoI;
UINTN CodeTwoIc;
UINTN CodeTwo7b;
UINTN CodeTwo5c;
UINTN CodeTwo9d;
UINTN CalleeAddr;
IsThunk = 1;
TargetEbcAddr = 0;
//
// FuncAddr points to the descriptor of the target instructions.
//
CalleeAddr = *((UINT64 *)FuncAddr);
//
// Processor specific code to check whether the callee is a thunk to EBC.
//
if (*((UINT64 *)CalleeAddr) != 0xBCCA000100000005) {
IsThunk = 0;
goto Action;
}
if (*((UINT64 *)CalleeAddr + 1) != 0x697623C1004A112E) {
IsThunk = 0;
goto Action;
}
CodeOne18 = RShiftU64 (*((UINT64 *)CalleeAddr + 2), 46) & 0x3FFFF;
CodeOne23 = (*((UINT64 *)CalleeAddr + 3)) & 0x7FFFFF;
CodeTwoI = RShiftU64 (*((UINT64 *)CalleeAddr + 3), 59) & 0x1;
CodeTwoIc = RShiftU64 (*((UINT64 *)CalleeAddr + 3), 44) & 0x1;
CodeTwo7b = RShiftU64 (*((UINT64 *)CalleeAddr + 3), 36) & 0x7F;
CodeTwo5c = RShiftU64 (*((UINT64 *)CalleeAddr + 3), 45) & 0x1F;
CodeTwo9d = RShiftU64 (*((UINT64 *)CalleeAddr + 3), 50) & 0x1FF;
TargetEbcAddr = CodeTwo7b;
TargetEbcAddr = TargetEbcAddr | LShiftU64 (CodeTwo9d, 7);
TargetEbcAddr = TargetEbcAddr | LShiftU64 (CodeTwo5c, 16);
TargetEbcAddr = TargetEbcAddr | LShiftU64 (CodeTwoIc, 21);
TargetEbcAddr = TargetEbcAddr | LShiftU64 (CodeOne18, 22);
TargetEbcAddr = TargetEbcAddr | LShiftU64 (CodeOne23, 40);
TargetEbcAddr = TargetEbcAddr | LShiftU64 (CodeTwoI, 63);
Action:
if (IsThunk == 1){
//
// The callee is a thunk to EBC, adjust the stack pointer down 16 bytes and
// put our return address and frame pointer on the VM stack.
// Then set the VM's IP to new EBC code.
//
VmPtr->R[0] -= 8;
VmWriteMemN (VmPtr, (UINTN) VmPtr->R[0], (UINTN) FramePtr);
VmPtr->FramePtr = (VOID *) (UINTN) VmPtr->R[0];
VmPtr->R[0] -= 8;
VmWriteMem64 (VmPtr, (UINTN) VmPtr->R[0], (UINT64) (VmPtr->Ip + Size));
VmPtr->Ip = (VMIP) (UINTN) TargetEbcAddr;
} else {
//
// The callee is not a thunk to EBC, call native code.
//
EbcLLCALLEXNative (FuncAddr, NewStackPointer, FramePtr);
//
// Get return value and advance the IP.
//
VmPtr->R[7] = EbcLLGetReturnValue ();
VmPtr->Ip += Size;
}
}

View File

@ -0,0 +1,56 @@
/*++
Copyright (c) 2006, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
EbcSupport.h
Abstract:
Definition of EBC Support function
Revision History
--*/
#ifndef _IPF_EBC_SUPPORT_H_
#define _IPF_EBC_SUPPORT_H_
#define VM_STACK_SIZE (1024 * 32)
#define EBC_THUNK_SIZE 128
#define STACK_REMAIN_SIZE (1024 * 4)
//
// For code execution, thunks must be aligned on 16-byte boundary
//
#define EBC_THUNK_ALIGNMENT 16
//
// Opcodes for IPF instructions. We'll need to hand-create thunk code (stuffing
// bits) to insert a jump to the interpreter.
//
#define OPCODE_NOP (UINT64) 0x00008000000
#define OPCODE_BR_COND_SPTK_FEW (UINT64) 0x00100000000
#define OPCODE_MOV_BX_RX (UINT64) 0x00E00100000
//
// Opcode for MOVL instruction
//
#define MOVL_OPCODE 0x06
VOID
EbcAsmLLCALLEX (
IN UINTN CallAddr,
IN UINTN EbcSp
);
#endif

View 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.
#*
#****************************************************************************
#****************************************************************************
# REV 1.0
#****************************************************************************
#
# Rev Date Description
# --- -------- ------------------------------------------------------------
# 1.0 05/09/12 Initial creation of file.
#
#****************************************************************************
#* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
# This code provides low level routines that support the Virtual Machine
# for option ROMs.
#* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
#---------------------------------------------------------------------------
# Equate files needed.
#---------------------------------------------------------------------------
#---------------------------------------------------------------------------
##GenericPostSegment SEGMENT USE16
#---------------------------------------------------------------------------
#****************************************************************************
# EbcLLCALLEX
#
# This function is called to execute an EBC CALLEX instruction.
# This instruction requires that we thunk out to external native
# code. For x64, we switch stacks, copy the arguments to the stack
# and jump to the specified function.
# On return, we restore the stack pointer to its original location.
#
# Destroys no working registers.
#****************************************************************************
.global _CopyMem;
# VOID EbcLLCALLEXNative(UINTN FuncAddr, UINTN NewStackPointer, VOID *FramePtr)
.global _EbcLLCALLEXNative;
_EbcLLCALLEXNative:
push %rbp
push %rbx
mov %rsp, %rbp
# Function prolog
# Copy FuncAddr to a preserved register.
mov %rcx, %rbx
# Set stack pointer to new value
sub %r8, %rdx
sub %rsp, %r8
mov %rsp, %rcx
sub %rsp, 0x20
call _CopyMem
add %rsp, 0x20
# Considering the worst case, load 4 potiential arguments
# into registers.
mov (%rsp), %rcx
mov 8(%rsp), %rdx
mov 10(%rsp), %r8
mov 18(%rsp), %r9
# Now call the external routine
call *%rbx
# Function epilog
mov %rbp, %rsp
pop %rbx
pop %rbp
ret
# UINTN EbcLLGetEbcEntryPoint(VOID);
# Routine Description:
# The VM thunk code stuffs an EBC entry point into a processor
# register. Since we can't use inline assembly to get it from
# the interpreter C code, stuff it into the return value
# register and return.
#
# Arguments:
# None.
#
# Returns:
# The contents of the register in which the entry point is passed.
#
.global _EbcLLGetEbcEntryPoint;
_EbcLLGetEbcEntryPoint:
ret
#/*++
#
#Routine Description:
#
# Return the caller's value of the stack pointer.
#
#Arguments:
#
# None.
#
#Returns:
#
# The current value of the stack pointer for the caller. We
# adjust it by 4 here because when they called us, the return address
# is put on the stack, thereby lowering it by 4 bytes.
#
#--*/
# UINTN EbcLLGetStackPointer()
.global _EbcLLGetStackPointer;
_EbcLLGetStackPointer:
mov %rsp, %rax
# Stack adjusted by this much when we were called,
# For this function, it's 4.
add $4, %rax
ret
.global _EbcLLGetReturnValue;
_EbcLLGetReturnValue:
# UINT64 EbcLLGetReturnValue(VOID);
# Routine Description:
# When EBC calls native, on return the VM has to stuff the return
# value into a VM register. It's assumed here that the value is still
# in the register, so simply return and the caller should get the
# return result properly.
#
# Arguments:
# None.
#
# Returns:
# The unmodified value returned by the native code.
#
ret

View File

@ -0,0 +1,154 @@
page ,132
title VM ASSEMBLY LANGUAGE ROUTINES
;****************************************************************************
;*
;* Copyright (c) 2006, Intel Corporation
;* All rights reserved. This program and the accompanying materials
;* are licensed and made available under the terms and conditions of the BSD License
;* which accompanies this distribution. The full text of the license may be found at
;* http://opensource.org/licenses/bsd-license.php
;*
;* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
;* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
;*
;****************************************************************************
;****************************************************************************
; REV 1.0
;****************************************************************************
;
; Rev Date Description
; --- -------- ------------------------------------------------------------
; 1.0 05/09/12 Initial creation of file.
;
;****************************************************************************
;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; This code provides low level routines that support the Virtual Machine
; for option ROMs.
;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;---------------------------------------------------------------------------
; Equate files needed.
;---------------------------------------------------------------------------
text SEGMENT
;---------------------------------------------------------------------------
;;GenericPostSegment SEGMENT USE16
;---------------------------------------------------------------------------
;****************************************************************************
; EbcLLCALLEX
;
; This function is called to execute an EBC CALLEX instruction.
; This instruction requires that we thunk out to external native
; code. For x64, we switch stacks, copy the arguments to the stack
; and jump to the specified function.
; On return, we restore the stack pointer to its original location.
;
; Destroys no working registers.
;****************************************************************************
; VOID EbcLLCALLEXNative(UINTN FuncAddr, UINTN NewStackPointer, VOID *FramePtr)
CopyMem PROTO Destination:PTR DWORD, Source:PTR DWORD, Count:DWORD
EbcLLCALLEXNative PROC NEAR PUBLIC
push rbp
push rbx
mov rbp, rsp
; Function prolog
; Copy FuncAddr to a preserved register.
mov rbx, rcx
; Set stack pointer to new value
sub r8, rdx
sub rsp, r8
mov rcx, rsp
sub rsp, 20h
call CopyMem
add rsp, 20h
; Considering the worst case, load 4 potiential arguments
; into registers.
mov rcx, qword ptr [rsp]
mov rdx, qword ptr [rsp+8h]
mov r8, qword ptr [rsp+10h]
mov r9, qword ptr [rsp+18h]
; Now call the external routine
call rbx
; Function epilog
mov rsp, rbp
pop rbx
pop rbp
ret
EbcLLCALLEXNative ENDP
; UINTN EbcLLGetEbcEntryPoint(VOID);
; Routine Description:
; The VM thunk code stuffs an EBC entry point into a processor
; register. Since we can't use inline assembly to get it from
; the interpreter C code, stuff it into the return value
; register and return.
;
; Arguments:
; None.
;
; Returns:
; The contents of the register in which the entry point is passed.
;
EbcLLGetEbcEntryPoint PROC NEAR PUBLIC
ret
EbcLLGetEbcEntryPoint ENDP
;/*++
;
;Routine Description:
;
; Return the caller's value of the stack pointer.
;
;Arguments:
;
; None.
;
;Returns:
;
; The current value of the stack pointer for the caller. We
; adjust it by 4 here because when they called us, the return address
; is put on the stack, thereby lowering it by 4 bytes.
;
;--*/
; UINTN EbcLLGetStackPointer()
EbcLLGetStackPointer PROC NEAR PUBLIC
mov rax, rsp ; get current stack pointer
; Stack adjusted by this much when we were called,
; For this function, it's 4.
add rax, 4
ret
EbcLLGetStackPointer ENDP
; UINT64 EbcLLGetReturnValue(VOID);
; Routine Description:
; When EBC calls native, on return the VM has to stuff the return
; value into a VM register. It's assumed here that the value is still
; in the register, so simply return and the caller should get the
; return result properly.
;
; Arguments:
; None.
;
; Returns:
; The unmodified value returned by the native code.
;
EbcLLGetReturnValue PROC NEAR PUBLIC
ret
EbcLLGetReturnValue ENDP
text ENDS
END

View File

@ -0,0 +1,619 @@
/*++
Copyright (c) 2006, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
EbcSupport.c
Abstract:
This module contains EBC support routines that are customized based on
the target x64 processor.
--*/
#include "EbcInt.h"
#include "EbcExecute.h"
//
// NOTE: This is the stack size allocated for the interpreter
// when it executes an EBC image. The requirements can change
// based on whether or not a debugger is present, and other
// platform-specific configurations.
//
#define VM_STACK_SIZE (1024 * 8)
#define EBC_THUNK_SIZE 64
#define STACK_REMAIN_SIZE (1024 * 4)
STATIC
VOID
PushU64 (
VM_CONTEXT *VmPtr,
UINT64 Arg
)
/*++
Routine Description:
Push a 64 bit unsigned value to the VM stack.
Arguments:
VmPtr - The pointer to current VM context.
Arg - The value to be pushed
Returns:
VOID
--*/
{
//
// Advance the VM stack down, and then copy the argument to the stack.
// Hope it's aligned.
//
VmPtr->R[0] -= sizeof (UINT64);
*(UINT64 *) VmPtr->R[0] = Arg;
return;
}
STATIC
UINT64
EbcInterpret (
UINTN Arg1,
UINTN Arg2,
UINTN Arg3,
UINTN Arg4,
UINTN Arg5,
UINTN Arg6,
UINTN Arg7,
UINTN Arg8,
UINTN Arg9,
UINTN Arg10,
UINTN Arg11,
UINTN Arg12,
UINTN Arg13,
UINTN Arg14,
UINTN Arg15,
UINTN Arg16
)
/*++
Routine Description:
Begin executing an EBC image. The address of the entry point is passed
in via a processor register, so we'll need to make a call to get the
value.
Arguments:
This is a thunk function. Microsoft x64 compiler only provide fast_call
calling convention, so the first four arguments are passed by rcx, rdx,
r8, and r9, while other arguments are passed in stack.
Returns:
The value returned by the EBC application we're going to run.
--*/
{
//
// Create a new VM context on the stack
//
VM_CONTEXT VmContext;
UINTN Addr;
EFI_STATUS Status;
UINTN StackIndex;
//
// Get the EBC entry point from the processor register.
// Don't call any function before getting the EBC entry
// point because this will collab the return register.
//
Addr = EbcLLGetEbcEntryPoint ();
//
// Now clear out our context
//
ZeroMem ((VOID *) &VmContext, sizeof (VM_CONTEXT));
//
// Set the VM instruction pointer to the correct location in memory.
//
VmContext.Ip = (VMIP) Addr;
//
// Initialize the stack pointer for the EBC. Get the current system stack
// pointer and adjust it down by the max needed for the interpreter.
//
Addr = EbcLLGetStackPointer ();
//
// Adjust the VM's stack pointer down.
//
Status = GetEBCStack((EFI_HANDLE)(UINTN)-1, &VmContext.StackPool, &StackIndex);
if (EFI_ERROR(Status)) {
return Status;
}
VmContext.StackTop = (UINT8*)VmContext.StackPool + (STACK_REMAIN_SIZE);
VmContext.R[0] = (UINT64) ((UINT8*)VmContext.StackPool + STACK_POOL_SIZE);
VmContext.HighStackBottom = (UINTN) VmContext.R[0];
VmContext.R[0] -= sizeof (UINTN);
//
// Align the stack on a natural boundary.
//
VmContext.R[0] &= ~(sizeof (UINTN) - 1);
//
// Put a magic value in the stack gap, then adjust down again.
//
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) VM_STACK_KEY_VALUE;
VmContext.StackMagicPtr = (UINTN *) (UINTN) VmContext.R[0];
//
// The stack upper to LowStackTop is belong to the VM.
//
VmContext.LowStackTop = (UINTN) VmContext.R[0];
//
// For the worst case, assume there are 4 arguments passed in registers, store
// them to VM's stack.
//
PushU64 (&VmContext, (UINT64) Arg16);
PushU64 (&VmContext, (UINT64) Arg15);
PushU64 (&VmContext, (UINT64) Arg14);
PushU64 (&VmContext, (UINT64) Arg13);
PushU64 (&VmContext, (UINT64) Arg12);
PushU64 (&VmContext, (UINT64) Arg11);
PushU64 (&VmContext, (UINT64) Arg10);
PushU64 (&VmContext, (UINT64) Arg9);
PushU64 (&VmContext, (UINT64) Arg8);
PushU64 (&VmContext, (UINT64) Arg7);
PushU64 (&VmContext, (UINT64) Arg6);
PushU64 (&VmContext, (UINT64) Arg5);
PushU64 (&VmContext, (UINT64) Arg4);
PushU64 (&VmContext, (UINT64) Arg3);
PushU64 (&VmContext, (UINT64) Arg2);
PushU64 (&VmContext, (UINT64) Arg1);
//
// Interpreter assumes 64-bit return address is pushed on the stack.
// The x64 does not do this so pad the stack accordingly.
//
PushU64 (&VmContext, (UINT64) 0);
PushU64 (&VmContext, (UINT64) 0x1234567887654321ULL);
//
// For x64, this is where we say our return address is
//
VmContext.StackRetAddr = (UINT64) VmContext.R[0];
//
// We need to keep track of where the EBC stack starts. This way, if the EBC
// accesses any stack variables above its initial stack setting, then we know
// it's accessing variables passed into it, which means the data is on the
// VM's stack.
// When we're called, on the stack (high to low) we have the parameters, the
// return address, then the saved ebp. Save the pointer to the return address.
// EBC code knows that's there, so should look above it for function parameters.
// The offset is the size of locals (VMContext + Addr + saved ebp).
// Note that the interpreter assumes there is a 16 bytes of return address on
// the stack too, so adjust accordingly.
// VmContext.HighStackBottom = (UINTN)(Addr + sizeof (VmContext) + sizeof (Addr));
//
//
// Begin executing the EBC code
//
EbcExecute (&VmContext);
//
// Return the value in R[7] unless there was an error
//
ReturnEBCStack(StackIndex);
return (UINT64) VmContext.R[7];
}
STATIC
UINT64
ExecuteEbcImageEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
/*++
Routine Description:
Begin executing an EBC image. The address of the entry point is passed
in via a processor register, so we'll need to make a call to get the
value.
Arguments:
ImageHandle - image handle for the EBC application we're executing
SystemTable - standard system table passed into an driver's entry point
Returns:
The value returned by the EBC application we're going to run.
--*/
{
//
// Create a new VM context on the stack
//
VM_CONTEXT VmContext;
UINTN Addr;
EFI_STATUS Status;
UINTN StackIndex;
//
// Get the EBC entry point from the processor register. Make sure you don't
// call any functions before this or you could mess up the register the
// entry point is passed in.
//
Addr = EbcLLGetEbcEntryPoint ();
//
// Now clear out our context
//
ZeroMem ((VOID *) &VmContext, sizeof (VM_CONTEXT));
//
// Save the image handle so we can track the thunks created for this image
//
VmContext.ImageHandle = ImageHandle;
VmContext.SystemTable = SystemTable;
//
// Set the VM instruction pointer to the correct location in memory.
//
VmContext.Ip = (VMIP) Addr;
//
// Initialize the stack pointer for the EBC. Get the current system stack
// pointer and adjust it down by the max needed for the interpreter.
//
Addr = EbcLLGetStackPointer ();
Status = GetEBCStack(ImageHandle, &VmContext.StackPool, &StackIndex);
if (EFI_ERROR(Status)) {
return Status;
}
VmContext.StackTop = (UINT8*)VmContext.StackPool + (STACK_REMAIN_SIZE);
VmContext.R[0] = (UINT64) ((UINT8*)VmContext.StackPool + STACK_POOL_SIZE);
VmContext.HighStackBottom = (UINTN) VmContext.R[0];
VmContext.R[0] -= sizeof (UINTN);
//
// Put a magic value in the stack gap, then adjust down again
//
*(UINTN *) (UINTN) (VmContext.R[0]) = (UINTN) VM_STACK_KEY_VALUE;
VmContext.StackMagicPtr = (UINTN *) (UINTN) VmContext.R[0];
//
// Align the stack on a natural boundary
VmContext.R[0] &= ~(sizeof(UINTN) - 1);
//
VmContext.LowStackTop = (UINTN) VmContext.R[0];
//
// Simply copy the image handle and system table onto the EBC stack.
// Greatly simplifies things by not having to spill the args.
//
PushU64 (&VmContext, (UINT64) SystemTable);
PushU64 (&VmContext, (UINT64) ImageHandle);
//
// VM pushes 16-bytes for return address. Simulate that here.
//
PushU64 (&VmContext, (UINT64) 0);
PushU64 (&VmContext, (UINT64) 0x1234567887654321ULL);
//
// For x64, this is where we say our return address is
//
VmContext.StackRetAddr = (UINT64) VmContext.R[0];
//
// Entry function needn't access high stack context, simply
// put the stack pointer here.
//
//
// Begin executing the EBC code
//
EbcExecute (&VmContext);
//
// Return the value in R[7] unless there was an error
//
ReturnEBCStack(StackIndex);
return (UINT64) VmContext.R[7];
}
EFI_STATUS
EbcCreateThunks (
IN EFI_HANDLE ImageHandle,
IN VOID *EbcEntryPoint,
OUT VOID **Thunk,
IN UINT32 Flags
)
/*++
Routine Description:
Create an IA32 thunk for the given EBC entry point.
Arguments:
ImageHandle - Handle of image for which this thunk is being created
EbcEntryPoint - Address of the EBC code that the thunk is to call
Thunk - Returned thunk we create here
Returns:
Standard EFI status.
--*/
{
UINT8 *Ptr;
UINT8 *ThunkBase;
UINT32 I;
UINT64 Addr;
INT32 Size;
INT32 ThunkSize;
//
// Check alignment of pointer to EBC code
//
if ((UINT32) (UINTN) EbcEntryPoint & 0x01) {
return EFI_INVALID_PARAMETER;
}
Size = EBC_THUNK_SIZE;
ThunkSize = Size;
Ptr = AllocatePool (Size);
if (Ptr == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// Print(L"Allocate TH: 0x%X\n", (UINT32)Ptr);
//
// Save the start address so we can add a pointer to it to a list later.
//
ThunkBase = Ptr;
//
// Give them the address of our buffer we're going to fix up
//
*Thunk = (VOID *) Ptr;
//
// Add a magic code here to help the VM recognize the thunk..
// mov rax, ca112ebccall2ebch => 48 B8 BC 2E 11 CA BC 2E 11 CA
//
*Ptr = 0x48;
Ptr++;
Size--;
*Ptr = 0xB8;
Ptr++;
Size--;
Addr = (UINT64) 0xCA112EBCCA112EBCULL;
for (I = 0; I < sizeof (Addr); I++) {
*Ptr = (UINT8) (UINTN) Addr;
Addr >>= 8;
Ptr++;
Size--;
}
//
// Add code bytes to load up a processor register with the EBC entry point.
// mov rax, 123456789abcdef0h => 48 B8 F0 DE BC 9A 78 56 34 12
// The first 8 bytes of the thunk entry is the address of the EBC
// entry point.
//
*Ptr = 0x48;
Ptr++;
Size--;
*Ptr = 0xB8;
Ptr++;
Size--;
Addr = (UINT64) EbcEntryPoint;
for (I = 0; I < sizeof (Addr); I++) {
*Ptr = (UINT8) (UINTN) Addr;
Addr >>= 8;
Ptr++;
Size--;
}
//
// Stick in a load of ecx with the address of appropriate VM function.
// Using r11 because it's a volatile register and won't be used in this
// point.
// mov r11 123456789abcdef0h => 49 BB F0 DE BC 9A 78 56 34 12
//
if (Flags & FLAG_THUNK_ENTRY_POINT) {
Addr = (UINTN) ExecuteEbcImageEntryPoint;
} else {
Addr = (UINTN) EbcInterpret;
}
//
// mov r11 Addr => 0x49 0xBB
//
*Ptr = 0x49;
Ptr++;
Size--;
*Ptr = 0xBB;
Ptr++;
Size--;
for (I = 0; I < sizeof (Addr); I++) {
*Ptr = (UINT8) Addr;
Addr >>= 8;
Ptr++;
Size--;
}
//
// Stick in jump opcode bytes for jmp r11 => 0x41 0xFF 0xE3
//
*Ptr = 0x41;
Ptr++;
Size--;
*Ptr = 0xFF;
Ptr++;
Size--;
*Ptr = 0xE3;
Size--;
//
// Double check that our defined size is ok (application error)
//
if (Size < 0) {
ASSERT (FALSE);
return EFI_BUFFER_TOO_SMALL;
}
//
// Add the thunk to the list for this image. Do this last since the add
// function flushes the cache for us.
//
EbcAddImageThunk (ImageHandle, (VOID *) ThunkBase, ThunkSize);
return EFI_SUCCESS;
}
VOID
EbcLLCALLEX (
IN VM_CONTEXT *VmPtr,
IN UINTN FuncAddr,
IN UINTN NewStackPointer,
IN VOID *FramePtr,
IN UINT8 Size
)
/*++
Routine Description:
This function is called to execute an EBC CALLEX instruction.
The function check the callee's content to see whether it is common native
code or a thunk to another piece of EBC code.
If the callee is common native code, use EbcLLCAllEXASM to manipulate,
otherwise, set the VM->IP to target EBC code directly to avoid another VM
be startup which cost time and stack space.
Arguments:
VmPtr - Pointer to a VM context.
FuncAddr - Callee's address
NewStackPointer - New stack pointer after the call
FramePtr - New frame pointer after the call
Size - The size of call instruction
Returns:
None.
--*/
{
UINTN IsThunk;
UINTN TargetEbcAddr;
IsThunk = 1;
TargetEbcAddr = 0;
//
// Processor specific code to check whether the callee is a thunk to EBC.
//
if (*((UINT8 *)FuncAddr) != 0x48) {
IsThunk = 0;
goto Action;
}
if (*((UINT8 *)FuncAddr + 1) != 0xB8) {
IsThunk = 0;
goto Action;
}
if (*((UINT8 *)FuncAddr + 2) != 0xBC) {
IsThunk = 0;
goto Action;
}
if (*((UINT8 *)FuncAddr + 3) != 0x2E) {
IsThunk = 0;
goto Action;
}
if (*((UINT8 *)FuncAddr + 4) != 0x11) {
IsThunk = 0;
goto Action;
}
if (*((UINT8 *)FuncAddr + 5) != 0xCA) {
IsThunk = 0;
goto Action;
}
if (*((UINT8 *)FuncAddr + 6) != 0xBC) {
IsThunk = 0;
goto Action;
}
if (*((UINT8 *)FuncAddr + 7) != 0x2E) {
IsThunk = 0;
goto Action;
}
if (*((UINT8 *)FuncAddr + 8) != 0x11) {
IsThunk = 0;
goto Action;
}
if (*((UINT8 *)FuncAddr + 9) != 0xCA) {
IsThunk = 0;
goto Action;
}
if (*((UINT8 *)FuncAddr + 10) != 0x48) {
IsThunk = 0;
goto Action;
}
if (*((UINT8 *)FuncAddr + 11) != 0xB8) {
IsThunk = 0;
goto Action;
}
CopyMem (&TargetEbcAddr, (UINT8 *)FuncAddr + 12, 8);
Action:
if (IsThunk == 1){
//
// The callee is a thunk to EBC, adjust the stack pointer down 16 bytes and
// put our return address and frame pointer on the VM stack.
// Then set the VM's IP to new EBC code.
//
VmPtr->R[0] -= 8;
VmWriteMemN (VmPtr, (UINTN) VmPtr->R[0], (UINTN) FramePtr);
VmPtr->FramePtr = (VOID *) (UINTN) VmPtr->R[0];
VmPtr->R[0] -= 8;
VmWriteMem64 (VmPtr, (UINTN) VmPtr->R[0], (UINT64) (VmPtr->Ip + Size));
VmPtr->Ip = (VMIP) (UINTN) TargetEbcAddr;
} else {
//
// The callee is not a thunk to EBC, call native code.
//
EbcLLCALLEXNative (FuncAddr, NewStackPointer, FramePtr);
//
// Get return value and advance the IP.
//
VmPtr->R[7] = EbcLLGetReturnValue ();
VmPtr->Ip += Size;
}
}

View File

@ -0,0 +1,931 @@
/*++
Copyright (c) 2006 - 2007, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
FtwLite.c
Abstract:
This is a simple fault tolerant write driver, based on PlatformFd library.
And it only supports write BufferSize <= SpareAreaLength.
This boot service only protocol provides fault tolerant write capability for
block devices. The protocol has internal non-volatile intermediate storage
of the data and private information. It should be able to recover
automatically from a critical fault, such as power failure.
Notes:
The implementation uses an FTW Lite (Fault Tolerant Write) Work Space.
This work space is a memory copy of the work space on the Woring Block,
the size of the work space is the FTW_WORK_SPACE_SIZE bytes.
--*/
#include <FtwLite.h>
//
// In write function, we should check the target range to prevent the user
// from writing Spare block and Working space directly.
//
//
// Fault Tolerant Write Protocol API
//
EFI_STATUS
EFIAPI
FtwLiteWrite (
IN EFI_FTW_LITE_PROTOCOL *This,
IN EFI_HANDLE FvbHandle,
IN EFI_LBA Lba,
IN UINTN Offset,
IN OUT UINTN *NumBytes,
IN VOID *Buffer
)
/*++
Routine Description:
Starts a target block update. This function will record data about write
in fault tolerant storage and will complete the write in a recoverable
manner, ensuring at all times that either the original contents or
the modified contents are available.
Arguments:
This - Calling context
FvbHandle - The handle of FVB protocol that provides services for
reading, writing, and erasing the target block.
Lba - The logical block address of the target block.
Offset - The offset within the target block to place the data.
NumBytes - The number of bytes to write to the target block.
Buffer - The data to write.
Returns:
EFI_SUCCESS - The function completed successfully
EFI_BAD_BUFFER_SIZE - The write would span a target block, which is not
a valid action.
EFI_ACCESS_DENIED - No writes have been allocated.
EFI_NOT_FOUND - Cannot find FVB by handle.
EFI_OUT_OF_RESOURCES - Cannot allocate memory.
EFI_ABORTED - The function could not complete successfully.
--*/
{
EFI_STATUS Status;
EFI_FTW_LITE_DEVICE *FtwLiteDevice;
EFI_FTW_LITE_RECORD *Record;
EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
EFI_PHYSICAL_ADDRESS FvbPhysicalAddress;
UINTN MyLength;
UINTN MyOffset;
UINTN MyBufferSize;
UINT8 *MyBuffer;
UINTN SpareBufferSize;
UINT8 *SpareBuffer;
UINTN Index;
UINT8 *Ptr;
EFI_DEV_PATH_PTR DevPtr;
//
// Refresh work space and get last record
//
FtwLiteDevice = FTW_LITE_CONTEXT_FROM_THIS (This);
Status = WorkSpaceRefresh (FtwLiteDevice);
if (EFI_ERROR (Status)) {
return EFI_ABORTED;
}
Record = FtwLiteDevice->FtwLastRecord;
//
// Check the flags of last write record
//
if ((Record->WriteAllocated == FTW_VALID_STATE) || (Record->SpareCompleted == FTW_VALID_STATE)) {
return EFI_ACCESS_DENIED;
}
//
// IF former record has completed, THEN use next record
//
if (Record->WriteCompleted == FTW_VALID_STATE) {
Record++;
FtwLiteDevice->FtwLastRecord = Record;
}
MyOffset = (UINT8 *) Record - FtwLiteDevice->FtwWorkSpace;
//
// Check if the input data can fit within the target block
//
if ((Offset +*NumBytes) > FtwLiteDevice->SpareAreaLength) {
return EFI_BAD_BUFFER_SIZE;
}
//
// Check if there is enough free space for allocate a record
//
if ((MyOffset + WRITE_TOTAL_SIZE) > FtwLiteDevice->FtwWorkSpaceSize) {
Status = FtwReclaimWorkSpace (FtwLiteDevice);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "FtwLite: Reclaim work space - %r", Status));
return EFI_ABORTED;
}
}
//
// Get the FVB protocol by handle
//
Status = FtwGetFvbByHandle (FvbHandle, &Fvb);
if (EFI_ERROR (Status)) {
return EFI_NOT_FOUND;
}
//
// Allocate a write record in workspace.
// Update Header->WriteAllocated as VALID
//
Status = FtwUpdateFvState (
FtwLiteDevice->FtwFvBlock,
FtwLiteDevice->FtwWorkSpaceLba,
FtwLiteDevice->FtwWorkSpaceBase + MyOffset,
WRITE_ALLOCATED
);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_FTW_LITE, "FtwLite: Allocate record - %r\n", Status));
return EFI_ABORTED;
}
Record->WriteAllocated = FTW_VALID_STATE;
//
// Prepare data of write record, filling DevPath with memory mapped address.
//
DevPtr.MemMap = (MEMMAP_DEVICE_PATH *) &Record->DevPath;
DevPtr.MemMap->Header.Type = HARDWARE_DEVICE_PATH;
DevPtr.MemMap->Header.SubType = HW_MEMMAP_DP;
SetDevicePathNodeLength (&DevPtr.MemMap->Header, sizeof (MEMMAP_DEVICE_PATH));
Status = Fvb->GetPhysicalAddress (Fvb, &FvbPhysicalAddress);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_FTW_LITE, "FtwLite: Get FVB physical address - %r\n", Status));
return EFI_ABORTED;
}
DevPtr.MemMap->MemoryType = EfiMemoryMappedIO;
DevPtr.MemMap->StartingAddress = FvbPhysicalAddress;
DevPtr.MemMap->EndingAddress = FvbPhysicalAddress +*NumBytes;
//
// ignored!
//
Record->Lba = Lba;
Record->Offset = Offset;
Record->NumBytes = *NumBytes;
//
// Write the record to the work space.
//
MyOffset = (UINT8 *) Record - FtwLiteDevice->FtwWorkSpace;
MyLength = FTW_LITE_RECORD_SIZE;
Status = FtwLiteDevice->FtwFvBlock->Write (
FtwLiteDevice->FtwFvBlock,
FtwLiteDevice->FtwWorkSpaceLba,
FtwLiteDevice->FtwWorkSpaceBase + MyOffset,
&MyLength,
(UINT8 *) Record
);
if (EFI_ERROR (Status)) {
return EFI_ABORTED;
}
//
// Record has been written to working block, then write data.
//
//
// Allocate a memory buffer
//
MyBufferSize = FtwLiteDevice->SpareAreaLength;
MyBuffer = AllocatePool (MyBufferSize);
if (MyBuffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// Starting at Lba, if the number of the rest blocks on Fvb is less
// than NumberOfSpareBlock.
//
//
// Read all original data from target block to memory buffer
//
if (IsInWorkingBlock (FtwLiteDevice, Fvb, Lba)) {
//
// If target block falls into working block, we must follow the process of
// updating working block.
//
Ptr = MyBuffer;
for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {
MyLength = FtwLiteDevice->SizeOfSpareBlock;
Status = FtwLiteDevice->FtwFvBlock->Read (
FtwLiteDevice->FtwFvBlock,
FtwLiteDevice->FtwWorkBlockLba + Index,
0,
&MyLength,
Ptr
);
if (EFI_ERROR (Status)) {
FreePool (MyBuffer);
return EFI_ABORTED;
}
Ptr += MyLength;
}
//
// Update Offset by adding the offset from the start LBA of working block to
// the target LBA. The target block can not span working block!
//
Offset = (((UINTN) (Lba - FtwLiteDevice->FtwWorkBlockLba)) * FtwLiteDevice->SizeOfSpareBlock + Offset);
ASSERT ((Offset +*NumBytes) <= FtwLiteDevice->SpareAreaLength);
} else {
Ptr = MyBuffer;
for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {
MyLength = FtwLiteDevice->SizeOfSpareBlock;
Status = Fvb->Read (Fvb, Lba + Index, 0, &MyLength, Ptr);
if (EFI_ERROR (Status)) {
FreePool (MyBuffer);
return EFI_ABORTED;
}
Ptr += MyLength;
}
}
//
// Overwrite the updating range data with
// the input buffer content
//
CopyMem (MyBuffer + Offset, Buffer, *NumBytes);
//
// Try to keep the content of spare block
// Save spare block into a spare backup memory buffer (Sparebuffer)
//
SpareBufferSize = FtwLiteDevice->SpareAreaLength;
SpareBuffer = AllocatePool (SpareBufferSize);
if (SpareBuffer == NULL) {
FreePool (MyBuffer);
return EFI_OUT_OF_RESOURCES;
}
Ptr = SpareBuffer;
for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {
MyLength = FtwLiteDevice->SizeOfSpareBlock;
Status = FtwLiteDevice->FtwBackupFvb->Read (
FtwLiteDevice->FtwBackupFvb,
FtwLiteDevice->FtwSpareLba + Index,
0,
&MyLength,
Ptr
);
if (EFI_ERROR (Status)) {
FreePool (MyBuffer);
FreePool (SpareBuffer);
return EFI_ABORTED;
}
Ptr += MyLength;
}
//
// Write the memory buffer to spare block
// Don't forget to erase Flash first.
//
Status = FtwEraseSpareBlock (FtwLiteDevice);
Ptr = MyBuffer;
for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {
MyLength = FtwLiteDevice->SizeOfSpareBlock;
Status = FtwLiteDevice->FtwBackupFvb->Write (
FtwLiteDevice->FtwBackupFvb,
FtwLiteDevice->FtwSpareLba + Index,
0,
&MyLength,
Ptr
);
if (EFI_ERROR (Status)) {
FreePool (MyBuffer);
FreePool (SpareBuffer);
return EFI_ABORTED;
}
Ptr += MyLength;
}
//
// Free MyBuffer
//
FreePool (MyBuffer);
//
// Set the SpareCompleteD in the FTW record,
//
MyOffset = (UINT8 *) Record - FtwLiteDevice->FtwWorkSpace;
Status = FtwUpdateFvState (
FtwLiteDevice->FtwFvBlock,
FtwLiteDevice->FtwWorkSpaceLba,
FtwLiteDevice->FtwWorkSpaceBase + MyOffset,
SPARE_COMPLETED
);
if (EFI_ERROR (Status)) {
FreePool (SpareBuffer);
return EFI_ABORTED;
}
Record->SpareCompleted = FTW_VALID_STATE;
//
// Since the content has already backuped in spare block, the write is
// guaranteed to be completed with fault tolerant manner.
//
Status = FtwWriteRecord (FtwLiteDevice, Fvb);
if (EFI_ERROR (Status)) {
FreePool (SpareBuffer);
return EFI_ABORTED;
}
Record++;
FtwLiteDevice->FtwLastRecord = Record;
//
// Restore spare backup buffer into spare block , if no failure happened during FtwWrite.
//
Status = FtwEraseSpareBlock (FtwLiteDevice);
Ptr = SpareBuffer;
for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {
MyLength = FtwLiteDevice->SizeOfSpareBlock;
Status = FtwLiteDevice->FtwBackupFvb->Write (
FtwLiteDevice->FtwBackupFvb,
FtwLiteDevice->FtwSpareLba + Index,
0,
&MyLength,
Ptr
);
if (EFI_ERROR (Status)) {
FreePool (SpareBuffer);
return EFI_ABORTED;
}
Ptr += MyLength;
}
//
// All success.
//
FreePool (SpareBuffer);
DEBUG (
(EFI_D_FTW_LITE,
"FtwLite: Write() success, (Lba:Offset)=(%lx:0x%x), NumBytes: 0x%x\n",
Lba,
Offset,
*NumBytes)
);
return EFI_SUCCESS;
}
EFI_STATUS
FtwWriteRecord (
IN EFI_FTW_LITE_DEVICE *FtwLiteDevice,
IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb
)
/*++
Routine Description:
Write a record with fault tolerant mannaer.
Since the content has already backuped in spare block, the write is
guaranteed to be completed with fault tolerant manner.
Arguments:
FtwLiteDevice - The private data of FTW_LITE driver
Fvb - The FVB protocol that provides services for
reading, writing, and erasing the target block.
Returns:
EFI_SUCCESS - The function completed successfully
EFI_ABORTED - The function could not complete successfully
--*/
{
EFI_STATUS Status;
EFI_FTW_LITE_RECORD *Record;
EFI_LBA WorkSpaceLbaOffset;
UINTN Offset;
//
// Spare Complete but Destination not complete,
// Recover the targt block with the spare block.
//
Record = FtwLiteDevice->FtwLastRecord;
//
// IF target block is working block, THEN Flush Spare Block To Working Block;
// ELSE IF target block is boot block, THEN Flush Spare Block To boot Block;
// ELSE flush spare block to normal target block.ENDIF
//
if (IsInWorkingBlock (FtwLiteDevice, Fvb, Record->Lba)) {
//
// If target block is working block, Attention:
// it's required to set SPARE_COMPLETED to spare block.
//
WorkSpaceLbaOffset = FtwLiteDevice->FtwWorkSpaceLba - FtwLiteDevice->FtwWorkBlockLba;
Offset = (UINT8 *) Record - FtwLiteDevice->FtwWorkSpace;
Status = FtwUpdateFvState (
FtwLiteDevice->FtwBackupFvb,
FtwLiteDevice->FtwSpareLba + WorkSpaceLbaOffset,
FtwLiteDevice->FtwWorkSpaceBase + Offset,
SPARE_COMPLETED
);
ASSERT_EFI_ERROR (Status);
Status = FlushSpareBlockToWorkingBlock (FtwLiteDevice);
} else if (IsBootBlock (FtwLiteDevice, Fvb, Record->Lba)) {
//
// Update boot block
//
Status = FlushSpareBlockToBootBlock (FtwLiteDevice);
} else {
//
// Update blocks other than working block or boot block
//
Status = FlushSpareBlockToTargetBlock (FtwLiteDevice, Fvb, Record->Lba);
}
ASSERT_EFI_ERROR (Status);
//
// Set WriteCompleted flag in record
//
Offset = (UINT8 *) Record - FtwLiteDevice->FtwWorkSpace;
Status = FtwUpdateFvState (
FtwLiteDevice->FtwFvBlock,
FtwLiteDevice->FtwWorkSpaceLba,
FtwLiteDevice->FtwWorkSpaceBase + Offset,
WRITE_COMPLETED
);
ASSERT_EFI_ERROR (Status);
Record->WriteCompleted = FTW_VALID_STATE;
return EFI_SUCCESS;
}
EFI_STATUS
FtwRestart (
IN EFI_FTW_LITE_DEVICE *FtwLiteDevice
)
/*++
Routine Description:
Restarts a previously interrupted write. The caller must provide the
block protocol needed to complete the interrupted write.
Arguments:
FtwLiteDevice - The private data of FTW_LITE driver
FvbHandle - The handle of FVB protocol that provides services for
reading, writing, and erasing the target block.
Returns:
EFI_SUCCESS - The function completed successfully
EFI_ACCESS_DENIED - No pending writes exist
EFI_NOT_FOUND - FVB protocol not found by the handle
EFI_ABORTED - The function could not complete successfully
--*/
{
EFI_STATUS Status;
EFI_FTW_LITE_RECORD *Record;
EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
EFI_DEV_PATH_PTR DevPathPtr;
//
// Spare Completed but Destination not complete,
// Recover the targt block with the spare block.
//
Record = FtwLiteDevice->FtwLastRecord;
//
// Only support memory mapped FVB device path by now.
//
DevPathPtr.MemMap = (MEMMAP_DEVICE_PATH *) &Record->DevPath;
if (!((DevPathPtr.MemMap->Header.Type == HARDWARE_DEVICE_PATH) && (DevPathPtr.MemMap->Header.SubType == HW_MEMMAP_DP))
) {
DEBUG ((EFI_D_FTW_LITE, "FtwLite: FVB Device Path is not memory mapped\n"));
return EFI_ABORTED;
}
Status = GetFvbByAddress (DevPathPtr.MemMap->StartingAddress, &Fvb);
if (EFI_ERROR (Status)) {
return EFI_NOT_FOUND;
}
//
// Since the content has already backuped in spare block, the write is
// guaranteed to be completed with fault tolerant manner.
//
Status = FtwWriteRecord (FtwLiteDevice, Fvb);
DEBUG ((EFI_D_FTW_INFO, "FtwLite: Restart() - %r\n", Status));
Record++;
FtwLiteDevice->FtwLastRecord = Record;
//
// Erase Spare block
// This is restart, no need to keep spareblock content.
//
FtwEraseSpareBlock (FtwLiteDevice);
return Status;
}
EFI_STATUS
FtwAbort (
IN EFI_FTW_LITE_DEVICE *FtwLiteDevice
)
/*++
Routine Description:
Aborts all previous allocated writes.
Arguments:
FtwLiteDevice - The private data of FTW_LITE driver
Returns:
EFI_SUCCESS - The function completed successfully
EFI_ABORTED - The function could not complete successfully.
EFI_NOT_FOUND - No allocated writes exist.
--*/
{
EFI_STATUS Status;
UINTN Offset;
if (FtwLiteDevice->FtwLastRecord->WriteCompleted == FTW_VALID_STATE) {
return EFI_NOT_FOUND;
}
//
// Update the complete state of the header as VALID and abort.
//
Offset = (UINT8 *) FtwLiteDevice->FtwLastRecord - FtwLiteDevice->FtwWorkSpace;
Status = FtwUpdateFvState (
FtwLiteDevice->FtwFvBlock,
FtwLiteDevice->FtwWorkSpaceLba,
FtwLiteDevice->FtwWorkSpaceBase + Offset,
WRITE_COMPLETED
);
if (EFI_ERROR (Status)) {
return EFI_ABORTED;
}
FtwLiteDevice->FtwLastRecord->WriteCompleted = FTW_VALID_STATE;
Status = FtwGetLastRecord (FtwLiteDevice, &FtwLiteDevice->FtwLastRecord);
//
// Erase the spare block
//
Status = FtwEraseSpareBlock (FtwLiteDevice);
DEBUG ((EFI_D_FTW_INFO, "FtwLite: Abort() success \n"));
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
InitializeFtwLite (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
/*++
Routine Description:
This function is the entry point of the Fault Tolerant Write driver.
Arguments:
ImageHandle - EFI_HANDLE: A handle for the image that is initializing
this driver
SystemTable - EFI_SYSTEM_TABLE: A pointer to the EFI system table
Returns:
EFI_SUCCESS - FTW has finished the initialization
EFI_ABORTED - FTW initialization error
--*/
{
EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
UINTN Index;
EFI_HANDLE *HandleBuffer;
UINTN HandleCount;
EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
EFI_PHYSICAL_ADDRESS BaseAddress;
EFI_FTW_LITE_DEVICE *FtwLiteDevice;
EFI_FTW_LITE_RECORD *Record;
UINTN Length;
EFI_STATUS Status;
UINTN Offset;
EFI_FV_BLOCK_MAP_ENTRY *FvbMapEntry;
UINT32 LbaIndex;
//
// Allocate Private data of this driver,
// INCLUDING THE FtwWorkSpace[FTW_WORK_SPACE_SIZE].
//
FtwLiteDevice = NULL;
FtwLiteDevice = AllocatePool (sizeof (EFI_FTW_LITE_DEVICE) + FTW_WORK_SPACE_SIZE);
if (FtwLiteDevice != NULL) {
Status = EFI_SUCCESS;
} else {
Status = EFI_OUT_OF_RESOURCES;
}
ASSERT_EFI_ERROR (Status);
ZeroMem (FtwLiteDevice, sizeof (EFI_FTW_LITE_DEVICE));
FtwLiteDevice->Signature = FTW_LITE_DEVICE_SIGNATURE;
//
// Initialize other parameters, and set WorkSpace as FTW_ERASED_BYTE.
//
FtwLiteDevice->FtwWorkSpace = (UINT8 *) (FtwLiteDevice + 1);
FtwLiteDevice->FtwWorkSpaceSize = FTW_WORK_SPACE_SIZE;
SetMem (
FtwLiteDevice->FtwWorkSpace,
FtwLiteDevice->FtwWorkSpaceSize,
FTW_ERASED_BYTE
);
FtwLiteDevice->FtwWorkSpaceHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) FtwLiteDevice->FtwWorkSpace;
FtwLiteDevice->FtwLastRecord = NULL;
FtwLiteDevice->WorkSpaceAddress = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageFtwWorkingBase);
FtwLiteDevice->WorkSpaceLength = (UINTN) PcdGet32 (PcdFlashNvStorageFtwWorkingSize);
FtwLiteDevice->SpareAreaAddress = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageFtwSpareBase);
FtwLiteDevice->SpareAreaLength = (UINTN) PcdGet32 (PcdFlashNvStorageFtwSpareSize);
ASSERT ((FtwLiteDevice->WorkSpaceLength != 0) && (FtwLiteDevice->SpareAreaLength != 0));
//
// Locate FVB protocol
//
Status = gBS->LocateHandleBuffer (
ByProtocol,
&gEfiFirmwareVolumeBlockProtocolGuid,
NULL,
&HandleCount,
&HandleBuffer
);
ASSERT_EFI_ERROR (Status);
ASSERT (HandleCount > 0);
FtwLiteDevice->FtwFvBlock = NULL;
FtwLiteDevice->FtwBackupFvb = NULL;
FtwLiteDevice->FtwWorkSpaceLba = (EFI_LBA) (-1);
FtwLiteDevice->FtwSpareLba = (EFI_LBA) (-1);
for (Index = 0; Index < HandleCount; Index += 1) {
Status = gBS->HandleProtocol (
HandleBuffer[Index],
&gEfiFirmwareVolumeBlockProtocolGuid,
(VOID **) &Fvb
);
ASSERT_EFI_ERROR (Status);
Status = Fvb->GetPhysicalAddress (Fvb, &BaseAddress);
if (EFI_ERROR (Status)) {
continue;
}
FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) BaseAddress);
if ((FtwLiteDevice->WorkSpaceAddress >= BaseAddress) &&
(FtwLiteDevice->WorkSpaceAddress <= (BaseAddress + FwVolHeader->FvLength))
) {
FtwLiteDevice->FtwFvBlock = Fvb;
//
// To get the LBA of work space
//
if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) {
//
// FV may have multiple types of BlockLength
//
FvbMapEntry = &FwVolHeader->BlockMap[0];
while (!((FvbMapEntry->NumBlocks == 0) && (FvbMapEntry->Length == 0))) {
for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) {
if (FtwLiteDevice->WorkSpaceAddress < (BaseAddress + FvbMapEntry->Length * LbaIndex)) {
FtwLiteDevice->FtwWorkSpaceLba = LbaIndex - 1;
//
// Get the Work space size and Base(Offset)
//
FtwLiteDevice->FtwWorkSpaceSize = FtwLiteDevice->WorkSpaceLength;
FtwLiteDevice->FtwWorkSpaceBase = (UINTN) (FtwLiteDevice->WorkSpaceAddress - (BaseAddress + FvbMapEntry->Length * (LbaIndex - 1)));
break;
}
}
//
// end for
//
FvbMapEntry++;
}
//
// end while
//
}
}
if ((FtwLiteDevice->SpareAreaAddress >= BaseAddress) &&
(FtwLiteDevice->SpareAreaAddress <= (BaseAddress + FwVolHeader->FvLength))
) {
FtwLiteDevice->FtwBackupFvb = Fvb;
//
// To get the LBA of spare
//
if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) {
//
// FV may have multiple types of BlockLength
//
FvbMapEntry = &FwVolHeader->BlockMap[0];
while (!((FvbMapEntry->NumBlocks == 0) && (FvbMapEntry->Length == 0))) {
for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) {
if (FtwLiteDevice->SpareAreaAddress < (BaseAddress + FvbMapEntry->Length * LbaIndex)) {
//
// Get the NumberOfSpareBlock and SizeOfSpareBlock
//
FtwLiteDevice->FtwSpareLba = LbaIndex - 1;
FtwLiteDevice->SizeOfSpareBlock = FvbMapEntry->Length;
FtwLiteDevice->NumberOfSpareBlock = FtwLiteDevice->SpareAreaLength / FtwLiteDevice->SizeOfSpareBlock;
//
// Check the range of spare area to make sure that it's in FV range
//
ASSERT ((FtwLiteDevice->FtwSpareLba + FtwLiteDevice->NumberOfSpareBlock) <= FvbMapEntry->NumBlocks);
break;
}
}
FvbMapEntry++;
}
//
// end while
//
}
}
}
//
// Calculate the start LBA of working block. Working block is an area which
// contains working space in its last block and has the same size as spare
// block, unless there are not enough blocks before the block that contains
// working space.
//
FtwLiteDevice->FtwWorkBlockLba = FtwLiteDevice->FtwWorkSpaceLba - FtwLiteDevice->NumberOfSpareBlock + 1;
if ((INT64) (FtwLiteDevice->FtwWorkBlockLba) < 0) {
FtwLiteDevice->FtwWorkBlockLba = 0;
}
if ((FtwLiteDevice->FtwFvBlock == NULL) ||
(FtwLiteDevice->FtwBackupFvb == NULL) ||
(FtwLiteDevice->FtwWorkSpaceLba == (EFI_LBA) (-1)) ||
(FtwLiteDevice->FtwSpareLba == (EFI_LBA) (-1))
) {
DEBUG ((EFI_D_ERROR, "FtwLite: Working or spare FVB not ready\n"));
ASSERT_EFI_ERROR (Status);
}
//
// Refresh workspace data from working block
//
Status = WorkSpaceRefresh (FtwLiteDevice);
ASSERT_EFI_ERROR (Status);
//
// If the working block workspace is not valid, try the spare block
//
if (!IsValidWorkSpace (FtwLiteDevice->FtwWorkSpaceHeader)) {
DEBUG ((EFI_D_FTW_LITE, "FtwLite: Workspace invalid, read from backup\n"));
//
// Read from spare block
//
Length = FtwLiteDevice->FtwWorkSpaceSize;
Status = FtwLiteDevice->FtwBackupFvb->Read (
FtwLiteDevice->FtwBackupFvb,
FtwLiteDevice->FtwSpareLba,
FtwLiteDevice->FtwWorkSpaceBase,
&Length,
FtwLiteDevice->FtwWorkSpace
);
ASSERT_EFI_ERROR (Status);
//
// If spare block is valid, then replace working block content.
//
if (IsValidWorkSpace (FtwLiteDevice->FtwWorkSpaceHeader)) {
Status = FlushSpareBlockToWorkingBlock (FtwLiteDevice);
DEBUG ((EFI_D_FTW_LITE, "FtwLite: Restart working block in Init() - %r\n", Status));
ASSERT_EFI_ERROR (Status);
FtwAbort (FtwLiteDevice);
//
// Refresh work space.
//
Status = WorkSpaceRefresh (FtwLiteDevice);
if (EFI_ERROR (Status)) {
return EFI_ABORTED;
}
} else {
DEBUG ((EFI_D_FTW_LITE, "FtwLite: Both are invalid, init workspace\n"));
//
// If both are invalid, then initialize work space.
//
SetMem (
FtwLiteDevice->FtwWorkSpace,
FtwLiteDevice->FtwWorkSpaceSize,
FTW_ERASED_BYTE
);
InitWorkSpaceHeader (FtwLiteDevice->FtwWorkSpaceHeader);
//
// Write to work space on the working block
//
Length = FtwLiteDevice->FtwWorkSpaceSize;
Status = FtwLiteDevice->FtwFvBlock->Write (
FtwLiteDevice->FtwFvBlock,
FtwLiteDevice->FtwWorkSpaceLba,
FtwLiteDevice->FtwWorkSpaceBase,
&Length,
FtwLiteDevice->FtwWorkSpace
);
if (EFI_ERROR (Status)) {
return EFI_ABORTED;
}
}
}
//
// Hook the protocol API
//
FtwLiteDevice->FtwLiteInstance.Write = FtwLiteWrite;
//
// Install protocol interface
//
Status = gBS->InstallProtocolInterface (
&FtwLiteDevice->Handle,
&gEfiFaultTolerantWriteLiteProtocolGuid,
EFI_NATIVE_INTERFACE,
&FtwLiteDevice->FtwLiteInstance
);
if (EFI_ERROR (Status)) {
return EFI_ABORTED;
}
//
// If (!SpareCompleted) THEN Abort to rollback.
//
if ((FtwLiteDevice->FtwLastRecord->WriteAllocated == FTW_VALID_STATE) &&
(FtwLiteDevice->FtwLastRecord->SpareCompleted != FTW_VALID_STATE)
) {
DEBUG ((EFI_D_FTW_LITE, "FtwLite: Init.. record not SpareCompleted, abort()\n"));
FtwAbort (FtwLiteDevice);
}
//
// if (SpareCompleted) THEN Restart to fault tolerant write.
//
if ((FtwLiteDevice->FtwLastRecord->SpareCompleted == FTW_VALID_STATE) &&
(FtwLiteDevice->FtwLastRecord->WriteCompleted != FTW_VALID_STATE)
) {
Status = FtwRestart (FtwLiteDevice);
DEBUG ((EFI_D_FTW_LITE, "FtwLite: Restart last write - %r\n", Status));
if (EFI_ERROR (Status)) {
return Status;
}
}
//
// To check the workspace buffer behind last records is EMPTY or not.
// If it's not EMPTY, FTW_LITE also need to call reclaim().
//
Record = FtwLiteDevice->FtwLastRecord;
Offset = (UINT8 *) Record - FtwLiteDevice->FtwWorkSpace;
if (FtwLiteDevice->FtwWorkSpace[Offset] != FTW_ERASED_BYTE) {
Offset += WRITE_TOTAL_SIZE;
}
if (!IsErasedFlashBuffer (
FTW_ERASE_POLARITY,
FtwLiteDevice->FtwWorkSpace + Offset,
FtwLiteDevice->FtwWorkSpaceSize - Offset
)) {
DEBUG ((EFI_D_FTW_LITE, "FtwLite: Workspace is dirty, call reclaim...\n"));
Status = FtwReclaimWorkSpace (FtwLiteDevice);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_FTW_LITE, "FtwLite: Workspace reclaim - %r\n", Status));
return EFI_ABORTED;
}
}
return EFI_SUCCESS;
}

View File

@ -0,0 +1,27 @@
/*++
Copyright (c) 2006, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
FtwLite.dxs
Abstract:
Dependency expression source file.
--*/
#include <DxeDepex.h>
DEPENDENCY_START
EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL_GUID AND EFI_ALTERNATE_FV_BLOCK_GUID
DEPENDENCY_END

View File

@ -0,0 +1,695 @@
/*++
Copyright (c) 2006, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
FtwLite.h
Abstract:
This is a simple fault tolerant write driver, based on PlatformFd library.
And it only supports write BufferSize <= SpareAreaLength.
This boot service only protocol provides fault tolerant write capability for
block devices. The protocol has internal non-volatile intermediate storage
of the data and private information. It should be able to recover
automatically from a critical fault, such as power failure.
--*/
#ifndef _EFI_FAULT_TOLERANT_WRITE_LITE_H_
#define _EFI_FAULT_TOLERANT_WRITE_LITE_H_
//
// The package level header files this module uses
//
#include <PiDxe.h>
//
// The protocols, PPI and GUID defintions for this module
//
#include <Protocol/PciRootBridgeIo.h>
#include <Guid/SystemNvDataGuid.h>
#include <Protocol/FaultTolerantWriteLite.h>
#include <Protocol/FirmwareVolumeBlock.h>
//
// The Library classes this module consumes
//
#include <Library/PcdLib.h>
#include <Library/DebugLib.h>
#include <Library/UefiDriverEntryPoint.h>
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Common/WorkingBlockHeader.h>
#define EFI_D_FTW_LITE EFI_D_ERROR
#define EFI_D_FTW_INFO EFI_D_INFO
//
// Flash erase polarity is 1
//
#define FTW_ERASE_POLARITY 1
#define FTW_VALID_STATE 0
#define FTW_INVALID_STATE 1
#define FTW_ERASED_BYTE ((UINT8) (255))
#define FTW_POLARITY_REVERT ((UINT8) (255))
typedef struct {
UINT8 WriteAllocated : 1;
UINT8 SpareCompleted : 1;
UINT8 WriteCompleted : 1;
UINT8 Reserved : 5;
#define WRITE_ALLOCATED 0x1
#define SPARE_COMPLETED 0x2
#define WRITE_COMPLETED 0x4
EFI_DEV_PATH DevPath;
EFI_LBA Lba;
UINTN Offset;
UINTN NumBytes;
//
// UINTN SpareAreaOffset;
//
} EFI_FTW_LITE_RECORD;
#define FTW_LITE_DEVICE_SIGNATURE EFI_SIGNATURE_32 ('F', 'T', 'W', 'L')
//
// MACRO for Block size.
// Flash Erasing will do in block granularity.
//
#ifdef FV_BLOCK_SIZE
#define FTW_BLOCK_SIZE FV_BLOCK_SIZE
#else
#define FV_BLOCK_SIZE 0x10000
#define FTW_BLOCK_SIZE FV_BLOCK_SIZE
#endif
//
// MACRO for FTW WORK SPACE Base & Size
//
#ifdef EFI_FTW_WORKING_OFFSET
#define FTW_WORK_SPACE_BASE EFI_FTW_WORKING_OFFSET
#else
#define FTW_WORK_SPACE_BASE 0x00E000
#endif
#ifdef EFI_FTW_WORKING_LENGTH
#define FTW_WORK_SPACE_SIZE EFI_FTW_WORKING_LENGTH
#else
#define FTW_WORK_SPACE_SIZE 0x002000
#endif
//
// MACRO for FTW header and record
//
#define FTW_WORKING_QUEUE_SIZE (FTW_WORK_SPACE_SIZE - sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER))
#define FTW_LITE_RECORD_SIZE (sizeof (EFI_FTW_LITE_RECORD))
#define WRITE_TOTAL_SIZE FTW_LITE_RECORD_SIZE
//
// EFI Fault tolerant protocol private data structure
//
typedef struct {
UINTN Signature;
EFI_HANDLE Handle;
EFI_FTW_LITE_PROTOCOL FtwLiteInstance;
EFI_PHYSICAL_ADDRESS WorkSpaceAddress;
UINTN WorkSpaceLength;
EFI_PHYSICAL_ADDRESS SpareAreaAddress;
UINTN SpareAreaLength;
UINTN NumberOfSpareBlock; // Number of the blocks in spare block
UINTN SizeOfSpareBlock; // Block size in bytes of the blocks in spare block
EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *FtwWorkSpaceHeader;
EFI_FTW_LITE_RECORD *FtwLastRecord;
EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FtwFvBlock; // FVB of working block
EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FtwBackupFvb; // FVB of spare block
EFI_LBA FtwSpareLba;
EFI_LBA FtwWorkBlockLba; // Start LBA of working block
EFI_LBA FtwWorkSpaceLba; // Start LBA of working space
UINTN FtwWorkSpaceBase; // Offset from LBA start addr
UINTN FtwWorkSpaceSize;
UINT8 *FtwWorkSpace;
//
// Following a buffer of FtwWorkSpace[FTW_WORK_SPACE_SIZE],
// Allocated with EFI_FTW_LITE_DEVICE.
//
} EFI_FTW_LITE_DEVICE;
#define FTW_LITE_CONTEXT_FROM_THIS(a) CR (a, EFI_FTW_LITE_DEVICE, FtwLiteInstance, FTW_LITE_DEVICE_SIGNATURE)
//
// Driver entry point
//
EFI_STATUS
EFIAPI
InitializeFtwLite (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
/*++
Routine Description:
This function is the entry point of the Fault Tolerant Write driver.
Arguments:
ImageHandle - EFI_HANDLE: A handle for the image that is initializing
this driver
SystemTable - EFI_SYSTEM_TABLE: A pointer to the EFI system table
Returns:
EFI_SUCCESS - FTW has finished the initialization
EFI_ABORTED - FTW initialization error
--*/
;
//
// Fault Tolerant Write Protocol API
//
EFI_STATUS
EFIAPI
FtwLiteWrite (
IN EFI_FTW_LITE_PROTOCOL *This,
IN EFI_HANDLE FvbHandle,
IN EFI_LBA Lba,
IN UINTN Offset,
IN UINTN *NumBytes,
IN VOID *Buffer
)
/*++
Routine Description:
Starts a target block update. This function will record data about write
in fault tolerant storage and will complete the write in a recoverable
manner, ensuring at all times that either the original contents or
the modified contents are available.
Arguments:
This - Calling context
FvbHandle - The handle of FVB protocol that provides services for
reading, writing, and erasing the target block.
Lba - The logical block address of the target block.
Offset - The offset within the target block to place the data.
NumBytes - The number of bytes to write to the target block.
Buffer - The data to write.
Returns:
EFI_SUCCESS - The function completed successfully
EFI_BAD_BUFFER_SIZE - The write would span a target block, which is not
a valid action.
EFI_ACCESS_DENIED - No writes have been allocated.
EFI_NOT_FOUND - Cannot find FVB by handle.
EFI_OUT_OF_RESOURCES - Cannot allocate memory.
EFI_ABORTED - The function could not complete successfully.
--*/
;
//
// Internal functions
//
EFI_STATUS
FtwRestart (
IN EFI_FTW_LITE_DEVICE *FtwLiteDevice
)
/*++
Routine Description:
Restarts a previously interrupted write. The caller must provide the
block protocol needed to complete the interrupted write.
Arguments:
FtwLiteDevice - The private data of FTW_LITE driver
FvbHandle - The handle of FVB protocol that provides services for
reading, writing, and erasing the target block.
Returns:
EFI_SUCCESS - The function completed successfully
EFI_ACCESS_DENIED - No pending writes exist
EFI_NOT_FOUND - FVB protocol not found by the handle
EFI_ABORTED - The function could not complete successfully
--*/
;
EFI_STATUS
FtwAbort (
IN EFI_FTW_LITE_DEVICE *FtwLiteDevice
)
/*++
Routine Description:
Aborts all previous allocated writes.
Arguments:
FtwLiteDevice - The private data of FTW_LITE driver
Returns:
EFI_SUCCESS - The function completed successfully
EFI_ABORTED - The function could not complete successfully.
EFI_NOT_FOUND - No allocated writes exist.
--*/
;
EFI_STATUS
FtwWriteRecord (
IN EFI_FTW_LITE_DEVICE *FtwLiteDevice,
IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb
)
/*++
Routine Description:
Write a record with fault tolerant mannaer.
Since the content has already backuped in spare block, the write is
guaranteed to be completed with fault tolerant manner.
Arguments:
FtwLiteDevice - The private data of FTW_LITE driver
Fvb - The FVB protocol that provides services for
reading, writing, and erasing the target block.
Returns:
EFI_SUCCESS - The function completed successfully
EFI_ABORTED - The function could not complete successfully
--*/
;
EFI_STATUS
FtwEraseBlock (
IN EFI_FTW_LITE_DEVICE *FtwLiteDevice,
EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
EFI_LBA Lba
)
/*++
Routine Description:
To Erase one block. The size is FTW_BLOCK_SIZE
Arguments:
FtwLiteDevice - Calling context
FvBlock - FVB Protocol interface
Lba - Lba of the firmware block
Returns:
EFI_SUCCESS - Block LBA is Erased successfully
Others - Error occurs
--*/
;
EFI_STATUS
FtwEraseSpareBlock (
IN EFI_FTW_LITE_DEVICE *FtwLiteDevice
)
/*++
Routine Description:
Erase spare block.
Arguments:
FtwLiteDevice - Calling context
Returns:
Status code
--*/
;
EFI_STATUS
FtwGetFvbByHandle (
IN EFI_HANDLE FvBlockHandle,
OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock
)
/*++
Routine Description:
Retrive the proper FVB protocol interface by HANDLE.
Arguments:
FvBlockHandle - The handle of FVB protocol that provides services for
reading, writing, and erasing the target block.
FvBlock - The interface of FVB protocol
Returns:
EFI_SUCCESS - The function completed successfully
EFI_ABORTED - The function could not complete successfully
--*/
;
EFI_STATUS
GetFvbByAddress (
IN EFI_PHYSICAL_ADDRESS Address,
OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock
)
/*++
Routine Description:
Get firmware block by address.
Arguments:
Address - Address specified the block
FvBlock - The block caller wanted
Returns:
Status code
EFI_NOT_FOUND - Block not found
--*/
;
BOOLEAN
IsInWorkingBlock (
EFI_FTW_LITE_DEVICE *FtwLiteDevice,
EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
EFI_LBA Lba
)
/*++
Routine Description:
Is it in working block?
Arguments:
FtwLiteDevice - Calling context
FvBlock - Fvb protocol instance
Lba - The block specified
Returns:
In working block or not
--*/
;
BOOLEAN
IsBootBlock (
EFI_FTW_LITE_DEVICE *FtwLiteDevice,
EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
EFI_LBA Lba
)
/*++
Routine Description:
Check whether the block is a boot block.
Arguments:
FtwLiteDevice - Calling context
FvBlock - Fvb protocol instance
Lba - Lba value
Returns:
Is a boot block or not
--*/
;
EFI_STATUS
FlushSpareBlockToTargetBlock (
EFI_FTW_LITE_DEVICE *FtwLiteDevice,
EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
EFI_LBA Lba
)
/*++
Routine Description:
Copy the content of spare block to a target block. Size is FTW_BLOCK_SIZE.
Spare block is accessed by FTW backup FVB protocol interface. LBA is
FtwLiteDevice->FtwSpareLba.
Target block is accessed by FvBlock protocol interface. LBA is Lba.
Arguments:
FtwLiteDevice - The private data of FTW_LITE driver
FvBlock - FVB Protocol interface to access target block
Lba - Lba of the target block
Returns:
EFI_SUCCESS - Spare block content is copied to target block
EFI_INVALID_PARAMETER - Input parameter error
EFI_OUT_OF_RESOURCES - Allocate memory error
EFI_ABORTED - The function could not complete successfully
--*/
;
EFI_STATUS
FlushSpareBlockToWorkingBlock (
EFI_FTW_LITE_DEVICE *FtwLiteDevice
)
/*++
Routine Description:
Copy the content of spare block to working block. Size is FTW_BLOCK_SIZE.
Spare block is accessed by FTW backup FVB protocol interface. LBA is
FtwLiteDevice->FtwSpareLba.
Working block is accessed by FTW working FVB protocol interface. LBA is
FtwLiteDevice->FtwWorkBlockLba.
Arguments:
FtwLiteDevice - The private data of FTW_LITE driver
Returns:
EFI_SUCCESS - Spare block content is copied to target block
EFI_OUT_OF_RESOURCES - Allocate memory error
EFI_ABORTED - The function could not complete successfully
Notes:
Since the working block header is important when FTW initializes, the
state of the operation should be handled carefully. The Crc value is
calculated without STATE element.
--*/
;
EFI_STATUS
FlushSpareBlockToBootBlock (
EFI_FTW_LITE_DEVICE *FtwLiteDevice
)
/*++
Routine Description:
Copy the content of spare block to a boot block. Size is FTW_BLOCK_SIZE.
Spare block is accessed by FTW backup FVB protocol interface. LBA is
FtwLiteDevice->FtwSpareLba.
Boot block is accessed by BootFvb protocol interface. LBA is 0.
Arguments:
FtwLiteDevice - The private data of FTW_LITE driver
Returns:
EFI_SUCCESS - Spare block content is copied to boot block
EFI_INVALID_PARAMETER - Input parameter error
EFI_OUT_OF_RESOURCES - Allocate memory error
EFI_ABORTED - The function could not complete successfully
Notes:
--*/
;
EFI_STATUS
FtwUpdateFvState (
IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
IN EFI_LBA Lba,
IN UINTN Offset,
IN UINT8 NewBit
)
/*++
Routine Description:
Update a bit of state on a block device. The location of the bit is
calculated by the (Lba, Offset, bit). Here bit is determined by the
the name of a certain bit.
Arguments:
FvBlock - FVB Protocol interface to access SrcBlock and DestBlock
Lba - Lba of a block
Offset - Offset on the Lba
NewBit - New value that will override the old value if it can be change
Returns:
EFI_SUCCESS - A state bit has been updated successfully
Others - Access block device error.
Notes:
Assume all bits of State are inside the same BYTE.
EFI_ABORTED - Read block fail
--*/
;
EFI_STATUS
FtwGetLastRecord (
IN EFI_FTW_LITE_DEVICE *FtwLiteDevice,
OUT EFI_FTW_LITE_RECORD **FtwLastRecord
)
/*++
Routine Description:
Get the last Write record pointer.
The last record is the record whose 'complete' state hasn't been set.
After all, this header may be a EMPTY header entry for next Allocate.
Arguments:
FtwLiteDevice - Private data of this driver
FtwLastRecord - Pointer to retrieve the last write record
Returns:
EFI_SUCCESS - Get the last write record successfully
EFI_ABORTED - The FTW work space is damaged
--*/
;
BOOLEAN
IsErasedFlashBuffer (
IN BOOLEAN Polarity,
IN UINT8 *Buffer,
IN UINTN BufferSize
)
/*++
Routine Description:
Check whether a flash buffer is erased.
Arguments:
Polarity - All 1 or all 0
Buffer - Buffer to check
BufferSize - Size of the buffer
Returns:
Erased or not.
--*/
;
EFI_STATUS
InitWorkSpaceHeader (
IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingHeader
)
/*++
Routine Description:
Initialize a work space when there is no work space.
Arguments:
WorkingHeader - Pointer of working block header
Returns:
EFI_SUCCESS - The function completed successfully
EFI_ABORTED - The function could not complete successfully.
--*/
;
EFI_STATUS
WorkSpaceRefresh (
IN EFI_FTW_LITE_DEVICE *FtwLiteDevice
)
/*++
Routine Description:
Read from working block to refresh the work space in memory.
Arguments:
FtwLiteDevice - Point to private data of FTW driver
Returns:
EFI_SUCCESS - The function completed successfully
EFI_ABORTED - The function could not complete successfully.
--*/
;
BOOLEAN
IsValidWorkSpace (
IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingHeader
)
/*++
Routine Description:
Check to see if it is a valid work space.
Arguments:
WorkingHeader - Pointer of working block header
Returns:
EFI_SUCCESS - The function completed successfully
EFI_ABORTED - The function could not complete successfully.
--*/
;
EFI_STATUS
CleanupWorkSpace (
IN EFI_FTW_LITE_DEVICE *FtwLiteDevice,
IN OUT UINT8 *BlockBuffer,
IN UINTN BufferSize
)
/*++
Routine Description:
Reclaim the work space. Get rid of all the completed write records
and write records in the Fault Tolerant work space.
Arguments:
FtwLiteDevice - Point to private data of FTW driver
FtwSpaceBuffer - Buffer to contain the reclaimed clean data
BufferSize - Size of the FtwSpaceBuffer
Returns:
EFI_SUCCESS - The function completed successfully
EFI_BUFFER_TOO_SMALL - The FtwSpaceBuffer is too small
EFI_ABORTED - The function could not complete successfully.
--*/
;
EFI_STATUS
FtwReclaimWorkSpace (
IN EFI_FTW_LITE_DEVICE *FtwLiteDevice
)
/*++
Routine Description:
Reclaim the work space on the working block.
Arguments:
FtwLiteDevice - Point to private data of FTW driver
Returns:
EFI_SUCCESS - The function completed successfully
EFI_OUT_OF_RESOURCES - Allocate memory error
EFI_ABORTED - The function could not complete successfully
--*/
;
#endif

View File

@ -0,0 +1,133 @@
#/** @file
# Component description file for FtwLite module.
#
# This driver provides fault tolerant write capability for block devices.
# Copyright (c) 2006 - 2007, Intel Corporation
#
# All rights reserved. This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
#
#**/
################################################################################
#
# Defines Section - statements that will be processed to create a Makefile.
#
################################################################################
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = FtwLite
FILE_GUID = 4C862FC6-0E54-4e36-8C8F-FF6F3167951F
MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.0
EDK_RELEASE_VERSION = 0x00020000
EFI_SPECIFICATION_VERSION = 0x00020000
ENTRY_POINT = InitializeFtwLite
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64 IPF EBC
#
################################################################################
#
# Sources Section - list of files that are required for the build to succeed.
#
################################################################################
[Sources.common]
FtwLite.dxs
FtwWorkSpace.c
FtwMisc.c
FtwLite.c
FtwLite.h
[Sources.Ia32]
Ia32/Ia32FtwMisc.c
[Sources.X64]
x64/x64FtwMisc.c
[Sources.IPF]
Ipf/IpfFtwMisc.c
[Sources.EBC]
Ia32/Ia32FtwMisc.c
################################################################################
#
# Package Dependency Section - list of Package files that are required for
# this module.
#
################################################################################
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
################################################################################
#
# Library Class Section - list of Library Classes that are required for
# this module.
#
################################################################################
[LibraryClasses]
UefiBootServicesTableLib
MemoryAllocationLib
BaseMemoryLib
UefiDriverEntryPoint
DebugLib
PcdLib
################################################################################
#
# Guid C Name Section - list of Guids that this module uses or produces.
#
################################################################################
[Guids]
gEfiSystemNvDataFvGuid # ALWAYS_CONSUMED
################################################################################
#
# Protocol C Name Section - list of Protocol and Protocol Notify C Names
# that this module uses or produces.
#
################################################################################
[Protocols]
gEfiFirmwareVolumeBlockProtocolGuid # PROTOCOL ALWAYS_CONSUMED
gEfiFaultTolerantWriteLiteProtocolGuid # PROTOCOL ALWAYS_PRODUCED
[Protocols.IA32]
gEfiPciRootBridgeIoProtocolGuid # PROTOCOL ALWAYS_CONSUMED
[Protocols.EBC]
gEfiPciRootBridgeIoProtocolGuid # PROTOCOL ALWAYS_CONSUMED
################################################################################
#
# Pcd DYNAMIC - list of PCDs that this module is coded for.
#
################################################################################
[PcdsDynamic.common]
PcdFlashNvStorageFtwWorkingSize|gEfiGenericPlatformTokenSpaceGuid
PcdFlashNvStorageFtwWorkingBase|gEfiGenericPlatformTokenSpaceGuid
PcdFlashNvStorageFtwSpareSize|gEfiGenericPlatformTokenSpaceGuid
PcdFlashNvStorageFtwSpareBase|gEfiGenericPlatformTokenSpaceGuid

View File

@ -0,0 +1,103 @@
<?xml version="1.0" encoding="UTF-8"?>
<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<MsaHeader>
<ModuleName>FtwLite</ModuleName>
<ModuleType>DXE_DRIVER</ModuleType>
<GuidValue>4C862FC6-0E54-4e36-8C8F-FF6F3167951F</GuidValue>
<Version>1.0</Version>
<Abstract>Component description file for FtwLite module.</Abstract>
<Description>This driver provides fault tolerant write capability for block devices.</Description>
<Copyright>Copyright (c) 2006 - 2007, Intel Corporation</Copyright>
<License>All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.</License>
<Specification>FRAMEWORK_BUILD_PACKAGING_SPECIFICATION 0x00000052</Specification>
</MsaHeader>
<ModuleDefinitions>
<SupportedArchitectures>IA32 X64 IPF EBC</SupportedArchitectures>
<BinaryModule>false</BinaryModule>
<OutputFileBasename>FtwLite</OutputFileBasename>
</ModuleDefinitions>
<LibraryClassDefinitions>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>PcdLib</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>DebugLib</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>UefiDriverEntryPoint</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>BaseMemoryLib</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>MemoryAllocationLib</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>UefiBootServicesTableLib</Keyword>
</LibraryClass>
</LibraryClassDefinitions>
<SourceFiles>
<Filename>FtwLite.h</Filename>
<Filename>FtwLite.c</Filename>
<Filename>FtwMisc.c</Filename>
<Filename>FtwWorkSpace.c</Filename>
<Filename>FtwLite.dxs</Filename>
<Filename SupArchList="IA32 EBC">Ia32/Ia32FtwMisc.c</Filename>
<Filename SupArchList="X64">x64/x64FtwMisc.c</Filename>
<Filename SupArchList="IPF">Ipf/IpfFtwMisc.c</Filename>
</SourceFiles>
<PackageDependencies>
<Package PackageGuid="1E73767F-8F52-4603-AEB4-F29B510B6766"/>
<Package PackageGuid="BA0D78D6-2CAF-414b-BD4D-B6762A894288"/>
</PackageDependencies>
<Protocols>
<Protocol Usage="ALWAYS_PRODUCED">
<ProtocolCName>gEfiFaultTolerantWriteLiteProtocolGuid</ProtocolCName>
</Protocol>
<Protocol Usage="ALWAYS_CONSUMED" SupArchList="IA32 EBC">
<ProtocolCName>gEfiPciRootBridgeIoProtocolGuid</ProtocolCName>
</Protocol>
<Protocol Usage="ALWAYS_CONSUMED">
<ProtocolCName>gEfiFirmwareVolumeBlockProtocolGuid</ProtocolCName>
</Protocol>
</Protocols>
<Guids>
<GuidCNames Usage="ALWAYS_CONSUMED">
<GuidCName>gEfiSystemNvDataFvGuid</GuidCName>
</GuidCNames>
</Guids>
<Externs>
<Specification>EFI_SPECIFICATION_VERSION 0x00020000</Specification>
<Specification>EDK_RELEASE_VERSION 0x00020000</Specification>
<Extern>
<ModuleEntryPoint>InitializeFtwLite</ModuleEntryPoint>
</Extern>
</Externs>
<PcdCoded>
<PcdEntry PcdItemType="DYNAMIC" Usage="ALWAYS_CONSUMED">
<C_Name>PcdFlashNvStorageFtwSpareBase</C_Name>
<TokenSpaceGuidCName>gEfiGenericPlatformTokenSpaceGuid</TokenSpaceGuidCName>
<HelpText>To get base address of the FTW spare block section in NV firmware volume.</HelpText>
</PcdEntry>
<PcdEntry PcdItemType="DYNAMIC" Usage="ALWAYS_CONSUMED">
<C_Name>PcdFlashNvStorageFtwSpareSize</C_Name>
<TokenSpaceGuidCName>gEfiGenericPlatformTokenSpaceGuid</TokenSpaceGuidCName>
<HelpText>To get size of the FTW spare block section in NV firmware volume.</HelpText>
</PcdEntry>
<PcdEntry PcdItemType="DYNAMIC" Usage="ALWAYS_CONSUMED">
<C_Name>PcdFlashNvStorageFtwWorkingBase</C_Name>
<TokenSpaceGuidCName>gEfiGenericPlatformTokenSpaceGuid</TokenSpaceGuidCName>
<HelpText>To get base address of the FTW working block section in NV firmware volume.</HelpText>
</PcdEntry>
<PcdEntry PcdItemType="DYNAMIC" Usage="ALWAYS_CONSUMED">
<C_Name>PcdFlashNvStorageFtwWorkingSize</C_Name>
<TokenSpaceGuidCName>gEfiGenericPlatformTokenSpaceGuid</TokenSpaceGuidCName>
<HelpText>To get size of the FTW working block section in NV firmware volume.</HelpText>
</PcdEntry>
</PcdCoded>
</ModuleSurfaceArea>

View File

@ -0,0 +1,530 @@
/*++
Copyright (c) 2006 - 2007, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
FtwMisc.c
Abstract:
Internal functions to support fault tolerant write.
Revision History
--*/
#include <FtwLite.h>
BOOLEAN
IsErasedFlashBuffer (
IN BOOLEAN Polarity,
IN UINT8 *Buffer,
IN UINTN BufferSize
)
/*++
Routine Description:
Check whether a flash buffer is erased.
Arguments:
Polarity - All 1 or all 0
Buffer - Buffer to check
BufferSize - Size of the buffer
Returns:
Erased or not.
--*/
{
UINT8 ErasedValue;
UINT8 *Ptr;
if (Polarity) {
ErasedValue = 0xFF;
} else {
ErasedValue = 0;
}
Ptr = Buffer;
while (BufferSize--) {
if (*Ptr++ != ErasedValue) {
return FALSE;
}
}
return TRUE;
}
EFI_STATUS
FtwEraseBlock (
IN EFI_FTW_LITE_DEVICE *FtwLiteDevice,
EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
EFI_LBA Lba
)
/*++
Routine Description:
To Erase one block. The size is FTW_BLOCK_SIZE
Arguments:
FtwLiteDevice - Calling context
FvBlock - FVB Protocol interface
Lba - Lba of the firmware block
Returns:
EFI_SUCCESS - Block LBA is Erased successfully
Others - Error occurs
--*/
{
return FvBlock->EraseBlocks (
FvBlock,
Lba,
FtwLiteDevice->NumberOfSpareBlock,
EFI_LBA_LIST_TERMINATOR
);
}
EFI_STATUS
FtwEraseSpareBlock (
IN EFI_FTW_LITE_DEVICE *FtwLiteDevice
)
/*++
Routine Description:
Erase spare block.
Arguments:
FtwLiteDevice - Calling context
Returns:
Status code
--*/
{
return FtwLiteDevice->FtwBackupFvb->EraseBlocks (
FtwLiteDevice->FtwBackupFvb,
FtwLiteDevice->FtwSpareLba,
FtwLiteDevice->NumberOfSpareBlock,
EFI_LBA_LIST_TERMINATOR
);
}
EFI_STATUS
FtwGetFvbByHandle (
IN EFI_HANDLE FvBlockHandle,
OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock
)
/*++
Routine Description:
Retrive the proper FVB protocol interface by HANDLE.
Arguments:
FvBlockHandle - The handle of FVB protocol that provides services for
reading, writing, and erasing the target block.
FvBlock - The interface of FVB protocol
Returns:
EFI_SUCCESS - The function completed successfully
EFI_ABORTED - The function could not complete successfully
--*/
{
//
// To get the FVB protocol interface on the handle
//
return gBS->HandleProtocol (
FvBlockHandle,
&gEfiFirmwareVolumeBlockProtocolGuid,
(VOID **) FvBlock
);
}
EFI_STATUS
GetFvbByAddress (
IN EFI_PHYSICAL_ADDRESS Address,
OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock
)
/*++
Routine Description:
Get firmware block by address.
Arguments:
Address - Address specified the block
FvBlock - The block caller wanted
Returns:
Status code
EFI_NOT_FOUND - Block not found
--*/
{
EFI_STATUS Status;
EFI_HANDLE *HandleBuffer;
UINTN HandleCount;
UINTN Index;
EFI_PHYSICAL_ADDRESS FvbBaseAddress;
EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
*FvBlock = NULL;
//
// Locate all handles of Fvb protocol
//
Status = gBS->LocateHandleBuffer (
ByProtocol,
&gEfiFirmwareVolumeBlockProtocolGuid,
NULL,
&HandleCount,
&HandleBuffer
);
if (EFI_ERROR (Status)) {
return EFI_NOT_FOUND;
}
//
// Search all FVB until find the right one
//
for (Index = 0; Index < HandleCount; Index += 1) {
Status = gBS->HandleProtocol (
HandleBuffer[Index],
&gEfiFirmwareVolumeBlockProtocolGuid,
(VOID **) &Fvb
);
if (EFI_ERROR (Status)) {
Status = EFI_NOT_FOUND;
break;
}
//
// Compare the address and select the right one
//
Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);
if (EFI_ERROR (Status)) {
continue;
}
FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);
if ((Address >= FvbBaseAddress) && (Address <= (FvbBaseAddress + (FwVolHeader->FvLength - 1)))) {
*FvBlock = Fvb;
Status = EFI_SUCCESS;
break;
}
}
FreePool (HandleBuffer);
return Status;
}
BOOLEAN
IsInWorkingBlock (
EFI_FTW_LITE_DEVICE *FtwLiteDevice,
EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
EFI_LBA Lba
)
/*++
Routine Description:
Is it in working block?
Arguments:
FtwLiteDevice - Calling context
FvBlock - Fvb protocol instance
Lba - The block specified
Returns:
In working block or not
--*/
{
//
// If matching the following condition, the target block is in working block.
// 1. Target block is on the FV of working block (Using the same FVB protocol instance).
// 2. Lba falls into the range of working block.
//
return (BOOLEAN)
(
(FvBlock == FtwLiteDevice->FtwFvBlock) &&
(Lba >= FtwLiteDevice->FtwWorkBlockLba) &&
(Lba <= FtwLiteDevice->FtwWorkSpaceLba)
);
}
EFI_STATUS
FlushSpareBlockToTargetBlock (
EFI_FTW_LITE_DEVICE *FtwLiteDevice,
EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
EFI_LBA Lba
)
/*++
Routine Description:
Copy the content of spare block to a target block. Size is FTW_BLOCK_SIZE.
Spare block is accessed by FTW backup FVB protocol interface. LBA is
FtwLiteDevice->FtwSpareLba.
Target block is accessed by FvBlock protocol interface. LBA is Lba.
Arguments:
FtwLiteDevice - The private data of FTW_LITE driver
FvBlock - FVB Protocol interface to access target block
Lba - Lba of the target block
Returns:
EFI_SUCCESS - Spare block content is copied to target block
EFI_INVALID_PARAMETER - Input parameter error
EFI_OUT_OF_RESOURCES - Allocate memory error
EFI_ABORTED - The function could not complete successfully
--*/
{
EFI_STATUS Status;
UINTN Length;
UINT8 *Buffer;
UINTN Count;
UINT8 *Ptr;
UINTN Index;
if ((FtwLiteDevice == NULL) || (FvBlock == NULL)) {
return EFI_INVALID_PARAMETER;
}
//
// Allocate a memory buffer
//
Length = FtwLiteDevice->SpareAreaLength;
Buffer = AllocatePool (Length);
if (Buffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// Read all content of spare block to memory buffer
//
Ptr = Buffer;
for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {
Count = FtwLiteDevice->SizeOfSpareBlock;
Status = FtwLiteDevice->FtwBackupFvb->Read (
FtwLiteDevice->FtwBackupFvb,
FtwLiteDevice->FtwSpareLba + Index,
0,
&Count,
Ptr
);
if (EFI_ERROR (Status)) {
FreePool (Buffer);
return Status;
}
Ptr += Count;
}
//
// Erase the target block
//
Status = FtwEraseBlock (FtwLiteDevice, FvBlock, Lba);
if (EFI_ERROR (Status)) {
FreePool (Buffer);
return EFI_ABORTED;
}
//
// Write memory buffer to block, using the FvbBlock protocol interface
//
Ptr = Buffer;
for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {
Count = FtwLiteDevice->SizeOfSpareBlock;
Status = FvBlock->Write (FvBlock, Lba + Index, 0, &Count, Ptr);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_FTW_LITE, "FtwLite: FVB Write block - %r\n", Status));
FreePool (Buffer);
return Status;
}
Ptr += Count;
}
FreePool (Buffer);
return Status;
}
EFI_STATUS
FlushSpareBlockToWorkingBlock (
EFI_FTW_LITE_DEVICE *FtwLiteDevice
)
/*++
Routine Description:
Copy the content of spare block to working block. Size is FTW_BLOCK_SIZE.
Spare block is accessed by FTW backup FVB protocol interface. LBA is
FtwLiteDevice->FtwSpareLba.
Working block is accessed by FTW working FVB protocol interface. LBA is
FtwLiteDevice->FtwWorkBlockLba.
Arguments:
FtwLiteDevice - The private data of FTW_LITE driver
Returns:
EFI_SUCCESS - Spare block content is copied to target block
EFI_OUT_OF_RESOURCES - Allocate memory error
EFI_ABORTED - The function could not complete successfully
Notes:
Since the working block header is important when FTW initializes, the
state of the operation should be handled carefully. The Crc value is
calculated without STATE element.
--*/
{
EFI_STATUS Status;
UINTN Length;
UINT8 *Buffer;
EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingBlockHeader;
EFI_LBA WorkSpaceLbaOffset;
UINTN Count;
UINT8 *Ptr;
UINTN Index;
//
// Allocate a memory buffer
//
Length = FtwLiteDevice->SpareAreaLength;
Buffer = AllocatePool (Length);
if (Buffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// To guarantee that the WorkingBlockValid is set on spare block
//
WorkSpaceLbaOffset = FtwLiteDevice->FtwWorkSpaceLba - FtwLiteDevice->FtwWorkBlockLba;
FtwUpdateFvState (
FtwLiteDevice->FtwBackupFvb,
FtwLiteDevice->FtwSpareLba + WorkSpaceLbaOffset,
FtwLiteDevice->FtwWorkSpaceBase + sizeof (EFI_GUID) + sizeof (UINT32),
WORKING_BLOCK_VALID
);
//
// Read from spare block to memory buffer
//
Ptr = Buffer;
for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {
Count = FtwLiteDevice->SizeOfSpareBlock;
Status = FtwLiteDevice->FtwBackupFvb->Read (
FtwLiteDevice->FtwBackupFvb,
FtwLiteDevice->FtwSpareLba + Index,
0,
&Count,
Ptr
);
if (EFI_ERROR (Status)) {
FreePool (Buffer);
return Status;
}
Ptr += Count;
}
//
// Clear the CRC and STATE, copy data from spare to working block.
//
WorkingBlockHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) (Buffer + (UINTN) WorkSpaceLbaOffset * FtwLiteDevice->SizeOfSpareBlock + FtwLiteDevice->FtwWorkSpaceBase);
InitWorkSpaceHeader (WorkingBlockHeader);
WorkingBlockHeader->WorkingBlockValid = FTW_ERASE_POLARITY;
WorkingBlockHeader->WorkingBlockInvalid = FTW_ERASE_POLARITY;
//
// target block is working block, then
// Set WorkingBlockInvalid in EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER
// before erase the working block.
//
// Offset = EFI_FIELD_OFFSET(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER,
// WorkingBlockInvalid);
// To skip Signature and Crc: sizeof(EFI_GUID)+sizeof(UINT32).
//
Status = FtwUpdateFvState (
FtwLiteDevice->FtwFvBlock,
FtwLiteDevice->FtwWorkSpaceLba,
FtwLiteDevice->FtwWorkSpaceBase + sizeof (EFI_GUID) + sizeof (UINT32),
WORKING_BLOCK_INVALID
);
if (EFI_ERROR (Status)) {
FreePool (Buffer);
return EFI_ABORTED;
}
FtwLiteDevice->FtwWorkSpaceHeader->WorkingBlockInvalid = FTW_VALID_STATE;
//
// Erase the working block
//
Status = FtwEraseBlock (
FtwLiteDevice,
FtwLiteDevice->FtwFvBlock,
FtwLiteDevice->FtwWorkBlockLba
);
if (EFI_ERROR (Status)) {
FreePool (Buffer);
return EFI_ABORTED;
}
//
// Write memory buffer to working block, using the FvbBlock protocol interface
//
Ptr = Buffer;
for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {
Count = FtwLiteDevice->SizeOfSpareBlock;
Status = FtwLiteDevice->FtwFvBlock->Write (
FtwLiteDevice->FtwFvBlock,
FtwLiteDevice->FtwWorkBlockLba + Index,
0,
&Count,
Ptr
);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_FTW_LITE, "FtwLite: FVB Write block - %r\n", Status));
FreePool (Buffer);
return Status;
}
Ptr += Count;
}
//
// Since the memory buffer will not be used, free memory Buffer.
//
FreePool (Buffer);
//
// Update the VALID of the working block
//
// Offset = EFI_FIELD_OFFSET(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER,
// WorkingBlockValid);
// Hardcode offset sizeof(EFI_GUID)+sizeof(UINT32), to skip Signature and Crc
//
Status = FtwUpdateFvState (
FtwLiteDevice->FtwFvBlock,
FtwLiteDevice->FtwWorkSpaceLba,
FtwLiteDevice->FtwWorkSpaceBase + sizeof (EFI_GUID) + sizeof (UINT32),
WORKING_BLOCK_VALID
);
if (EFI_ERROR (Status)) {
return EFI_ABORTED;
}
FtwLiteDevice->FtwWorkSpaceHeader->WorkingBlockValid = FTW_VALID_STATE;
return EFI_SUCCESS;
}

View File

@ -0,0 +1,561 @@
/*++
Copyright (c) 2006 - 2007, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
FtwWorkSpace.c
Abstract:
Revision History
--*/
#include <FtwLite.h>
BOOLEAN
IsValidWorkSpace (
IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingHeader
)
/*++
Routine Description:
Check to see if it is a valid work space.
Arguments:
WorkingHeader - Pointer of working block header
Returns:
EFI_SUCCESS - The function completed successfully
EFI_ABORTED - The function could not complete successfully.
--*/
{
EFI_STATUS Status;
EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER WorkingBlockHeader;
ASSERT (WorkingHeader != NULL);
if (WorkingHeader->WorkingBlockValid != FTW_VALID_STATE) {
return FALSE;
}
//
// Check signature with gEfiSystemNvDataFvGuid
//
if (!CompareGuid (&gEfiSystemNvDataFvGuid, &WorkingHeader->Signature)) {
return FALSE;
}
//
// Check the CRC of header
//
CopyMem (
&WorkingBlockHeader,
WorkingHeader,
sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER)
);
//
// Filter out the Crc and State fields
//
SetMem (
&WorkingBlockHeader.Crc,
sizeof (UINT32),
FTW_ERASED_BYTE
);
WorkingBlockHeader.WorkingBlockValid = FTW_ERASE_POLARITY;
WorkingBlockHeader.WorkingBlockInvalid = FTW_ERASE_POLARITY;
//
// Calculate the Crc of woking block header
//
Status = gBS->CalculateCrc32 (
(UINT8 *) &WorkingBlockHeader,
sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER),
&WorkingBlockHeader.Crc
);
ASSERT_EFI_ERROR (Status);
if (WorkingBlockHeader.Crc != WorkingHeader->Crc) {
DEBUG ((EFI_D_FTW_LITE, "FtwLite: Work block header CRC check error\n"));
return FALSE;
}
return TRUE;
}
EFI_STATUS
InitWorkSpaceHeader (
IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingHeader
)
/*++
Routine Description:
Initialize a work space when there is no work space.
Arguments:
WorkingHeader - Pointer of working block header
Returns:
EFI_SUCCESS - The function completed successfully
EFI_ABORTED - The function could not complete successfully.
--*/
{
EFI_STATUS Status;
ASSERT (WorkingHeader != NULL);
//
// Here using gEfiSystemNvDataFvGuid as the signature.
//
CopyMem (
&WorkingHeader->Signature,
&gEfiSystemNvDataFvGuid,
sizeof (EFI_GUID)
);
WorkingHeader->WriteQueueSize = FTW_WORKING_QUEUE_SIZE;
//
// Crc is calculated with all the fields except Crc and STATE
//
WorkingHeader->WorkingBlockValid = FTW_ERASE_POLARITY;
WorkingHeader->WorkingBlockInvalid = FTW_ERASE_POLARITY;
SetMem (&WorkingHeader->Crc, sizeof (UINT32), FTW_ERASED_BYTE);
//
// Calculate the CRC value
//
Status = gBS->CalculateCrc32 (
(UINT8 *) WorkingHeader,
sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER),
&WorkingHeader->Crc
);
ASSERT_EFI_ERROR (Status);
//
// Restore the WorkingBlockValid flag to VALID state
//
WorkingHeader->WorkingBlockValid = FTW_VALID_STATE;
WorkingHeader->WorkingBlockInvalid = FTW_INVALID_STATE;
return EFI_SUCCESS;
}
EFI_STATUS
FtwUpdateFvState (
IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
IN EFI_LBA Lba,
IN UINTN Offset,
IN UINT8 NewBit
)
/*++
Routine Description:
Update a bit of state on a block device. The location of the bit is
calculated by the (Lba, Offset, bit). Here bit is determined by the
the name of a certain bit.
Arguments:
FvBlock - FVB Protocol interface to access SrcBlock and DestBlock
Lba - Lba of a block
Offset - Offset on the Lba
NewBit - New value that will override the old value if it can be change
Returns:
EFI_SUCCESS - A state bit has been updated successfully
Others - Access block device error.
Notes:
Assume all bits of State are inside the same BYTE.
EFI_ABORTED - Read block fail
--*/
{
EFI_STATUS Status;
UINT8 State;
UINTN Length;
//
// Read state from device, assume State is only one byte.
//
Length = sizeof (UINT8);
Status = FvBlock->Read (FvBlock, Lba, Offset, &Length, &State);
if (EFI_ERROR (Status)) {
return EFI_ABORTED;
}
State ^= FTW_POLARITY_REVERT;
State = (UINT8) (State | NewBit);
State ^= FTW_POLARITY_REVERT;
//
// Write state back to device
//
Length = sizeof (UINT8);
Status = FvBlock->Write (FvBlock, Lba, Offset, &Length, &State);
return Status;
}
EFI_STATUS
FtwGetLastRecord (
IN EFI_FTW_LITE_DEVICE *FtwLiteDevice,
OUT EFI_FTW_LITE_RECORD **FtwLastRecord
)
/*++
Routine Description:
Get the last Write record pointer.
The last record is the record whose 'complete' state hasn't been set.
After all, this header may be a EMPTY header entry for next Allocate.
Arguments:
FtwLiteDevice - Private data of this driver
FtwLastRecord - Pointer to retrieve the last write record
Returns:
EFI_SUCCESS - Get the last write record successfully
EFI_ABORTED - The FTW work space is damaged
--*/
{
EFI_FTW_LITE_RECORD *Record;
Record = (EFI_FTW_LITE_RECORD *) (FtwLiteDevice->FtwWorkSpaceHeader + 1);
while (Record->WriteCompleted == FTW_VALID_STATE) {
//
// If Offset exceed the FTW work space boudary, return error.
//
if ((UINTN) ((UINT8 *) Record - FtwLiteDevice->FtwWorkSpace) > FtwLiteDevice->FtwWorkSpaceSize) {
return EFI_ABORTED;
}
Record++;
}
//
// Last write record is found
//
*FtwLastRecord = Record;
return EFI_SUCCESS;
}
EFI_STATUS
WorkSpaceRefresh (
IN EFI_FTW_LITE_DEVICE *FtwLiteDevice
)
/*++
Routine Description:
Read from working block to refresh the work space in memory.
Arguments:
FtwLiteDevice - Point to private data of FTW driver
Returns:
EFI_SUCCESS - The function completed successfully
EFI_ABORTED - The function could not complete successfully.
--*/
{
EFI_STATUS Status;
UINTN Length;
UINTN Offset;
EFI_FTW_LITE_RECORD *Record;
//
// Initialize WorkSpace as FTW_ERASED_BYTE
//
SetMem (
FtwLiteDevice->FtwWorkSpace,
FtwLiteDevice->FtwWorkSpaceSize,
FTW_ERASED_BYTE
);
//
// Read from working block
//
Length = FtwLiteDevice->FtwWorkSpaceSize;
Status = FtwLiteDevice->FtwFvBlock->Read (
FtwLiteDevice->FtwFvBlock,
FtwLiteDevice->FtwWorkSpaceLba,
FtwLiteDevice->FtwWorkSpaceBase,
&Length,
FtwLiteDevice->FtwWorkSpace
);
if (EFI_ERROR (Status)) {
return EFI_ABORTED;
}
//
// Refresh the FtwLastRecord
//
Status = FtwGetLastRecord (FtwLiteDevice, &FtwLiteDevice->FtwLastRecord);
Record = FtwLiteDevice->FtwLastRecord;
Offset = (UINTN) (UINT8 *) Record - (UINTN) FtwLiteDevice->FtwWorkSpace;
//
// IF work space has error or Record is out of the workspace limit, THEN
// call reclaim.
//
if (EFI_ERROR (Status) || (Offset + WRITE_TOTAL_SIZE >= FtwLiteDevice->FtwWorkSpaceSize)) {
//
// reclaim work space in working block.
//
Status = FtwReclaimWorkSpace (FtwLiteDevice);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_FTW_LITE, "FtwLite: Reclaim workspace - %r\n", Status));
return EFI_ABORTED;
}
}
return EFI_SUCCESS;
}
EFI_STATUS
CleanupWorkSpace (
IN EFI_FTW_LITE_DEVICE *FtwLiteDevice,
IN OUT UINT8 *FtwSpaceBuffer,
IN UINTN BufferSize
)
/*++
Routine Description:
Reclaim the work space. Get rid of all the completed write records
and write records in the Fault Tolerant work space.
Arguments:
FtwLiteDevice - Point to private data of FTW driver
FtwSpaceBuffer - Buffer to contain the reclaimed clean data
BufferSize - Size of the FtwSpaceBuffer
Returns:
EFI_SUCCESS - The function completed successfully
EFI_BUFFER_TOO_SMALL - The FtwSpaceBuffer is too small
EFI_ABORTED - The function could not complete successfully.
--*/
{
UINTN Length;
EFI_FTW_LITE_RECORD *Record;
//
// To check if the buffer is large enough
//
Length = FtwLiteDevice->FtwWorkSpaceSize;
if (BufferSize < Length) {
return EFI_BUFFER_TOO_SMALL;
}
//
// Clear the content of buffer that will save the new work space data
//
SetMem (FtwSpaceBuffer, Length, FTW_ERASED_BYTE);
//
// Copy EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER to buffer
//
CopyMem (
FtwSpaceBuffer,
FtwLiteDevice->FtwWorkSpaceHeader,
sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER)
);
//
// Get the last record
//
Record = FtwLiteDevice->FtwLastRecord;
if ((Record != NULL) && (Record->WriteAllocated == FTW_VALID_STATE) && (Record->WriteCompleted != FTW_VALID_STATE)) {
CopyMem (
(UINT8 *) FtwSpaceBuffer + sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER),
Record,
WRITE_TOTAL_SIZE
);
}
return EFI_SUCCESS;
}
EFI_STATUS
FtwReclaimWorkSpace (
IN EFI_FTW_LITE_DEVICE *FtwLiteDevice
)
/*++
Routine Description:
Reclaim the work space on the working block.
Arguments:
FtwLiteDevice - Point to private data of FTW driver
Returns:
EFI_SUCCESS - The function completed successfully
EFI_OUT_OF_RESOURCES - Allocate memory error
EFI_ABORTED - The function could not complete successfully
--*/
{
EFI_STATUS Status;
UINT8 *TempBuffer;
UINTN TempBufferSize;
UINT8 *Ptr;
UINTN Length;
UINTN Index;
UINTN SpareBufferSize;
UINT8 *SpareBuffer;
EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingBlockHeader;
DEBUG ((EFI_D_FTW_LITE, "FtwLite: start to reclaim work space\n"));
//
// Read all original data from working block to a memory buffer
//
TempBufferSize = FtwLiteDevice->SpareAreaLength;
TempBuffer = AllocateZeroPool (TempBufferSize);
if (TempBuffer != NULL) {
return EFI_OUT_OF_RESOURCES;
}
Ptr = TempBuffer;
for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {
Length = FtwLiteDevice->SizeOfSpareBlock;
Status = FtwLiteDevice->FtwFvBlock->Read (
FtwLiteDevice->FtwFvBlock,
FtwLiteDevice->FtwWorkBlockLba + Index,
0,
&Length,
Ptr
);
if (EFI_ERROR (Status)) {
FreePool (TempBuffer);
return EFI_ABORTED;
}
Ptr += Length;
}
//
// Clean up the workspace, remove all the completed records.
//
Ptr = TempBuffer +
((UINTN) (FtwLiteDevice->FtwWorkSpaceLba - FtwLiteDevice->FtwWorkBlockLba)) *
FtwLiteDevice->SizeOfSpareBlock + FtwLiteDevice->FtwWorkSpaceBase;
Status = CleanupWorkSpace (
FtwLiteDevice,
Ptr,
FtwLiteDevice->FtwWorkSpaceSize
);
CopyMem (
FtwLiteDevice->FtwWorkSpace,
Ptr,
FtwLiteDevice->FtwWorkSpaceSize
);
Status = FtwGetLastRecord (FtwLiteDevice, &FtwLiteDevice->FtwLastRecord);
//
// Set the WorkingBlockValid and WorkingBlockInvalid as INVALID
//
WorkingBlockHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) Ptr;
WorkingBlockHeader->WorkingBlockValid = FTW_INVALID_STATE;
WorkingBlockHeader->WorkingBlockInvalid = FTW_INVALID_STATE;
//
// Try to keep the content of spare block
// Save spare block into a spare backup memory buffer (Sparebuffer)
//
SpareBufferSize = FtwLiteDevice->SpareAreaLength;
SpareBuffer = AllocatePool (SpareBufferSize);
if (SpareBuffer == NULL) {
FreePool (TempBuffer);
return EFI_OUT_OF_RESOURCES;
}
Ptr = SpareBuffer;
for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {
Length = FtwLiteDevice->SizeOfSpareBlock;
Status = FtwLiteDevice->FtwBackupFvb->Read (
FtwLiteDevice->FtwBackupFvb,
FtwLiteDevice->FtwSpareLba + Index,
0,
&Length,
Ptr
);
if (EFI_ERROR (Status)) {
FreePool (TempBuffer);
FreePool (SpareBuffer);
return EFI_ABORTED;
}
Ptr += Length;
}
//
// Write the memory buffer to spare block
//
Status = FtwEraseSpareBlock (FtwLiteDevice);
Ptr = TempBuffer;
for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {
Length = FtwLiteDevice->SizeOfSpareBlock;
Status = FtwLiteDevice->FtwBackupFvb->Write (
FtwLiteDevice->FtwBackupFvb,
FtwLiteDevice->FtwSpareLba + Index,
0,
&Length,
Ptr
);
if (EFI_ERROR (Status)) {
FreePool (TempBuffer);
FreePool (SpareBuffer);
return EFI_ABORTED;
}
Ptr += Length;
}
//
// Free TempBuffer
//
FreePool (TempBuffer);
//
// Write the spare block to working block
//
Status = FlushSpareBlockToWorkingBlock (FtwLiteDevice);
if (EFI_ERROR (Status)) {
FreePool (SpareBuffer);
return Status;
}
//
// Restore spare backup buffer into spare block , if no failure happened during FtwWrite.
//
Status = FtwEraseSpareBlock (FtwLiteDevice);
Ptr = SpareBuffer;
for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {
Length = FtwLiteDevice->SizeOfSpareBlock;
Status = FtwLiteDevice->FtwBackupFvb->Write (
FtwLiteDevice->FtwBackupFvb,
FtwLiteDevice->FtwSpareLba + Index,
0,
&Length,
Ptr
);
if (EFI_ERROR (Status)) {
FreePool (SpareBuffer);
return EFI_ABORTED;
}
Ptr += Length;
}
FreePool (SpareBuffer);
DEBUG ((EFI_D_FTW_LITE, "FtwLite: reclaim work space success\n"));
return EFI_SUCCESS;
}

View File

@ -0,0 +1,403 @@
/*++
Copyright (c) 2006 - 2007, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
Ia32FtwMisc.c
Abstract:
Ia32 platform related code to support FtwLite..
Revision History
--*/
#include <FtwLite.h>
//
// MACROs for boot block update
//
#define BOOT_BLOCK_BASE 0xFFFF0000
//
// (LPC -- D31:F0)
//
#define LPC_BUS_NUMBER 0x00
#define LPC_DEVICE_NUMBER 0x1F
#define LPC_IF 0xF0
//
// Top swap
//
#define GEN_STATUS 0xD4
#define TOP_SWAP_BIT (1 << 13)
STATIC
UINT32
ReadPciRegister (
IN UINT32 Offset
)
/*++
Routine Description:
Read PCI register value.
Arguments:
Offset - Offset of the register
Returns:
The value.
--*/
{
EFI_STATUS Status;
UINT32 Value;
EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
Value = 0;
Status = gBS->LocateProtocol (&gEfiPciRootBridgeIoProtocolGuid, NULL, (VOID **) &PciRootBridgeIo);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "FtwLite: Locate PCI root bridge io protocol - %r", Status));
return 0;
}
Status = PciRootBridgeIo->Pci.Read (
PciRootBridgeIo,
EfiPciWidthUint32,
EFI_PCI_ADDRESS (
LPC_BUS_NUMBER,
LPC_DEVICE_NUMBER,
LPC_IF,
Offset
),
1,
&Value
);
ASSERT_EFI_ERROR (Status);
return Value;
}
STATIC
EFI_STATUS
GetSwapState (
IN EFI_FTW_LITE_DEVICE *FtwLiteDevice,
OUT BOOLEAN *SwapState
)
/*++
Routine Description:
Get swap state
Arguments:
FtwLiteDevice - Calling context
SwapState - Swap state
Returns:
EFI_SUCCESS - State successfully got
--*/
{
//
// Top swap status is 13 bit
//
*SwapState = (BOOLEAN) ((ReadPciRegister (GEN_STATUS) & TOP_SWAP_BIT) != 0);
return EFI_SUCCESS;
}
STATIC
EFI_STATUS
SetSwapState (
IN EFI_FTW_LITE_DEVICE *FtwLiteDevice,
IN BOOLEAN TopSwap
)
/*++
Routine Description:
Set swap state.
Arguments:
FtwLiteDevice - Indicates a pointer to the calling context.
TopSwap - New swap state
Returns:
EFI_SUCCESS - The function completed successfully
Note:
the Top-Swap bit (bit 13, D31: F0, Offset D4h). Note that
software will not be able to clear the Top-Swap bit until the system is
rebooted without GNT[A]# being pulled down.
--*/
{
UINT32 GenStatus;
EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
EFI_STATUS Status;
//
// Top-Swap bit (bit 13, D31: F0, Offset D4h)
//
GenStatus = ReadPciRegister (GEN_STATUS);
//
// Set 13 bit, according to input NewSwapState
//
if (TopSwap) {
GenStatus |= TOP_SWAP_BIT;
} else {
GenStatus &= ~TOP_SWAP_BIT;
}
Status = gBS->LocateProtocol (&gEfiPciRootBridgeIoProtocolGuid, NULL, (VOID **) &PciRootBridgeIo);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "FtwLite: Locate PCI root bridge io protocol - %r", Status));
return Status;
}
//
// Write back the GenStatus register
//
Status = PciRootBridgeIo->Pci.Write (
PciRootBridgeIo,
EfiPciWidthUint32,
EFI_PCI_ADDRESS (
LPC_BUS_NUMBER,
LPC_DEVICE_NUMBER,
LPC_IF,
GEN_STATUS
),
1,
&GenStatus
);
DEBUG_CODE_BEGIN ();
if (TopSwap) {
DEBUG ((EFI_D_ERROR, "SAR: Set top swap\n"));
} else {
DEBUG ((EFI_D_ERROR, "SAR: Clear top swap\n"));
}
DEBUG_CODE_END ();
return EFI_SUCCESS;
}
BOOLEAN
IsBootBlock (
EFI_FTW_LITE_DEVICE *FtwLiteDevice,
EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
EFI_LBA Lba
)
/*++
Routine Description:
Check whether the block is a boot block.
Arguments:
FtwLiteDevice - Calling context
FvBlock - Fvb protocol instance
Lba - Lba value
Returns:
Is a boot block or not
--*/
{
EFI_STATUS Status;
EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *BootFvb;
Status = GetFvbByAddress (BOOT_BLOCK_BASE, &BootFvb);
if (EFI_ERROR (Status)) {
return FALSE;
}
//
// Compare the Fvb
//
return (BOOLEAN) (FvBlock == BootFvb);
}
EFI_STATUS
FlushSpareBlockToBootBlock (
EFI_FTW_LITE_DEVICE *FtwLiteDevice
)
/*++
Routine Description:
Copy the content of spare block to a boot block. Size is FTW_BLOCK_SIZE.
Spare block is accessed by FTW backup FVB protocol interface. LBA is
FtwLiteDevice->FtwSpareLba.
Boot block is accessed by BootFvb protocol interface. LBA is 0.
Arguments:
FtwLiteDevice - The private data of FTW_LITE driver
Returns:
EFI_SUCCESS - Spare block content is copied to boot block
EFI_INVALID_PARAMETER - Input parameter error
EFI_OUT_OF_RESOURCES - Allocate memory error
EFI_ABORTED - The function could not complete successfully
Notes:
FTW will do extra work on boot block update.
FTW should depend on a protocol of EFI_ADDRESS_RANGE_SWAP_PROTOCOL,
which is produced by a chipset driver.
FTW updating boot block steps:
1. Erase top swap block (0xFFFE-0xFFFEFFFF) and write data to it ready
2. Read data from top swap block to memory buffer
3. SetSwapState(EFI_SWAPPED)
4. Erasing boot block (0xFFFF-0xFFFFFFFF)
5. Programming boot block until the boot block is ok.
6. SetSwapState(UNSWAPPED)
Notes:
1. Since the SwapState bit is saved in CMOS, FTW can restore and continue
even in the scenario of power failure.
2. FTW shall not allow to update boot block when battery state is error.
--*/
{
EFI_STATUS Status;
UINTN Length;
UINT8 *Buffer;
UINTN Count;
UINT8 *Ptr;
UINTN Index;
BOOLEAN TopSwap;
EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *BootFvb;
EFI_LBA BootLba;
//
// Allocate a memory buffer
//
Length = FtwLiteDevice->SpareAreaLength;
Buffer = AllocatePool (Length);
if (Buffer == NULL) {
}
//
// Get TopSwap bit state
//
Status = GetSwapState (FtwLiteDevice, &TopSwap);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "FtwLite: Get Top Swapped status - %r\n", Status));
FreePool (Buffer);
return EFI_ABORTED;
}
if (TopSwap) {
//
// Get FVB of current boot block
//
Status = GetFvbByAddress (FtwLiteDevice->SpareAreaAddress + FTW_BLOCK_SIZE, &BootFvb);
if (EFI_ERROR (Status)) {
FreePool (Buffer);
return Status;
}
//
// Read data from current boot block
//
BootLba = 0;
Ptr = Buffer;
for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {
Count = FtwLiteDevice->SizeOfSpareBlock;
Status = BootFvb->Read (
BootFvb,
BootLba + Index,
0,
&Count,
Ptr
);
if (EFI_ERROR (Status)) {
FreePool (Buffer);
return Status;
}
Ptr += Count;
}
} else {
//
// Read data from spare block
//
Ptr = Buffer;
for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {
Count = FtwLiteDevice->SizeOfSpareBlock;
Status = FtwLiteDevice->FtwBackupFvb->Read (
FtwLiteDevice->FtwBackupFvb,
FtwLiteDevice->FtwSpareLba + Index,
0,
&Count,
Ptr
);
if (EFI_ERROR (Status)) {
FreePool (Buffer);
return Status;
}
Ptr += Count;
}
//
// Set TopSwap bit
//
Status = SetSwapState (FtwLiteDevice, TRUE);
DEBUG ((EFI_D_ERROR, "FtwLite: Set Swap State - %r\n", Status));
ASSERT_EFI_ERROR (Status);
}
//
// Erase boot block. After setting TopSwap bit, it's spare block now!
//
Status = FtwEraseSpareBlock (FtwLiteDevice);
if (EFI_ERROR (Status)) {
FreePool (Buffer);
return EFI_ABORTED;
}
//
// Write memory buffer to currenet spare block
//
Ptr = Buffer;
for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {
Count = FtwLiteDevice->SizeOfSpareBlock;
Status = FtwLiteDevice->FtwBackupFvb->Write (
FtwLiteDevice->FtwBackupFvb,
FtwLiteDevice->FtwSpareLba + Index,
0,
&Count,
Ptr
);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_FTW_LITE, "FtwLite: FVB Write boot block - %r\n", Status));
FreePool (Buffer);
return Status;
}
Ptr += Count;
}
FreePool (Buffer);
//
// Clear TopSwap bit
//
Status = SetSwapState (FtwLiteDevice, FALSE);
DEBUG ((EFI_D_ERROR, "FtwLite: Clear Swap State - %r\n", Status));
ASSERT_EFI_ERROR (Status);
return EFI_SUCCESS;
}

View File

@ -0,0 +1,143 @@
/*++
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:
IpfFtwMisc.c
Abstract:
Ipf platform related code to support FtwLite..
Revision History
--*/
#include <FtwLite.h>
//
// MACROs for boot block update
//
#define BOOT_BLOCK_BASE
STATIC
EFI_STATUS
GetSwapState (
IN EFI_FTW_LITE_DEVICE *FtwLiteDevice,
OUT BOOLEAN *SwapState
)
/*++
Routine Description:
Get swap state
Arguments:
FtwLiteDevice - Calling context
SwapState - Swap state
Returns:
EFI_SUCCESS - State successfully got
--*/
{
return EFI_SUCCESS;
}
STATIC
EFI_STATUS
SetSwapState (
IN EFI_FTW_LITE_DEVICE *FtwLiteDevice,
IN BOOLEAN TopSwap
)
/*++
Routine Description:
Set swap state.
Arguments:
FtwLiteDevice - Indicates a pointer to the calling context.
TopSwap - New swap state
Returns:
EFI_SUCCESS - The function completed successfully
Note:
the Top-Swap bit (bit 13, D31: F0, Offset D4h). Note that
software will not be able to clear the Top-Swap bit until the system is
rebooted without GNT[A]# being pulled down.
--*/
{
return EFI_SUCCESS;
}
BOOLEAN
IsBootBlock (
EFI_FTW_LITE_DEVICE *FtwLiteDevice,
EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
EFI_LBA Lba
)
/*++
Routine Description:
Check whether the block is a boot block.
Arguments:
FtwLiteDevice - Calling context
FvBlock - Fvb protocol instance
Lba - Lba value
Returns:
Is a boot block or not
--*/
{
//
// IPF doesn't support safe bootblock update
// so treat bootblock as normal block
//
return FALSE;
}
EFI_STATUS
FlushSpareBlockToBootBlock (
EFI_FTW_LITE_DEVICE *FtwLiteDevice
)
/*++
Routine Description:
Copy the content of spare block to a boot block. Size is FTW_BLOCK_SIZE.
Spare block is accessed by FTW backup FVB protocol interface. LBA is
FtwLiteDevice->FtwSpareLba.
Boot block is accessed by BootFvb protocol interface. LBA is 0.
Arguments:
FtwLiteDevice - The private data of FTW_LITE driver
Returns:
EFI_SUCCESS - Spare block content is copied to boot block
EFI_INVALID_PARAMETER - Input parameter error
EFI_OUT_OF_RESOURCES - Allocate memory error
EFI_ABORTED - The function could not complete successfully
Notes:
--*/
{
return EFI_SUCCESS;
}

View File

@ -0,0 +1,140 @@
/*++
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:
x64FtwMisc.c
Abstract:
X64 platform related code to support FtwLite..
Revision History
--*/
#include <FtwLite.h>
//
// MACROs for boot block update
//
#define BOOT_BLOCK_BASE
// STATIC
EFI_STATUS
GetSwapState (
IN EFI_FTW_LITE_DEVICE *FtwLiteDevice,
OUT BOOLEAN *SwapState
)
/*++
Routine Description:
Get swap state
Arguments:
FtwLiteDevice - Calling context
SwapState - Swap state
Returns:
EFI_SUCCESS - State successfully got
--*/
{
return EFI_SUCCESS;
}
// STATIC
EFI_STATUS
SetSwapState (
IN EFI_FTW_LITE_DEVICE *FtwLiteDevice,
IN BOOLEAN TopSwap
)
/*++
Routine Description:
Set swap state.
Arguments:
FtwLiteDevice - Indicates a pointer to the calling context.
TopSwap - New swap state
Returns:
EFI_SUCCESS - The function completed successfully
Note:
the Top-Swap bit (bit 13, D31: F0, Offset D4h). Note that
software will not be able to clear the Top-Swap bit until the system is
rebooted without GNT[A]# being pulled down.
--*/
{
return EFI_SUCCESS;
}
BOOLEAN
IsBootBlock (
EFI_FTW_LITE_DEVICE *FtwLiteDevice,
EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,
EFI_LBA Lba
)
/*++
Routine Description:
Check whether the block is a boot block.
Arguments:
FtwLiteDevice - Calling context
FvBlock - Fvb protocol instance
Lba - Lba value
Returns:
Is a boot block or not
--*/
{
return FALSE;
}
EFI_STATUS
FlushSpareBlockToBootBlock (
EFI_FTW_LITE_DEVICE *FtwLiteDevice
)
/*++
Routine Description:
Copy the content of spare block to a boot block. Size is FTW_BLOCK_SIZE.
Spare block is accessed by FTW backup FVB protocol interface. LBA is
FtwLiteDevice->FtwSpareLba.
Boot block is accessed by BootFvb protocol interface. LBA is 0.
Arguments:
FtwLiteDevice - The private data of FTW_LITE driver
Returns:
EFI_SUCCESS - Spare block content is copied to boot block
EFI_INVALID_PARAMETER - Input parameter error
EFI_OUT_OF_RESOURCES - Allocate memory error
EFI_ABORTED - The function could not complete successfully
Notes:
--*/
{
return EFI_SUCCESS;
}

View File

@ -0,0 +1,230 @@
/*++
Copyright (c) 2006 - 2007, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
Crc32SectionExtract.c
Abstract:
Implements GUIDed section extraction protocol interface with
a specific GUID: CRC32.
Please refer to the Framewokr Firmware Volume Specification 0.9.
--*/
#include <GuidedSection.h>
#include <Crc32SectionExtract.h>
EFI_STATUS
EFIAPI
InitializeCrc32GuidedSectionExtractionProtocol (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
/*++
Routine Description:
Entry point of the CRC32 GUIDed section extraction protocol.
Creates and initializes an instance of the GUIDed section
extraction protocol with CRC32 GUID.
Arguments:
ImageHandle EFI_HANDLE: A handle for the image that is initializing
this driver
SystemTable EFI_SYSTEM_TABLE: A pointer to the EFI system table
Returns:
EFI_SUCCESS: Driver initialized successfully
EFI_LOAD_ERROR: Failed to Initialize or has been loaded
EFI_OUT_OF_RESOURCES: Could not allocate needed resources
--*/
{
EFI_STATUS Status;
EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *Crc32GuidedSep;
EFI_HANDLE Handle;
//
// Call all constructors per produced protocols
//
Status = GuidedSectionExtractionProtocolConstructor (
&Crc32GuidedSep,
(EFI_EXTRACT_GUIDED_SECTION) Crc32ExtractSection
);
if (EFI_ERROR (Status)) {
if (Crc32GuidedSep != NULL) {
FreePool (Crc32GuidedSep);
}
return Status;
}
//
// Pass in a NULL to install to a new handle
//
Handle = NULL;
Status = gBS->InstallProtocolInterface (
&Handle,
&gEfiCrc32GuidedSectionExtractionProtocolGuid,
EFI_NATIVE_INTERFACE,
Crc32GuidedSep
);
if (EFI_ERROR (Status)) {
FreePool (Crc32GuidedSep);
return EFI_LOAD_ERROR;
}
return EFI_SUCCESS;
}
STATIC
UINT32
EFIAPI
GetSectionLength (
IN EFI_COMMON_SECTION_HEADER *CommonHeader
)
/*++
Routine Description:
Get a length of section.
Parameters:
CommonHeader - Pointer to the common section header.
Return Value:
The length of the section, including the section header.
--*/
// TODO: function comment is missing 'Arguments:'
// TODO: function comment is missing 'Returns:'
// TODO: CommonHeader - add argument and description to function comment
{
UINT32 Size;
Size = *(UINT32 *) CommonHeader->Size & 0x00FFFFFF;
return Size;
}
STATIC
EFI_STATUS
EFIAPI
Crc32ExtractSection (
IN EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *This,
IN VOID *InputSection,
OUT VOID **OutputBuffer,
OUT UINTN *OutputSize,
OUT UINT32 *AuthenticationStatus
)
/*++
Routine Description:
This function reads and extracts contents of a section from an
encapsulating section.
Parameters:
This - Indicates the calling context.
InputSection - Buffer containing the input GUIDed section
to be processed.
OutputBuffer - *OutputBuffer is allocated from boot services
pool memory and containing the new section
stream. The caller is responsible for freeing
this buffer.
AuthenticationStatus - Pointer to a caller allocated UINT32 that
indicates the authentication status of the
output buffer
Return Value:
EFI_SUCCESS
EFI_OUT_OF_RESOURCES
EFI_INVALID_PARAMETER
EFI_NOT_AVAILABLE_YET
--*/
// TODO: function comment is missing 'Arguments:'
// TODO: function comment is missing 'Returns:'
// TODO: This - add argument and description to function comment
// TODO: InputSection - add argument and description to function comment
// TODO: OutputBuffer - add argument and description to function comment
// TODO: OutputSize - add argument and description to function comment
// TODO: AuthenticationStatus - add argument and description to function comment
// TODO: EFI_INVALID_PARAMETER - add return value to function comment
// TODO: EFI_INVALID_PARAMETER - add return value to function comment
// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment
// TODO: EFI_SUCCESS - add return value to function comment
{
EFI_STATUS Status;
CRC32_SECTION_HEADER *Crc32SectionHeader;
EFI_GUID_DEFINED_SECTION *GuidedSectionHeader;
UINT8 *Image;
UINT32 Crc32Checksum;
VOID *DummyInterface;
if (OutputBuffer == NULL) {
return EFI_INVALID_PARAMETER;
}
*OutputBuffer = NULL;
//
// Points to the section header
//
Crc32SectionHeader = (CRC32_SECTION_HEADER *) InputSection;
GuidedSectionHeader = (EFI_GUID_DEFINED_SECTION *) InputSection;
//
// Check if the GUID is a CRC32 section GUID
//
if (!CompareGuid (
&(GuidedSectionHeader->SectionDefinitionGuid),
&gEfiCrc32GuidedSectionExtractionProtocolGuid
)) {
return EFI_INVALID_PARAMETER;
}
Image = (UINT8 *) InputSection + (UINT32) (GuidedSectionHeader->DataOffset);
*OutputSize = GetSectionLength ((EFI_COMMON_SECTION_HEADER *) InputSection) - (UINT32) GuidedSectionHeader->DataOffset;
*OutputBuffer = AllocatePool (*OutputSize);
if (*OutputBuffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// Implictly CRC32 GUIDed section should have STATUS_VALID bit set
//
ASSERT (GuidedSectionHeader->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID);
*AuthenticationStatus = EFI_LOCAL_AUTH_STATUS_IMAGE_SIGNED | EFI_AGGREGATE_AUTH_STATUS_IMAGE_SIGNED;
//
// Check whether there exists EFI_SECURITY_POLICY_PROTOCOL_GUID.
//
Status = gBS->LocateProtocol (&gEfiSecurityPolicyProtocolGuid, NULL, &DummyInterface);
if (!EFI_ERROR (Status)) {
*AuthenticationStatus |= EFI_LOCAL_AUTH_STATUS_PLATFORM_OVERRIDE | EFI_AGGREGATE_AUTH_STATUS_PLATFORM_OVERRIDE;
} else {
//
// Calculate CRC32 Checksum of Image
//
gBS->CalculateCrc32 (Image, *OutputSize, &Crc32Checksum);
if (Crc32Checksum != Crc32SectionHeader->CRC32Checksum) {
*AuthenticationStatus |= EFI_LOCAL_AUTH_STATUS_TEST_FAILED | EFI_AGGREGATE_AUTH_STATUS_TEST_FAILED;
}
}
CopyMem (*OutputBuffer, Image, *OutputSize);
return EFI_SUCCESS;
}

View 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:
Crc32SectionExtraction.dxs
Abstract:
Dependency expression file.
--*/
#include "DxeDepex.h"
DEPENDENCY_START
EFI_RUNTIME_ARCH_PROTOCOL_GUID
DEPENDENCY_END

View File

@ -0,0 +1,112 @@
/*++
Copyright (c) 2006 - 2007, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
Crc32SectionExtract.h
Abstract:
Header file for Crc32SectionExtract.c
Please refer to the Framewokr Firmware Volume Specification 0.9.
--*/
#ifndef _CRC32_GUIDED_SECTION_EXTRACTION_H
#define _CRC32_GUIDED_SECTION_EXTRACTION_H
//
// The package level header files this module uses
//
#include <PiDxe.h>
//
// The protocols, PPI and GUID defintions for this module
//
#include <Protocol/SecurityPolicy.h>
#include <Protocol/GuidedSectionExtaction.h>
//
// The Library classes this module consumes
//
#include <Library/MemoryAllocationLib.h>
#include <Library/DebugLib.h>
#include <Library/UefiDriverEntryPoint.h>
#include <Library/BaseMemoryLib.h>
#include <Library/UefiBootServicesTableLib.h>
typedef struct {
EFI_GUID_DEFINED_SECTION GuidedSectionHeader;
UINT32 CRC32Checksum;
} CRC32_SECTION_HEADER;
//
// Function prototype declarations
//
STATIC
EFI_STATUS
EFIAPI
Crc32ExtractSection (
IN EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *This,
IN VOID *InputSection,
OUT VOID **OutputBuffer,
OUT UINTN *OutputSize,
OUT UINT32 *AuthenticationStatus
)
/*++
Routine Description:
TODO: Add function description
Arguments:
This - TODO: add argument description
InputSection - TODO: add argument description
OutputBuffer - TODO: add argument description
OutputSize - TODO: add argument description
AuthenticationStatus - TODO: add argument description
Returns:
TODO: add return values
--*/
;
EFI_STATUS
EFIAPI
InitializeCrc32GuidedSectionExtractionProtocol (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
/*++
Routine Description:
Entry point of the CRC32 GUIDed section extraction protocol.
Creates and initializes an instance of the GUIDed section
extraction protocol with CRC32 GUID.
Arguments:
ImageHandle EFI_HANDLE: A handle for the image that is initializing
this driver
SystemTable EFI_SYSTEM_TABLE: A pointer to the EFI system table
Returns:
EFI_SUCCESS: Driver initialized successfully
EFI_LOAD_ERROR: Failed to Initialize or has been loaded
EFI_OUT_OF_RESOURCES: Could not allocate needed resources
--*/
;
#endif

View File

@ -0,0 +1,88 @@
#/** @file
# Component description file for Crc32SectionExtract module.
#
# This driver implements CRC32 GUIDed section extraction protocol interface.
# Copyright (c) 2006 - 2007, Intel Corporation
#
# All rights reserved. This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
#
#**/
################################################################################
#
# Defines Section - statements that will be processed to create a Makefile.
#
################################################################################
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = Crc32SectionExtract
FILE_GUID = 51C9F40C-5243-4473-B265-B3C8FFAFF9FA
MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.0
EDK_RELEASE_VERSION = 0x00020000
EFI_SPECIFICATION_VERSION = 0x00020000
ENTRY_POINT = InitializeCrc32GuidedSectionExtractionProtocol
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64 IPF EBC
#
################################################################################
#
# Sources Section - list of files that are required for the build to succeed.
#
################################################################################
[Sources.common]
Crc32SectionExtract.dxs
GuidedSection.h
GuidedSection.c
Crc32SectionExtract.h
Crc32SectionExtract.c
################################################################################
#
# Package Dependency Section - list of Package files that are required for
# this module.
#
################################################################################
[Packages]
MdePkg/MdePkg.dec
IntelFrameworkPkg/IntelFrameworkPkg.dec
################################################################################
#
# Library Class Section - list of Library Classes that are required for
# this module.
#
################################################################################
[LibraryClasses]
MemoryAllocationLib
UefiBootServicesTableLib
BaseMemoryLib
UefiDriverEntryPoint
DebugLib
################################################################################
#
# Protocol C Name Section - list of Protocol and Protocol Notify C Names
# that this module uses or produces.
#
################################################################################
[Protocols]
gEfiSecurityPolicyProtocolGuid # PROTOCOL SOMETIMES_CONSUMED
gEfiCrc32GuidedSectionExtractionProtocolGuid # PROTOCOL ALWAYS_PRODUCED

View File

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8"?>
<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<MsaHeader>
<ModuleName>Crc32SectionExtract</ModuleName>
<ModuleType>DXE_DRIVER</ModuleType>
<GuidValue>51C9F40C-5243-4473-B265-B3C8FFAFF9FA</GuidValue>
<Version>1.0</Version>
<Abstract>Component description file for Crc32SectionExtract module.</Abstract>
<Description>This driver implements CRC32 GUIDed section extraction protocol interface.</Description>
<Copyright>Copyright (c) 2006 - 2007, Intel Corporation</Copyright>
<License>All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.</License>
<Specification>FRAMEWORK_BUILD_PACKAGING_SPECIFICATION 0x00000052</Specification>
</MsaHeader>
<ModuleDefinitions>
<SupportedArchitectures>IA32 X64 IPF EBC</SupportedArchitectures>
<BinaryModule>false</BinaryModule>
<OutputFileBasename>Crc32SectionExtract</OutputFileBasename>
</ModuleDefinitions>
<LibraryClassDefinitions>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>DebugLib</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>UefiDriverEntryPoint</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>BaseMemoryLib</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>UefiBootServicesTableLib</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>MemoryAllocationLib</Keyword>
</LibraryClass>
</LibraryClassDefinitions>
<SourceFiles>
<Filename>Crc32SectionExtract.c</Filename>
<Filename>Crc32SectionExtract.h</Filename>
<Filename>GuidedSection.c</Filename>
<Filename>GuidedSection.h</Filename>
<Filename>Crc32SectionExtract.dxs</Filename>
</SourceFiles>
<PackageDependencies>
<Package PackageGuid="1E73767F-8F52-4603-AEB4-F29B510B6766"/>
</PackageDependencies>
<Protocols>
<Protocol Usage="SOMETIMES_CONSUMED">
<ProtocolCName>gEfiSecurityPolicyProtocolGuid</ProtocolCName>
</Protocol>
<Protocol Usage="ALWAYS_PRODUCED">
<ProtocolCName>gEfiCrc32GuidedSectionExtractionProtocolGuid</ProtocolCName>
</Protocol>
</Protocols>
<Externs>
<Specification>EFI_SPECIFICATION_VERSION 0x00020000</Specification>
<Specification>EDK_RELEASE_VERSION 0x00020000</Specification>
<Extern>
<ModuleEntryPoint>InitializeCrc32GuidedSectionExtractionProtocol</ModuleEntryPoint>
</Extern>
</Externs>
</ModuleSurfaceArea>

View File

@ -0,0 +1,61 @@
/*++
Copyright (c) 2006 - 2007, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
GuidedSection.c
Abstract:
GUIDed section extraction protocol implementation.
This contains the common constructor of GUIDed section
extraction protocol. GUID specific implementation of each
GUIDed section extraction protocol can be found in other
files under the same directory.
--*/
#include "GuidedSection.h"
EFI_STATUS
GuidedSectionExtractionProtocolConstructor (
OUT EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL **GuidedSep,
IN EFI_EXTRACT_GUIDED_SECTION ExtractSection
)
/*++
Routine Description:
Constructor for the GUIDed section extraction protocol. Initializes
instance data.
Arguments:
This Instance to construct
Returns:
EFI_SUCCESS: Instance initialized.
--*/
// TODO: GuidedSep - add argument and description to function comment
// TODO: ExtractSection - add argument and description to function comment
// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment
{
*GuidedSep = AllocatePool (sizeof (EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL));
if (*GuidedSep == NULL) {
return EFI_OUT_OF_RESOURCES;
}
(*GuidedSep)->ExtractSection = ExtractSection;
return EFI_SUCCESS;
}

View File

@ -0,0 +1,54 @@
/*++
Copyright (c) 2006 - 2007, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
GuidedSection.h
Abstract:
Header file for GuidedSection.c
Please refer to the Framewokr Firmware Volume Specification 0.9.
--*/
#ifndef _GUIDED_SECTION_EXTRACTION_H
#define _GUIDED_SECTION_EXTRACTION_H
#include "Crc32SectionExtract.h"
//
// Function prototype declarations
//
EFI_STATUS
GuidedSectionExtractionProtocolConstructor (
OUT EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL **GuidedSep,
IN EFI_EXTRACT_GUIDED_SECTION ExtractSection
)
/*++
Routine Description:
TODO: Add function description
Arguments:
GuidedSep - TODO: add argument description
ExtractSection - TODO: add argument description
Returns:
TODO: add return values
--*/
;
#endif

View File

@ -0,0 +1,214 @@
/*++
Copyright (c) 2006 - 2007, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
NullMemoryTest.c
Abstract:
--*/
#include "NullMemoryTest.h"
//
// Module global members
//
UINT64 mTestedSystemMemory = 0;
UINT64 mTotalSystemMemory = 0;
EFI_HANDLE mGenericMemoryTestHandle;
//
// Driver entry here
//
EFI_GENERIC_MEMORY_TEST_PROTOCOL mGenericMemoryTest = {
InitializeMemoryTest,
GenPerformMemoryTest,
GenMemoryTestFinished,
GenCompatibleRangeTest
};
EFI_STATUS
EFIAPI
GenericMemoryTestEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
/*++
Routine Description:
The generic memory test driver's entry point, it can initialize private data
to default value
Arguments:
ImageHandle of the loaded driver
Pointer to the System Table
Returns:
Status
EFI_SUCCESS - Protocol successfully installed
EFI_OUT_OF_RESOURCES - Can not allocate protocol data structure in base
memory
--*/
{
EFI_STATUS Status;
//
// Install the protocol
//
Status = gBS->InstallProtocolInterface (
&mGenericMemoryTestHandle,
&gEfiGenericMemTestProtocolGuid,
EFI_NATIVE_INTERFACE,
&mGenericMemoryTest
);
return Status;
}
//
// EFI_GENERIC_MEMORY_TEST_PROTOCOL implementation
//
EFI_STATUS
EFIAPI
InitializeMemoryTest (
IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This,
IN EXTENDMEM_COVERAGE_LEVEL Level,
OUT BOOLEAN *RequireSoftECCInit
)
/*++
Routine Description:
Arguments:
Returns:
--*/
{
UINTN NumberOfDescriptors;
EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;
UINTN Index;
gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);
for (Index = 0; Index < NumberOfDescriptors; Index++) {
if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeReserved &&
(MemorySpaceMap[Index].Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==
(EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)
) {
gDS->RemoveMemorySpace (
MemorySpaceMap[Index].BaseAddress,
MemorySpaceMap[Index].Length
);
gDS->AddMemorySpace (
EfiGcdMemoryTypeSystemMemory,
MemorySpaceMap[Index].BaseAddress,
MemorySpaceMap[Index].Length,
MemorySpaceMap[Index].Capabilities &~
(EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME)
);
mTestedSystemMemory += MemorySpaceMap[Index].Length;
mTotalSystemMemory += MemorySpaceMap[Index].Length;
} else if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeSystemMemory) {
mTotalSystemMemory += MemorySpaceMap[Index].Length;
}
}
FreePool (MemorySpaceMap);
*RequireSoftECCInit = FALSE;
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
GenPerformMemoryTest (
IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This,
IN OUT UINT64 *TestedMemorySize,
OUT UINT64 *TotalMemorySize,
OUT BOOLEAN *ErrorOut,
IN BOOLEAN TestAbort
)
/*++
Routine Description:
Arguments:
Returns:
--*/
{
*ErrorOut = FALSE;
*TestedMemorySize = mTestedSystemMemory;
*TotalMemorySize = mTotalSystemMemory;
return EFI_NOT_FOUND;
}
EFI_STATUS
EFIAPI
GenMemoryTestFinished (
IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This
)
/*++
Routine Description:
Arguments:
Returns:
--*/
{
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
GenCompatibleRangeTest (
IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This,
IN EFI_PHYSICAL_ADDRESS StartAddress,
IN UINT64 Length
)
/*++
Routine Description:
Arguments:
Returns:
--*/
{
EFI_GCD_MEMORY_SPACE_DESCRIPTOR descriptor;
gDS->GetMemorySpaceDescriptor (StartAddress, &descriptor);
gDS->RemoveMemorySpace (StartAddress, Length);
gDS->AddMemorySpace (
EfiGcdMemoryTypeSystemMemory,
StartAddress,
Length,
descriptor.Capabilities &~(EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME)
);
return EFI_SUCCESS;
}

View File

@ -0,0 +1,25 @@
/*++
Copyright (c) 2006, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
NullMemoryTest.dxs
Abstract:
Dependency expression source file.
--*/
#include <DxeDepex.h>
DEPENDENCY_START
TRUE
DEPENDENCY_END

View File

@ -0,0 +1,124 @@
/*++
Copyright (c) 2006, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
NullMemoryTest.h
Abstract:
The generic memory test driver definition
--*/
#ifndef _NULL_MEMORY_TEST_H
#define _NULL_MEMORY_TEST_H
//
// The package level header files this module uses
//
#include <PiDxe.h>
//
// The protocols, PPI and GUID defintions for this module
//
#include <Protocol/GenericMemoryTest.h>
//
// The Library classes this module consumes
//
#include <Library/DebugLib.h>
#include <Library/UefiDriverEntryPoint.h>
#include <Library/DxeServicesTableLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/MemoryAllocationLib.h>
//
// attributes for reserved memory before it is promoted to system memory
//
#define EFI_MEMORY_PRESENT 0x0100000000000000ULL
#define EFI_MEMORY_INITIALIZED 0x0200000000000000ULL
#define EFI_MEMORY_TESTED 0x0400000000000000ULL
//
// Some global define
//
#define GENERIC_CACHELINE_SIZE 0x40
//
// The SPARSE_SPAN_SIZE size can not small then the MonoTestSize
//
#define TEST_BLOCK_SIZE 0x2000000
#define QUICK_SPAN_SIZE (TEST_BLOCK_SIZE >> 2)
#define SPARSE_SPAN_SIZE (TEST_BLOCK_SIZE >> 4)
//
// This structure records every nontested memory range parsed through GCD
// service.
//
#define EFI_NONTESTED_MEMORY_RANGE_SIGNATURE EFI_SIGNATURE_32 ('N', 'T', 'M', 'E')
typedef struct {
UINTN Signature;
LIST_ENTRY Link;
EFI_PHYSICAL_ADDRESS StartAddress;
UINT64 Length;
UINT64 Capabilities;
BOOLEAN Above4G;
BOOLEAN AlreadyMapped;
} NONTESTED_MEMORY_RANGE;
#define NONTESTED_MEMORY_RANGE_FROM_LINK(link) \
CR(link, NONTESTED_MEMORY_RANGE, Link, EFI_NONTESTED_MEMORY_RANGE_SIGNATURE)
//
// This is the memory test driver's structure definition
//
#define EFI_GENERIC_MEMORY_TEST_PRIVATE_SIGNATURE EFI_SIGNATURE_32 ('G', 'E', 'M', 'T')
//
// Function Prototypes
//
EFI_STATUS
EFIAPI
InitializeMemoryTest (
IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This,
IN EXTENDMEM_COVERAGE_LEVEL Level,
OUT BOOLEAN *RequireSoftECCInit
)
;
EFI_STATUS
EFIAPI
GenPerformMemoryTest (
IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This,
IN OUT UINT64 *TestedMemorySize,
OUT UINT64 *TotalMemorySize,
OUT BOOLEAN *ErrorOut,
IN BOOLEAN TestAbort
)
;
EFI_STATUS
EFIAPI
GenMemoryTestFinished (
IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This
)
;
EFI_STATUS
EFIAPI
GenCompatibleRangeTest (
IN EFI_GENERIC_MEMORY_TEST_PROTOCOL *This,
IN EFI_PHYSICAL_ADDRESS StartAddress,
IN UINT64 Length
)
;
#endif

View File

@ -0,0 +1,88 @@
#/** @file
# Component description file for NullMemoryTest module.
#
# This driver installs EFI_GENERIC_MEMORY_TEST_PROTOCOL to
# provide simple generic memory test functions.
# Copyright (c) 2006 - 2007, Intel Corporation
#
# All rights reserved. This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
#
#**/
################################################################################
#
# Defines Section - statements that will be processed to create a Makefile.
#
################################################################################
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = NullMemoryTest
FILE_GUID = 96B5C032-DF4C-4b6e-8232-438DCF448D0E
MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.0
EDK_RELEASE_VERSION = 0x00020000
EFI_SPECIFICATION_VERSION = 0x00020000
ENTRY_POINT = GenericMemoryTestEntryPoint
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64 IPF EBC
#
################################################################################
#
# Sources Section - list of files that are required for the build to succeed.
#
################################################################################
[Sources.common]
NullMemoryTest.dxs
NullMemoryTest.h
NullMemoryTest.c
################################################################################
#
# Package Dependency Section - list of Package files that are required for
# this module.
#
################################################################################
[Packages]
MdeModulePkg/MdeModulePkg.dec
MdePkg/MdePkg.dec
################################################################################
#
# Library Class Section - list of Library Classes that are required for
# this module.
#
################################################################################
[LibraryClasses]
MemoryAllocationLib
UefiBootServicesTableLib
DxeServicesTableLib
UefiDriverEntryPoint
DebugLib
################################################################################
#
# Protocol C Name Section - list of Protocol and Protocol Notify C Names
# that this module uses or produces.
#
################################################################################
[Protocols]
gEfiGenericMemTestProtocolGuid # PROTOCOL ALWAYS_PRODUCED

View File

@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8"?>
<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<MsaHeader>
<ModuleName>NullMemoryTest</ModuleName>
<ModuleType>DXE_DRIVER</ModuleType>
<GuidValue>96B5C032-DF4C-4b6e-8232-438DCF448D0E</GuidValue>
<Version>1.0</Version>
<Abstract>Component description file for NullMemoryTest module.</Abstract>
<Description>This driver installs EFI_GENERIC_MEMORY_TEST_PROTOCOL to
provide simple generic memory test functions.</Description>
<Copyright>Copyright (c) 2006 - 2007, Intel Corporation</Copyright>
<License>All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.</License>
<Specification>FRAMEWORK_BUILD_PACKAGING_SPECIFICATION 0x00000052</Specification>
</MsaHeader>
<ModuleDefinitions>
<SupportedArchitectures>IA32 X64 IPF EBC</SupportedArchitectures>
<BinaryModule>false</BinaryModule>
<OutputFileBasename>NullMemoryTest</OutputFileBasename>
</ModuleDefinitions>
<LibraryClassDefinitions>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>DebugLib</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>UefiDriverEntryPoint</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>DxeServicesTableLib</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>UefiBootServicesTableLib</Keyword>
</LibraryClass>
<LibraryClass Usage="ALWAYS_CONSUMED">
<Keyword>MemoryAllocationLib</Keyword>
</LibraryClass>
</LibraryClassDefinitions>
<SourceFiles>
<Filename>Common.h</Filename>
<Filename>NullMemoryTest.c</Filename>
<Filename>NullMemoryTest.h</Filename>
<Filename>NullMemoryTest.dxs</Filename>
</SourceFiles>
<PackageDependencies>
<Package PackageGuid="1E73767F-8F52-4603-AEB4-F29B510B6766"/>
<Package PackageGuid="BA0D78D6-2CAF-414b-BD4D-B6762A894288"/>
</PackageDependencies>
<Protocols>
<Protocol Usage="ALWAYS_PRODUCED">
<ProtocolCName>gEfiGenericMemTestProtocolGuid</ProtocolCName>
</Protocol>
</Protocols>
<Externs>
<Specification>EFI_SPECIFICATION_VERSION 0x00020000</Specification>
<Specification>EDK_RELEASE_VERSION 0x00020000</Specification>
<Extern>
<ModuleEntryPoint>GenericMemoryTestEntryPoint</ModuleEntryPoint>
</Extern>
</Externs>
</ModuleSurfaceArea>