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