From b7c51c9cf4864df6aabb99a1ae843becd577237c Mon Sep 17 00:00:00 2001 From: raywu Date: Fri, 15 Jun 2018 00:00:50 +0800 Subject: init. 1AQQW051 --- Library/EfiLib.c | 4779 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 4779 insertions(+) create mode 100644 Library/EfiLib.c (limited to 'Library/EfiLib.c') diff --git a/Library/EfiLib.c b/Library/EfiLib.c new file mode 100644 index 0000000..f937c89 --- /dev/null +++ b/Library/EfiLib.c @@ -0,0 +1,4779 @@ +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2012, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** + +//********************************************************************** +// $Header: /Alaska/Projects/Intel/Haswell/LynxPoint_SharkBay-DT_Crb_1AQQW/Library/EfiLib.c 3 4/16/14 3:11a Chaseliu $ +// +// $Revision: 3 $ +// +// $Date: 4/16/14 3:11a $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/Projects/Intel/Haswell/LynxPoint_SharkBay-DT_Crb_1AQQW/Library/EfiLib.c $ +// +// 3 4/16/14 3:11a Chaseliu +// [TAG] EIP163569 +// [Category] Improvement +// [Description] Update for support 2014 BIOS Security Disclosures. +// [Files] +// Library\PeiLib.c +// Library\EfiLib.c +// Core\EM\NVRAM\NVRAMDXE.c +// Core\EM\Capsule2_0\Capsule2_0.c +// Core\CORE_DXE\FwVolBlock.c +// +// 112 2/28/14 5:41p Artems +// EIP 154195 Fixed vulnerability where memory pointer was stored in NVRaM +// and may be compromised +// +// 109 7/19/12 6:00p Felixp +// Enhacement: +// IsValidDevicePath is updated to make sure that device path node length +// is not less than +// sizeof(EFI_DEVICE_PATH_PROTOCOL). +// This prevents dead loops on device path nodes with a zero length. +// +// 108 7/12/12 5:22p Oleksiyy +// [TAG] EIP95266 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Build error in AmiFillFpdt function +// [RootCause] multiplying 64 bit values with the help of "*" operator +// [Solution] Mul64() function is used now +// [Files] EfiLib.c +// +// 107 6/12/12 3:24p Oleksiyy +// TAG] EIP90322 +// [Category] Improvement +// [Description] Extern declaradion of gAmiGlobalVariableGuid moved to +// AmiLib.h. +// [Files] AmiLib.h, Misc.c, EfiLib.c, AcpiCore.c and S3Resume.c +// +// 106 6/12/12 11:19a Oleksiyy +// [TAG] EIP88889 +// [Category] Improvement +// [Description] FACP ver 5.0 structure added, FPDT mesurment accuracy +// improved. +// [Files] ACPI50.h, ACPI.sdl, AcpiCore.c, S3Resume.c, Image.c, +// EfiLib.c +// +// 105 5/22/12 4:27p Oleksiyy +// [TAG] EIP90322 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] ChiefRiver SCT Fail, improper variable FPDT_Variable in +// ACPI module +// [RootCause] EFI_GLOBAL_VARIABLE guid is used in non EFI defined +// variable. +// [Solution] New guig AMI_GLOBAL_VARIABLE_GUID is created and used. +// [Files] AmiLib.h, Misc.c, EfiLib.c, AcpiCore.c and S3Resume.c +// +// 104 4/30/12 3:57p Artems +// [TAG] EIP N/A +// [Category] Improvement +// [Description] Modified GraphicsConsole driver to output whole string +// instead of symbol-by-symbol output +// [Files] Gc.c, AmiDxeLib.h, EfiLib.c, UefiHiiUtils.c +// +// 103 4/12/12 3:01p Artems +// [TAG] EIP N/A +// [Category] Improvement +// [Description] System may deadlock when parsing corrupted device path. +// Added function to validate device path before using in LoadImage +// [Files] Image.c EfiLib.c +// +// 102 2/22/12 12:17p Oleksiyy +// [TAG] EIP83714 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] S3 resume failure when using EFI_S3_SAVE_STATE_PROTOCOL +// [RootCause] GUID in _GetBootScriptSaveInterface was redefined in +// different file and because of this wrong protocol was located and +// _GetBootScriptSaveInterface was working incorrectly. +// [Solution] Declaration of GUID in _GetBootScriptSaveInterface +// function in EfiLib.c change to use unique name and static. +// [Files] EfiLib.c +// +// 101 11/11/11 5:28p Oleksiyy +// [TAG] EIP64296 +// [Category] New Feature +// [Description] Creation and filling of Firmware Performance Data Table +// is added. FirmPerfDataTab.h renamed to ACPI50.h +// [Files] AcpiCore.c, EfiLib.c, S3Resume.c and ACPI50.h added. +// +// 100 11/08/11 5:20p Oleksiyy +// [TAG] EIP64296 +// [Category] New Feature +// [Description] Creation and filling of Firmware Performance Data Table +// is added. +// [Files] AcpiCore.c, AmiDxeLib.h, CSM.c, DxeMain.c, EfiLib.c, +// Image.c, S3Resume.c and FirmPerfDataTab.h +// +// 99 10/24/11 5:38p Artems +// EIP 70530: Fixed bug reported by SCT 2.3.1 for TW plugfest. +// Function compare languages should ignore case as per RFC 4646 +// +// 98 10/20/11 5:15p Oleksiyy +// [TAG] EIP72806 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Runtime status code hangs +// [RootCause] Not converting actual status code functions addresses on +// Virtual Address Change event. +// [Solution] Status code functions converted. +// [Files] EfiLib.c, StatusCode.sdl and StatusCodeRuntime.c +// +// 97 7/18/11 3:43p Felixp +// Enhancement: InitSmmHandlerPi is updated to remove dependency on +// SmmBase2 (SmmBasePi) from the not-in-SMM branch. +// +// 96 7/13/11 3:06p Felixp +// Undo pElement->pPrev initialization introduced by prev. check in. It is +// not required. +// +// 95 7/13/11 2:50p Felixp +// Bug fixes in DListInsert(EIP64811): +// - The function corrupted the memory if pAfter was the last element in +// the list. +// - pElement->pPrev was not initialized. +// +// 94 6/24/11 1:45p Felixp +// _GetBootScriptSaveInterface function is added. +// +// 93 6/16/11 9:28a Felixp +// Enhancements: SMM-related functions and global variables are split into +// Framework and PI instances. Proper instance is selected based on +// supported version of the PI specification and module type. +// +// 92 5/19/11 2:25p Artems +// EIP 60634: Modified DPCreateNode function to fill allocated buffer with +// zeroes before using it +// +// 91 3/17/11 4:58p Felixp +// Enhancement: FindDeviceName functions is updated with +// a workaround for mass storage devices that have no partition +// (floppy or USB key formatted as floppy). The name for these devices +// is provided by more than one driver. +// One of the name sources if file system driver. It provides a name like +// "FAT File System", +// which is not very interesting. The real device name like "Kingston +// DataTreveler" +// (that comes from other driver) is far more useful. +// This workaround is to ignore name returned by a consumer of the disk +// I/O protocol, +// which is a file system driver. +// +// 90 2/05/11 3:17p Artems +// Added helper function to initialize global pointers in SMM +// Replaced FirmwareVolume protocol with FirmwareVolume2 protocol +// +// 89 10/07/10 12:30p Felixp +// USE_DXE_STATUS_CODE_INSTANCE_IN_SMM SDL token support is added. +// +// 88 10/06/10 5:01p Felixp +// LibInitStatusCodePtr is updated not to call LocateProtocol from SMM +// +// 87 10/01/10 4:38p Oleksiyy +// Issue Number: 39752 +// +// Category: Improvement +// +// Description: Runtime trace support added. +// +// Files: Files: Uart1.asl, Tokens.c, Runtime.c, GenericSio.c, EfiLib.c, +// CsmLib.c, AmiDxeLib.h and StatusCode eModule. +// +// 85 9/02/10 11:16a Felixp +// Enhancement: do not use pRS in AmiLibGoVirtual; +// the pointer may have already been already converted to the virtual +// address by the library consumer. +// Use the internal library copy instead. +// +// 84 8/23/10 3:30p Felixp +// Enhancement(EIP 29307, 39752): AMI DXE library is updated to handle +// runtime +// and SMM instances of the status code protocol. +// +// 83 5/25/10 11:12a Felixp +// Bug fix in the TimerStart function +// +// 82 3/12/10 10:28a Felixp +// Bug fix: Potential UEFI OS Problem; +// pRS pointer has been in used in AmiLibGoVirtual function after +// virtualization. +// +// 81 2/23/10 10:16p Felixp +// HiiLibSetBrowserData function is added +// +// 80 11/25/09 1:30p Felixp +// Trace functions is updated to suppress Trace message +// if message Level defined by the first parameter is disabled using +// TRACE_LEVEL_MASK SDL token. +// +// 79 11/25/09 12:00p Felixp +// Behavior of GetImageName and GetControllerName functions in UEFI 2.1 +// mode is extended. +// The functions will now use ComponentName protocol if ComponentName2 +// protocol is not available. +// +// 78 11/24/09 10:41a Felixp +// +// 77 10/28/09 4:21p Felixp +// ReadImage function is updated. Temporary buffer was not deallocated(EIP +// 28575). +// +// 76 10/21/09 2:52p Felixp +// +// 74 10/14/09 10:41p Felixp +// +// 73 10/09/09 4:54p Felixp +// UEFI 2.1-related changes: +// 1. Library files are update to support Framework and UEFI 2.1 HII +// (based on EFI_SPECIFICATION_VERSION value). +// 2. GetDefaultLang function is no longer supported +// 3. New HII-related functions are added +// (the functions support both Framework and UEFI HII): +// HiiLibGetString, HiiLibSetString, HiiLibPublishPackages, +// HiiLibGetBrowserData. +// +// 72 8/21/09 2:50p Felixp +// 1. LanguageCodesEqual function is added. +// The function compares language codes in the format appropriate +// for the supported version of UEFI sepcification +// (defined by EFI_SPECIFICATION_VERSION SDL token). +// 2. Component Name related library functions are updated to support +// both ComponentName and ComponentName2 protocols. +// +// 71 8/05/09 12:23p Yakovlevs +// Fixed TRACE Size issue to work with IA32 mode. +// +// 70 7/30/09 4:37p Vyacheslava +// Fixed comments. +// +// 69 7/28/09 4:46p Vyacheslava +// Bug fix. EIP#24453: Synopsis: CPU exception when printing long debug messages. +// +// 68 7/23/09 11:17a Yakovlevs +// Fixed issue in LibAllocCspResource function with IO ONLY resources (EIP +// 24323). +// +// 67 7/10/09 4:32p Felixp +// +// 66 7/10/09 4:01p Felixp +// Function headers added +// +// 65 6/05/09 6:32p Yakovlevs +// Fixed issue in LibAllocCspResources when RT attributes were acidentaly +// cleared. +// +// 64 5/21/09 4:49p Felixp +// New function InitAmiRuntimeLib is added. +// The function can be used by Runtime drivers to initialize library +// (the function calls InitAmiLib) and register callbacks +// on exit boot services and virtual address change events. +// +// 63 5/14/09 5:26p Felixp +// +// 62 5/14/09 9:32a Felixp +// New feature: SMM version of Runtime Services +// InitSmmHandler function is updated ot override pRS with the SMM +// instance of RS table. +// New functions +// InitSmmHandlerEx and GetSmstConfigurationTable area added +// +// 61 5/04/09 4:08p Felixp +// GetControllerName function is updated to search +// for controller name using handlers of all ancestors of the given +// controller +// (used to be just immediate parent). +// +// 60 12/16/08 1:24a Iminglin +// The function value of TimerStart for compliance. +// +// 59 10/07/08 12:53p Artems +// Minor improvements of WritePerformanceDataToOS function +// +// 58 9/30/08 12:15a Felixp +// +// 57 9/30/08 12:10a Felixp +// +// 56 9/30/08 12:07a Felixp +// WriteBootToOsPerformanceData function added +// +// 55 6/06/08 10:56a Felixp +// Bug fix in DPCut routine +// +// 54 5/06/08 10:05a Felixp +// Performance API added +// +// 53 10/22/07 6:29p Felixp +// Bug fix in DListInsert library routine. Size field of the DLIST +// structure was not updated. +// +// 52 9/04/07 12:09p Felixp +// TheImageHandle global variable is added. The variable is initialized in +// the InitAmiLib routine with the current image handle. +// +// 51 8/30/07 11:04p Felixp +// GetBootMode routine is added. The routine can be used by DXE/EFI +// modules to get current boot mode. +// +// 50 8/02/07 1:36a Felixp +// Always define Trace and GetImageName routines (used to be only when +// EFI_DEBUG is defined). This is needed to support selective debugging. +// +// 49 5/22/07 3:42p Felixp +// Bug fix in LibAllocCspResource: runtime attribute has been ignored. +// It caused stop error 1E early during EFI Longhorn Server installation. +// +// 48 5/14/07 7:35p Yakovlevs +// +// 47 5/14/07 7:30p Yakovlevs +// Improved AllocateCSPResource() function logic. +// +// 46 4/19/07 12:36p Felixp +// New functions added: LibGetDxeSvcTbl and LibAllocateCspResource +// LibAllocateCspResource replaces AllocCspResource +// AllocCspResource preserved for backward compatibility. +// +// 44 4/17/07 10:54a Yakovlevs +// AllocCspResource function preserved for compatibility witn core 4.5.3 +// +// 43 4/13/07 6:17p Yakovlevs +// Functions LibGetDxeSvcTbl() and LibAllocCspResource() was added +// +// 41 3/30/07 4:53p Felixp +// 1. DPAddNode, DPAdd updated to handle NULL parameters in accordance +// with UEFI2.0 Errata. +// 2. DPLength update: protection from junk data added. +// +// 40 10/13/06 12:23p Felixp +// +// 39 10/13/06 12:20p Felixp +// +// 38 10/13/06 9:32a Felixp +// +// 37 10/13/06 9:28a Felixp +// UEFI2.0 compliant invalid handling of parameters in DPxxx routines +// +// 36 10/13/06 12:17a Felixp +// Device Path functions updated to correctly handle invalid parameters +// +// 35 10/12/06 6:44p Felixp +// DPNextInstance, DPCreateNode, DPIsMultiInstance functions added +// +// 34 10/12/06 9:40a Felixp +// CreateLegacyBootEvent & CreateReadyToBootEvent functions added +// +// 33 10/07/06 10:21a Felixp +// UEFI2.0 compliance: pRT->ReportStatusCode changed to +// StatusCodePtr->ReportStatusCode +// +// 32 9/08/06 9:25a Felixp +// +// 31 8/24/06 9:27a Felixp +// Preliminary x64 support (work in progress) +// +// 30 5/23/06 4:10a Felixp +// GetImageName function improved +// +// 29 5/19/06 10:28p Felixp +// Updated to use NEXT_NODE & NODE_LENGTH macros +// +// 28 3/13/06 1:52a Felixp +// +// 27 11/16/05 11:07a Yakovlevs +// DPCmp(), DPCut() functions added +// +// 26 11/11/05 11:45a Markw +// Renamed IntallSmmHandler to InitSmmHandler because of build errors +// because another driver used InstallSmmHandler. +// +// 25 11/11/05 11:38a Felixp +// GetControllerName function added +// +// 24 11/08/05 5:58p Markw +// Created InstallSmiHandler library function. +// +// 23 11/07/05 10:33a Felixp +// ReadImage improvements: If file path is +// MEDIA_FV_FILEPATH_DP and +// no FV device specified, function will scan all FVs trying to locate the +// file. +// +// 22 6/29/05 10:41a Yakovlevs +// +// 21 6/28/05 6:47p Yakovlevs +// Function AllocCspResources added +// +// 20 6/03/05 3:43p Yakovlevs +// Added DPGetLastNode(EFI_DEVICE_PATH_PROTOCOL *pDp) function +// +// 19 4/06/05 9:34a Felixp +// function LoadStrings added +// +// 18 4/04/05 7:29p Felixp +// +// 16 4/04/05 2:59p Felixp +// LoadResources function added +// +// 15 4/04/05 9:32a Felixp +// Small inprovements in GetEfiVariable +// +// 14 3/25/05 11:32a Felixp +// RegisterProtocolCallback function added +// +// 13 3/17/05 6:35p Felixp +// +// 12 3/17/05 1:29p Felixp +// ReadImageResource function added +// +// 11 3/04/05 10:52a Mandal +// +// 10 3/03/05 12:30p Felixp +// GetDefaultLang added +// +// 9 2/11/05 5:55p Felixp +// New DevicePath function added(DPAddNode, DPAddInstance). +// Implementation of DPLength and DPAdd improved. +// +// 8 2/08/05 5:24p Felixp +// Parameter added to DPIsOneOf. +// +// 7 2/07/05 5:21p Felixp +// GetEfiVariable funciton added +// +// 6 2/07/05 4:09p Yakovlevs +// MallocZ function added - Allocates "0x00" filled Pool. +// +// 5 2/03/05 7:59p Felixp +// DPIsOneOf function added +// +// 4 1/28/05 1:06p Felixp +// InitAmiLib change to ignore second call +// +// 2 1/18/05 3:22p Felixp +// PrintDebugMessage renamed to Trace +// +// 1 12/23/04 9:42a Felixp +// +// 31 12/21/04 4:58p Markw +// Modified device path defines for consistency. +// +// 30 12/17/04 7:24p Olegi +// PrintDebugMessageVaList added +// +// 29 11/24/04 9:37a Felixp +// GetImageName extended to use ComponentName protocol +// +// 28 11/19/04 1:33a Felixp +// GetImageName debug routine added (image name by image handle) +// +// 27 11/18/04 6:09p Felixp +// FindNextHobByType deleted (moved to AmiLib(Misc.c)) +// +// 26 11/10/04 5:16p Felixp +// Level parameter added to Trace fucntion +// +// 25 10/22/04 7:42p Felixp +// +// 24 8/28/04 1:49a Felixp +// NVRAM Routines fixes +// +// 23 8/23/04 3:12p Felixp +// +// 22 8/20/04 6:34p Felixp +// +// 21 8/20/04 11:49a Felixp +// +// 20 8/18/04 3:16p Felixp +// +// 19 7/21/04 8:16p Yakovlevs +// +// 18 7/16/04 3:57p Felixp +// Changes to support both 7f and ff values for the device path end type +// +// 17 7/13/04 10:42a Felixp +// +// 16 4/22/04 5:39p Markw +// Changed FvReadFile to FvReadPe32Image and fixed ReadFile. +// +// 15 4/22/04 12:15p Markw +// Fixed FvReadFile. +// +// 14 4/17/04 4:23p Felixp +// +// 13 4/14/04 4:18p Markw +// Using EFI_ERROR. +// +// 12 4/14/04 11:37a Markw +// Fixed FvReadFile. Now frees correct Buffer. +// +// 11 4/14/04 11:02a Markw +// Added FvReadFile. +// +// 6 4/07/04 12:46a Felixp +// REAL PLATFORM DEBUGGING (lots of bug fixes) +// +// 3 3/29/04 5:27p Markw +// Added a function to print debug messages. +// +//********************************************************************** +// +// +// Name: EfiLib.c +// +// Description: +// Contains generic EFI library functions. +// +// +//************************************************************************* +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if SMM_SUPPORT +#include +#endif +#include +#include +#include + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_SYSTEM_TABLE *pST=NULL; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_BOOT_SERVICES *pBS=NULL; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_RUNTIME_SERVICES *pRS=NULL; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_SMM_BASE_PROTOCOL *pSmmBaseFramework=NULL; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_SMM_SYSTEM_TABLE *pSmstFramework=NULL; +#if PI_SPECIFICATION_VERSION >= 0x0001000A +GLOBAL_REMOVE_IF_UNREFERENCED EFI_SMM_BASE2_PROTOCOL*pSmmBasePi=NULL; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_SMM_SYSTEM_TABLE2 *pSmstPi=NULL; +#endif +GLOBAL_REMOVE_IF_UNREFERENCED DXE_SERVICES *pDxe=NULL; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_HANDLE TheImageHandle=NULL; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID guidFS = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID guidFileInfo = EFI_FILE_INFO_ID; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID guidLoadFile = EFI_LOAD_FILE_PROTOCOL_GUID; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID guidDevicePath = EFI_DEVICE_PATH_PROTOCOL_GUID; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID guidFV = EFI_FIRMWARE_VOLUME2_PROTOCOL_GUID; +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID guidDxeSvcTbl = DXE_SERVICES_TABLE_GUID; + +extern EFI_GUID gEfiLoadedImageProtocolGuid; +extern EFI_GUID gEfiComponentName2ProtocolGuid; +#if EFI_SPECIFICATION_VERSION<=0x20000 +//for backward compatibility +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID guidHII = EFI_HII_PROTOCOL_GUID; +#endif +#if EFI_SPECIFICATION_VERSION>=0x20000 +extern EFI_GUID gEfiStatusCodeRuntimeProtocolGuid; +static EFI_STATUS_CODE_PROTOCOL *StatusCodePtr = NULL; +#endif +#if SMM_SUPPORT +static EFI_SMM_STATUS_CODE_PROTOCOL *StatusCodeSmmPtr = NULL; +#endif +GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID SmmRsTableGuid = EFI_SMM_RUNTIME_SERVICES_TABLE_GUID; + +static BOOLEAN IsAtRuntime = FALSE; +static BOOLEAN IsInVirtualMode = FALSE; +static BOOLEAN IsInSmm = FALSE; + +//************************************************************************* +// +// +// Name: Device_Path_Functions +// +// Description: +// Device path related functions defined in the AMI library. +// +// Fields: Header Function Description +// ------------------------------------------------------------------ +// AmiDxeLib DPLength Find the size of a device path in bytes. +// AmiDxeLib DPAddNode Create new device path with the contents of one device path + the first element from another. +// AmiDxeLib DPAdd Create new device path by appending a device path's elements to another device path. +// AmiDxeLib DPAddInstance Create new device path utilizing two provided device paths as instances. +// AmiDxeLib DPCopy Create new device path containing the exact contents of another device path. +// AmiDxeLib DPIsOneOf Determine whether a device path contains a user provided device path. +// AmiDxeLib DPGetLastNode Return the last node of a device path prior to END_OF_DEVICE_PATH. +// AmiDxeLib DPCmp Determine whether two device paths are equivalent. +// AmiDxeLib DPCut Create new device path with all but the last node of another device path. +// AmiDxeLib DPGetEndNode Return the last node of a device path. +// AmiDxeLib DPNextInstance Create a copy of the current device path instance and updates the device path to point to the next instance. +// AmiDxeLib DPCreateNode Create a device path node. +// AmiDxeLib DPIsMultiInstance Determine whether device path is single or multi-instance. +// +// Notes: +// Header details which header file contains the function prototype for +// the above functions. Append .h to the given name. +// +// +//************************************************************************* + +//************************************************************************* +// +// +// Name: Performance_Measurement_Functions +// +// Description: +// Functions which are used to measure boot performance that are defined in +// the AMI library. +// +// Fields: Header Function Description +// ------------------------------------------------------------------ +// AmiPeiLib PEI_PERF_START Macro that starts timing for performance measurement. +// AmiPeiLib PEI_PERF_END Macro that stops timing for performance measurement. +// AmiPeiLib PeiPerfMeasure Start or stop timing performance measurement. +// AmiDxeLib PERF_START Macro that starts timing for performance measurement. +// AmiDxeLib StartMeasure Start timing for performance measurement. +// AmiDxeLib PERF_END Macro that stops timing for performance measurement. +// AmiDxeLib EndMeasure Stop timing for performance measurement. +// AmiDxeLib PERF_CODE Macro that inserts performance measurement related code. +// AmiPeiLib PEI_PERF_SAVE_S3_DATA Macro that saves performance information to a HOB for S3 measurement. +// AmiPeiLib SaveS3PerformanceData Save performance information to a HOB for S3 measurement. +// AmiDxeLib WriteBootToOsPerformanceData Write performance information. +// +// Notes: +// Header details which header file contains the function prototype for +// the above functions. Append .h to the given name. +// +// +//************************************************************************* + +//************************************************************************* +// +// +// Name: Doubly_Linked_List_Functions +// +// Description: +// The following functions are provided by the AMI library as a basic API for +// a doubly-linked list. Note that the DLINK node structure does not include +// an entry for the actual data. There are several methods for getting +// around this limitation. +// +// The easiest method is to create a new structure type which contains +// a DLINK structure as its first member and the data afterwards. This new +// structure can then be typecasted to the old DLINK type when using the +// API. See notes for an example. +// +// There are presently no search functions provided for this API. +// +// Fields: Header Name Description +// ------------------------------------------------------------------ +// AmiDxeLib DLIST Doubly-linked list structure. +// AmiDxeLib DLINK Doubly-linked list node. +// AmiDxeLib DListInit Initialize a DLIST list structure. +// AmiDxeLib DListAdd Add a DLINK node to the end of a DLIST. +// AmiDxeLib DListDelete Remove a DLINK node from a DLIST. +// AmiDxeLib DListInsert Insert a DLINK node after a specific DLINK node inside a DLIST. +// AmiDxeLib DListEmpty Determine whether a DLIST is empty. +// +// Notes: +// Header details which header file contains the function prototype for +// the above functions; append .h to the given name. None indicates that +// no header file contains a function prototype. +// +// The following code demonstrates creating a node which +// contains a UINT32 data member, inserting it into a list, then changing +// its value. +// +// typedef struct { +// DLINK Link; +// UINT32 Data; +// } UINT32_NODE; +// +// DLIST ExampleList; +// UINT32_NODE ExampleNode; +// +// ExampleNode.Data = 0xDEADBEEF; +// +// DListInit(&ExampleList); +// DListAdd(&ExampleList, (DLINK*) &ExampleNode); +// ((UINT32_NODE*)ExampleList.pHead)->Data = 0x12345678; +// +// +//************************************************************************* + +//************************************************************************* +// +// +// Name: InitAmiLib +// +// Description: +// VOID InitAmiLib(IN EFI_HANDLE ImageHandle, +// IN EFI_SYSTEM_TABLE *SystemTable) initializes the global variables used by +// library routines. It must be called before any other library routine is +// used. See notes for variables initialized. +// +// Input: +// IN EFI_HANDLE ImageHandle +// The image handle. +// +// IN EFI_SYSTEM_TABLE *SystemTable +// Pointer to the EFI System Table. +// +// Output: +// VOID. +// +// Modified: +// pST +// pBS +// pRS +// TheImageHandle +// +// Referrals: +// +// Notes: +// The global variables initialized by this function are: +// pST Pointer to the EFI System Table. +// pBS Pointer to the Boot Services Table. +// pRS Pointer to the Runtime Services Table. +// TheImageHandle Image handle. +// +// +//************************************************************************* +VOID InitAmiLib( + IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable +) +{ + if (pST) return; + pST = SystemTable; + pBS = pST->BootServices; + pRS = pST->RuntimeServices; + TheImageHandle = ImageHandle; +} + +//************************************************************************* +// +// +// Name: GetEfiConfigurationTable +// +// Description: +// VOID *GetEfiConfigurationTable(IN EFI_SYSTEM_TABLE *SystemTable, +// IN EFI_GUID *Guid) retrieves a pointer to the system configuration table +// from the EFI System Table based on a specified GUID. If a match is found, +// then a pointer to the configuration table is returned. If a matching GUID +// is not found, then NULL is returned. +// +// Input: +// IN EFI_SYSTEM_TABLE *SystemTable +// Pointer to the EFI System Table. +// +// IN EFI_GUID *Guid +// Pointer to table's GUID type. +// +// Output: +// VOID* pointer to configuration table if a match is found; otherwise NULL. +// +// Modified: +// +// Referrals: +// guidcmp +// +// Notes: +// +// +//************************************************************************* +VOID * GetEfiConfigurationTable( + IN EFI_SYSTEM_TABLE *SystemTable, + IN EFI_GUID *Guid + ) +{ + EFI_CONFIGURATION_TABLE *Table = SystemTable->ConfigurationTable; + UINTN i = SystemTable->NumberOfTableEntries; + + for (;i;--i,++Table) + { + if (guidcmp(&Table->VendorGuid,Guid)==0) return Table->VendorTable; + } + return 0; +} + +#if EFI_SPECIFICATION_VERSION>=0x20000 +//************************************************************************* +// +// +// Name: LibInitStatusCodePtr +// +// Description: +// This function initializes pointers to StatusCode protocols in and outside SMM. +// +// Input: None +// +// Output: +// EFI_STATUS: EFI_SUCCESS - if pointer already initialized or LocateProtocol was successful. +// EFI_UNSUPPORTED - if no protocol was located. +// +// +//************************************************************************* +EFI_STATUS LibInitStatusCodePtr() +{ + EFI_STATUS Status = EFI_SUCCESS; +#if SMM_SUPPORT && !USE_DXE_STATUS_CODE_INSTANCE_IN_SMM + if (IsInSmm){ + if (!StatusCodeSmmPtr){ + if (IsAtRuntime) return EFI_UNSUPPORTED; + Status = pBS->LocateProtocol( + &gEfiSmmStatusCodeProtocolGuid,NULL,&StatusCodeSmmPtr + ); + } + return Status; + }else +#endif + if (!StatusCodePtr){ + if (IsAtRuntime) return EFI_UNSUPPORTED; + Status = pBS->LocateProtocol( + &gEfiStatusCodeRuntimeProtocolGuid,NULL,&StatusCodePtr + ); + } + return Status; +} + +//************************************************************************* +// +// +// Name: LibReportStatusCode +// +// Description: +// EFI_STATUS LibReportStatusCode(IN EFI_STATUS_CODE_TYPE Type, +// IN EFI_STATUS_CODE_VALUE Value, IN UINT32 Instance, +// IN EFI_GUID *CallerId OPTIONAL, IN EFI_STATUS_CODE_DATA *Data OPTIONAL) +// abstracts status code reporting. The Framework moved from a proprietary +// to a UEFI 2.0-based mechanism. This function abstracts the caller from +// how the status code is reported to prevent the code from having to change +// with this version of the specification supported. +// +// Input: +// IN EFI_STATUS_CODE_TYPE Type +// Indicates the type of status code being reported. +// +// IN EFI_STATUS_CODE_VALUE Value +// Describes the current status of a hardware or software entity. This +// includes information about the class and subclass that is used to classify +// the entity as well as an operation. For progress codes, the operation is +// the current activity. For error codes, it is the exception. For debug +// codes, it is not defined at this time. +// +// IN UINT32 Instance +// The enumeration of a hardware or software entity within the system. A +// system may contain multiple entities that match a class/subclass pairing. +// The instance differentiates between them. An instance of 0 indicates that +// instance information is unavailable, not meaningful, or not relevant. +// Valid instance numbers start with 1. +// +// IN EFI_GUID *CallerId OPTIONAL +// This optional parameter may be used to identify the caller. This parameter +// allows the status code driver to apply different rules to different +// callers. +// +// IN EFI_STATUS_CODE_DATA *Data OPTIONAL +// This optional parameter may be used to pass additional data. The contents +// of this data type may have additional GUID-specific data. +// +// Output: +// EFI_UNSUPPORTED, if Status Code protocol unavailable. +// Otherwise, EFI_SUCCESS. +// +// Modified: +// +// Referrals: +// +// Notes: +// +// +//************************************************************************* + +EFI_STATUS LibReportStatusCode( + IN EFI_STATUS_CODE_TYPE Type, IN EFI_STATUS_CODE_VALUE Value, + IN UINT32 Instance, IN EFI_GUID *CallerId OPTIONAL, + IN EFI_STATUS_CODE_DATA *Data OPTIONAL +){ + EFI_STATUS Status; +#if SMM_SUPPORT && !USE_DXE_STATUS_CODE_INSTANCE_IN_SMM + if (IsInSmm){ + if (StatusCodeSmmPtr==NULL) return EFI_NOT_FOUND; + return StatusCodeSmmPtr->ReportStatusCode(StatusCodeSmmPtr,Type,Value,Instance,CallerId,Data); + }else +#endif + Status = LibInitStatusCodePtr(); + if(EFI_ERROR(Status)) return Status; + return StatusCodePtr->ReportStatusCode(Type,Value,Instance,CallerId,Data); +} +#endif + +//************************************************************************* +// +// Name: PrintDebugMessageVaList +// +// Description: +// VOID PrintDebugMessageVaList(IN UINTN Level, IN CHAR8 *sFormat, +// IN va_list ArgList) generates a Status Code string with +// PrepareStatusCodeString, then outputs it through LibReportStatusCode. +// +// Input: +// IN UINTN Level +// The error level of the debug message. +// +// IN CHAR8 *sFormat +// Format string for the debug message to print. +// +// IN va_list ArgList +// Argument list for the format string. +// +// Output: +// VOID. +// +// Modified: +// +// Referrals: +// PrepareStatusCodeString +// LibReportStatusCode +// +// Notes: +// Helper function for Trace. +// +//************************************************************************* +VOID PrintDebugMessageVaList(UINTN Level, CHAR8 *sFormat, va_list ArgList) +{ + CHAR8 Buffer[2048]; + + PrepareStatusCodeString( Buffer, sizeof(Buffer), sFormat, ArgList ); + LibReportStatusCode( + EFI_DEBUG_CODE, + EFI_SOFTWARE_UNSPECIFIED, + 0, + NULL, + (EFI_STATUS_CODE_DATA*)Buffer + ); +} + +//************************************************************************* +// +// +// Name: Trace +// +// Description: +// VOID Trace(IN UINTN Level, IN CHAR8 *sFormat, IN ...) prints a debug +// message using status code protocol if the specified error level is +// enabled. +// +// Input: +// IN UINTN Level +// The error level of the debug message. +// +// IN CHAR8 *sFormat +// Format string for the debug message to print. +// +// IN ... +// Argument list for the format string. +// +// Output: +// VOID. +// +// Modified: +// +// Referrals: +// va_start +// PrintDebugMessageVaList +// va_end +// TRACE(Arguments) +// Sprintf +// +// Notes: +// Use the TRACE(Arguments) macro for generating debug messages in DXE. +// This allows the DEBUG_MODE token to control whether the debug message is +// included or removed in the build process. See Sprintf for format string +// parameters. +// +// +//************************************************************************* +VOID Trace(UINTN Level, CHAR8 *sFormat,...) +{ + extern const UINT32 TraceLevelMask; + va_list ArgList; + if ( ((UINT32)Level & TraceLevelMask) == 0 ) return; + ArgList = va_start(ArgList,sFormat); + PrintDebugMessageVaList(Level, sFormat, ArgList); + va_end(ArgList); +} + +//************************************************************************* +// +// +// Name: GetImageName +// +// Description: +// BOOLEAN GetImageName(IN EFI_HANDLE ImageHandle, OUT CHAR8 *sName) +// retrieves the name of the image specified by ImageHandle and returns it +// in sName. +// +// Input: +// IN EFI_HANDLE ImageHandle +// The image handle whose name is desired. +// +// OUT CHAR8 *sName +// Address of the null-terminated ASCII string to put image name into. User +// is reponsible for allocating the necessary memory resources. +// +// Output: +// TRUE if the image name has been found; otherwise, FALSE. +// +// Modified: +// +// Referrals: +// GetName +// Sprintf +// +// Notes: +// +// +//************************************************************************* +BOOLEAN GetImageName(EFI_HANDLE ImageHandle, CHAR8 *sName) +{ + EFI_LOADED_IMAGE_PROTOCOL *pImage; + EFI_COMPONENT_NAME_PROTOCOL *pComponentName; + CHAR16 *wsName; + EFI_STATUS Status; + if ( !EFI_ERROR(Status = pBS->HandleProtocol(ImageHandle,&gEfiLoadedImageProtocolGuid,&pImage)) + && GetName((UINT8*)pImage->ImageBase,sName) + ) return TRUE; + + if ( !EFI_ERROR(pBS->HandleProtocol(ImageHandle,&gEfiComponentName2ProtocolGuid,&pComponentName)) + && !EFI_ERROR(pComponentName->GetDriverName(pComponentName,LANGUAGE_CODE_ENGLISH,&wsName)) +#if EFI_SPECIFICATION_VERSION > 0x20000 +//Try UEFI 2.0 ComponentName protocol + || !EFI_ERROR(pBS->HandleProtocol(ImageHandle,&gEfiComponentNameProtocolGuid,&pComponentName)) + && !EFI_ERROR(pComponentName->GetDriverName(pComponentName,"eng",&wsName)) +#endif + ) + { + Sprintf(sName,"%S", wsName); + return TRUE; + } + if ( !EFI_ERROR(Status) + && pImage->FilePath->Type==MEDIA_DEVICE_PATH + && pImage->FilePath->SubType==MEDIA_FV_FILEPATH_DP + ) + { + Sprintf(sName,"[%G]",&((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH*)pImage->FilePath)->NameGuid); + return TRUE; + } + Sprintf(sName,"Unknown"); + return FALSE; +} + +//************************************************************************* +// +// +// Name: FindDeviceName +// +// Description: +// BOOLEAN FindDeviceName( IN EFI_HANDLE Controller, IN EFI_HANDLE Child, +// OUT CHAR16 **wsName) checks all the protocols associated with a device +// handle and its child controller for its name; if a child is not defined, +// checks all associated protocols. +// +// Input: +// IN EFI_HANDLE Controller +// The image handle whose name is desired. +// +// IN EFI_HANDLE Child +// The child handle to be checked. If set to NULL, checks all protocols +// associated with the Controller instead. +// +// OUT CHAR16 **wsName +// Address of the null-terminated Unicode string to put device name into. +// User is reponsible for allocating the necessary memory resources. +// +// Output: +// TRUE if device name found; otherwise, FALSE. +// +// Modified: +// +// Referrals: +// +// Notes: +// +// +//************************************************************************* +BOOLEAN FindDeviceName( + EFI_HANDLE Controller, EFI_HANDLE Child, + CHAR16 **wsName, BOOLEAN *ChildFound +){ + UINTN i, Count; + EFI_GUID **ppGuid; + BOOLEAN NameFound = FALSE; + UINT32 Attributes = Child ? EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER : EFI_OPEN_PROTOCOL_BY_DRIVER; + if (EFI_ERROR(pBS->ProtocolsPerHandle(Controller, &ppGuid, &Count))) return FALSE; + if (ChildFound) *ChildFound=FALSE; + for(i=0; !NameFound && iOpenProtocolInformation( + Controller,ppGuid[i],&pInfo,&InfoCount + ))) continue; + for(j=0; jHandleProtocol( + pInfo[j].AgentHandle,&gEfiComponentName2ProtocolGuid,&pComponentName + ))){ + if (!EFI_ERROR(pComponentName->GetControllerName( + pComponentName,Controller,Child,LANGUAGE_CODE_ENGLISH,wsName + ))){NameFound=TRUE; break;} + } +#if EFI_SPECIFICATION_VERSION > 0x20000 +//Try UEFI 2.0 ComponentName protocol + if (!EFI_ERROR(pBS->HandleProtocol( + pInfo[j].AgentHandle,&gEfiComponentNameProtocolGuid,&pComponentName + ))){ + if (!EFI_ERROR(pComponentName->GetControllerName( + pComponentName,Controller,Child,"eng",wsName + ))){NameFound=TRUE; break;} + } +#endif + } + if (InfoCount) pBS->FreePool(pInfo); + } + if (Count) pBS->FreePool(ppGuid); + return NameFound; +} + +//************************************************************************* +// +// +// Name: GetControllerName +// +// Description: +// BOOLEAN GetControllerName(IN EFI_HANDLE Controller, OUT CHAR16 **wsName) +// retrieves the name of the controller specified by Controller and copies +// it into the caller allocated Unicode string at address wsName. +// +// Input: +// IN EFI_HANDLE Controller +// Handle of the controller whose name is desired. +// +// OUT CHAR16 **wsName +// Address of the null-terminated Unicode string to put controller name into. +// +// Output: +// TRUE if name found; otherwise, FALSE. +// +// Modified: +// +// Referrals: +// FindDeviceName +// DPCopy +// DPGetLastNode +// +// Notes: +// +// +//************************************************************************* +BOOLEAN GetControllerName(EFI_HANDLE Controller, CHAR16 **wsName) +{ + const EFI_DEVICE_PATH_PROTOCOL End = {END_DEVICE_PATH,END_ENTIRE_SUBTYPE,sizeof(EFI_DEVICE_PATH_PROTOCOL)}; + BOOLEAN NameFound; + EFI_HANDLE Parent; + EFI_DEVICE_PATH_PROTOCOL *pDevicePath, *pLastNode, *pDp; + BOOLEAN ChildFound; + + if (FindDeviceName(Controller, NULL, wsName, NULL)) return TRUE; + if (EFI_ERROR(pBS->HandleProtocol(Controller, &guidDevicePath, &pDevicePath))) return FALSE; + pDevicePath = DPCopy(pDevicePath); + do{ + ChildFound=TRUE; + pDp = pDevicePath; + pLastNode = DPGetLastNode(pDevicePath); + if (!pLastNode){ + NameFound = FALSE; + break; + } + *pLastNode = End; + if ( !EFI_ERROR(pBS->LocateDevicePath(&guidDevicePath, &pDp, &Parent)) + && pDp==pLastNode + ){ + NameFound = FindDeviceName(Parent, Controller, wsName, &ChildFound); + }else{ + NameFound = FALSE; + break; + } + }while(!ChildFound); + pBS->FreePool(pDevicePath); + return NameFound; +} + +//************************************************************************* +// +// +// Name: FvReadPe32Image +// +// Description: +// EFI_STATUS FvReadPe32Image(IN EFI_GUID *NameGuid, IN OUT VOID **Buffer, +// IN OUT UINTN *BufferSize, OUT UINT32 *AuthenticationStatus) +// +// Input: +// IN EFI_GUID *NameGuid +// GUID associated with the image in the firmware volume. +// +// IN OUT VOID **Buffer +// Pointer to buffer for the image to be returned in. Caller may specify +// *Buffer = NULL, in which case FvReadPe32Image will dynamically allocate +// the necessary amount of memory and return the pointer to the buffer +// here. +// +// IN OUT UINTN *BufferSize +// If Buffer is caller allocated, caller must put size of the Buffer here. +// Returns with the size of the image, even in the case the caller allocated +// Buffer is too small. +// +// OUT UINT32 *AuthenticationStatus) +// Pointer to a caller-allocated UINT32 in which the authentication status +// is returned. See Possible AuthenticationStatus Bit Values in the EFI +// Firmware Volume Specification for more information. +// +// Output: +// EFI_WARN_BUFFER_TOO_SMALL, if Buffer is too small to contain image. +// BufferSize is updated with the necessary size, +// and Buffer is filled with the truncated image. +// EFI_OUT_OF_RESOURCES, if an allocation failure occurred. +// EFI_NOT_FOUND, if the requested file or EFI_SECTION_PE32 was +// not found. +// EFI_DEVICE_ERROR, if a hardware error occurred when attempting +// to access the firmware volume. +// EFI_ACCESS_DENIED, if the firmware volume is configured to +// disallow reads. +// EFI_PROTOCOL_ERROR, if the GUIDED_SECTION_EXTRACTION_PROTOCOL for +// the EFI_SECTION_PE32 was not found. +// Otherwise, EFI_SUCCESS. +// +// Modified: +// +// Referrals: +// guidFV +// +// Notes: +// +// +//************************************************************************* +EFI_STATUS FvReadPe32Image ( + IN EFI_GUID *NameGuid, + IN OUT VOID **Buffer, + IN OUT UINTN *BufferSize, + OUT UINT32 *AuthenticationStatus) +{ + EFI_FIRMWARE_VOLUME_PROTOCOL *Fv; + + EFI_STATUS Status; + UINTN NumHandles; + EFI_HANDLE *HandleBuffer; + UINTN i; + + Status = pBS->LocateHandleBuffer(ByProtocol,&guidFV,NULL,&NumHandles,&HandleBuffer); + if (EFI_ERROR(Status)) return Status; + + for (i = 0; i< NumHandles; ++i) + { + pBS->HandleProtocol(HandleBuffer[i],&guidFV,&Fv); + Status = Fv->ReadSection( + Fv,NameGuid, + EFI_SECTION_PE32,0, + Buffer,BufferSize, + AuthenticationStatus + ); + if (!EFI_ERROR(Status)) break; + } + + pBS->FreePool(HandleBuffer); + return Status; +} + +//************************************************************************* +// +// +// Name: Malloc +// +// Description: +// VOID *Malloc(IN UINTN Size) allocates Size bytes of memory from +// EfiBootServicesData and returns a pointer to the allocated space. +// +// Input: +// IN UINTN Size +// The number of bytes to be allocated. +// +// Output: +// VOID* address of the allocated memory. +// +// Modified: +// +// Referrals: +// +// Notes: +// This function is available only in the DXE phase. Use +// pBS->FreePool(VOID*) to return memory to the pool once it's no longer +// needed. +// +// +//************************************************************************* +void* Malloc(UINTN Size){ + VOID *p=NULL; + pBS->AllocatePool(EfiBootServicesData,Size,&p); + return p; +} + +//************************************************************************* +// +// +// Name: MallocZ +// +// Description: +// VOID* MallocZ(IN UINTN Size) allocates Size bytes of memory from +// EfiBootServicesData, initializes it to zero, then returns a pointer to +// the allocated space. +// +// Input: +// IN UINTN Size +// The number of bytes to be allocated. +// +// Output: +// VOID* address of the allocated and zeroed memory. +// +// Modified: +// +// Referrals: +// Malloc +// +// Notes: +// +// +//************************************************************************* +void* MallocZ(UINTN Size){ + VOID *p=NULL; + p=Malloc(Size); + if(!p) return p; + pBS->SetMem(p,Size,0); + return p; +} + +static UINT8 DevicePathTypes[] = { + HARDWARE_DEVICE_PATH, + ACPI_DEVICE_PATH, + MESSAGING_DEVICE_PATH, + MEDIA_DEVICE_PATH, + BBS_DEVICE_PATH, + END_DEVICE_PATH, + END_DEVICE_PATH1 +}; + +static UINTN DevicePathTypesSize = sizeof(DevicePathTypes) / sizeof(UINT8); +#define MAX_DP_SIZE 0x10000 + +EFI_STATUS IsValidDevicePath( + IN EFI_DEVICE_PATH_PROTOCOL *pDp +) +{ + UINTN i; + UINTN DevicePathSize = 0; + + for( ; !(isEndNode(pDp) && pDp->SubType == END_ENTIRE_SUBTYPE); pDp = NEXT_NODE(pDp) ) { + UINTN NodeLength = NODE_LENGTH(pDp); + if (NodeLength < sizeof(EFI_DEVICE_PATH_PROTOCOL)) return EFI_INVALID_PARAMETER; + DevicePathSize += NodeLength; + for(i = 0; i < DevicePathTypesSize; i++) { + if(pDp->Type == DevicePathTypes[i]) + break; + } + if((i == DevicePathTypesSize) || (DevicePathSize > MAX_DP_SIZE)) //unknown device path type or big size + return EFI_INVALID_PARAMETER; + } + return EFI_SUCCESS; +} + +//************************************************************************* +// +// +// Name: DPLength +// +// Description: +// UINTN DPLength(IN EFI_DEVICE_PATH_PROTOCOL *pDp) returns the length of +// the provided device path, pDp (including the size of EndOfDevicePath). +// +// Input: +// IN EFI_DEVICE_PATH_PROTOCOL *pDp +// The device path whose length is desired. +// +// Output: +// UINTN size of the device path, pDp, including EndOfDevicePath. +// +// Modified: +// +// Referrals: +// isEndNode +// NEXT_NODE +// NODE_LENGTH +// +// Notes: +// +// +//************************************************************************* +UINTN DPLength(EFI_DEVICE_PATH_PROTOCOL *pDp) +{ + UINTN Size; + if (!pDp) return 0; + Size = 0; + for( + ; !(isEndNode(pDp) && pDp->SubType==END_ENTIRE_SUBTYPE) + ; pDp = NEXT_NODE(pDp) + ){ + UINTN Length = NODE_LENGTH(pDp); + //Protection from the junk data. + //Zero type and zero length are illegal. + //If we encountered them, return + if (!pDp->Type || !Length) return Size; + Size += Length; + } + return Size + sizeof(EFI_DEVICE_PATH_PROTOCOL); // add size of END_DEVICE_PATH node +} + +static EFI_DEVICE_PATH_PROTOCOL EndOfDevicePathNode = { + END_DEVICE_PATH, END_ENTIRE_SUBTYPE, + {sizeof(EFI_DEVICE_PATH_PROTOCOL),0} +}; + +//************************************************************************* +// +// +// Name: DPAddNode +// +// Description: +// VOID* DPAddNode(IN EFI_DEVICE_PATH_PROTOCOL *pDp1, +// IN EFI_DEVICE_PATH_PROTOCOL *pDp2) adds the very first element of pDp2 to +// pDp1 just before its device path terminator, and returns the result in a +// newly allocated buffer. +// +// Input: +// IN EFI_DEVICE_PATH_PROTOCOL *pDp1 +// The device path to be appended to. Element will be inserted prior to +// pDp1's device path terminator. Device path will not be altered. +// +// IN EFI_DEVICE_PATH_PROTOCOL *pDp2 +// The device path to be read from. The very first element will be appended +// to pDp1; note that pDp2 does not require a device path terminator. +// +// Output: +// VOID* address of the modified device path. User is responsible for +// managing this piece of memory. +// +// Modified: +// +// Referrals: +// DPCopy +// DPLength +// Malloc +// MemCpy +// NODE_LENGTH +// +// Notes: +// +// +//************************************************************************* +VOID* DPAddNode(EFI_DEVICE_PATH_PROTOCOL *pDp1, EFI_DEVICE_PATH_PROTOCOL *pDp2) +{ + UINTN l1; + UINT8 *NewDp, *p; + + if (!pDp2) return (pDp1) ? DPCopy(pDp1) : DPCopy(&EndOfDevicePathNode); + + l1 = pDp1 ? DPLength(pDp1)-sizeof(EFI_DEVICE_PATH_PROTOCOL) : 0; + NewDp = Malloc(l1+NODE_LENGTH(pDp2)+sizeof(EFI_DEVICE_PATH_PROTOCOL)); + p = NewDp; + + if (l1) { MemCpy(p, pDp1, l1); p+=l1; } + MemCpy(p, pDp2, NODE_LENGTH(pDp2)); p+=NODE_LENGTH(pDp2); + *((EFI_DEVICE_PATH_PROTOCOL*)p) = EndOfDevicePathNode; + return NewDp; +} + +//************************************************************************* +// +// +// Name: DPAdd +// +// Description: +// VOID* DPAdd(IN EFI_DEVICE_PATH_PROTOCOL *pDp1, +// IN EFI_DEVICE_PATH_PROTOCOL *pDp2) appends all the elements of pDp2 just +// before the device path terminator of pDp1, and returns the result in a +// newly allocated buffer. +// +// Input: +// IN EFI_DEVICE_PATH_PROTOCOL *pDp1 +// The device path to be appended to. Element(s) will be inserted prior to +// pDp1's device path terminator. Device path will not be altered. +// +// IN EFI_DEVICE_PATH_PROTOCOL *pDp2 +// The device path to be read from. All elements will be appended to pDp1. +// If NULL, returns copy of pDp1. +// +// Output: +// VOID* address of the modified device path. User is responsible for +// managing this piece of memory. +// +// Modified: +// +// Referrals: +// DPCopy +// DPLength +// Malloc +// MemCpy +// +// Notes: +// +// +//************************************************************************* +VOID* DPAdd(EFI_DEVICE_PATH_PROTOCOL *pDp1, EFI_DEVICE_PATH_PROTOCOL *pDp2) +{ + UINTN l1,l2; + UINT8 *NewDp,*p; + + if (!pDp1) return (pDp2) ? DPCopy(pDp2) : DPCopy(&EndOfDevicePathNode); + if (!pDp2) return DPCopy(pDp1); + + l1 = DPLength(pDp1)-sizeof(EFI_DEVICE_PATH_PROTOCOL); + l2 = DPLength(pDp2); + NewDp = Malloc(l1+l2); + p = NewDp; + + MemCpy(p, pDp1, l1); p+=l1; + MemCpy(p, pDp2, l2); + return NewDp; +} + +//************************************************************************* +// +// +// Name: DPAddInstance +// +// Description: +// VOID* DPAddInstance(IN EFI_DEVICE_PATH_PROTOCOL *pDp1, +// IN EFI_DEVICE_PATH_PROTOCOL *pDp2) makes a new device path with pDp1 as +// its first instance and pDp2 as its second instance, then returns the +// result in a newly allocated buffer. +// +// Input: +// IN EFI_DEVICE_PATH_PROTOCOL *pDp1 +// The first device path instance. +// +// IN EFI_DEVICE_PATH_PROTOCOL *pDp2 +// The second device path instance. +// +// Output: +// VOID* address of the modified device path. User is responsible for +// managing this piece of memory. +// +// Modified: +// +// Referrals: +// DPCopy +// DPLength +// Malloc +// MemCpy +// +// Notes: +// +// +//************************************************************************* +VOID* DPAddInstance(EFI_DEVICE_PATH_PROTOCOL *pDp1, EFI_DEVICE_PATH_PROTOCOL *pDp2) +{ + UINTN l1,l2; + UINT8 *NewDp,*p; + + if (!pDp2) return NULL; + if (!pDp1) return DPCopy(pDp2); + //Uncomment if pDp2 can be NULL:if (!pDp2) return DPCopy(pDp1); + + l1 = DPLength(pDp1); + l2 = DPLength(pDp2); + NewDp = Malloc(l1+l2); + p = NewDp; + + MemCpy(p, pDp1, l1); p+=l1; + (((EFI_DEVICE_PATH_PROTOCOL*)p)-1)->SubType = END_INSTANCE_SUBTYPE; + MemCpy(p, pDp2, l2); + return NewDp; +} + +//************************************************************************* +// +// +// Name: DPCopy +// +// Description: +// VOID* DPCopy(IN EFI_DEVICE_PATH_PROTOCOL *pDp) copies the user provided +// device path into a new buffer and returns its address. +// +// Input: +// IN EFI_DEVICE_PATH_PROTOCOL *pDp +// The device path to be copied. +// +// Output: +// VOID* address of the new copy of pDp. User is responsible for managing +// this piece of memory. +// +// Modified: +// +// Referrals: +// DPLength +// Malloc +// MemCpy +// +// Notes: +// +// +//************************************************************************* +VOID* DPCopy(EFI_DEVICE_PATH_PROTOCOL *pDp) +{ + UINTN l; + UINT8 *p; + + if (!pDp) return NULL; + l = DPLength(pDp); + p = Malloc(l); + MemCpy(p, pDp, l); + return p; +} + +//************************************************************************* +// +// +// Name: DPIsOneOf +// +// Description: +// BOOLEAN DPIsOneOf(IN EFI_DEVICE_PATH_PROTOCOL *pAll, +// IN EFI_DEVICE_PATH_PROTOCOL *pOne, IN BOOLEAN ExactMatch) determines +// whether a device path, pAll, contains another device path, pOne. If the +// ExactMatch parameter is TRUE, it checks for an exact match instead. +// +// +// Input: +// IN EFI_DEVICE_PATH_PROTOCOL *pAll +// The device path to be scanned. +// +// IN EFI_DEVICE_PATH_PROTOCOL *pOne +// The device path to locate within pAll. +// +// IN BOOLEAN ExactMatch +// If TRUE, checks whether pAll is exactly pOne. +// +// Output: +// TRUE if pAll contains pOne and ExactMatch is FALSE, or if pAll equals +// pOne and ExactMatch is TRUE. Otherwise, FALSE. +// +// Modified: +// +// Referrals: +// NODE_LENGTH +// isEndNode +// MemCmp +// NEXT_NODE +// +// Notes: +// +// +//************************************************************************* +BOOLEAN DPIsOneOf(EFI_DEVICE_PATH_PROTOCOL *pAll, EFI_DEVICE_PATH_PROTOCOL *pOne, BOOLEAN ExactMatch) +{ + do{ + EFI_DEVICE_PATH_PROTOCOL *pPath; + for( pPath = pOne + ; NODE_LENGTH(pPath)==NODE_LENGTH(pAll) + && !isEndNode(pPath) + && !MemCmp(pPath, pAll, NODE_LENGTH(pAll)) + ; pPath=NEXT_NODE(pPath), pAll=NEXT_NODE(pAll) + ) ; + if (isEndNode(pAll) && (!ExactMatch || isEndNode(pPath))) return TRUE; + for(; !isEndNode(pAll); pAll = NEXT_NODE(pAll)) ; + if (pAll->SubType==END_ENTIRE_SUBTYPE) return FALSE; + pAll++ ; + }while (TRUE); +} + +//************************************************************************* +// +// +// Name: DPGetLastNode +// +// Description: +// VOID* DPGetLastNode(IN EFI_DEVICE_PATH_PROTOCOL *pDp) returns a pointer +// to the very last device path node before END_OF_DEVICE_PATH node. +// +// Input: +// IN EFI_DEVICE_PATH_PROTOCOL *pDp +// The device path whose last node is needed. +// +// Output: +// VOID* address of the last device path node before END_OF_DEVICE_PATH in +// the provided device path, pDp. +// +// Modified: +// +// Referrals: +// isEndNode +// NEXT_NODE +// +// Notes: +// +// +//************************************************************************* +VOID* DPGetLastNode(EFI_DEVICE_PATH_PROTOCOL *pDp) +{ + EFI_DEVICE_PATH_PROTOCOL *dp=NULL; +//--------------------------------- + if(!pDp)return dp; + for( ; !isEndNode(pDp); pDp=NEXT_NODE(pDp)) dp = pDp; + return dp; +} + +//************************************************************************* +// +// +// Name: DPCmp +// +// Description: +// INTN DPCmp(IN EFI_DEVICE_PATH_PROTOCOL *pDp1, +// IN EFI_DEVICE_PATH_PROTOCOL *pDp2) compares two device paths, pDp1 and +// pDp2, and returns zero if both are equivalent; otherwise, it returns +// a non-zero value. +// +// Input: +// IN EFI_DEVICE_PATH_PROTOCOL *pDp1 +// Address of the first device path to compare. +// +// IN EFI_DEVICE_PATH_PROTOCOL *pDp2 +// Address of the second device path to compare. +// +// Output: +// INTN non-zero value if both input device paths are not equivalent; +// otherwise, zero. +// +// Modified: +// +// Referrals: +// DPLength +// MemCmp +// +// Notes: +// +// +//************************************************************************* +//Compares Dp1 and Dp2 returns ZERO if Dp1==Dp2, NONZERO if Dp1!=Dp2 +INTN DPCmp(EFI_DEVICE_PATH_PROTOCOL *pDp1, EFI_DEVICE_PATH_PROTOCOL *pDp2){ + UINTN len; +//--------------------- + if(!pDp1 && !pDp2) return 0; //if both is NULL than Dp1==Dp2 + if(!pDp1 || !pDp2) return -1; // if one is NULL than Dp1!=Dp2 + len=DPLength(pDp1); + if(DPLength(pDp2)!=len) return -1; + return MemCmp(pDp1,pDp2, len); +} + +//************************************************************************* +// +// +// Name: DPCut +// +// Description: +// VOID* DPCut(IN EFI_DEVICE_PATH_PROTOCOL *pDp) creates a new device path +// containing all but the last node of pDp, then returns the address to the +// new device path. +// +// Input: +// IN EFI_DEVICE_PATH_PROTOCOL *pDp +// The device path to be copied. +// +// Output: +// VOID* address of the new copy of pDp containing all but the last node. +// Returns NULL if there is not enough memory or pDp is NULL. +// +// Modified: +// +// Referrals: +// DPGetLastNode +// Malloc +// MemCpy +// SET_NODE_LENGTH +// +// Notes: +// +// +//************************************************************************* +VOID *DPCut(EFI_DEVICE_PATH_PROTOCOL *pDp) +{ + EFI_DEVICE_PATH_PROTOCOL *pdp, *edp; + UINTN len; +//------------------------------ + if(!pDp)return NULL; + pdp=DPGetLastNode(pDp); + len=(UINTN)pdp-(UINTN)pDp; + if(len==0) return NULL; + pdp=Malloc(len+sizeof(EFI_DEVICE_PATH_PROTOCOL)); + ASSERT(pdp) + MemCpy(pdp,pDp,len); + edp=(EFI_DEVICE_PATH_PROTOCOL*)((UINT8*)pdp+len); + edp->Type=END_DEVICE_PATH; + edp->SubType=END_ENTIRE_SUBTYPE; + SET_NODE_LENGTH(edp,END_DEVICE_PATH_LENGTH); + return pdp; +} + +//************************************************************************* +// +// +// Name: DPGetEndNode +// +// Description: +// EFI_DEVICE_PATH_PROTOCOL* DPGetEndNode(IN EFI_DEVICE_PATH_PROTOCOL *pDp) +// returns the end of the device path node for the specified device path. +// +// Input: +// IN EFI_DEVICE_PATH_PROTOCOL *pDp +// Address of the device path. +// +// Output: +// EFI_DEVICE_PATH_PROTOCOL* address of the end of device path node. NULL +// if pDp is NULL. +// +// Modified: +// +// Referrals: +// isEndNode +// NEXT_NODE +// +// Notes: +// +// +//************************************************************************* +EFI_DEVICE_PATH_PROTOCOL* DPGetEndNode(EFI_DEVICE_PATH_PROTOCOL *pDp) +{ + if(!pDp)return NULL; + for( ; !isEndNode(pDp); pDp=NEXT_NODE(pDp)) ; + return pDp; +} + +//************************************************************************* +// +// +// Name: DPNextInstance +// +// Description: +// VOID* DPNextInstance(IN OUT EFI_DEVICE_PATH_PROTOCOL **ppDp, +// OUT UINTN *pSize) creates a copy of the current device path instance. It +// also updates DevicePath to point to the next device path instance in the +// device path (or NULL if no more) and updates Size to hold the size of the +// device path instance copy. If DevicePath is NULL, then NULL is returned. +// If there is not enough memory to allocate space for the new device path, +// then NULL is returned. The memory is allocated from EFI boot services +// memory. It is the responsibility of the caller to free the memory +// allocated. +// +// Input: +// IN OUT EFI_DEVICE_PATH_PROTOCOL **ppDp +// On input, this holds the pointer to the current device path instance. On +// output, this holds the pointer to the next device path instance or NULL +// if there are no more device path instances in the device path pointer to +// a device path data structure. +// +// OUT UINTN *pSize +// On output, this holds the size of the device path instance, in bytes, or +// zero if DevicePath is NULL. +// +// Output: +// VOID* address of a copy of the next device path instance. NULL if there +// are no more device path instances, or not enough memory, or the provided +// device path was NULL. It is the responsibility of the caller to free the +// memory allocated. +// +// Modified: +// +// Referrals: +// DPGetEndNode +// Malloc +// MemCpy +// +// Notes: +// +// +//************************************************************************* +VOID* DPNextInstance(EFI_DEVICE_PATH_PROTOCOL **ppDp, UINTN *pSize) +{ + EFI_DEVICE_PATH_PROTOCOL *pEnd, *pNew; + UINTN Size; + if (pSize) *pSize=0; + if (!ppDp) return NULL; + pEnd = DPGetEndNode(*ppDp); + if (!pEnd) return NULL; + Size = (UINT8*)(pEnd+1) - (UINT8*)*ppDp; + if (pSize) *pSize=Size; + if (!(pNew = Malloc(Size))) return NULL; + MemCpy(pNew,*ppDp, Size); + ((EFI_DEVICE_PATH_PROTOCOL*)((UINT8*)pNew+Size)-1)->SubType = END_ENTIRE_SUBTYPE; + if (pEnd->SubType==END_ENTIRE_SUBTYPE) *ppDp = NULL; + else *ppDp = pEnd+1; + return pNew; +} + +//************************************************************************* +// +// +// Name: DPCreateNode +// +// Description: +// VOID* DPCreateNode(IN UINT8 Type, IN UINT8 SubType, IN UINT16 Length) +// creates a new device node in a newly allocated buffer of size NodeLength +// and initializes the device path node header with NodeType and NodeSubType. +// The new device path node is returned. If NodeLength is smaller than a +// device path header, then NULL is returned. If there is not enough memory +// to allocate space for the new device path, then NULL is returned. The +// memory is allocated from EFI boot services memory. It is the +// responsibility of the caller to free the memory allocated. +// +// Input: +// IN UINT8 Type +// The device node type for the new device node. +// +// IN UINT8 SubType +// The device node sub-type for the new device node. +// +// IN UINT16 Length +// The length of the new device node. +// +// Output: +// VOID* address of the new device path node. NULL if NodeLength is +// smaller than a device path header, or there is not enough memory. +// +// Modified: +// +// Referrals: +// Malloc +// SET_NODE_LENGTH +// +// Notes: +// +// +//************************************************************************* +VOID* DPCreateNode(UINT8 Type, UINT8 SubType, UINT16 Length) +{ + EFI_DEVICE_PATH_PROTOCOL *pDp; + + if (LengthType = Type; + pDp->SubType = SubType; + SET_NODE_LENGTH(pDp,Length); + return pDp; +} + +//************************************************************************* +// +// +// Name: DPIsMultiInstance +// +// Description: +// BOOLEAN DPIsMultiInstance(IN EFI_DEVICE_PATH_PROTOCOL* pDp) determines +// if a device path is single or multi-instance. This function returns TRUE +// if the device path specified by pDp is multi-instance. Otherwise, FALSE +// is returned. If pDp is NULL, then FALSE is returned. +// +// Input: +// IN EFI_DEVICE_PATH_PROTOCOL* pDp +// A pointer to a device path data structure. +// +// Output: +// TRUE if the device path specified by DevicePath is multi-instance. +// FALSE if pDp is NULL or not multi-instance. +// +// Modified: +// +// Referrals: +// DPGetEndNode +// +// Notes: +// +// +//************************************************************************* +BOOLEAN DPIsMultiInstance(EFI_DEVICE_PATH_PROTOCOL* pDp) +{ + if (!pDp) return FALSE; + return DPGetEndNode(pDp)->SubType != END_ENTIRE_SUBTYPE; +} + +//************************************************************************* +// +// +// Name: TimerIsSet +// +// Description: +// VOID TimerIsSet(IN EFI_EVENT Event, IN OUT VOID *Context) +// +// Input: +// +// Output: +// +// Modified: +// +// Referrals: +// +// Notes: +// +// +//************************************************************************* +VOID TimerIsSet(EFI_EVENT Event, VOID *Context) +{ + *(BOOLEAN*)Context = TRUE; +} + +//************************************************************************* +// +// +// Name: TimerStart +// +// Description: +// EFI_EVENT TimerStart(OUT BOOLEAN *pTimerFlag, IN UINT64 Delay) +// +// Input: +// +// Output: +// +// Modified: +// +// Referrals: +// TimerIsSet +// +// Notes: +// +// +//************************************************************************* +EFI_EVENT TimerStart(BOOLEAN *pTimerFlag, UINT64 Delay) +{ + EFI_STATUS Status; + EFI_EVENT Event; + + *pTimerFlag = FALSE; + + Status = pBS->CreateEvent( + EVT_TIMER|EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + TimerIsSet, + pTimerFlag, + &Event + ); + if (EFI_ERROR(Status)) return NULL; + + + Status = pBS->SetTimer(Event, TimerRelative, Delay); + if (EFI_ERROR(Status)) + { + pBS->CloseEvent(Event); + return NULL; + } + + return Event; +} + +//************************************************************************* +// +// +// Name: TimerStop +// +// Description: +// VOID TimerStop(IN BOOLEAN TimerFlag, IN EFI_EVENT Event) +// +// Input: +// +// Output: +// +// Modified: +// +// Referrals: +// +// Notes: +// +// +//************************************************************************* +void TimerStop(BOOLEAN TimerFlag, EFI_EVENT Event) +{ + if (!TimerFlag) pBS->SetTimer(Event, TimerCancel,0); + pBS->CloseEvent(Event); +} + +//************************************************************************* +// +// +// Name: FSReadFile +// +// Description: +// EFI_STATUS FSReadFile(IN EFI_HANDLE hDevice, IN EFI_DEVICE_PATH_PROTOCOL* pPath, OUT VOID** ppSource, OUT UINTN *pSize) +// +// Input: +// +// Output: +// +// Modified: +// +// Referrals: +// isEndNode +// NODE_LENGTH +// MemCpy +// Malloc +// NEXT_NODE +// +// Notes: +// +// +//************************************************************************* +EFI_STATUS FSReadFile(EFI_HANDLE hDevice, EFI_DEVICE_PATH_PROTOCOL* pPath, VOID** ppSource, UINTN *pSize) +{ + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *pFS; + EFI_FILE_PROTOCOL *pRootFile=NULL, *pFile=NULL; +//S.Y. +//FileInfo contains not a pointer to FileName Buffer +//But Copy of the file name at the very end of the file + EFI_FILE_INFO *pFileInfo=NULL; +//S.Y. + UINTN Size=0; + CHAR16 *wsFileName; + EFI_DEVICE_PATH_PROTOCOL *pDp; + VOID *pSource = NULL; + EFI_STATUS Status; + if (EFI_ERROR(pBS->HandleProtocol(hDevice, &guidFS, &pFS))) return EFI_NOT_FOUND; + if (EFI_ERROR(pFS->OpenVolume(pFS,&pRootFile))) return EFI_NOT_FOUND; + //create file name + //1. Determine Buffer size to hold filename + Size = 0; + pDp = pPath; + while(!isEndNode(pDp)){ + if(pDp->Type == MEDIA_DEVICE_PATH && pDp->SubType == MEDIA_FILEPATH_DP){ + Size=Size+(NODE_LENGTH(pDp)-sizeof(EFI_DEVICE_PATH_PROTOCOL)); + } else break; + pDp = NEXT_NODE(pDp); + } + + if ( !isEndNode(pDp) ) return EFI_NOT_FOUND; + //2. Alocate buffer for file name + wsFileName = Malloc(Size); + if (!wsFileName) return EFI_OUT_OF_RESOURCES; + //3.Copy Characters fron FileDevicePAth to the Buffer + Size=0;//Now Size will show position of char in wsFileName buffer + pDp = pPath; + while(!isEndNode(pDp)){ + if(pDp->Type == MEDIA_DEVICE_PATH && pDp->SubType == MEDIA_FILEPATH_DP){ + UINTN l = NODE_LENGTH(pDp)-sizeof(EFI_DEVICE_PATH_PROTOCOL); + MemCpy(wsFileName+Size,pDp+1,l); + Size=Size+(l/sizeof(CHAR16)); +//TODO//TODO//TODO//TODO//TODO//TODO//TODO//TODO +//EFI Shell prepares File DevicePath very strange it should not be like this +//when you calling App from fsX:\DIR_NAME> app_name it creates following dev path entry +//(\DIR_NAME);('.');(APP_NAME.efi);(END_DP). +//but when you type fsX:\> DIR_NAME\app_name it creates +// (\);(DIR_NAME\);(app_name);(END_DP). + //repleace str_terminator with "\" char if previouse char is not "\" + if(wsFileName[Size-2]!=0x005c) wsFileName[Size-1]=0x005c; //"\"symbol + else Size--; +//TODO//TODO//TODO//TODO//TODO//TODO//TODO//TODO + } else break; + pDp = NEXT_NODE(pDp); + } + + wsFileName[Size-1]=0; + Status = pRootFile->Open(pRootFile,&pFile,wsFileName,EFI_FILE_MODE_READ,0); + pBS->FreePool(wsFileName); + if (EFI_ERROR(Status)) return EFI_NOT_FOUND; +//S.Y. + //Size = sizeof(FileInfo); + Size=0; + //Try to determine Size of memory to allocate for EFI_FILE_INFO var + Status=pFile->GetInfo(pFile,&guidFileInfo,&Size,pFileInfo); +// if (!EFI_ERROR(Status=pFile->GetInfo(pFile,&guidFileInfo,&Size,&FileInfo))) + if(EFI_ERROR(Status)){ + if (Status==EFI_BUFFER_TOO_SMALL){ + pFileInfo=Malloc(Size); + if(!pFileInfo) { + Status=EFI_OUT_OF_RESOURCES; + goto Done; + } + } else goto Done; + } + + Status=pFile->GetInfo(pFile,&guidFileInfo,&Size,pFileInfo); + if(EFI_ERROR(Status)){ + pBS->FreePool(pFileInfo); + goto Done; + } + + Size = (UINTN)pFileInfo->FileSize; + + pBS->FreePool(pFileInfo); + + pSource=Malloc(Size); + if (!pSource) Status=EFI_OUT_OF_RESOURCES; + else Status=pFile->Read(pFile,&Size,pSource); + +Done: + if(pFile)pFile->Close(pFile); + if(pRootFile)pRootFile->Close(pRootFile); + if (EFI_ERROR(Status) && pSource){ + pBS->FreePool(pSource); + return Status; + } + *ppSource = pSource; + *pSize = Size; + return EFI_SUCCESS; +} + +//************************************************************************* +// +// +// Name: FVReadFile +// +// Description: +// EFI_STATUS FVReadFile(IN EFI_HANDLE hDevice, IN EFI_GUID* pFileName, OUT VOID** ppSource, OUT UINTN *pSize) +// +// Input: +// +// Output: +// +// Modified: +// +// Referrals: +// +// Notes: +// +// +//************************************************************************* +EFI_STATUS FVReadFile(EFI_HANDLE hDevice, EFI_GUID* pFileName, VOID** ppSource, UINTN *pSize) +{ + EFI_FIRMWARE_VOLUME_PROTOCOL *pFV; + UINT32 AuthStatus; + if (EFI_ERROR(pBS->HandleProtocol(hDevice, &guidFV, &pFV))) return EFI_NOT_FOUND; + // TODO: add support for raw files + if (EFI_ERROR(pFV->ReadSection(pFV, pFileName, EFI_SECTION_PE32, + 0, ppSource, pSize, &AuthStatus + ) + ) + ) return EFI_UNSUPPORTED; + return EFI_SUCCESS; +} + +//************************************************************************* +// +// +// Name: LFReadFile +// +// Description: +// EFI_STATUS LFReadFile(IN EFI_HANDLE hDevice, IN EFI_DEVICE_PATH_PROTOCOL* pPath, IN BOOLEAN BootPolicy, OUT VOID** ppSource, OUT UINTN *pSize) +// +// Input: +// +// Output: +// +// Modified: +// +// Referrals: +// +// Notes: +// +// +//************************************************************************* +EFI_STATUS LFReadFile(EFI_HANDLE hDevice, EFI_DEVICE_PATH_PROTOCOL* pPath, BOOLEAN BootPolicy, VOID** ppSource, UINTN *pSize) +{ + EFI_LOAD_FILE_PROTOCOL *pLoadFile; + VOID *pSource = NULL; + UINTN Size=0; + if (EFI_ERROR(pBS->HandleProtocol(hDevice, &guidLoadFile, &pLoadFile))) return EFI_NOT_FOUND; + //TODO: This is patch for SCT!!!! They return EFI_SUCCESS even though Size and pSource are zeroes!!! + //if (pLoadFile->LoadFile(pLoadFile, pPath, BootPolicy, &Size, pSource)!=EFI_BUFFER_TOO_SMALL) return EFI_NOT_FOUND; + pLoadFile->LoadFile(pLoadFile, pPath, BootPolicy, &Size, pSource); + if (!Size) return EFI_NOT_FOUND; + pSource=Malloc(Size); + if (!pSource) return EFI_OUT_OF_RESOURCES; + if (EFI_ERROR(pLoadFile->LoadFile(pLoadFile, pPath, BootPolicy, &Size, pSource)!=EFI_BUFFER_TOO_SMALL)) + { + pBS->FreePool(pSource); + return EFI_NOT_FOUND; + } + *ppSource = pSource; + *pSize = Size; + return EFI_SUCCESS; +} + +//************************************************************************* +// +// +// Name: ReadImage +// +// Description: +// EFI_STATUS ReadImage(IN BOOLEAN BootPolicy, +// IN EFI_DEVICE_PATH_PROTOCOL *FilePath, IN OUT VOID **ppSource, +// IN OUT UINTN *pSourceSize OPTIONAL, OUT UINTN *pImageSize OPTIONAL, +// OUT EFI_HANDLE *phDevice OPTIONAL, +// OUT EFI_DEVICE_PATH_PROTOCOL **ppPath OPTIONAL) +// +// Input: +// +// +// Output: +// +// Modified: +// +// Referrals: +// +// Notes: +// +// +//************************************************************************* +EFI_STATUS ReadImage ( + IN BOOLEAN BootPolicy, IN EFI_DEVICE_PATH_PROTOCOL *FilePath, + IN OUT VOID **ppSource, IN OUT UINTN *pSourceSize OPTIONAL, + OUT UINTN *pImageSize OPTIONAL, + OUT EFI_HANDLE *phDevice OPTIONAL, OUT EFI_DEVICE_PATH_PROTOCOL **ppPath OPTIONAL +) +{ + EFI_HANDLE hDevice = NULL; + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *pPath = FilePath; + VOID *pSource = NULL; + if (!ppSource) return EFI_INVALID_PARAMETER; + if (!*ppSource) + { + UINTN Size; + Status = pBS->LocateDevicePath(&guidDevicePath, &pPath, &hDevice); + if (EFI_ERROR(Status)) + {//if device for the FV File is not found + //scan all FVs + UINTN Number,i; + EFI_HANDLE *Handle; + if ( pPath->Type != MEDIA_DEVICE_PATH + || pPath->SubType != MEDIA_FV_FILEPATH_DP + ) return EFI_NOT_FOUND; + Status=pBS->LocateHandleBuffer(ByProtocol, &guidFV, NULL, &Number, &Handle); + if (EFI_ERROR(Status)) return EFI_NOT_FOUND; + for(i=0; iFreePool(Handle); + if (EFI_ERROR(Status)) return Status; + } + else if (pPath->Type == MEDIA_DEVICE_PATH) + { + if(pPath->SubType == MEDIA_FV_FILEPATH_DP) + { + if (EFI_ERROR(Status = FVReadFile(hDevice, (EFI_GUID*)(pPath+1), &pSource, &Size))) return Status; + } + else if(pPath->SubType == MEDIA_FILEPATH_DP) + { + if (EFI_ERROR(Status = FSReadFile(hDevice, pPath, &pSource, &Size))) return Status; + } + } + else + { + if (EFI_ERROR(Status = LFReadFile(hDevice, pPath, BootPolicy, &pSource, &Size))) return Status; + } + if (pSourceSize) *pSourceSize = Size; + *ppSource = pSource; + } + else + { + //TODO: Should it be EFI_INVALID_PARAMETER??? + //EFI Spec does not answer the question, however, + //SCT checks for EFI_LOAD_ERROR. + if (!pSourceSize || !*pSourceSize) return EFI_LOAD_ERROR; + } + if (!IsPeImageValid(*ppSource)) return EFI_LOAD_ERROR; + if (pImageSize) *pImageSize = GetImageSize(*ppSource); + if (phDevice) *phDevice = hDevice; + if (ppPath) *ppPath = pPath; + return EFI_SUCCESS; +} + +// =================================== LIST +//List functions + +//************************************************************************* +// +// +// Name: DLIST +// +// Description: +// DLIST is a type defined structure used in an AMILIB provided +// doubly-linked list API to maintain pointers for a list's head, tail, and +// size. +// +// Fields: Name Type Description +// ------------------------------------------------------------------ +// Size UINTN Number of DLINK nodes contained by the DLIST. +// pHead DLINK* Pointer to the head node (start) of the list. +// pTail DLINK* Pointer to the tail node (end) of the list. +// +// Referrals: +// Doubly_Linked_List_Functions +// DLINK +// DListInit +// DListEmpty +// DListAdd +// DListDelete +// DListInsert +// DListEmpty +// +// Notes: +// Prototype provided in AmiDxeLib.h. See Doubly_Linked_List_Functions for +// example usage. +// +// +//************************************************************************* + +//************************************************************************* +// +// +// Name: DLINK +// +// Description: +// DLINK is a type defined structure used in an AMILIB provided +// doubly-linked list API which is used as a node for an entry into the list. +// +// Fields: Name Type Description +// ------------------------------------------------------------------ +// pNext DLINK* Pointer to the next node in the list. +// pPrev DLINK* Pointer to the previous node in the list. +// +// Referrals: +// Doubly_Linked_List_Functions +// DLIST +// +// Notes: +// Prototype provided in AmiDxeLib.h. See Doubly_Linked_List_Functions for +// example usage. +// +// +//************************************************************************* + +//************************************************************************* +// +// +// Name: DListEmpty +// +// Description: +// DlistEmpty(IN DLIST *pList) is a macro which returns NULL if the provided +// DLIST is empty. +// +// Input: +// IN DLIST *pList +// A pointer to the doubly linked list structure. +// +// Output: +// DLINK* address of the list's head; NULL if the list is empty. +// +// Modified: +// +// Referrals: +// +// Notes: +// Macro defined in AmiDxeLib.h. No validation performed on pList. +// +// +//************************************************************************* + +//************************************************************************* +// +// +// Name: DListInit +// +// Description: +// VOID DListInit(IN DLIST *pList) initializes the head, tail links and +// number of elements of a new linked list structure. After initializing a +// linked list with this function, the other linked list functions may be +// used to add and remove nodes from the linked list. It is up to the caller +// of this function to allocate the memory for pList. +// +// Input: +// IN DLIST *pList +// A pointer to the doubly linked list structure. +// +// Output: +// VOID. +// +// Modified: +// +// Referrals: +// +// Notes: +// It is up to the caller of this function to allocate the memory for pList. +// +// +//************************************************************************* + +VOID DListInit(DLIST* pList){ + pList->pHead = NULL; + pList->pTail = NULL; + pList->Size = 0; +} + +//************************************************************************* +// +// +// Name: DListAdd +// +// Description: +// VOID DListAdd(IN DLIST *pList, IN DLINK *pElement) adds the node pElement +// to the end of the doubly linked list denoted by pList. +// +// Input: +// IN DLIST *pList +// A pointer to the doubly linked list structure. +// +// IN DLINK *pElement +// A pointer to a node that is to be added at the end of the doubly linked +// list. +// +// Output: +// VOID. +// +// Modified: +// +// Referrals: +// +// Notes: +// +// +//************************************************************************* +VOID DListAdd(DLIST* pList, DLINK* pElement){ + pElement->pNext = NULL; + pElement->pPrev = pList->pTail; + if (!pList->pHead) pList->pHead = pElement; + else pList->pTail->pNext = pElement; + pList->pTail = pElement; + pList->Size++; +} + +//************************************************************************* +// +// +// Name: DListDelete +// +// Description: +// VOID DListDelete(IN DLIST *pList, IN DLINK *pElement) removes the node +// pElement from a doubly linked list. It is up to the caller of this +// function to release the memory used by this node if that is required. +// +// Input: +// IN DLIST *pList +// A pointer to the doubly linked list structure. +// +// IN DLINK *pElement +// A pointer to a node that is to be deleted from the end of the doubly +// linked list. +// +// Output: +// VOID. +// +// Modified: +// +// Referrals: +// +// Notes: +// It is up to the caller of this function to release the memory used by +// this node if that is required. +// +// +//************************************************************************* +VOID DListDelete(DLIST* pList, DLINK* pElement){ + + if (pList->pTail == pElement) pList->pTail = pElement->pPrev; + else pElement->pNext->pPrev = pElement->pPrev; + if (pList->pHead == pElement) pList->pHead = pElement->pNext; + else pElement->pPrev->pNext = pElement->pNext; + pList->Size--; +} + +//************************************************************************* +// +// +// Name: DListInsert +// +// Description: +// VOID DListInsert(IN DLIST* pList, IN DLINK* pElement, IN DLINK* pAfter) +// inserts the node pElement in the doubly linked list denoted by pList +// immediately after the node pAfter. +// +// Input: +// IN DLIST *pList +// A pointer to the doubly linked list structure. +// +// IN DLINK *pElement +// A pointer to a node that is to be added to the doubly linked list. +// +// IN DLINK *pAfter +// A pointer to a node after which pElement is to be added. +// +// Output: +// VOID. +// +// Modified: +// +// Referrals: +// +// Notes: +// +// +//************************************************************************* +VOID DListInsert(DLIST* pList, DLINK* pElement, DLINK* pAfter){ + pElement->pPrev = pAfter; + if (pAfter) + { + pElement->pNext = pAfter->pNext; + if (pAfter==pList->pTail) pList->pTail=pElement; + else pAfter->pNext->pPrev = pElement; + pAfter->pNext = pElement; + } + else + { + pElement->pNext = pList->pHead; + if (pList->pHead) pList->pHead->pPrev = pElement; + else pList->pTail = pElement; + pList->pHead = pElement; + } + pList->Size++; +} + +//************************************************************************* +// +// +// Name: GetEfiVariable +// +// Description: +// EFI_STATUS GetEfiVariable(IN CHAR16 *sName, IN EFI_GUID *pGuid, +// OUT UINT32 *pAttributes OPTIONAL, IN OUT UINTN *pDataSize, +// OUT VOID **ppData) reads an EFI variable with the name Name and GUID Guid. +// If variable is found, variable attributes, size, and data are returned +// using Attributes, DataSize, and Data parameters and EFI_SUCCESS is +// returned. If variable is not found, EFI_NOT_FOUND is returned. The output +// buffer is specified by a double indirection of the Data parameter. The +// input value of *Data is used to determine if the output buffer is caller +// allocated or is dynamically allocated by this functions. If the input +// value of *Data is not NULL, it indicates that the output buffer is caller +// allocated. In this case, the input value of *DataSize indicates the size +// of the caller-allocated output buffer. If the output buffer is not large +// enough to contain the variable data, it is freed and new buffer of +// sufficient size is allocated from boot services pool memory, which will be +// returned in *Data. If the input value of *Data not NULL, it indicates +// that the output buffer is allocated by GetEfiVariable routine. In this +// case, GetEfiVariable will allocate an appropriately sized buffer from boot +// services pool memory, which will be returned in *Data. +// +// Input: +// IN CHAR16 *sName +// Pointer to the null-terminated Unicode string with name of the EFI +// Variable to read. +// +// IN EFI_GUID *pGuid +// Pointer to GUID of the EFI Variable to read. +// +// OUT UINT32 *pAttributes OPTIONAL +// Pointer to the Attributes of the EFI Variable. +// +// IN OUT UINTN *pDataSize +// Pointer to the variable data size. +// +// OUT VOID **ppData +// Pointer to the variable data. +// +// Output: +// EFI_NOT_FOUND, if variable is not found. +// Otherwise, EFI_SUCCESS. +// +// Modified: +// +// Referrals: +// Malloc +// +// Notes: +// +// +//************************************************************************* +EFI_STATUS GetEfiVariable( + IN CHAR16 *sName, IN EFI_GUID *pGuid, + OUT UINT32 *pAttributes OPTIONAL, + IN OUT UINTN *pDataSize, OUT VOID **ppData +) +{ + EFI_STATUS Status; + if (!*ppData) *pDataSize=0; + Status = pRS->GetVariable(sName, pGuid, pAttributes, pDataSize, *ppData); + if (!EFI_ERROR(Status)) return Status; + if (Status==EFI_BUFFER_TOO_SMALL) + { + if (*ppData) pBS->FreePool(*ppData); + if (!(*ppData=Malloc(*pDataSize))) return EFI_OUT_OF_RESOURCES; + Status = pRS->GetVariable(sName, pGuid, pAttributes, pDataSize, *ppData); + } + return Status; +} + +//************************************************************************* +// +// +// Name: ReadImageResource +// +// Description: +// EFI_STATUS ReadImageResource(IN EFI_HANDLE ImageHandle, +// IN EFI_GUID *pGuid, OUT VOID **ppData, OUT UINTN *pDataSize) +// +// Input: +// +// Output: +// +// Modified: +// +// Referrals: +// +// Notes: +// +// +//************************************************************************* +EFI_STATUS ReadImageResource( + EFI_HANDLE ImageHandle, EFI_GUID *pGuid, + VOID **ppData, UINTN *pDataSize +) +{ + EFI_STATUS Status; + EFI_LOADED_IMAGE_PROTOCOL *pImage; + EFI_FIRMWARE_VOLUME_PROTOCOL *pFV; + UINTN i=0, DataSize; + EFI_GUID *pSectionGuid; + UINT32 Authentication; + Status=pBS->HandleProtocol(ImageHandle, &gEfiLoadedImageProtocolGuid, &pImage); + if (EFI_ERROR(Status)) return Status; + Status=pBS->HandleProtocol(pImage->DeviceHandle, &guidFV, &pFV); + if (EFI_ERROR(Status)) return Status; + do{ + pSectionGuid=NULL; + DataSize=0; + Status=pFV->ReadSection ( + pFV,&((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH*)(pImage->FilePath))->NameGuid, + EFI_SECTION_FREEFORM_SUBTYPE_GUID,i++, &pSectionGuid, &DataSize, + &Authentication + ); + if (!EFI_ERROR(Status)&&!guidcmp(pSectionGuid,pGuid)) break; + pBS->FreePool(pSectionGuid); + }while(!EFI_ERROR(Status)); + if (EFI_ERROR(Status)) return Status; + *ppData = pSectionGuid; + if (pDataSize) *pDataSize = DataSize; + return EFI_SUCCESS; +} + +//************************************************************************* +// +// +// Name: RegisterProtocolCallback +// +// Description: +// EFI_STATUS RegisterProtocolCallback(IN EFI_GUID *pProtocol, +// IN EFI_EVENT_NOTIFY NotifyFunction, IN VOID *pNotifyContext, +// OUT EFI_EVENT *pEvent, OUT VOID **ppRegistration) creates a notification +// event and registers that event with protocol instances specified by +// ProtocolGuid. Every time a protocol of type ProtocolGuid instance is +// installed or reinstalled, the notification function is executed. This +// function returns EFI_SUCCESS if notification event has been created. +// +// Input: +// IN EFI_GUID *pProtocol +// Supplies GUID of the protocol upon whose installation the event is fired. +// +// IN EFI_EVENT_NOTIFY NotifyFunction +// Supplies the function to notify when the event is signaled. +// +// IN VOID *pNotifyContext +// The context parameter to pass to NotifyFunction. This is an optional +// parameter and may be NULL. +// +// OUT EFI_EVENT *pEvent +// Event created event. +// +// OUT VOID **ppRegistration +// A pointer to a memory location to receive the registration value. This +// value is passed to LocateHandle() to obtain new handles that have been +// added that support the ProtocolGuid-specified protocol. +// +// Output: +// EFI_OUT_OF_RESOURCES, if space for the notification event could not be +// allocated. +// EFI_INVALID_PARAMETER, if Protocol, Event, or Registration are NULL. +// Otherwise, EFI_SUCCESS +// +// Modified: +// +// Referrals: +// +// Notes: +// +// +//************************************************************************* +EFI_STATUS RegisterProtocolCallback( + IN EFI_GUID *pProtocol, IN EFI_EVENT_NOTIFY NotifyFunction, + IN VOID *pNotifyContext, OUT EFI_EVENT *pEvent, + OUT VOID **ppRegistration +) +{ + EFI_STATUS Status; + Status = pBS->CreateEvent( + EVT_NOTIFY_SIGNAL,TPL_CALLBACK, + NotifyFunction, pNotifyContext, pEvent + ); + if (EFI_ERROR(Status)) return Status; + return pBS->RegisterProtocolNotify(pProtocol, *pEvent, ppRegistration); +} + +HII_UTILITIES_PROTOCOL *GetHiiUtilitiesInterface(){ + static HII_UTILITIES_PROTOCOL *HiiUtilities = NULL; + if ( HiiUtilities == NULL + && EFI_ERROR(pBS->LocateProtocol( + &gHiiUtilitiesProtocolGuid, NULL, &HiiUtilities + )) + //if LocateProtocol has failed, HiiUtilities is undefined. + //set it to NULL. + ) HiiUtilities = NULL; + return HiiUtilities; +} + +//************************************************************************* +// +// +// Name: HiiLibPublishPackages +// +// Description: Publishes submitted array of HII packages into HII database. +// +// Input: +// IN VOID *PackagePointers - array of pointers to the HII packages +// IN UINTN NumberOfPackages - number of pointers in the PackagePointers array +// IN EFI_GUID *PackageGuid - package list GUID +// IN EFI_HANDLE DriverHandle OPTIONAL - Handle to associate with the package list +// OUT EFI_HII_HANDLE *HiiHandle - HII handle of the package list +// +// Output: +// EFI_STATUS +// +// +//************************************************************************* +EFI_STATUS HiiLibPublishPackages( + IN VOID *PackagePointers, IN UINTN NumberOfPackages, + IN EFI_GUID *PackageGuid, IN EFI_HANDLE DriverHandle OPTIONAL, + OUT EFI_HII_HANDLE *HiiHandle +){ + HII_UTILITIES_PROTOCOL *HiiUtilities = GetHiiUtilitiesInterface(); + return + (HiiUtilities==NULL) + ? EFI_UNSUPPORTED + : HiiUtilities->PublishPackages( + PackagePointers, NumberOfPackages, + PackageGuid, DriverHandle, HiiHandle + ); +} + +//************************************************************************* +// +// +// Name: LoadStrings +// +// Description: +// EFI_STATUS LoadStrings(EFI_HANDLE ImageHandle, +// EFI_HII_HANDLE *pHiiHandle) - loads HII string packages associated with +// the specified image and publishes them to the HII database +// +// Input: +// EFI_HANDLE ImageHandle - Image Handle +// EFI_HII_HANDLE *pHiiHandle - HII package list handle +// +// Output: +// EFI_STATUS +// +// +//************************************************************************* +EFI_STATUS LoadStrings( + EFI_HANDLE ImageHandle, EFI_HII_HANDLE *pHiiHandle +) +{ + HII_UTILITIES_PROTOCOL *HiiUtilities = GetHiiUtilitiesInterface(); + return + (HiiUtilities==NULL) + ? EFI_UNSUPPORTED + : HiiUtilities->LoadStrings(ImageHandle, pHiiHandle); +} + +//************************************************************************* +// +// +// Name: LoadResources +// +// Description: +// EFI_STATUS LoadResources(EFI_HANDLE ImageHandle, +// UINTN NumberOfCallbacks, CALLBACK_INFO *pCallBack, +// INIT_HII_PACK InitFunction) - loads HII packages associated with +// the specified image and publishes them to the HII database +// +// Input: +// IN EFI_HANDLE ImageHandle - Image Handle +// IN UINTN NumberOfCallbacks - Number of the structures in the pCallBack array +// IN OUT CALLBACK_INFO *pCallBack - Array of IFR package descriptors. +// IN INIT_HII_PACK InitFunction - initialization function to be launched once resources are published. +// +// Output: +// EFI_STATUS +// +// +//************************************************************************* +EFI_STATUS LoadResources( + EFI_HANDLE ImageHandle, UINTN NumberOfCallbacks, + CALLBACK_INFO *pCallBack, INIT_HII_PACK InitFunction +) +{ + HII_UTILITIES_PROTOCOL *HiiUtilities = GetHiiUtilitiesInterface(); + return + (HiiUtilities==NULL) + ? EFI_UNSUPPORTED + : HiiUtilities->LoadResources( + ImageHandle, NumberOfCallbacks, + pCallBack, InitFunction + ); +} + +//************************************************************************* +// +// +// Name: HiiLibGetString +// +// Description: Reads string from the HII database in current language. +// +// Input: +// IN EFI_HII_HANDLE HiiHandle - Package list handle +// IN EFI_STRING_ID StringId - ID of the string to read +// IN OUT UINTN *StringSize - On entry, points to the size of the buffer pointed to by String, +// in bytes. On return, points to the length of the string, in bytes. +// OUT EFI_STRING String - Points to the output null-terminated string. +// +// Output: +// EFI_STATUS +// +// +//************************************************************************* +EFI_STATUS HiiLibGetString( + IN EFI_HII_HANDLE HiiHandle, IN STRING_REF StringId, + IN OUT UINTN *StringSize, OUT EFI_STRING String +){ + HII_UTILITIES_PROTOCOL *HiiUtilities = GetHiiUtilitiesInterface(); + return + (HiiUtilities==NULL) + ? EFI_UNSUPPORTED + : HiiUtilities->GetString(HiiHandle, StringId, StringSize, String); +} + +//************************************************************************* +// +// +// Name: HiiLibSetString +// +// Description: Updates string in the HII database in all languages supported by the package list. +// +// Input: +// IN EFI_HII_HANDLE HiiHandle - Package list handle +// IN EFI_STRING_ID StringId - ID of the string to udpate +// IN EFI_STRING String - Points to the new null-terminated string. +// +// Output: +// EFI_STATUS +// +// +//************************************************************************* +EFI_STATUS HiiLibSetString( + IN EFI_HII_HANDLE HiiHandle, IN STRING_REF StringId, IN EFI_STRING String +){ + HII_UTILITIES_PROTOCOL *HiiUtilities = GetHiiUtilitiesInterface(); + return + (HiiUtilities==NULL) + ? EFI_UNSUPPORTED + : HiiUtilities->SetString(HiiHandle, StringId,String); +} + +//************************************************************************* +// +// +// Name: HiiLibGetBrowserData +// +// Description: Retrieves uncommitted state data from the HII browser. +// Only works in UEFI 2.1 mode. +// +// Input: +// IN OUT UINTN *BufferSize - A pointer to the size of the buffer associated with Buffer. +// On input, the size in bytes of Buffer. On output, the size of data returned in Buffer. +// OUT VOID *Buffer - A data returned from an IFR browser. +// IN CONST EFI_GUID *VarStoreGuid OPTIONAL - An optional field to indicate the target variable GUID name to use. +// IN CONST CHAR16 *VarStoreName OPTIONAL - An optional field to indicate the target variable name. +// +// Output: +// EFI_STATUS +// +// +//************************************************************************* +EFI_STATUS HiiLibGetBrowserData( + IN OUT UINTN *BufferSize, OUT VOID *Buffer, + IN CONST EFI_GUID *VarStoreGuid OPTIONAL, + IN CONST CHAR16 *VarStoreName OPTIONAL +){ + HII_UTILITIES_PROTOCOL *HiiUtilities = GetHiiUtilitiesInterface(); + return + (HiiUtilities==NULL) + ? EFI_UNSUPPORTED + : HiiUtilities->GetBrowserData( + BufferSize, Buffer, VarStoreGuid, VarStoreName + ); +} + +//************************************************************************* +// +// +// Name: HiiLibSetBrowserData +// +// Description: Updates uncommitted state data of the HII browser. +// Only works in UEFI 2.1 mode. +// +// Input: +// IN UINTN BufferSize - Size of the buffer associated with Buffer. +// IN VOID *Buffer - A data to send to an IFR browser. +// IN CONST EFI_GUID *VarStoreGuid OPTIONAL - An optional field to indicate the target variable GUID name to use. +// IN CONST CHAR16 *VarStoreName OPTIONAL - An optional field to indicate the target variable name. +// +// Output: +// EFI_STATUS +// +// +//************************************************************************* +EFI_STATUS HiiLibSetBrowserData( + IN UINTN BufferSize, IN VOID *Buffer, + IN CONST EFI_GUID *VarStoreGuid, OPTIONAL + IN CONST CHAR16 *VarStoreName OPTIONAL +){ + HII_UTILITIES_PROTOCOL *HiiUtilities = GetHiiUtilitiesInterface(); + return + (HiiUtilities==NULL) + ? EFI_UNSUPPORTED + : HiiUtilities->SetBrowserData( + BufferSize, Buffer, VarStoreGuid, VarStoreName + ); +} + +//************************************************************************* +// +// +// Name: HiiLibSetString +// +// Description: Updates string in the HII database in all languages supported by the package list. +// +// Input: +// IN EFI_HII_HANDLE HiiHandle - Package list handle +// IN EFI_STRING_ID StringId - ID of the string to udpate +// IN EFI_STRING String - Points to the new null-terminated string. +// +// Output: +// EFI_STATUS +// +// +//************************************************************************* +EFI_STATUS HiiLibGetGlyphWidth( + IN CHAR16 Char, OUT UINT16 *Width +){ + HII_UTILITIES_PROTOCOL *HiiUtilities = GetHiiUtilitiesInterface(); + return + (HiiUtilities==NULL) + ? EFI_UNSUPPORTED + : HiiUtilities->GetGlyphWidth(Char, Width); +} + +//************************************************************************* +// +// +// Name: LibGetDxeSvcTbl +// +// Description: +// EFI_STATUS LibGetDxeSvcTbl(OUT DXE_SERVICES **ppDxe OPTIONAL) locates the +// DXE Service Table in the EFI System Table and returns it in ppDxe. If +// pointer is found, EFI_SUCCESS is returned. +// +// Input: +// OUT DXE_SERVICES **ppDxe OPTIONAL +// Places the address of the DXE Services Table at *ppDxe, if **ppDxe not +// equal to NULL. +// +// Output: +// EFI_INVALID_PARAMETER, if InitAmiLib() was not called prior to invoking +// this function. +// EFI_NOT_AVAILABLE_YET, if EFI Configuration Table does not have the DXE +// Services Table pointer initialized yet. +// Otherwise, EFI_SUCCESS. +// +// Modified: +// +// Referrals: +// GetEfiConfigurationTable +// +// Notes: +// +// +//************************************************************************* +EFI_STATUS LibGetDxeSvcTbl(DXE_SERVICES **ppDxe OPTIONAL){ + //Check if we have pST pointer initialized. + if(pST==NULL) return EFI_INVALID_PARAMETER; + if(pDxe==NULL){ + //Locate Dxe Services Table + pDxe=(DXE_SERVICES*)GetEfiConfigurationTable(pST,&guidDxeSvcTbl); + if(pDxe==NULL) return EFI_NOT_AVAILABLE_YET; + } + if(ppDxe!=NULL)*ppDxe=pDxe; + return EFI_SUCCESS; +} + +//************************************************************************* +// +// +// Name: LibAllocCspResource +// +// Description: +// EFI_STATUS LibAllocCspResource(IN CSP_RES_ITEM *ResTable, +// IN UINTN ResCount, IN EFI_HANDLE ImgHandle, IN EFI_HANDLE CntrHandle) uses +// GCD services to allocate list of resources specified by ResTable. +// +// Input: +// IN CSP_RES_ITEM *ResTable +// Table of requested GCD resources. +// +// IN UINTN ResCount +// Number of elements in the ResTable. +// +// IN EFI_HANDLE ImgHandle +// Handle of the image to allocate resources to. +// +// IN EFI_HANDLE CntrHandle +// Handle of the controller to allocate resources to. +// +// Output: +// EFI_ERROR_CODE, if function fails. +// Otherwise, EFI_SUCCESS. +// +// Modified: +// +// Referrals: +// LibGetDxeSvcTbl +// +// Notes: +// +// +//************************************************************************* +#define CACHEABILITY_ATTRIBUTES \ + (EFI_MEMORY_UC|EFI_MEMORY_WC|EFI_MEMORY_WT|EFI_MEMORY_WB|EFI_MEMORY_WP) +EFI_STATUS LibAllocCspResource(CSP_RES_ITEM *ResTable, UINTN ResCount, + EFI_HANDLE ImgHandle,EFI_HANDLE CntrHandle) +{ + UINTN i; + CSP_RES_ITEM *Res=NULL; + EFI_STATUS Status=0; + UINT64 top=0, bot=-1, len=0; + UINTN uccnt=0, memcnt=0; + EFI_GCD_MEMORY_SPACE_DESCRIPTOR mdsc; + EFI_GCD_IO_SPACE_DESCRIPTOR idsc; +//-------------------------------- + //Get Dxe Services Table + if(pDxe==NULL){ + Status=LibGetDxeSvcTbl(NULL); + if(EFI_ERROR(Status)){ + TRACE((-1, "Dxe Services Table could not be found! Status = %r",Status)); + ASSERT_EFI_ERROR(Status); + return Status; + } + } + //Add this Space as MMIO to the GCD + for(i=0; iAttributes==-1){ + Status=pDxe->AddIoSpace(Res->ResType,Res->ResBase,Res->ResLength); + TRACE((-1, "GCD: AddI/O")); + } else { + //Some attempt to optimize region caching + //we will try to group some regions based on their cache requirements. + memcnt++; + if(Res->Attributes & EFI_MEMORY_UC) uccnt++; + if((Res->ResBase+Res->ResLength) > top ) top=Res->ResBase+Res->ResLength; + if(Res->ResBase < bot) bot=Res->ResBase; + Status=pDxe->AddMemorySpace(Res->ResType,Res->ResBase,Res->ResLength,GCD_COMMON_MMIO_CAPS); + TRACE((-1, "GCD: AddMem")); + } + TRACE((-1, "Space B=%lX, L=%X, i=%d, S=%r\n",Res->ResBase,Res->ResLength,i,Status)); + + //Allocate the Space + if(Res->Attributes==-1) { + //Check Gcd IO we are trying to Allocate + Status=pDxe->GetIoSpaceDescriptor(Res->ResBase, &idsc); + if(idsc.ImageHandle != NULL) continue; + //If Space is not allocated but marked as different type of Space - use the one we got + else if(idsc.GcdIoType!=Res->ResType /*&& + idsc.BaseAddress<=Res->ResBase && + (idsc.BaseAddress+idsc.Length) >= (Res->ResBase+Res->ResLength)*/ + ) Res->ResType=idsc.GcdIoType; + Status=pDxe->AllocateIoSpace(EfiGcdAllocateAddress, + Res->ResType,0, Res->ResLength, &Res->ResBase, ImgHandle, CntrHandle); + TRACE((-1, "GCD: AllocI/O")); + } else { + //Check Gcd Memory we are trying to Allocate + Status=pDxe->GetMemorySpaceDescriptor(Res->ResBase, &mdsc); + //the resource has been allocated earlier by MRC or trough HOB + if(mdsc.ImageHandle != NULL) continue; + //If Space is not allocated but marked as different type of Space - use the one we got + else if(mdsc.GcdMemoryType!=Res->ResType /*&& + mdsc.BaseAddress<=Res->ResBase && + (mdsc.BaseAddress+mdsc.Length) >= (Res->ResBase+Res->ResLength)*/ + ) Res->ResType=mdsc.GcdMemoryType; + + Status=pDxe->AllocateMemorySpace(EfiGcdAllocateAddress, + Res->ResType, 0, Res->ResLength, &Res->ResBase, ImgHandle, CntrHandle); + TRACE((-1, "GCD: AllocMem")); + } + TRACE((-1, "Space B=%lX, L=%X, i=%d, S=%r\n",Res->ResBase,Res->ResLength,i,Status)); + if(EFI_ERROR(Status)){ + ASSERT_EFI_ERROR(Status); + return Status; + } + } //for loop for allocation + + //this is the case when entire region suppose to be uncached + if(memcnt && (memcnt==uccnt)){ + EFI_GCD_MEMORY_SPACE_DESCRIPTOR md; + UINT64 newb, newt, newl; + //---------------------- + //Adjust Caching Attribute Address to fit PAGES + len=top-bot; + if(bot & EFI_PAGE_MASK){ + bot&=(~EFI_PAGE_MASK); + len = (len&(~EFI_PAGE_MASK))+EFI_PAGE_SIZE; + } + if(len & EFI_PAGE_MASK) len = (len&(~EFI_PAGE_MASK))+EFI_PAGE_SIZE; + + //Now we must apply Caching attributes but must be wery careful + //not to clean RT attributes if it was set by earlier call + TRACE((-1, "GCD: SpaceAttr (UC ALL) B=%lX; L=%lX; \n",bot,top-bot)); + + newb=bot; + + for(;;){ + Status=pDxe->GetMemorySpaceDescriptor(newb,&md); + ASSERT_EFI_ERROR(Status); + if(EFI_ERROR(Status)) break; + + newt=md.BaseAddress+md.Length; + if(newt>=top) newt=top; + newl=newt-newb; + + if(md.Attributes & EFI_MEMORY_UC){ + TRACE((-1, "GCD:(UC ALL) skipping")); + } else { + md.Attributes|=EFI_MEMORY_UC; + Status=pDxe->SetMemorySpaceAttributes(newb,newl, md.Attributes); + TRACE((-1, "GCD:(UC ALL) setting ")); + } + TRACE((-1," B=%lX, L=%lX, A=%lX; S=%r\n",newb,newl,md.Attributes, Status)); + + if(newt>=top) break; + newb=newt; + } + + } + //set cacheability attributes + for(i=0; iSetMemorySpaceAttributes(ResTable[i].ResBase,ResTable[i].ResLength,ResTable[i].Attributes); + TRACE((-1, "GCD: SpaceAttr A=%lX B=%lX, L=%X, i=%X, S=%r\n", + ResTable[i].Attributes, ResTable[i].ResBase, ResTable[i].ResLength,i,Status)); + if EFI_ERROR(Status){ + //Attempt to set attributes failed; + //Let's set non-cacheability attributes + UINT64 attr=ResTable[i].Attributes & ~CACHEABILITY_ATTRIBUTES; + //If all descriptors are uncacheable add US attribute + if(memcnt==uccnt) attr|=EFI_MEMORY_UC; + Status=pDxe->SetMemorySpaceAttributes(ResTable[i].ResBase,ResTable[i].ResLength, attr); + } + } + return Status; +} + +//************************************************************************* +// +// +// Name: AllocCspResource +// +// Description: +// EFI_STATUS AllocCspResource(IN DXE_SERVICES *Dxe, +// IN CSP_RES_ITEM *ResTable, IN UINTN ResCount, IN EFI_HANDLE ImgHandle, +// IN EFI_HANDLE CntrHandle, IN BOOLEAN AddSpace) provides compatibility with +// core 4.5.3; acts as a wrapper for LibAllocCspResource. +// +// Input: +// IN DXE_SERVICES *Dxe +// Unused. +// +// IN CSP_RES_ITEM *ResTable +// Table of requested GCD resources. +// +// IN UINTN ResCount +// Number of elements in the ResTable. +// +// IN EFI_HANDLE ImgHandle +// Handle of the image to allocate resources to. +// +// IN EFI_HANDLE CntrHandle +// Handle of the controller to allocate resources to. +// +// IN BOOLEAN AddSpace +// Unused. +// +// Output: +// EFI_ERROR_CODE, if function fails. +// Otherwise, EFI_SUCCESS. +// +// Modified: +// +// Referrals: +// LibAllocCspResource +// +// Notes: +// Use LibAllocCspResource unless you are using core 4.5.3 or older. +// +// +//************************************************************************* +EFI_STATUS AllocCspResource(DXE_SERVICES *Dxe, CSP_RES_ITEM *ResTable, UINTN ResCount, + EFI_HANDLE ImgHandle,EFI_HANDLE CntrHandle, BOOLEAN AddSpace) +{ + return LibAllocCspResource(ResTable, ResCount,ImgHandle, CntrHandle); +} + +//************************************************************************* +// +// +// Name: GetSmstConfigurationTable +// +// Description: +// VOID *GetEfiConfigurationTable( IN EFI_GUID *TableGuid) +// retrieves a pointer to the system configuration table +// from the SMM System Table based on a specified GUID. If a match is found, +// then a pointer to the configuration table is returned. If a matching GUID +// is not found, then NULL is returned. +// +// Input: +// IN EFI_GUID *TableGuid +// Pointer to table's GUID type. +// +// Output: +// VOID* pointer to configuration table if a match is found; otherwise NULL. +// +// Referrals: +// guidcmp +// +// Notes: +// This function only works in SMM. It relies on global initialization performed +// by InitSmmHandler(or InitSmmHandlerEx) function. +// +// +//************************************************************************* +VOID* GetSmstConfigurationTableFramework(IN EFI_GUID *TableGuid){ + EFI_CONFIGURATION_TABLE *Table; + UINTN i; + + ASSERT(pSmstFramework!=NULL); //pSmstFramework must be initialized with the call to InitSmiHandler + if (pSmstFramework==NULL) return NULL; + Table = pSmstFramework->SmmConfigurationTable; + i = pSmstFramework->NumberOfTableEntries; + + for (;i;--i,++Table) + { + if (guidcmp(&Table->VendorGuid,TableGuid)==0) + return Table->VendorTable; + } + return NULL; +} + +#if PI_SPECIFICATION_VERSION >= 0x0001000A +VOID* GetSmstConfigurationTablePi(IN EFI_GUID *TableGuid){ + EFI_CONFIGURATION_TABLE *Table; + UINTN i; + + ASSERT(pSmstPi!=NULL); //pSmstFramework must be initialized with the call to InitSmiHandler + if (pSmstPi==NULL) return NULL; + Table = pSmstPi->SmmConfigurationTable; + i = pSmstPi->NumberOfTableEntries; + + for (;i;--i,++Table) + { + if (guidcmp(&Table->VendorGuid,TableGuid)==0) + return Table->VendorTable; + } + return NULL; +} +#endif + +//************************************************************************* +// +// +// Name: InitSmmHandler +// +// Description: +// EFI_STATUS InitSmmHandler(IN EFI_HANDLE ImageHandle, +// IN EFI_SYSTEM_TABLE *SystemTable, +// IN EFI_STATUS (*InSmmFunction)(EFI_HANDLE ImageHandle, +// EFI_SYSTEM_TABLE *SystemTable), +// IN EFI_STATUS (*NotInSmmFunction)(EFI_HANDLE ImageHandle, +// EFI_SYSTEM_TABLE *SystemTable) OPTIONAL) first calls the provided +// NotInSmmFunction (if provided), then runs the InSmmFunction in SMM. +// +// Input: +// IN EFI_HANDLE ImageHandle +// This driver's image handle. +// +// IN EFI_SYSTEM_TABLE *SystemTable +// Pointer to the system table. +// +// IN EFI_STATUS (*InSmmFunction)(EFI_HANDLE ImageHandle EFI_SYSTEM_TABLE *SystemTable) +// Pointer to the function to be run inside SMM. +// +// IN EFI_STATUS (*NotInSmmFunction)(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) OPTIONAL +// Pointer to the function to be run outside SMM. +// +// Output: +// EFI_NOT_FOUND, if the SMM Base Protocol is not installed. +// Otherwise, EFI_SUCCESS. +// +// Modified: +// +// Referrals: +// +// Notes: +// +// +//************************************************************************* +EFI_STATUS InitSmmHandlerFramework( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable, + IN EFI_STATUS (*InSmmFunction)(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable), + IN EFI_STATUS (*NotInSmmFunction)(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) OPTIONAL +) +{ + BOOLEAN InSmm; + EFI_STATUS Status; + EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; + EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath; + EFI_DEVICE_PATH_PROTOCOL *FilePath; + EFI_HANDLE Handle; + VOID *p; + + InitAmiLib(ImageHandle,SystemTable); + Status = pBS->LocateProtocol(&gEfiSmmBaseProtocolGuid, NULL, &pSmmBaseFramework); + if (EFI_ERROR(Status)) return Status; + + pSmmBaseFramework->InSmm(pSmmBaseFramework, &InSmm); + + if (!InSmm) { + //First do non InSmm initialization. + if (NotInSmmFunction) { + Status = NotInSmmFunction(ImageHandle,SystemTable); + if (EFI_ERROR(Status)) return Status; + } + + // Get this driver's image's FilePath + Status = pBS->HandleProtocol( + ImageHandle, &gEfiLoadedImageProtocolGuid, &LoadedImage); + if (EFI_ERROR(Status)) return Status; + + Status = pBS->HandleProtocol( + LoadedImage->DeviceHandle, &guidDevicePath, (VOID*)&ImageDevicePath + ); + if (EFI_ERROR(Status)) return Status; + + FilePath = DPAdd( + ImageDevicePath, LoadedImage->FilePath + ); + + //Load the image in Smram. The driver is called again in smm. + Status = pSmmBaseFramework->Register(pSmmBaseFramework, FilePath, NULL, 0, &Handle, FALSE); + pBS->FreePool(FilePath); + return Status; + } + + Status = pSmmBaseFramework->GetSmstLocation(pSmmBaseFramework,&pSmstFramework); + if (EFI_ERROR(Status)) return Status; + + p = GetSmstConfigurationTable(&SmmRsTableGuid); + if (p!=NULL) pRS = p; + IsInSmm = TRUE; + IsAtRuntime = FALSE; + LibInitStatusCodePtr(); + IsAtRuntime = TRUE; + return InSmmFunction(ImageHandle,SystemTable); +} + +#if PI_SPECIFICATION_VERSION >= 0x0001000A +EFI_STATUS InitSmmHandlerPi( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable, + IN EFI_STATUS (*InSmmFunction)(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable), + IN EFI_STATUS (*NotInSmmFunction)(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) OPTIONAL +) +{ + BOOLEAN InSmm; + EFI_STATUS Status; + VOID *p; + + InitAmiLib(ImageHandle,SystemTable); + Status = pBS->LocateProtocol(&gEfiSmmBase2ProtocolGuid, NULL, &pSmmBasePi); + if (!EFI_ERROR(Status)) pSmmBasePi->InSmm(pSmmBasePi, &InSmm); + + if (EFI_ERROR(Status) || !InSmm) { + //First do non InSmm initialization. + if (NotInSmmFunction) { + Status = NotInSmmFunction(ImageHandle,SystemTable); + } + return Status; + } + + Status = pSmmBasePi->GetSmstLocation(pSmmBasePi,&pSmstPi); + if (EFI_ERROR(Status)) return Status; + + p = GetSmstConfigurationTablePi(&SmmRsTableGuid); + if (p!=NULL) pRS = p; + IsInSmm = TRUE; + IsAtRuntime = FALSE; + LibInitStatusCodePtr(); + IsAtRuntime = TRUE; + return InSmmFunction(ImageHandle,SystemTable); +} +#endif + +EFI_STATUS InitAmiSmmLibFramework( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable) +{ + BOOLEAN InSmm; + EFI_STATUS Status; + VOID *p; + + InitAmiLib(ImageHandle,SystemTable); + if(pSmmBaseFramework==NULL){ + Status = pBS->LocateProtocol(&gEfiSmmBaseProtocolGuid, NULL, &pSmmBaseFramework); + if (EFI_ERROR(Status)) return Status; + } + + pSmmBaseFramework->InSmm(pSmmBaseFramework, &InSmm); + + if(InSmm){ + Status = pSmmBaseFramework->GetSmstLocation(pSmmBaseFramework,&pSmstFramework); + if (EFI_ERROR(Status)) return Status; + + p = GetSmstConfigurationTable(&SmmRsTableGuid); + if (p!=NULL) pRS = p; + IsAtRuntime = FALSE; + IsInSmm = TRUE; + LibInitStatusCodePtr(); + IsAtRuntime = TRUE; + } + return Status; +} + +#if PI_SPECIFICATION_VERSION >= 0x0001000A +EFI_STATUS InitAmiSmmLibPi( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable) +{ + BOOLEAN InSmm; + EFI_STATUS Status; + VOID *p; + + + InitAmiLib(ImageHandle,SystemTable); + if(pSmmBasePi==NULL){ + Status = pBS->LocateProtocol(&gEfiSmmBase2ProtocolGuid, NULL, &pSmmBasePi); + if (EFI_ERROR(Status)) return Status; + } + + pSmmBasePi->InSmm(pSmmBasePi, &InSmm); + + if(InSmm){ + Status = pSmmBasePi->GetSmstLocation(pSmmBasePi,&pSmstPi); + if (EFI_ERROR(Status)) return Status; + + p = GetSmstConfigurationTablePi(&SmmRsTableGuid); + if (p!=NULL) pRS = p; + IsInSmm = TRUE; + IsAtRuntime = FALSE; + LibInitStatusCodePtr(); + IsAtRuntime = TRUE; + } + return Status; +} +#endif + +static EFI_STATUS InitSmmCallback(IN EFI_EVENT Event, IN VOID *Context) +{ + EFI_DEVICE_PATH_PROTOCOL *FilePath; + EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath; + EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; + EFI_HANDLE Handle; + EFI_STATUS Status; + + Status = pBS->LocateProtocol(&gEfiSmmBaseProtocolGuid, NULL, &pSmmBaseFramework); + if (EFI_ERROR(Status)) return Status; + + // Get this driver's image's FilePath + Status = pBS->HandleProtocol( + TheImageHandle, &gEfiLoadedImageProtocolGuid, &LoadedImage + ); + if (EFI_ERROR(Status)) return Status; + + Status = pBS->HandleProtocol( + LoadedImage->DeviceHandle, &guidDevicePath, (VOID*)&ImageDevicePath + ); + if (EFI_ERROR(Status)) return Status; + + FilePath = DPAdd( + ImageDevicePath, LoadedImage->FilePath + ); + + //Load the image in Smram. The driver is called again in smm. + Status = pSmmBaseFramework->Register(pSmmBaseFramework, FilePath, NULL, 0, &Handle, FALSE); + pBS->FreePool(FilePath); + return Status; +} + +//************************************************************************* +// +// +// Name: InitSmmHandlerEx +// +// Description: +// The function is similar to InitSmmHandler function. +// The difference between the two is handling of missing SmmBase protocol. +// If SmmBase protocol is not available, InitSmmHandler function returns error. +// This function registers callback and loads module to SMM once SmmBase is available. +// +// Input: +// IN EFI_HANDLE ImageHandle +// This driver's image handle. +// +// IN EFI_SYSTEM_TABLE *SystemTable +// Pointer to the system table. +// +// IN EFI_STATUS (*InSmmFunction)(EFI_HANDLE ImageHandle EFI_SYSTEM_TABLE *SystemTable) +// Pointer to the function to be run inside SMM. +// +// IN EFI_STATUS (*NotInSmmFunction)(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) OPTIONAL +// Pointer to the function to be run outside SMM. +// +// Output: +// EFI_NOT_FOUND, if the SMM Base Protocol is not installed. +// Otherwise, EFI_SUCCESS. +// +// Modified: +// +// Referrals: +// +// Notes: +// +// +//************************************************************************* +EFI_STATUS InitSmmHandlerExFramework( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable, + IN EFI_STATUS (*InSmmFunction)(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable), + IN EFI_STATUS (*NotInSmmFunction)(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) OPTIONAL +) +{ + static BOOLEAN Registered = FALSE; + BOOLEAN InSmm = FALSE; + EFI_STATUS Status, SmmBaseStatus; + EFI_EVENT SmmBaseEvent; + VOID *p; + + InitAmiLib(ImageHandle,SystemTable); + SmmBaseStatus = pBS->LocateProtocol(&gEfiSmmBaseProtocolGuid, NULL, &pSmmBaseFramework); + + if (!EFI_ERROR(SmmBaseStatus)) pSmmBaseFramework->InSmm(pSmmBaseFramework, &InSmm); + if (EFI_ERROR(SmmBaseStatus) || !InSmm) + { + //First do non InSmm initialization. + if (NotInSmmFunction) { + Status = NotInSmmFunction(ImageHandle,SystemTable); + if (EFI_ERROR(Status)) return Status; + } + if (Registered) return Status; + if (EFI_ERROR(SmmBaseStatus)) + Status = RegisterProtocolCallback(&gEfiSmmBaseProtocolGuid, InitSmmCallback, + NULL, &SmmBaseEvent, &p + ); + else + Status = InitSmmCallback(NULL, NULL); + if (!EFI_ERROR(Status)) Registered = TRUE; + return Status; + } + Status = pSmmBaseFramework->GetSmstLocation(pSmmBaseFramework,&pSmstFramework); + if (EFI_ERROR(Status)) return Status; + p = GetSmstConfigurationTable(&SmmRsTableGuid); + if (p!=NULL) pRS = p; + IsAtRuntime = FALSE; + IsInSmm = TRUE; + LibInitStatusCodePtr(); + IsAtRuntime = TRUE; + return InSmmFunction(ImageHandle,SystemTable); +} + +//************************************************************************* +// +// +// Name: DummyFunction +// +// Description: +// VOID DummyFunction(IN EFI_EVENT Event, IN VOID *Context) is an empty +// VOID function which does nothing. +// +// Input: +// IN EFI_EVENT Event +// Unused. +// +// IN VOID *Context +// Unused. +// +// Output: +// VOID. +// +// Modified: +// +// Referrals: +// +// Notes: +// +// +//************************************************************************* +VOID DummyFunction(IN EFI_EVENT Event, IN VOID *Context) {} + +//************************************************************************* +// +// +// Name: CreateReadyToBootEvent +// +// Description: +// EFI_STATUS CreateReadyToBootEvent(IN EFI_TPL NotifyTpl, +// IN EFI_EVENT_NOTIFY NotifyFunction, IN VOID *pNotifyContext, +// OUT EFI_EVENT *pEvent) creates an EFI event in the Ready To Boot Event +// Group and allows the caller to specify a notification function. Prior to +// UEFI 2.0 this was done via a non-standard UEFI extension, and this library +// abstracts the implementation mechanism of this event from the caller. +// +// Input: +// IN EFI_TPL NotifyTpl +// The task priority level of the event. +// +// IN EFI_EVENT_NOTIFY NotifyFunction +// The notification function to call when the event is signaled. +// +// IN VOID *pNotifyContext +// The content to pass to NotifyFunction when the event is signaled. +// +// OUT EFI_EVENT *pEvent +// Return the event that was created. +// +// Output: +// EFI_INVALID_PARAMETER, if the input parameters are incorrect. +// EFI_OUT_OF_RESOURCES, if the event could not be allocated. +// Otherwise, EFI_SUCCESS. +// +// Modified: +// +// Referrals: +// +// Notes: +// +// +//************************************************************************* +EFI_STATUS CreateReadyToBootEvent( + IN EFI_TPL NotifyTpl, IN EFI_EVENT_NOTIFY NotifyFunction, + IN VOID *pNotifyContext, OUT EFI_EVENT *pEvent +) +{ +#if EFI_SPECIFICATION_VERSION<0x20000 + return pBS->CreateEvent( + (NotifyFunction) ? EFI_EVENT_SIGNAL_READY_TO_BOOT + : (EFI_EVENT_SIGNAL_READY_TO_BOOT | EFI_EVENT_NOTIFY_SIGNAL_ALL), + NotifyTpl, NotifyFunction, pNotifyContext, pEvent + ); +#else + static EFI_GUID guidReadyToBoot = EFI_EVENT_GROUP_READY_TO_BOOT; + return pBS->CreateEventEx( + EVT_NOTIFY_SIGNAL, NotifyTpl, + (NotifyFunction) ? NotifyFunction : DummyFunction, + pNotifyContext, &guidReadyToBoot, + pEvent + ); +#endif +} + +//************************************************************************* +// +// +// Name: CreateLegacyBootEvent +// +// Description: +// EFI_STATUS CreateLegacyBootEvent(IN EFI_TPL NotifyTpl, +// IN EFI_EVENT_NOTIFY NotifyFunction, IN VOID *pNotifyContext, +// OUT EFI_EVENT *pEvent) creates an EFI event in the Legacy Boot Event Group +// and allows the caller to specify a notification function. Prior to +// UEFI 2.0 this was done via a non-standard UEFI extension, and this library +// abstracts the implementation mechanism of this event from the caller. +// +// Input: +// IN EFI_TPL NotifyTpl +// The task priority level of the event. +// +// IN EFI_EVENT_NOTIFY NotifyFunction +// The notification function to call when the event is signaled. +// +// IN VOID *pNotifyContext +// The content to pass to NotifyFunction when the event is signaled. +// +// OUT EFI_EVENT *pEvent +// Return the event that was created +// +// Output: +// EFI_INVALID_PARAMETER, if the input parameters are incorrect. +// EFI_OUT_OF_RESOURCES, if the event could not be allocated. +// Otherwise, EFI_SUCCESS. +// +// Modified: +// +// Referrals: +// +// Notes: +// +// +//************************************************************************* +EFI_STATUS CreateLegacyBootEvent( + IN EFI_TPL NotifyTpl, IN EFI_EVENT_NOTIFY NotifyFunction, + IN VOID *pNotifyContext, OUT EFI_EVENT *pEvent +) +{ +#if EFI_SPECIFICATION_VERSION<0x20000 + return pBS->CreateEvent( + (NotifyFunction) ? EFI_EVENT_SIGNAL_LEGACY_BOOT + : (EFI_EVENT_SIGNAL_LEGACY_BOOT | EFI_EVENT_NOTIFY_SIGNAL_ALL), + NotifyTpl, NotifyFunction, pNotifyContext, pEvent + ); +#else + static EFI_GUID guidLegacyBoot = EFI_EVENT_LEGACY_BOOT_GUID; + return pBS->CreateEventEx( + EVT_NOTIFY_SIGNAL, NotifyTpl, + (NotifyFunction) ? NotifyFunction : DummyFunction, + pNotifyContext, &guidLegacyBoot, + pEvent + ); +#endif +} + +//************************************************************************* +// +// +// Name: GetBootMode +// +// Description: +// EFI_BOOT_MODE GetBootMode() returns current boot mode. If no boot mode +// information is available, BOOT_WITH_FULL_CONFIGURATION is returned. +// +// Input: +// VOID. +// +// Output: +// BOOT_WITH_FULL_CONFIGURATION, if no boot mode information is available. +// Otherwise, the current EFI_BOOT_MODE. +// +// Modified: +// +// Referrals: +// GetEfiConfigurationTable +// +// Notes: +// +// +//************************************************************************* +EFI_BOOT_MODE GetBootMode() +{ + static EFI_GUID guidHob = HOB_LIST_GUID; + EFI_HOB_HANDOFF_INFO_TABLE *pHit; + //Get Boot Mode + pHit = GetEfiConfigurationTable(pST, &guidHob); + return (pHit) ? pHit->BootMode : BOOT_WITH_FULL_CONFIGURATION; +} + +//********************************************************************** +// PERFORMANCE FUNCTIONS AND STRUCTURES +//********************************************************************** + +#define EFI_PERF_PEI_ENTRY_MAX_NUM 50 + +typedef struct { + CHAR8 Token[EFI_PERF_PDBFILENAME_LENGTH]; + UINT32 Duration; +} EFI_PERF_DATA; + +typedef struct { + UINT64 BootToOs; + UINT64 S3Resume; + UINT32 S3EntryNum; + EFI_PERF_DATA S3Entry[EFI_PERF_PEI_ENTRY_MAX_NUM]; + UINT64 CpuFreq; + UINT64 BDSRaw; + UINT32 Count; + UINT32 Signiture; +} EFI_PERF_HEADER; + +//************************************************************************* +// +// +// Name: PERF_START +// +// Description: +// PERF_START(Handle, Token, Host, Ticker) is a macro which invokes the +// StartMeasure function to log a timer entry for measuring performance if +// the DXE_PERFORMANCE SDL token is turned on. If the DXE_PERFORMANCE SDL +// token is turned off, the macro does nothing. +// +// Input: +// IN EFI_HANDLE Handle +// Handle to measure. +// +// IN CHAR16 *Token +// Token to measure. +// +// IN CHAR16 *Host +// Host to measure. +// +// IN UINT64 Ticker +// Set gauge data's StartTick. If 0, StartTick is current timer value. +// +// Output: +// EFI_OUT_OF_RESOURCES, if not enough memory available for new item. +// Otherwise, EFI_SUCCESS. +// +// Modified: +// +// Referrals: +// StartMeasure +// +// Notes: +// This macro is defined in AmiDxeLib.h. +// +// +//************************************************************************* + +//************************************************************************* +// +// +// Name: StartMeasure +// +// Description: +// EFI_STATUS StartMeasure (IN EFI_HANDLE Handle, IN CHAR16 *Token, +// IN CHAR16 *Host, IN UINT64 Ticker) starts timing on a specified handle, +// token and host, with Ticker as the start tick. See notes for proper +// usage. +// +// Input: +// IN EFI_HANDLE Handle +// Handle to measure. +// +// IN CHAR16 *Token +// Token to measure. +// +// IN CHAR16 *Host +// Host to measure. +// +// IN UINT64 Ticker +// Set gauge data's StartTick. If 0, StartTick is current timer. +// +// Output: +// EFI_OUT_OF_RESOURCES, if not enough memory available for new item. +// Otherwise, EFI_SUCCESS. +// +// Modified: +// +// Referrals: +// PERF_START +// +// Notes: +// To properly use this function, use the PERF_START macro defined in +// AmiDxeLib.h; this allows the DXE_PERFORMANCE SDL token to control +// enabling and disabling performance measurement in DXE. +// +// +//************************************************************************* +EFI_STATUS StartMeasure ( + IN EFI_HANDLE Handle, IN CHAR16 *Token, + IN CHAR16 *Host, IN UINT64 Ticker +) +{ + EFI_STATUS Status; + EFI_PERFORMANCE_PROTOCOL *Perf; + + Status = pBS->LocateProtocol (&gEfiPerformanceProtocolGuid, NULL, (VOID **) &Perf); + if (EFI_ERROR (Status)) { + return Status; + } + return Perf->StartGauge (Perf, Handle, Token, Host, Ticker); +} + +//************************************************************************* +// +// +// Name: PERF_END +// +// Description: +// PERF_END(Handle, Token, Host, Ticker) is a macro which invokes the +// EndMeasure function to stop timing for a performance entry in order to +// determine performance if the DXE_PERFORMANCE SDL token is turned on. If +// the DXE_PERFORMANCE SDL token is turned off, the macro does nothing. +// +// Input: +// IN EFI_HANDLE Handle +// Handle to stop. +// +// IN CHAR16 *Token +// Token to stop. +// +// IN CHAR16 *Host +// Host to stop. +// +// IN UINT64 Ticker +// End tick for timing; if 0, then EndMeasure gets current timer. +// +// Output: +// EFI_NOT_FOUND, if node or Performance Protocol not found. +// Otherwise, EFI_SUCCESS. +// +// Modified: +// +// Referrals: +// EndMeasure +// +// Notes: +// This macro is defined in AmiDxeLib.h. +// +// +//************************************************************************* + +//************************************************************************* +// +// +// Name: EndMeasure +// +// Description: +// EFI_STATUS EndMeasure(IN EFI_HANDLE Handle, IN CHAR16 *Token, +// IN CHAR16 *Host, IN UINT64 Ticker) ends timing on a specified handle, +// token and host, with Ticker as the end tick. See notes for proper usage. +// +// Input: +// IN EFI_HANDLE Handle +// Handle to stop. +// +// IN CHAR16 *Token +// Token to stop. +// +// IN CHAR16 *Host +// Host to stop. +// +// IN UINT64 Ticker +// End tick for timing; if 0, then EndMeasure gets current timer. +// +// Output: +// EFI_NOT_FOUND, if node or Performance Protocol not found. +// Otherwise, EFI_SUCCESS. +// +// Modified: +// +// Referrals: +// PERF_END +// +// Notes: +// To properly use this function, use the PERF_END macro defined in +// AmiDxeLib.h; this allows the DXE_PERFORMANCE SDL token to control +// enabling and disabling performance measurement in DXE. +// +// +//************************************************************************* +EFI_STATUS EndMeasure ( + IN EFI_HANDLE Handle, IN CHAR16 *Token, + IN CHAR16 *Host, IN UINT64 Ticker +) +{ + EFI_STATUS Status; + EFI_PERFORMANCE_PROTOCOL *Perf; + + Status = pBS->LocateProtocol (&gEfiPerformanceProtocolGuid, NULL, (VOID **) &Perf); + if (Status != EFI_SUCCESS) { + return Status; + } + return (Perf->EndGauge( Perf, Handle, Token, Host, Ticker)) ; +} + +//************************************************************************* +// +// +// Name: PERF_CODE +// +// Description: +// PERF_CODE(Code) is a macro which places the provided code block into the +// requested location if the DXE_PERFORMANCE SDL token is turned on. If the +// DXE_PERFORMANCE SDL token is turned off, the macro inserts nothing. +// +// Input: +// Code +// Block or line of code to be inserted if the DXE_PERFORMANCE SDL token is +// enabled. +// +// Output: +// VOID. +// +// Modified: +// +// Referrals: +// EndMeasure +// +// Notes: +// This macro is defined in AmiDxeLib.h. +// +// +//************************************************************************* + +//************************************************************************* +// +// +// Name: WriteBootToOsPerformanceData +// +// Description: +// VOID WriteBootToOsPerformanceData() allocates a block of memory and +// writes performance data into it. +// +// Input: +// VOID. +// +// Output: +// VOID. +// +// Modified: +// +// Referrals: +// GetCpuTimer +// Div64 +// Strcpy +// +// Notes: +// This function must only be called once; by default, it is called by BDS. +// +// +//************************************************************************* +VOID WriteBootToOsPerformanceData (){ + static EFI_PHYSICAL_ADDRESS AcpiLowMemoryBase = 0x00000000ffffffff; + static BOOLEAN FirstCall = TRUE; + + EFI_STATUS Status; + EFI_CPU_ARCH_PROTOCOL *Cpu; + EFI_PERFORMANCE_PROTOCOL *DrvPerf; + UINT32 AcpiLowMemoryLength; + UINT32 LimitCount; + EFI_PERF_HEADER PerfHeader; + EFI_PERF_DATA PerfData; + EFI_GAUGE_DATA *DumpData; + EFI_HANDLE *Handles; + UINTN NoHandles; + UINT8 *Ptr; + UINT8 *PdbFileName; + UINT32 Index; + UINT64 Ticker; + UINT64 Freq; + UINT32 Duration; + UINT64 CurrentTicker; + UINT64 TimerPeriod; + EFI_GUID gEfiGlobalVariableGuid = EFI_GLOBAL_VARIABLE; + IN CHAR8 *Dest; + IN CHAR16 *Src; + + + + // Retrive time stamp count as early as possilbe + Ticker = GetCpuTimer (); + + // Allocate a block of memory that contain performance data to OS for the first call + if(FirstCall) + { + Status = pBS->AllocatePages ( + AllocateMaxAddress, + EfiRuntimeServicesData, + 4, + &AcpiLowMemoryBase + ); + if (EFI_ERROR (Status)) { + return ; + } + } + + AcpiLowMemoryLength = EFI_PAGES_TO_SIZE(4); + + Ptr = (UINT8 *) ((UINT32) AcpiLowMemoryBase + sizeof (EFI_PERF_HEADER)); + LimitCount = (AcpiLowMemoryLength - sizeof (EFI_PERF_HEADER)) / sizeof (EFI_PERF_DATA); + + // Get performance architecture protocol + Status = pBS->LocateProtocol ( + &gEfiPerformanceProtocolGuid, + NULL, + &DrvPerf + ); + if (EFI_ERROR (Status)) { + pBS->FreePages (AcpiLowMemoryBase, 4); + return ; + } + // Initialize performance data structure + pBS->SetMem (&PerfHeader, sizeof (EFI_PERF_HEADER), 0); + + // Get CPU frequency + Status = pBS->LocateProtocol ( + &gEfiCpuArchProtocolGuid, + NULL, + &Cpu + ); + if (EFI_ERROR (Status)) { + pBS->FreePages (AcpiLowMemoryBase, 4); + return ; + } + // Get Cpu Frequency + Status = Cpu->GetTimerValue (Cpu, 0, &(CurrentTicker), &TimerPeriod); + if (EFI_ERROR (Status)) { + pBS->FreePages (AcpiLowMemoryBase, 4); + return ; + } + + Freq = Div64(1000000000000, (UINTN) TimerPeriod, NULL); + PerfHeader.CpuFreq = Freq; + + // Record current raw performance data + PerfHeader.BDSRaw = Ticker; + + // Put Detailed performance data into memory + Handles = NULL; + Status = pBS->LocateHandleBuffer ( + AllHandles, + NULL, + NULL, + &NoHandles, + &Handles + ); + if (EFI_ERROR (Status)) { + pBS->FreePages (AcpiLowMemoryBase, 1); + return ; + } + + // Get DXE drivers performance + for (Index = 0; Index < NoHandles; Index++) { + Ticker = 0; + PdbFileName = NULL; + DumpData = DrvPerf->GetGauge ( + DrvPerf, // Context + NULL, // Handle + NULL, // Token + NULL, // Host + NULL // PrecGauge + ); + while (DumpData) { + if (DumpData->Handle == Handles[Index]) { + PdbFileName = &(DumpData->PdbFileName[0]); + if (DumpData->StartTick < DumpData->EndTick) { + Ticker += (DumpData->EndTick - DumpData->StartTick); + } + } + + DumpData = DrvPerf->GetGauge ( + DrvPerf, // Context + NULL, // Handle + NULL, // Token + NULL, // Host + DumpData // PrecGauge + ); + } + + Duration = (UINT32) Div64 ( + Ticker, + (UINT32) Freq, + NULL + ); + + if (Duration > 0) { + pBS->SetMem (&PerfData, sizeof (EFI_PERF_DATA), 0); + + if (PdbFileName != NULL) { + Strcpy (PerfData.Token, PdbFileName); + } + + PerfData.Duration = Duration; + + pBS->CopyMem (Ptr, &PerfData, sizeof (EFI_PERF_DATA)); + Ptr += sizeof (EFI_PERF_DATA); + + PerfHeader.Count++; + if (PerfHeader.Count == LimitCount) { + goto Done; + } + } + } + + pBS->FreePool (Handles); + + // Get inserted performance data + DumpData = DrvPerf->GetGauge ( + DrvPerf, // Context + NULL, // Handle + NULL, // Token + NULL, // Host + NULL // PrecGauge + ); + while (DumpData) { + if ((DumpData->Handle) || (DumpData->StartTick > DumpData->EndTick)) { + DumpData = DrvPerf->GetGauge ( + DrvPerf, // Context + NULL, // Handle + NULL, // Token + NULL, // Host + DumpData // PrecGauge + ); + continue; + } + + pBS->SetMem (&PerfData, sizeof (EFI_PERF_DATA), 0); + + //convert CHAR16 string to CHAR8 string + Src = DumpData->Token; + Dest = (UINT8 *) PerfData.Token; + while (*Src) *Dest++ = (UINT8) (*Src++); + *Dest = 0; + + PerfData.Duration = (UINT32) Div64 ( + DumpData->EndTick - DumpData->StartTick, + (UINT32) Freq, + NULL + ); + + pBS->CopyMem(Ptr, &PerfData, sizeof (EFI_PERF_DATA)); + Ptr += sizeof (EFI_PERF_DATA); + + PerfHeader.Count++; + if (PerfHeader.Count == LimitCount) { + goto Done; + } + + DumpData = DrvPerf->GetGauge ( + DrvPerf, // Context + NULL, // Handle + NULL, // Token + NULL, // Host + DumpData // PrecGauge + ); + } + +Done: + PerfHeader.Signiture = 0x66726550; + + // Put performance data to memory + pBS->CopyMem ( + (UINTN *) (UINTN) AcpiLowMemoryBase, + &PerfHeader, + sizeof (EFI_PERF_HEADER) + ); + + if(FirstCall) + { + pRS->SetVariable ( + L"PerfDataMemAddrInternal", + &gAmiGlobalVariableGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, + sizeof (UINT32), + (VOID *) &AcpiLowMemoryBase); + + Status = pRS->SetVariable ( + L"PerfDataMemAddr", + &gAmiGlobalVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + sizeof (UINT32), + (VOID *) &AcpiLowMemoryBase); + + + TRACE((-1, "Setting PerfDataMemAddr Var. Status = %r",Status)); + if (EFI_ERROR (Status)) return; + FirstCall = FALSE; + + } +} + +static EFI_FPDT_STRUCTURE *FpdtVar = NULL; +//************************************************************************* +// +// +// Name: AmiFillFpdt +// +// Description: +// VOID AmiFillFpdt () Finds address of Bas Boot Perf Record and +// writes performance data into it, based on inpoot parameter. +// +// Input: +// FPDT_FILL_TYPE FieldToFill - Indicator which field in Bas Boot Perf Record to fill +// +// Output: +// VOID. +// +// +//************************************************************************* +VOID AmiFillFpdt (IN FPDT_FILL_TYPE FieldToFill){ + BASIC_BOOT_PERF_REC *BasBootPerRec; + EFI_STATUS StatusFpdt; + UINTN VarSize = sizeof(UINT32); + + if ((FpdtVar == NULL) || (FpdtVar->NanoFreq == 0) || (FpdtVar->BasBootPointer == 0)){ + StatusFpdt = pRS->GetVariable( + EFI_FPDT_VARIABLE, &gAmiGlobalVariableGuid, + NULL, &VarSize, &FpdtVar + ); + if (EFI_ERROR (StatusFpdt) || (FpdtVar->NanoFreq == 0) || (FpdtVar->BasBootPointer == 0)) + return; + } + if (((PERF_TAB_HEADER*)(UINT8*)(FpdtVar->BasBootPointer))->Signature != 0x54504246) + return; + BasBootPerRec = (BASIC_BOOT_PERF_REC*)((UINT8*)(FpdtVar->BasBootPointer) + sizeof(PERF_TAB_HEADER)); + if (BasBootPerRec->Header.PerfRecType != 2) return; + switch (FieldToFill) + { + case FillOsLoaderLoadImageStart: + + BasBootPerRec->OsLoaderLoadImageStart = Div64 (Mul64 (GetCpuTimer (), (UINTN)FpdtVar->NanoFreq), 1000000 , NULL); + break; + + case FillOsLoaderStartImageStart: + + BasBootPerRec->OsLoaderStartImageStart = Div64 (Mul64 (GetCpuTimer (), (UINTN)FpdtVar->NanoFreq), 1000000 , NULL); + break; + + case FillExitBootServicesEntry: + + BasBootPerRec->ExitBootServicesEntry = Div64 (Mul64 (GetCpuTimer (), (UINTN)FpdtVar->NanoFreq), 1000000 , NULL); + break; + + case FillExitBootServicesExit: + + BasBootPerRec->ExitBootServicesExit = Div64 (Mul64 (GetCpuTimer (), (UINTN)FpdtVar->NanoFreq), 1000000 , NULL); + break; + + } + +} + + + + +static INT32 NumberOfGoVirtualCallbacks=0; +static INT32 NumberOfExitBsCallbacks=0; +static EFI_RUNTIME_SERVICES *LibTempCopyOfpRs=NULL; + +static VOID AmiLibExitBs (IN EFI_EVENT Event, IN VOID *Context){ + IsAtRuntime=TRUE; + if (Context!=NULL) ((EFI_EVENT_NOTIFY)Context)(Event,NULL); + if (--NumberOfExitBsCallbacks==0){ + pBS = NULL; + LibTempCopyOfpRs = pRS; + } +} +static VOID AmiLibGoVirtual (IN EFI_EVENT Event, IN VOID *Context){ + IsInVirtualMode=TRUE; + if (Context!=NULL) ((EFI_EVENT_NOTIFY)Context)(Event,NULL); + if (--NumberOfGoVirtualCallbacks==0){ + // at this point it is not safe to use pRS + // because it may have been already converted to the virtual address + // by the library consumer. + LibTempCopyOfpRs->ConvertPointer(0,&pST); + LibTempCopyOfpRs->ConvertPointer(0,&pRS); + if (StatusCodePtr != NULL) LibTempCopyOfpRs->ConvertPointer(0,&StatusCodePtr); + } +} + +//************************************************************************* +// +// +// Name: InitAmiRuntimeLib +// +// Description: +// VOID InitAmiRuntimeLib(IN EFI_HANDLE ImageHandle, +// IN EFI_SYSTEM_TABLE *SystemTable, IN EFI_EVENT_NOTIFY ExitBsCallback OPTIONAL, +// IN EFI_EVENT_NOTIFY GoVirtualCallback OPTIONAL) initializes the global variables using call to InitAmiLib. +// Runtime drivers should use this function instead of InitAmiLib. +// +// Input: +// IN EFI_HANDLE ImageHandle +// The image handle. +// +// IN EFI_SYSTEM_TABLE *SystemTable +// Pointer to the EFI System Table. +// +// IN EFI_EVENT_NOTIFY ExitBsCallback OPTIONAL +// Optional Exit Boot Services callback function pointer +// +// IN EFI_EVENT_NOTIFY GoVirtualCallback OPTIONAL +// Optional Virtual Address Change callback function pointer +// +// Output: +// VOID. +// +// Modified: +// pST +// pBS +// pRS +// TheImageHandle +// +// Referrals: +// +// Notes: +// The global variables initialized by this function are: +// pST Pointer to the EFI System Table. +// pBS Pointer to the Boot Services Table. +// pRS Pointer to the Runtime Services Table. +// TheImageHandle Image handle. +// +// +//************************************************************************* +VOID EFIAPI InitAmiRuntimeLib( + IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable, + IN EFI_EVENT_NOTIFY ExitBsCallback OPTIONAL, + IN EFI_EVENT_NOTIFY GoVirtualCallback OPTIONAL +){ + EFI_EVENT Event; + InitAmiLib(ImageHandle,SystemTable); + LibInitStatusCodePtr(); + NumberOfExitBsCallbacks++; + NumberOfGoVirtualCallbacks++; + pBS->CreateEvent( + EVT_SIGNAL_EXIT_BOOT_SERVICES,TPL_CALLBACK, + &AmiLibExitBs, ExitBsCallback, &Event + ); + pBS->CreateEvent( + EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,TPL_CALLBACK, + &AmiLibGoVirtual, GoVirtualCallback, &Event + ); +} + +//************************************************************************* +// +// +// Name: EfiAtRuntime +// +// Description: +// BOOLEAN EFIAPI EfiAtRuntime ( VOID ) returns TRUE if system has already +// transitioned to runtime(ExitBootServices has been called), otherwise returns FALSE. +// This function can only be used is driver has been initialized using InitAmiRuntimeLib function. +// +// Input: +// None +// +// Output: +// BOOLEAN TRUE - system is in UEFI Runtime. +// FALSE - system is in the boot time. +// +// Referrals: +// InitAmiRuntimeLib +// +// Notes: +// This function can only be used if driver has been initialized using InitAmiRuntimeLib function. +// This function does not detect legacy boot. +// It will keep returning FALSE if called after the boot to legacy OS. +// +// +//************************************************************************* +BOOLEAN EFIAPI EfiAtRuntime ( VOID ) {return IsAtRuntime;} + +//************************************************************************* +// +// +// Name: EfiGoneVirtual +// +// Description: +// BOOLEAN EFIAPI EfiGoneVirtual ( VOID ) returns TRUE if system has already +// transitioned to the virtual addressing mode (SetVirtualAddressMap has been called), otherwise returns FALSE. +// This function can only be used is driver has been initialized using InitAmiRuntimeLib function. +// +// Input: +// None +// +// Output: +// BOOLEAN TRUE - system is in virtual addressing mode. +// FALSE - system is not in virtual addressing mode. +// +// Referrals: +// InitAmiRuntimeLib +// +// Notes: +// This function can only be used if driver has been initialized using InitAmiRuntimeLib function. +// +// +//************************************************************************* +BOOLEAN EFIAPI EfiGoneVirtual ( VOID ) {return IsInVirtualMode;} + +//************************************************************************* +// +// +// Name: StrcmpNoCase +// +// Description: +// Function compares two CHAR8 strings ignoring case for letters +// +// Input: +// CHAR8 *Str1 - pointer to first string +// CHAR8 *Str2 - pointer to second string +// +// Output: +// BOOLEAN TRUE - strings are equal (en-us is equal to en-US) +// FALSE - strings are not equal +// +// Referrals: +// None +// +// +//************************************************************************* +BOOLEAN StrcmpNoCase(CHAR8 *Str1, CHAR8 *Str2) +{ + CHAR8 Char1; + CHAR8 Char2; + while (*Str1) { + if(*Str1 != *Str2) { + Char1 = (*Str1 >= 0x41 && *Str1 <= 0x5a) ? *Str1 : (*Str1 >= 0x61 && *Str1 <= 0x7a) ? *Str1 - 0x20 : 0xff; + Char2 = (*Str2 >= 0x41 && *Str2 <= 0x5a) ? *Str2 : (*Str2 >= 0x61 && *Str2 <= 0x7a) ? *Str2 - 0x20 : 0; + if(Char1 != Char2) + return FALSE; + } + Str1++; + Str2++; + } + return (*Str1 == *Str2); +} + +//************************************************************************* +// +// +// Name: LanguageCodesEqual +// +// Description: +// BOOLEAN LanguageCodesEqual(CONST CHAR8* LangCode1, CONST CHAR8* LangCode2) +// compares two language codes and returns TRUE if they are equal. +// Case is ignored (RFC 4646 requirement) +// +// Input: +// CONST CHAR8* LangCode1 - first language code +// CONST CHAR8* LangCode2 - second language code +// +// Output: +// BOOLEAN TRUE - the language codes are equal +// FALSE - the language codes are not equal +// +// Notes: +// if EFI_SPECIFICATION_VERSION is greater than 0x00020000, the function +// expects language codes in RFC 4646 format. +// if EFI_SPECIFICATION_VERSION is less or equal than 0x00020000, the function +// expects language codes in ISO 639-2 format. +// +// +//************************************************************************* +BOOLEAN LanguageCodesEqual(CONST CHAR8* LangCode1, CONST CHAR8* LangCode2) { + return +#if EFI_SPECIFICATION_VERSION<=0x20000 + LangCode1[0]==LangCode2[0] + && LangCode1[1]==LangCode2[1] + && LangCode1[2]==LangCode2[2]; +#else + StrcmpNoCase((CHAR8*)LangCode1, (CHAR8*)LangCode2); +#endif +} + +VOID* _GetBootScriptSaveInterface(){ + static VOID* BootScriptSaveInterface = NULL; + static EFI_GUID gEfiBootScriptSaveInterfaceGuid = EFI_BOOT_SCRIPT_SAVE_GUID; + EFI_STATUS Status; + + if (BootScriptSaveInterface != NULL) return BootScriptSaveInterface; + ASSERT(pBS!=NULL) + Status = pBS->LocateProtocol( + &gEfiBootScriptSaveInterfaceGuid,NULL,&BootScriptSaveInterface + ); + if (EFI_ERROR(Status)) BootScriptSaveInterface = NULL; + return BootScriptSaveInterface; +} + +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2012, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** -- cgit v1.2.3