diff options
Diffstat (limited to 'Core/EM/SecurityPkg/SecSMIFlash')
-rw-r--r-- | Core/EM/SecurityPkg/SecSMIFlash/SecSMIFlash.c | 1810 | ||||
-rw-r--r-- | Core/EM/SecurityPkg/SecSMIFlash/SecSMIFlash.cif | 16 | ||||
-rw-r--r-- | Core/EM/SecurityPkg/SecSMIFlash/SecSMIFlash.dxs | 67 | ||||
-rw-r--r-- | Core/EM/SecurityPkg/SecSMIFlash/SecSMIFlash.mak | 108 | ||||
-rw-r--r-- | Core/EM/SecurityPkg/SecSMIFlash/SecSMIFlash.sdl | 74 | ||||
-rw-r--r-- | Core/EM/SecurityPkg/SecSMIFlash/VerifyFwCapsule.c | 790 |
6 files changed, 2865 insertions, 0 deletions
diff --git a/Core/EM/SecurityPkg/SecSMIFlash/SecSMIFlash.c b/Core/EM/SecurityPkg/SecSMIFlash/SecSMIFlash.c new file mode 100644 index 0000000..170461a --- /dev/null +++ b/Core/EM/SecurityPkg/SecSMIFlash/SecSMIFlash.c @@ -0,0 +1,1810 @@ +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2014, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** + +//********************************************************************** +// $Header: /Alaska/SOURCE/Modules/SecureFlashPkg/SecureSmiFlash/SecSMIFlash.c 61 9/10/14 5:03p Alexp $ +// +// $Revision: 61 $ +// +// $Date: 9/10/14 5:03p $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/SecureFlashPkg/SecureSmiFlash/SecSMIFlash.c $ +// +// 61 9/10/14 5:03p Alexp +// EIP176297: Harden external parameter checks in SW SMI API +// Fixes are made to address: +// #7. Arbitrary SMRAM overwrite in SetFlUpdMethod() +// #8. Integer overflow leading to buffer overflow in +// LoadFwImage in SecSMIFlash SMI handler +// +// 60 8/04/14 11:59a Alexp +// 1. Use internal RomLayout map to process Flash Erase/Write requests. +// Issue- new RomMap may be different - exposing rom holes in wrong +// places +// 2. SetFlUpdMethod() - SecSmiFlash.RomLayout is updated to a map from a +// new image but not used. +// Later may compare the maps to find inconsistencies. +// 3. BeforeSecureUpdate() - bug in calculating the flash range within +// RomArea +// +// 59 7/29/14 12:07p Alexp +// Add a code to erase existing CapsuleUpdate and FlashUdate vars +// Fixes the case when vars exist with different attributes which prevent +// SecSmiFlash to set new valid var. +// +// 57 7/03/14 10:16a Alexp +// EIP176297: Harden external parameter checks in SW SMI API +// +// 56 6/11/14 10:16a Alexp +// EIP#168391:The power button does not work with failed NVRAM +// - harden SmiS5CapsuleCallback() +// - memory allocation for gpEfiCapsuleHdr changed from runtime memory to +// SMRAM. +// +// 55 3/20/14 3:20p Alexp +// 1. EIP#159507 : S3 resume time improvement: Use EfiReservedMemoryType +// instead of EfiACPIMemoryNVS for large buffer allocations. +// FwCapsule buffer to be allocated below 4GB. +// 2. Allow gpPubKeyHndl to be accessed from externally linked code +// +// 54 1/24/14 4:02p Alexp +// SetFlUpdMethod() +// 1. Set SecSmiFlash.RomLayout only for Runtime and Capsule update +// 2. removed dummy code " SecSmiFlash.pFwCapsule = +// SecSmiFlash.pFwCapsule" +// +// 53 10/11/13 2:50p Alexp +// +// 52 6/21/13 10:56a Alexp +// EIP#125800: add more error checking in release mode inside +// InSmmFunction() +// +// 51 6/12/13 3:52p Alexp +// CapsuleValidate() made external function in SecSmiFlash API +// +// 50 6/06/13 4:03p Alexp +// EIP#125800 : Privilege escalation into SMM via Secure SMI Flash SMM +// driver via GetFlUpdPolicy and SetFlUpdMethod - BugID 305294 +// add IsAddressInSmram() checks inside exposed API functions +// +// 49 4/23/13 2:49p Alexp +// GetFlUpdPolicy() to return FwKey up to 256 bytes. +// +// +// 47 2/26/13 6:14p Alexp +// Set data size for Capsule Upd variable as +// size of (EFI_PHYSICAL_ADDRESS) +// +// +// 45 12/28/12 2:19p Alexp +// fix "cppcheck: code style issues +// +// 42 11/21/12 10:42a Alexp +// Replace direct calls to Hash() in CryptoLib with API calls +// +// 41 11/13/12 3:26p Alexp +// 1. Calculate offset to RomLayout table within FwCapsHdr instead of +// using hardwired location. Pkcs#7 +// cert will differ in size and offset may change +// 2. Remove assert after GetKey function. +// +// 40 11/09/12 5:44p Alexp +// fixed branch for FWCAPSULE_2_0_SUPPORT +// +// 39 10/18/12 10:17a Alexp +// Bug fix: make allocation of HashCtx buffer not to be dependent on +// CAPSULE_RECOVERY support. +// +// 38 8/28/12 4:12p Alexp +// fix spelling +// +// 37 8/22/12 9:40a Alexp +// Allow to insrtall SecSmi Flash handler if RomLayout map not detected +// during module Init +// +// 36 8/16/12 11:31a Alexp +// use global pSmmBase ptr in InSmmFunction() +// +// 35 7/25/12 6:21p Alexp +// replaced custom Capsule module defined _EFI_CAPSULE_BLOCK_DESCRIPTOR_ +// with generic UEFI EFI_CAPSULE_BLOCK_DESCRIPTOR structure +// +// 34 6/26/12 9:49a Alexp +// include GetRomLayout under +// #if RUNTIME_SECURE_UPDATE_FLOW == 1 +// +// 33 6/12/12 5:33p Alexp +// EIP74625:New Capsule PPI required by latest Intel's MRC code +// -Fw Capsule upload supports new Capsule_2_0 format without extra +// CapHdr in the Mailbox +// EIP90678: MonotonicCounter variable guid changed +// -Use AMI_GLOBAL_VARIABLE_GUID +// +// 30 5/21/12 4:55p Alexp +// keep a pointer to FwCaps Hdr withing Capsule image. Streamlines +// creation of Capsule Mailbox. +// +// 29 5/18/12 5:27p Alexp +// 1. Replace Hash PPI calls with calls to Crypto lib functions. +// 2. Enforce flash update security by replacing SMM Flash protocol +// Write/Erase functions with local functions +// 3. Include RomLayout map pointer to SecSmiFlash protocol table. Local +// RomMap table is replaced with new one from valid FwCapsule image +// +// 28 2/29/12 4:15p Alexp +// Removed "gAmiSig->GetKey" from driver entry point. Will use VerifyKey +// instead. FW Key may be stored as a Hash in FW Key file storage. +// +// 27 2/16/12 9:38a Alexp +// SetFlUpdMethod() - removed condition #if NEW_BIOS_MEM_ALLOC != 0 left +// out from older logic +// +// 26 2/03/12 2:42p Alexp +// Use SHA256 Hash for Hash table +// +// 25 1/27/12 12:14p Alexp +// move defines for HASH_TBL_... to SecSmiFlash header file +// +// 23 1/13/12 4:18p Alexp +// Replace "AFU_FLASH_PAGE_SIZE" with "FLASH_BLOCK_SIZE" +// +// 22 1/10/12 6:22p Alexp +// 1. Always perform Hash match for new bios data block with one +// calculated during Capsule verification +// 2. Flash block available for hashing is determined by SDL token +// FLASH_BLOCK_SIZE and not by AFU interface +// +// 21 12/16/11 1:19p Alexp +// Bug fix: UpdateCapsule() +// While preparing MailBox discriptor, the pointer gpCapsuleMailboxPtr +// went outside of allocated memory pEfiCapsuleHdr +// +// 19 12/01/11 3:34p Alexp +// 1.SmiS5CapsuleCallback-> Introduce a call to Chipset defined +// SBLib_ResetSystem(WarmReset) +// Call is included based on the SDL switch CSLIB_WARM_RESET_SUPPORTED +// It replaces sample oimplementation of WarmReset via S3 & RTC wake up +// 2. SetFlUpdMethod-> Add temp w/a for AFU rev 3.0. Wrong image size(0) +// is reported by AFU in pSessionBlock->FlUpdBlock.ImageSize +// 3. Updated conditional statements to match newly defined SDL tokens: +// INSTALL_SECURE_FLASH_SW_SMI_HNDL and CSLIB_WARM_RESET_SUPPORTED +// +// 17 11/30/11 8:11p Alexp +// 1. Replaced dependencies from WARM_REBOOT flag to generic +// FWCAPSULE_RECOVERY_SUPPORT +// 2. SetFlUpdMethod() corercted behavior of some AFU implementations for +// CApsule Set mode. Size should have been provided +// 3. Memory for Capsule Mailbox allocation moved form "EfiRuntime" to +// more appropriate "AcpiNvs" +// +// 16 11/11/11 12:50p Alexp +// fixed InSmmFunction() when building without FWCAPSULE_RECOVERY_SUPPORT +// +// 15 11/03/11 6:45p Alexp +// skip SecSMIFlashSMIHandler() if OFBD Secure Flash module is active +// +// 14 10/17/11 11:25a Alexp +// update Hdr & Footer. Clear BIOS buffer +// +// 13 10/11/11 12:28p Alexp +// add OFBD dependency +// +// 12 9/30/11 4:39p Alexp +// add porting notes +// +// 11 8/24/11 6:51p Alexp +// replaced CAPSULE_SUPPORT check to FWCAPSULE_RECOVERY_SUPPORT +// +// 10 8/24/11 11:30a Alexp +// Clear Capsule update capability in gFlUpdatePolicy.FlashUpdate if no +// Capsule Driver or WarmReboot tokens are defined +// +// 9 8/09/11 7:45p Alexp +// +// 8 8/09/11 9:54a Alexp +// bug fix: NEW #if NEW_BIOS_MEM_ALLOC != 0, OLD: #if NEW_BIOS_MEM_ALLOC +// +// 7 8/08/11 7:23p Alexp +// SetFlashUpdateVar - assign Attributes to SetVar via CounterHi variable. +// old init method "A | B | C" had wrong Attributes passed to the SetVar +// +// 6 8/06/11 11:35a Alexp +// LoadImage-> clear out FSHndl. Need to be set to valid value only if +// image Verification complete inside SetFlMethod +// +// 5 8/05/11 3:43p Alexp +// hardwire Flash Upd policy (staticly provided from SDL tokens) +// +// 4 7/21/11 3:13p Alexp +// removed mistakenly put while(1){} statement at the end of +// SmiS5CapsuleCallback() +// +// 3 7/20/11 7:20p Alexp +// removed dependency on Capsule module. +// +// 2 7/20/11 6:22p Alexp +// include sample implementation to enter S3 on AMD chipsets +// +// 1 7/01/11 4:41p Alexp +// +// 1 7/01/11 4:37p Alexp +// +// 10 6/24/11 4:32p Alexp +// move around debug comments +// +// 9 6/24/11 2:09p Alexp +// SetFlUpd: abort if capsule size passed by AFU is greater then allocated +// buffer in gRomFileSize +// +// 8 6/23/11 7:08p Alexp +// SetFlashUpd: update local buffer with Ptr to AFU allocated buffer with +// rom image +// +// 14 6/20/11 2:10p Alexp +// // AFU updates the address in CapsuleMailboxPtr if +// SetFlashMethod: update for the case if AFU provided address in memory +// for new BIOS image +// +// 7 6/17/11 5:47p Alexp +// bug fix: GetKey expects valid buffer size on input +// +// 6 6/01/11 12:35p Alexp +// fix FSHandle init value +// +// 5 5/25/11 8:31p Alexp +// forse Implemented flag to "1" if SecSMIFlash supported. ASFU would +// check for combination, Version>-12 and this flag to determine if SecSMI +// Flash API is supported +// +// 4 5/17/11 12:58p Alexp +// add build switch for location of temp BIOS image +// +// 3 5/12/11 7:58p Alexp +// +// 2 5/10/11 5:10p Alexp +// Hash guids are defined globally +// +// 1 5/10/11 10:01a Alexp +// +// 13 5/06/11 11:59a Alexp +// +// 12 5/02/11 3:22p Alexp +// merged capsule hdr and mailbox into one mem allocation unit +// +// 11 4/28/11 6:21p Alexp +// tbd: in release mode get FW pub key may fail +// +// 10 4/28/11 10:45a Alexp +// update Capsule mailbox format. Add extra Efi Capsule Hdr that will be +// discarded by CApsul PEI service while coalescing the Capsule into a Hob +// +// 8 4/22/11 4:36p Alexp +// temp debug: init MC field in FlashUpd var with 0 if MC Var is missing. +// +// 7 4/19/11 6:42p Alexp +// tested Reboot and Online flash. Recovery flow fails. +// +// 6 4/18/11 7:22p Alexp +// working version. Need to review HashTable as it may not be practical if +// block sizes do not mach BLOCK_SIZE +// +// 5 4/13/11 7:14p Alexp +// locate RomMap for easy location of Fid.ffs for VersionControl +// Create HashTable for uplaoded Fw Image. Used for runtime updates only +// generate FSHandle for future use +// +// 4 4/11/11 2:10p Alexp +// -Revision 12 and upper to support "Installed" field in Flash Info as +// bit mask +// -Add support for new CApsule SigningCert header +// - Replace PKpub with new FW Sign key as a root Platform key to verify +// Capsule Sig with +// +// 3 4/05/11 6:38p Alexp +// use GetVariable to get PK Pub key +// +// 2 3/11/11 6:51p Alexp +// +// 1 3/10/11 4:59p Alexp +// +// 1 3/03/11 6:34p Alexp +// +//********************************************************************** + +#include <Token.h> +#include <AmiDxeLib.h> +#include <Protocol\SmiFlash.h> +#include <Protocol\SmmBase.h> +#include <Protocol\SmmSwDispatch.h> +#include <Protocol\SmmSxDispatch.h> +#include <Protocol\DevicePath.h> +#include <Protocol\LoadedImage.h> +#include <AmiSmm.h> +//PI 1.1 ++ +#if defined(PI_SPECIFICATION_VERSION)&&(PI_SPECIFICATION_VERSION>=0x0001000A) +#include <Protocol\SmmAccess2.h> +#else +#include <Protocol\SmmAccess.h> +#endif + +#if FWCAPSULE_RECOVERY_SUPPORT == 1 +#include <Capsule.h> +#endif + +#include <AmiHobs.h> + +#include <Protocol\SecSmiFlash.h> +#include <Protocol\FlashProtocol.h> + +//---------------------------------------------------------------------- +// Module defined global variables +static EFI_GUID gSwSmiCpuTriggerGuid = SW_SMI_CPU_TRIGGER_GUID; +static EFI_GUID gEfiSmmSwDispatchProtocolGuid = EFI_SMM_SW_DISPATCH_PROTOCOL_GUID; +static EFI_GUID gEfiSmmSxDispatchProtocolGuid = EFI_SMM_SX_DISPATCH_PROTOCOL_GUID; +//extern EFI_GUID gEfiSmmSxDispatchProtocolGuid = EFI_SMM_SX_DISPATCH_PROTOCOL_GUID; + +// AMI_GLOBAL_VARIABLE_GUID must be defined in AmiLib.h (Core 4.6.5.4 +) +#if defined(AMI_GLOBAL_VARIABLE_GUID) +static EFI_GUID gAmiGlobalVariableGuid = AMI_GLOBAL_VARIABLE_GUID; +#else +static EFI_GUID gAmiGlobalVariableGuid = EFI_GLOBAL_VARIABLE; +#endif + +static EFI_GUID FlashUpdGuid = FLASH_UPDATE_GUID; + +EFI_GUID gFWCapsuleGuid = APTIO_FW_CAPSULE_GUID; +EFI_GUID gPRKeyGuid = PR_KEY_GUID; +EFI_GUID gFwCapFfsGuid = AMI_FW_CAPSULE_FFS_GUID; + +static FLASH_UPD_POLICY FlUpdatePolicy = {FlashUpdatePolicy, BBUpdatePolicy}; + +EFI_SHA256_HASH *gHashTbl = NULL; +UINT8 gHashDB[SHA256_DIGEST_SIZE]; +CRYPT_HANDLE gpPubKeyHndl; + +AMI_DIGITAL_SIGNATURE_PROTOCOL *gAmiSig; + +#if FWCAPSULE_RECOVERY_SUPPORT == 1 +static EFI_GUID CapsuleVendorGuid = EFI_CAPSULE_AMI_GUID; +EFI_CAPSULE_BLOCK_DESCRIPTOR *gpEfiCapsuleHdr = NULL; +#endif + +// BIOS allocates the space in AcpiNVS for new BIOS image to be uploaded by Flash tool +// Alternatively the buffer may be reserved within the SMM TSEG. Check NEW_BIOS_MEM_ALLOC Token +// AFU would have to execute a sequence of SW SMI calls to load new BIOS image to mem +UINTN gFwCapMaxSize = FWCAPSULE_IMAGE_SIZE; +UINT32 *pFwCapsuleLowMem = NULL; + +static EFI_SMRAM_DESCRIPTOR *mSmramRanges; +static UINTN mSmramRangeCount; +//---------------------------------------------------------------------- +// Flash Upd Protocol defines +//---------------------------------------------------------------------- +typedef EFI_STATUS (EFIAPI *FLASH_READ_WRITE)( + VOID* FlashAddress, UINTN Size, VOID* DataBuffer +); +typedef EFI_STATUS (EFIAPI *FLASH_ERASE)( + VOID* FlashAddress, UINTN Size +); + +FLASH_PROTOCOL *Flash; + +FLASH_READ_WRITE pFlashWrite; // Original Ptr inside FlashAPI +FLASH_ERASE pFlashErase; + +static UINT32 Flash4GBMapStart; +ROM_AREA *RomLayout = NULL; +//---------------------------------------------------------------------- + +//---------------------------------------------------------------------- +// UpFront Function definitions +BOOLEAN SupportUpdateCapsuleReset ( + VOID +); +EFI_STATUS CapsuleValidate ( + IN OUT UINT8 **pFwCapsule, + IN OUT APTIO_FW_CAPSULE_HEADER **pFwCapsuleHdr +); +EFI_STATUS LoadFwImage( + IN OUT FUNC_BLOCK *pFuncBlock +); +EFI_STATUS GetFlUpdPolicy( + IN OUT FLASH_POLICY_INFO_BLOCK *InfoBlock +); +EFI_STATUS SetFlUpdMethod( + IN OUT FUNC_FLASH_SESSION_BLOCK *pSessionBlock +); +EFI_STATUS FindCapHdrFFS( + IN VOID *pCapsule, + OUT UINT8 **pFfsData +); +BOOLEAN IsAddressInSmram ( + IN EFI_PHYSICAL_ADDRESS Buffer, + IN UINT64 Length +); + +//---------------------------------------------------------------------- +//<AMI_PHDR_START> +//---------------------------------------------------------------------- +// Procedure: SecSmiFlash +// +// Description: +// +// Input: +// +// Output: +// +// Returns: +// +//---------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_SEC_SMI_FLASH_PROTOCOL SecSmiFlash = { + LoadFwImage, + GetFlUpdPolicy, + SetFlUpdMethod, + CapsuleValidate, + 0,// pFwImageLowMem + 0,// RomLayout, + 0,// gSha256HashTbl, + 0,// FSHandle +}; + +#if FWCAPSULE_RECOVERY_SUPPORT == 1 + +#if CSLIB_WARM_RESET_SUPPORTED == 0 + +//#if (defined x64_BUILD && x64_BUILD == 1) +//VOID flushcaches(); +void DisableCacheInCR0(); +//#endif + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// FUNCTION: ReadRtcIndexedRegister +// +// DESCRIPTION: Used to read RTC register indexed by the argument +// +// Input: +// IN UINT8 Index Index of the register to read +// +// +// Output: +// UINT8 Current value of the register +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> +UINT8 ReadRtcIndexedRegister(IN UINT8 Index){ + + UINT8 Byte = IoRead8(0x70) & 0x80; // preserve bit 7 + IoWrite8(0x70, Index | Byte); + Byte = IoRead8(0x71); + return Byte; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// FUNCTION: ReadRtcIndexedRegister +// +// DESCRIPTION: Used to write to RTC register indexed by the argument +// +// Input: +// IN UINT8 Index Index of the register to write to +// +// IN UINT8 Value Value to write to the RTC register +// +// Output: +// VOID +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> +VOID WriteRtcIndexedRegister(IN UINT8 Index, IN UINT8 Value){ + + IoWrite8(0x70,Index | (IoRead8(0x70) & 0x80)); + IoWrite8(0x71,Value); +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: S3RTCresume +// +// Description: This function puts system into ACPI S3 State. +// if token ENABLE_RTC_ONE_SECOND_WAKEUP = 1, then it setups RTC +// 1 second alarm as well. +// +// Input: None +// +// Output: None, system will enter ACPI S3 State. +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID S3RTCresume (VOID) +{ + UINT32 IoData; + UINT8 Hour, Minute, Second; + BOOLEAN inBCD = TRUE; + + //flush caches befor going to S3 +//#if (defined x64_BUILD && x64_BUILD == 1) +// flushcaches(); + DisableCacheInCR0(); +//#else +// _asm wbinvd +//#endif + + // determine if RTC is in BCD mode + if( ReadRtcIndexedRegister(0xB) & 0x4 ) // bit 2 + inBCD = FALSE; + // wait for time update to complete before reading the values + while( ReadRtcIndexedRegister(0xA) & 0x80 ); // while bit 7 is set the + // time update is in progress + //read current hour, minute, second + Hour = ReadRtcIndexedRegister(0x4); + Minute = ReadRtcIndexedRegister(0x2); + Second = ReadRtcIndexedRegister(0x0); + + //convert second to decimal from BCD and increment by 1 + if(inBCD) + Second = (Second >> 4) * 10 + (Second & 0x0F); + Second += 2; + + if(Second > 59){ + Second -= 60; + if(inBCD) + Minute = (Minute >> 4) * 10 + (Minute & 0x0F); + Minute++; + if(Minute > 59){ + Minute = 0; + if(inBCD) + Hour = (Hour >> 4) * 10 + (Hour & 0x0F); + Hour++; + // check 24 hour mode/12 hour mode + if( ReadRtcIndexedRegister(0xB) & 0x2 ) {// bit 1 1=24hour else 12 hour + if(Hour > 23) + Hour = 0; + } else { + if(Hour > 11) + Hour = 0; + } + + if(inBCD) + Hour = Hour % 10 + ( (Hour / 10) << 4 ) ; + } + if(inBCD) + Minute = Minute % 10 + ( (Minute / 10) << 4 ) ; + } + + //convert from decimal to BCD + if(inBCD) + Second = Second % 10 + ( (Second / 10) << 4 ) ; + + //set the alarm + + WriteRtcIndexedRegister(0x5, Hour); + WriteRtcIndexedRegister(0x3, Minute); + WriteRtcIndexedRegister(0x1, Second); + //enable the alarm + WriteRtcIndexedRegister(0xB, ( ReadRtcIndexedRegister(0xB) | ((UINT8)( 1 << 5 )) )); + +// ========== PORTING REQUIRED =========================================================== +// Current implementation to simulate the Warm Reboot may not be sufficient on some platforms. +// S3 transition may require additional Chipset/Platform coding. +// If needed add any necessary OEM hooks to be able to put the system into S3 at the end of this handler +//======================================================================================== + + //set RTC_EN bit in PM1_EN to wake up from the alarm + IoWrite16(PM_BASE_ADDRESS + 0x02, ( IoRead16(PM_BASE_ADDRESS + 0x02) | (1 << 10) )); + + //Disable Sleep SMI to avoid SMI re-entrance. +// IoWrite16(PM_BASE_ADDRESS + 0x30, ( IoRead16(PM_BASE_ADDRESS + 0x30) & (~BIT4) )); + + //modify power management control register to reflect S3 + IoData = IoRead32(PM_BASE_ADDRESS + 0x04); + //following code is applicable to Intel PCH only. + IoData &= ~(0x1C00); + IoData |= 0x1400; //Suspend to RAM +/* + // AMD w/a to enter S3 state + IoData |= 0x2C00; //Suspend to RAM + { + UINT8 Temp8; + IoWrite8(0xCD6, 0x004); + Temp8 = IoRead8(0xCD7); + Temp8 &= ~(BIT7); + IoWrite8(0xCD6, 0x004); + IoWrite8(0xCD7, Temp8); + IoWrite8(0xCD6, 0x007); + IoWrite8(0xCD7, BIT7); + } +} +*/ + IoWrite32(PM_BASE_ADDRESS + 0x04, IoData ); +} +//#else +//extern SBLib_ResetSystem( IN EFI_RESET_TYPE ResetType ); +#endif +extern SBLib_ResetSystem( IN EFI_RESET_TYPE ResetType ); +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// FUNCTION: SmiS5CapsuleCallback +// +// DESCRIPTION: SMI handler to perform capsule reset (bounce from S5 to S3) +// ========== PORTING REQUIRED =========================================================== +// Current implementation to simulate the Warm Reboot may not be sufficient on some platforms. +// S3 transition may require additional Chipset/Platform coding. +// If needed add any necessary OEM hooks to be able to put the system into S3 at the end of this handler +//======================================================================================== +// +// Input: +// IN EFI_HANDLE DispatchHandle Handle of SMI dispatch +// protocol +// IN EFI_SMM_SX_DISPATCH_CONTEXT* DispatchContext Pointer to SMI dispatch +// context structure +// +// Output: +// VOID +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> +VOID SmiS5CapsuleCallback ( IN EFI_HANDLE DispatchHandle, + IN EFI_SMM_SX_DISPATCH_CONTEXT *DispatchContext +){ + EFI_PHYSICAL_ADDRESS IoData; + UINTN Size; + EFI_CAPSULE_HEADER *CapsuleHeader; + AMI_FLASH_UPDATE_BLOCK FlUpdateBlock; + + TRACE((TRACE_ALWAYS,"SecSMI. S5 Trap\n")); + + // + //Check if the Capsule update is supported by platform policy + // + if (!SupportUpdateCapsuleReset()) + return; + + Size=sizeof(AMI_FLASH_UPDATE_BLOCK); + if(EFI_ERROR(pRS->GetVariable(FLASH_UPDATE_VAR,&FlashUpdGuid, NULL, &Size, &FlUpdateBlock)) || + FlUpdateBlock.FlashOpType != FlCapsule) + return; + + // verify the FW capsule is in memory. + Size = sizeof(EFI_PHYSICAL_ADDRESS); + if(EFI_ERROR(pRS->GetVariable(CAPSULE_UPDATE_VAR,&CapsuleVendorGuid, NULL, &Size, &IoData))) + return; + + if(IoData != (EFI_PHYSICAL_ADDRESS)gpEfiCapsuleHdr || + !IsAddressInSmram((EFI_PHYSICAL_ADDRESS)IoData, sizeof(EFI_PHYSICAL_ADDRESS))) + return; + + CapsuleHeader = (EFI_CAPSULE_HEADER*)gpEfiCapsuleHdr[0].DataBlock; + // + // Compare GUID with APTIO_FW_CAPSULE_GUID + // + if (guidcmp (&CapsuleHeader->CapsuleGuid, &gFWCapsuleGuid)) + return; + +#if CSLIB_WARM_RESET_SUPPORTED == 1 + SBLib_ResetSystem(EfiResetWarm); +#else + S3RTCresume(); +#endif +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: SupportUpdateCapsuleReset +// +// Description: This function returns platform policy capability for capsule update via a system reset. +// +// Input: None +// +// Output: TRUE - memory can be preserved across reset +// FALSE - memory integrity across reset is not guaranteed +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +BOOLEAN SupportUpdateCapsuleReset ( + VOID +) +{ + // + //If the platform has a way to guarantee the memory integrity across a system reset, return + //TRUE, else FALSE. + // + if( (FlUpdatePolicy.FlashUpdate & FlCapsule) || + (FlUpdatePolicy.BBUpdate & FlCapsule)) + return TRUE; + + return FALSE; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: UpdateCapsule +// +// Description: This code prepares Capsule Update EFI Variable +// +// Input: +// IN EFI_CAPSULE_HEADER **CapsuleHeaderArray - array of pointers to capsule headers passed in +// +// Output: EFI_SUCCESS - capsule processed successfully +// EFI_INVALID_PARAMETER - CapsuleCount is less than 1,CapsuleGuid is not supported +// EFI_DEVICE_ERROR - capsule processing failed +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS UpdateCapsule ( + IN FUNC_FLASH_SESSION_BLOCK *pSessionBlock, + IN APTIO_FW_CAPSULE_HEADER *pFwCapsuleHdr +){ + EFI_STATUS Status; + EFI_CAPSULE_HEADER *pEfiCapsuleHdr = NULL; + EFI_CAPSULE_BLOCK_DESCRIPTOR *pCapsuleMailboxPtr; + UINT32 Attributes, Index; + + // + //Compare GUID with APTIO_FW_CAPSULE_GUID + // + if (!pFwCapsuleHdr || + guidcmp (&pFwCapsuleHdr->CapHdr.CapsuleGuid, &gFWCapsuleGuid) + ) + return EFI_DEVICE_ERROR; + + pCapsuleMailboxPtr = gpEfiCapsuleHdr; + Index = 0; +#if !defined(FWCAPSULE_2_0_SUPPORT) || FWCAPSULE_2_0_SUPPORT == 0 + pEfiCapsuleHdr = (EFI_CAPSULE_HEADER*)&pCapsuleMailboxPtr[4]; +// New Capsule PPI supports single CapHdr. +// construct dummy EfiCapHdr struct within pEfiCapsuleHdr as 1st element to be linked from Mailbox + MemCpy((VOID*)pEfiCapsuleHdr, &gFWCapsuleGuid, sizeof(EFI_GUID)); + pEfiCapsuleHdr->Flags = CAPSULE_FLAGS_PERSIST_ACROSS_RESET; + pEfiCapsuleHdr->HeaderSize = sizeof(EFI_CAPSULE_HEADER); + pEfiCapsuleHdr->CapsuleImageSize = pFwCapsuleHdr->CapHdr.CapsuleImageSize + sizeof(EFI_CAPSULE_HEADER); + // create ScatterGather list: use pre-allocated runtime memory + pCapsuleMailboxPtr[Index].Length = pEfiCapsuleHdr->HeaderSize; + pCapsuleMailboxPtr[Index].DataBlock = (EFI_PHYSICAL_ADDRESS)pEfiCapsuleHdr; + Index++; +#endif + pCapsuleMailboxPtr[Index].Length = pFwCapsuleHdr->CapHdr.HeaderSize; + pCapsuleMailboxPtr[Index].DataBlock = (EFI_PHYSICAL_ADDRESS)pFwCapsuleHdr; + pCapsuleMailboxPtr[Index+1].Length = pFwCapsuleHdr->CapHdr.CapsuleImageSize-pFwCapsuleHdr->CapHdr.HeaderSize; + if((UINT32*)pFwCapsuleLowMem == (UINT32*)pFwCapsuleHdr) { + // Fw Cap Hdr is on top of Payload + + pCapsuleMailboxPtr[Index+1].DataBlock = pCapsuleMailboxPtr[Index].DataBlock+pCapsuleMailboxPtr[Index].Length; + } else { + // Fw Cap Hdr is embedded inside Payload + pCapsuleMailboxPtr[Index+1].DataBlock = (EFI_PHYSICAL_ADDRESS)pFwCapsuleLowMem; + } + pCapsuleMailboxPtr[Index+2].Length = 0; + pCapsuleMailboxPtr[Index+2].DataBlock = 0; + // + //Check if the platform supports update capsule across a system reset + // + if (!SupportUpdateCapsuleReset()) { + return EFI_UNSUPPORTED; + } + // Erase prev copy + Status = pRS->SetVariable ( CAPSULE_UPDATE_VAR, &CapsuleVendorGuid,0,0,NULL); + Attributes = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS; + Status = pRS->SetVariable ( CAPSULE_UPDATE_VAR, &CapsuleVendorGuid, + Attributes, sizeof(EFI_PHYSICAL_ADDRESS),(VOID*)&pCapsuleMailboxPtr); + + if(!EFI_ERROR(Status)) + return Status; + + return EFI_DEVICE_ERROR; +} + +#endif //#if FWCAPSULE_RECOVERY_SUPPORT == 1 + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: SetFlashUpdateVar +// +// Description: This code finds if the capsule needs reset to update, if no, update immediately. +// +// Input: +// IN EFI_CAPSULE_HEADER **CapsuleHeaderArray - array of pointers to capsule headers passed in +// IN UINTN CapsuleCount - number of capsule +// IN EFI_PHYSICAL_ADDRESS ScatterGatherList - physical address of datablock list points to capsule +// +// Output: EFI_SUCCESS - capsule processed successfully +// EFI_INVALID_PARAMETER - CapsuleCount is less than 1,CapsuleGuid is not supported +// EFI_DEVICE_ERROR - capsule processing failed +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS SetFlashUpdateVar ( + IN FUNC_FLASH_SESSION_BLOCK *pSessionBlock +){ + EFI_STATUS Status; + UINTN Size; + UINT32 CounterHi; + + if(pSessionBlock->FlUpdBlock.FlashOpType == FlRecovery && + pSessionBlock->FlUpdBlock.FwImage.AmiRomFileName[0] == 0 + ) + return EFI_DEVICE_ERROR; + + CounterHi = 0; + Size = sizeof(UINT32); +// MonotonicCounter is a boot time service, hence the variable may have restricted access in runtime + if(EFI_ERROR(pRS->GetVariable(L"MonotonicCounter", &gAmiGlobalVariableGuid, + NULL, &Size, &CounterHi)) + ) +// return Status;//EFI_DEVICE_ERROR; +//SetMode should set FlashUpd even if no MC var detected. + CounterHi=0xffffffff; + + pSessionBlock->FlUpdBlock.MonotonicCounter = CounterHi; + CounterHi = (EFI_VARIABLE_NON_VOLATILE | + EFI_VARIABLE_RUNTIME_ACCESS | + EFI_VARIABLE_BOOTSERVICE_ACCESS); + // Erase prev copy + Status = pRS->SetVariable ( FLASH_UPDATE_VAR, &FlashUpdGuid,0,0,NULL); + Status = pRS->SetVariable ( FLASH_UPDATE_VAR, &FlashUpdGuid, CounterHi, + sizeof(AMI_FLASH_UPDATE_BLOCK), (VOID*) &pSessionBlock->FlUpdBlock + ); + + if(!EFI_ERROR(Status)) + return Status; + + return EFI_DEVICE_ERROR; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------- +// Procedure: GetFlUpdPolicy +// +// Description: +// +// Input: +// +// Output: +// +// Returns: +// +//---------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS GetFlUpdPolicy( + IN OUT FLASH_POLICY_INFO_BLOCK *InfoBlock +) +{ + UINT32 KeySize = DEFAULT_RSA_KEY_MODULUS_LEN; + +//TRACE((TRACE_ALWAYS,"SecSMI. GetPolicy. %X_%X\n",FlUpdatePolicy.FlashUpdate, FlUpdatePolicy.BBUpdate)); + + if(IsAddressInSmram((EFI_PHYSICAL_ADDRESS)InfoBlock, sizeof(FLASH_POLICY_INFO_BLOCK))) + return EFI_DEVICE_ERROR; + + MemCpy(&InfoBlock->FlUpdPolicy, &FlUpdatePolicy, sizeof(FLASH_UPD_POLICY)); + MemSet(&InfoBlock->PKpub, KeySize, 0xFF); + if(gpPubKeyHndl.BlobSize < KeySize) + KeySize = gpPubKeyHndl.BlobSize; + MemCpy(&InfoBlock->PKpub, gpPubKeyHndl.Blob, KeySize); + + InfoBlock->ErrorCode = 0; + + return EFI_SUCCESS; +} +//<AMI_PHDR_START> +//---------------------------------------------------------------------- +// Procedure: SetFlUpdMethod +// +// Description: +// +// Input: +// +// Output: +// +// Returns: +// +//---------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS SetFlUpdMethod( + IN OUT FUNC_FLASH_SESSION_BLOCK *pSessionBlock +) +{ + EFI_STATUS Status = EFI_DEVICE_ERROR; +#if RUNTIME_SECURE_UPDATE_FLOW == 1 + UINT32 HashBlock; + UINT32 BlockSize; + UINT8 *BlockAddr; +#endif + UINT32 *FSHandl; + APTIO_FW_CAPSULE_HEADER *pFwCapsuleHdr; + +//TRACE((TRACE_ALWAYS,"SecSMI. SetFlash\nSize : %X\n",pSessionBlock->FlUpdBlock.ImageSize)); + + if(IsAddressInSmram((EFI_PHYSICAL_ADDRESS)pSessionBlock, sizeof(FUNC_FLASH_SESSION_BLOCK))) + return EFI_DEVICE_ERROR; + +//if(pSessionBlock->FlUpdBlock.FlashOpType == FlRecovery) +//TRACE((TRACE_ALWAYS,"File Name: %s\n",pSessionBlock->FlUpdBlock.FwImage.AmiRomFileName)); +//else +//TRACE((TRACE_ALWAYS,"Image Adr: %X\n",pSessionBlock->FlUpdBlock.FwImage.CapsuleMailboxPtr[0])); + +//TRACE((TRACE_ALWAYS,"ROMmap : %X\n",pSessionBlock->FlUpdBlock.ROMSection)); +//TRACE((TRACE_ALWAYS,"FlOpType : %X\n",pSessionBlock->FlUpdBlock.FlashOpType)); +// Verify if chosen Flash method is compatible with FlUpd Policy + if(((pSessionBlock->FlUpdBlock.ROMSection & (1<<BOOT_BLOCK)) && (pSessionBlock->FlUpdBlock.FlashOpType & FlUpdatePolicy.BBUpdate)) || + (!(pSessionBlock->FlUpdBlock.ROMSection & (1<<BOOT_BLOCK))&& (pSessionBlock->FlUpdBlock.FlashOpType & FlUpdatePolicy.FlashUpdate)) + ){ + +//TRACE((TRACE_ALWAYS,"Buff Adr : %X\nBuff Size: %X\n",pFwCapsuleLowMem, gRomFileSize)); +//!!! make sure Flash blocks BOOT_BLOCK, MAIN_, NV_ and EC_ are matching enum types in FlashUpd.h + // Get Flash Update mode + switch(pSessionBlock->FlUpdBlock.FlashOpType) + { +#if FWCAPSULE_RECOVERY_SUPPORT == 1 + case FlCapsule: +#endif + case FlRuntime: + // common for FlRuntime or Capsule + if(pSessionBlock->FlUpdBlock.ImageSize > gFwCapMaxSize) + break; // suspecting buffer overrun. + + SecSmiFlash.pFwCapsule = pFwCapsuleLowMem; + // AFU updates the address in CapsuleMailboxPtr if + // it's capable of allocating large buffer to load entire FW Capsule image + if(pSessionBlock->FlUpdBlock.FwImage.CapsuleMailboxPtr[0] != 0 ) + { + if(IsAddressInSmram((EFI_PHYSICAL_ADDRESS)pSessionBlock->FlUpdBlock.FwImage.CapsuleMailboxPtr[0], + pSessionBlock->FlUpdBlock.ImageSize)) + return EFI_DEVICE_ERROR; +#if NEW_BIOS_MEM_ALLOC != 2 + if(SecSmiFlash.pFwCapsule != NULL) { + // prevent leaking of the SMM code to the external buffer + if(!IsAddressInSmram((EFI_PHYSICAL_ADDRESS)SecSmiFlash.pFwCapsule, sizeof(UINTN))) + return EFI_DEVICE_ERROR; + + MemCpy((UINT8*)SecSmiFlash.pFwCapsule, + (UINT8*)pSessionBlock->FlUpdBlock.FwImage.CapsuleMailboxPtr[0], + pSessionBlock->FlUpdBlock.ImageSize); + } + else +#endif + SecSmiFlash.pFwCapsule = (UINT32*)pSessionBlock->FlUpdBlock.FwImage.CapsuleMailboxPtr[0]; + } + // else AFU must've uploaded the image to designated SMM space using LoadFw command + + // verify we got a capsule at pFwCapsuleLowMem, update a ptr to FwCapHdr within Payload image + Status = CapsuleValidate((UINT8**)&(SecSmiFlash.pFwCapsule), &pFwCapsuleHdr); + if(!pFwCapsuleHdr || + EFI_ERROR(Status)) break; + // capture RomLayout from new Secure Image if it's loaded in memory and validated + SecSmiFlash.RomLayout = (ROM_AREA *)(UINTN)((UINT32)pFwCapsuleHdr+pFwCapsuleHdr->RomLayoutOffset); + if(pSessionBlock->FlUpdBlock.FlashOpType == FlRuntime) + { +#if RUNTIME_SECURE_UPDATE_FLOW == 1 + // Fill in gShaHashTbl Hash Table + BlockSize = FLASH_BLOCK_SIZE; + BlockAddr = (UINT8*)SecSmiFlash.pFwCapsule; + for(HashBlock = 0; HashBlock < SEC_FLASH_HASH_TBL_BLOCK_COUNT; HashBlock++) + { + + Status = gAmiSig->Hash(gAmiSig, &gEfiHashAlgorithmSha256Guid, + 1, &BlockAddr, (const UINTN*)&BlockSize, gHashTbl[HashBlock]); + if (EFI_ERROR(Status)) break; + BlockAddr+= (UINTN)(BlockSize); + } +#endif + // done for Runtime Upd + break; + } + // Set Capsule EFI Var if Capsule(Verify Capsule Mailbox points to FW_CAPSULE) + pSessionBlock->FlUpdBlock.ImageSize = pFwCapsuleHdr->CapHdr.CapsuleImageSize; +#if FWCAPSULE_RECOVERY_SUPPORT == 1 + Status = UpdateCapsule (pSessionBlock, pFwCapsuleHdr); + if(EFI_ERROR(Status)) break; +#endif + // common for Recovery or Capsule + case FlRecovery: + // Set FlUpd EFI Var (Get MC, verify RecFileName) + Status = SetFlashUpdateVar (pSessionBlock); + break; + + default: + Status = EFI_DEVICE_ERROR; + } + } + + // Set Error Status + if (Status != EFI_SUCCESS) { + SecSmiFlash.FSHandle = 0; + SecSmiFlash.pFwCapsule = NULL; + SecSmiFlash.RomLayout = RomLayout; // back to default RomLayout + pSessionBlock->FSHandle = 0; + pSessionBlock->ErrorCode = 1; + + return EFI_DEVICE_ERROR; + } + // FSHandle is updated if Capsule validation passed. + // Create FSHandle as 1st 4 bytes of gHashTbl. It must be different each time + // SetMethod is called with new Image + FSHandl = (UINT32*)gHashTbl; + SecSmiFlash.FSHandle = *FSHandl; // should be unique per Capsule; + pSessionBlock->FSHandle = SecSmiFlash.FSHandle; + pSessionBlock->ErrorCode = 0; + + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------- +// Procedure: LoadFwImage +// +// Description: Routine is called in a loop by the Flash tool. +// Depending on the OS environment, Flash tool passes either an entire +// Flash Image into SMM buffer or block by block. +// E.g AFUDOS could allocate a contiguous buffer for the entire ROM buffer, +// while certain OSes (Linux) may only allocate limited buffer sizes +// +// Input: FUNC_BLOCK -> Address, size +// +// Output: FUNC_BLOCK -> Status +// +// Returns: +// +//---------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS LoadFwImage( + IN OUT FUNC_BLOCK *pFuncBlock +) +{ + if(IsAddressInSmram((EFI_PHYSICAL_ADDRESS)pFuncBlock, sizeof(FUNC_BLOCK))) + return EFI_DEVICE_ERROR; + + // prevent leaking of the SMM code to the external buffer + if(IsAddressInSmram((EFI_PHYSICAL_ADDRESS)pFuncBlock->BufAddr, pFuncBlock->BlockSize)) + return EFI_DEVICE_ERROR; + + pFuncBlock->ErrorCode = 1; + + SecSmiFlash.FSHandle = 0; // clear out Hndl. Will be set to valid number in SetFlashMethod + SecSmiFlash.pFwCapsule = NULL; + SecSmiFlash.RomLayout = RomLayout; // back to default RomLayout + +//TRACE((TRACE_ALWAYS,"SecSMI. LoadImage at %X, size %X\n",(UINT32)pFwCapsuleLowMem + pFuncBlock->BlockAddr, pFuncBlock->BlockSize)); + + if(pFwCapsuleLowMem == NULL) + return EFI_DEVICE_ERROR; + +// assuming the address in 0 based offset in new ROM image + if((UINT64)((UINT32)pFwCapsuleLowMem + pFuncBlock->BlockAddr + pFuncBlock->BlockSize) > + (UINT64)((UINT32)pFwCapsuleLowMem + gFwCapMaxSize) + ) + return EFI_DEVICE_ERROR; + + MemCpy((VOID*)((UINT32)pFwCapsuleLowMem+pFuncBlock->BlockAddr), + (UINT8*)pFuncBlock->BufAddr, pFuncBlock->BlockSize); + + pFuncBlock->ErrorCode = (UINT8)MemCmp( + (VOID*)((UINT32)pFwCapsuleLowMem+pFuncBlock->BlockAddr), + (VOID*)pFuncBlock->BufAddr, pFuncBlock->BlockSize); + + pFuncBlock->ErrorCode = 0; + + return EFI_SUCCESS; +} +// End Secured Flash Update API + +#if RUNTIME_SECURE_UPDATE_FLOW == 1 +// <AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Name: BeforeSecureUpdate +// +// Description: Verifies if the Update range is protected by Signature +// 1. return Success if flash region is inside unSigned RomArea +// 2. if region is signed - compare its hash with pre-calculated Hash in smm +// and return pointer to internal DataBuffer +// +// Input: +// VOID* FlashAddress Pointer to address of a flash +// +// Output: Status +// +//-------------------------------------------------------------------------- +// <AMI_PHDR_END> +EFI_STATUS BeforeSecureUpdate ( + VOID* FlashAddress, UINTN Size, UINT8 **DataBuffer +) +{ + EFI_STATUS Status = EFI_SUCCESS; + ROM_AREA *Area; + UINT8 *BuffAddr; + UINT8 *PageAddr; + UINT8 HashCounter; + UINTN PageSize; + UINTN PageCount; + UINT32 *FSHandl; + + // enforce write protection if RomArea undefined + if ( RomLayout == NULL ) + Status = EFI_WRITE_PROTECTED; + + for (Area = RomLayout; Area && Area->Size!=0; Area++) + { + if(Area->Address == 0) // construct an Address field if not initialized + Area->Address = (UINT64)((0xFFFFFFFF - FLASH_SIZE) + 1)+Area->Offset; +//TRACE((-1, "RomArea %8X(%8X) + Size %8X = %8X, Attr %X\n",Area->Address,Area->Offset, Area->Size, (UINT64)((UINTN)Area->Address+Area->Size), Area->Attributes)); + if( + (((UINT64)FlashAddress >= (UINT64)(Area->Address)) && + ((UINT64)FlashAddress < (UINT64)(Area->Address+Area->Size))) + || + (((UINT64)(Area->Address) >= (UINT64)FlashAddress) && + ((UINT64)(Area->Address) < (UINT64)((UINT64)FlashAddress + Size))) ) + { + if (Area->Attributes & ROM_AREA_FV_SIGNED) + { + Status = EFI_WRITE_PROTECTED; + break; + } +//TRACE((-1, "\nSignAttr %x(%x)\nRomArea %8X, Size %8X, (%8X)\nFlsAddr %8X, Size %8X, (%8X)\n", Area->Attributes, (Area->Attributes & ROM_AREA_FV_SIGNED), +// Area->Address, Area->Size, (UINT64)((UINTN)Area->Address+Area->Size), +// (UINTN)FlashAddress, Size, (UINT64)((UINTN)FlashAddress+Size))); + } + } +//if(Status != EFI_WRITE_PROTECTED) { +// TRACE((-1, "SpiOffs %8X, Size %8X, (%8X)\n", (0-(UINTN)FlashAddress), Size, (0-(EFI_PHYSICAL_ADDRESS)((UINTN)FlashAddress+Size)))); +//} + if(Status == EFI_WRITE_PROTECTED && + (FlUpdatePolicy.FlashUpdate & FlRuntime) + ){ + // check Verify status by comparing FSHandl with gHashTbl[0] + // should be unique per Capsule; + FSHandl = (UINT32*)gHashTbl; + if(SecSmiFlash.FSHandle == 0 || + SecSmiFlash.FSHandle != *FSHandl) + return Status; // EFI_WRITE_PROTECTED + + PageSize = FLASH_BLOCK_SIZE; + PageCount=( (UINTN)FlashAddress - Flash4GBMapStart) / PageSize; + + if(SecSmiFlash.pFwCapsule != NULL) + { + // Flash Write -> Update ptr to internal Acpi NVS or SMM Buffer + BuffAddr = (UINT8*)SecSmiFlash.pFwCapsule; + PageAddr = (UINT8*)((UINTN)BuffAddr + (PageSize * PageCount)); + BuffAddr = (UINT8*)((UINTN)BuffAddr + ((UINTN)FlashAddress - Flash4GBMapStart)); + + Status = EFI_SUCCESS; + HashCounter = 2; // addr may rollover to next flash page + while(HashCounter-- && PageCount < SEC_FLASH_HASH_TBL_BLOCK_COUNT) + { + // compare calculated block hash with corresponding hash from the Hw Hash Table + // if no match -> make Size=0 to skip Flash Write Op + Status = gAmiSig->Hash(gAmiSig, &gEfiHashAlgorithmSha256Guid, + 1, (const UINT8**)&PageAddr, (const UINTN*)&PageSize, gHashDB); + if(EFI_ERROR(Status) || + MemCmp(gHashDB, SecSmiFlash.HashTbl[PageCount], SHA256_DIGEST_SIZE) + ){ +//TRACE((-1, "Hash Err! FlashBuff = %8X, Data = %8X, BlockAddr=%x, BlockSize=%x\n", BuffAddr, *((UINT32*)BuffAddr), PageAddr, Size)); + return EFI_WRITE_PROTECTED; + } + // repeat Hash check on next Flash Block if Write Block overlaps the Flash Block boundary + PageCount++; + PageAddr = (UINT8*)((UINTN)PageAddr + PageSize); + if((BuffAddr+Size) <= PageAddr) + break; + } + // Erase + if(DataBuffer != NULL) + *DataBuffer = BuffAddr; + } + } + + return Status; +} +// <AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Name: SecureFlashWrite +// +// Description: Allows to write to flash device is Secure Capsule is loaded into memory +// Function replacing Flash->Write API call +// +// Input: VOID* FlashAddress, UINTN Size, VOID* DataBuffer +// +// +// Output: EFI_SUCCESS +// +//-------------------------------------------------------------------------- +// <AMI_PHDR_END> +EFI_STATUS SecureFlashWrite ( + VOID* FlashAddress, UINTN Size, VOID* DataBuffer +) +{ + EFI_STATUS Status; + UINT8 *CurrBuff; + + CurrBuff = (UINT8*)DataBuffer; + Status = BeforeSecureUpdate(FlashAddress, Size, &CurrBuff); +//TRACE((-1, "SecSMIFlash Write %X, BuffAddr=%X(%X) Lock Status=%r\n", FlashAddress, DataBuffer, CurrBuff, Status)); + if(!EFI_ERROR(Status)) + return pFlashWrite(FlashAddress, Size, CurrBuff); + + return Status; +} + +// <AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Name: SecureFlashErase +// +// Description: Allows erase of flash device is Secure Capsule is loaded into memory +// Function replacing Flash->Erase API call +// +// Input: NON +// +// +// Output: EFI_SUCCESS +// +//-------------------------------------------------------------------------- +// <AMI_PHDR_END> +EFI_STATUS SecureFlashErase ( + VOID* FlashAddress, UINTN Size +) +{ + EFI_STATUS Status; + + Status = BeforeSecureUpdate(FlashAddress, Size, NULL); +//TRACE((-1, "SecSMIFlash Erase %X - %X Lock Status=%r\n", FlashAddress, Size, Status)); + if(!EFI_ERROR(Status)) + return pFlashErase(FlashAddress, Size); + + return Status;//EFI_SUCCESS; +} + +//********************************************************************** +//<AMI_PHDR_START> +// +// Procedure: GetFwCapFfs +// +// Description: Loads binary from RAW section of X firwmare volume +// +// Input: +// NameGuid - The guid of binary file +// Buffer - Returns a pointer to allocated memory. Caller must free it when done. +// Size - Returns the size of the binary loaded into the buffer. +// +// Output: Buffer - returns a pointer to allocated memory. Caller +// must free it when done. +// Size - returns the size of the binary loaded into the +// buffer. +// EFI_NOT_FOUND - Can't find the binary. +// EFI_LOAD_ERROR - Load fail. +// EFI_SUCCESS - Load success. +// +//<AMI_PHDR_END> +//********************************************************************** +EFI_STATUS +GetFwCapFfs ( + IN EFI_GUID *NameGuid, + IN OUT VOID **Buffer, + IN OUT UINTN *Size + ) +{ + EFI_STATUS Status; + UINTN HandleCount; + UINTN Index; + EFI_FIRMWARE_VOLUME_PROTOCOL *Fv; + EFI_HANDLE *HandleBuff; + UINT32 AuthenticationStatus; + + *Buffer=0; + *Size=0; + Status = pBS->LocateHandleBuffer (ByProtocol,&gEfiFirmwareVolumeProtocolGuid,NULL,&HandleCount,&HandleBuff); + if (EFI_ERROR (Status) || HandleCount == 0) { + return EFI_NOT_FOUND; + } + // + // Find desired image in all Fvs + // + for (Index = 0; Index < HandleCount; Index++) { + Status = pBS->HandleProtocol (HandleBuff[Index],&gEfiFirmwareVolumeProtocolGuid,&Fv); + + if (EFI_ERROR (Status)) { + continue;//return EFI_LOAD_ERROR; + } + // + // Try a raw file + // + Status = Fv->ReadSection ( + Fv, + NameGuid, //&gFwCapFfsGuid, + EFI_SECTION_FREEFORM_SUBTYPE_GUID,//EFI_SECTION_RAW + 0, //Instance + Buffer, + Size, + &AuthenticationStatus + ); + + if (Status == EFI_SUCCESS) break; + } + + pBS->FreePool(HandleBuff); + + if (Index >= HandleCount) { + return EFI_NOT_FOUND; + } + + return EFI_SUCCESS; +} + +// <AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Name: GetRomLayout +// +// Description: +// +// Input: +// IN EFI_HANDLE ImageHandle Image Handle +// IN EFI_SYSTEM_TABLE *SystemTable Pointer to System Table +// +// Output: EFI_STATUS +// +//-------------------------------------------------------------------------- +// <AMI_PHDR_END> +EFI_STATUS GetRomLayout( + IN EFI_SYSTEM_TABLE *SystemTable, + EFI_SMM_BASE_PROTOCOL *SmmBase, + OUT ROM_AREA **RomLayout +) +{ + EFI_STATUS Status; + static EFI_GUID HobListGuid = HOB_LIST_GUID; + static EFI_GUID AmiRomLayoutHobGuid = AMI_ROM_LAYOUT_HOB_GUID; + ROM_LAYOUT_HOB *RomLayoutHob; + UINTN RomLayoutSize=0, Size; + ROM_AREA *Area; + APTIO_FW_CAPSULE_HEADER *FwCapHdr; + UINT8* pFwCapHdr=NULL; + +// 1. Try to locate RomLayout from embedded CapHdr Ffs + Status = GetFwCapFfs(&gFwCapFfsGuid, &pFwCapHdr, &Size); + if(!EFI_ERROR(Status)) + { + // Skip over Section GUID + FwCapHdr = (APTIO_FW_CAPSULE_HEADER*)pFwCapHdr; + (UINT8*)FwCapHdr += sizeof (EFI_GUID); + Size -= sizeof (EFI_GUID); + *RomLayout = (ROM_AREA *)(UINTN)((UINT32)FwCapHdr+FwCapHdr->RomLayoutOffset); + RomLayoutSize = sizeof(ROM_AREA); + for (Area=*RomLayout; Area->Size!=0 && RomLayoutSize<=(Size - FwCapHdr->RomLayoutOffset); Area++) + { + RomLayoutSize+=sizeof(ROM_AREA); + } +// TRACE((-1, "Get Rom Map from the FwCap FFS at %X(size 0x%X)\nRomLayout offs %X(size 0x%X)\n", FwCapHdr, Size, FwCapHdr->RomLayoutOffset, RomLayoutSize)); + Area=*RomLayout; + } + else + { +// 2. Backup: Use primary RomLayout from Rom Layout HOB. +// This one does not yet report the Rom Hole regions + //----- Get HobList ------------------------------------- + RomLayoutHob = GetEfiConfigurationTable(SystemTable, &HobListGuid); + if (RomLayoutHob!=NULL) + { + // -------- Get RomLayoutHob ---------------------- + if (!EFI_ERROR( + FindNextHobByGuid(&AmiRomLayoutHobGuid, &RomLayoutHob) + )) + { + RomLayoutSize = RomLayoutHob->Header.Header.HobLength + - sizeof(ROM_LAYOUT_HOB); + + Area=(ROM_AREA*)((UINT8*)RomLayoutHob+1); + //TRACE((-1, "Get Default Rom Map from the Hob at %X\n", Area)); + } + } + } + if(RomLayoutSize) + { + //---Allocate memory in SMRAM for RomLayout--- + *RomLayout = NULL; + Status = pSmst->SmmAllocatePool(EfiRuntimeServicesData, RomLayoutSize,(void **)RomLayout); + if (EFI_ERROR(Status) || *RomLayout == NULL) + return EFI_NOT_FOUND; + + pBS->CopyMem( *RomLayout, Area, RomLayoutSize); + + if(pFwCapHdr) + pBS->FreePool(pFwCapHdr); + + return EFI_SUCCESS; + } + + return EFI_NOT_FOUND; +} +#endif //#if RUNTIME_SECURE_UPDATE_FLOW == 1 + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: IsAddressInSmram +// +// Description: CThis function check if the address is in SMRAM +// +// Input: +// Address - the buffer address to be checked. +// Range - the buffer length to be checked +// +// Output: +// TRUE this address is in SMRAM. +// FALSE this address is NOT in SMRAM. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> +BOOLEAN IsAddressInSmram ( + IN EFI_PHYSICAL_ADDRESS Buffer, + IN UINT64 Length +) +{ + UINTN Index; +//TRACE((TRACE_ALWAYS,"Addr in SMRAM %X_%X\n",Buffer, Length)); + for (Index = 0; Index < mSmramRangeCount; Index ++) { + if (((Buffer >= mSmramRanges[Index].CpuStart) && (Buffer < mSmramRanges[Index].CpuStart + mSmramRanges[Index].PhysicalSize)) || + ((mSmramRanges[Index].CpuStart >= Buffer) && (mSmramRanges[Index].CpuStart < Buffer + Length))) { +//TRACE((TRACE_ALWAYS,"TRUE\n")); + return TRUE; + } + } +//TRACE((TRACE_ALWAYS,"FALSE\n")); + return FALSE; +} + +// !!! do not install if OFBD SecFlash is installed +#if INSTALL_SECURE_FLASH_SW_SMI_HNDL == 1 +//<AMI_PHDR_START> +//---------------------------------------------------------------------- +// Procedure: SecSMIFlashSMIHandler +// +// Description: +// +// Input: +// +// Output: +// +// Returns: +// +//---------------------------------------------------------------------- +//<AMI_PHDR_END> +VOID SecSMIFlashSMIHandler ( + IN EFI_HANDLE DispatchHandle, + IN EFI_SMM_SW_DISPATCH_CONTEXT *DispatchContext +) +{ + EFI_SMM_CPU_SAVE_STATE *pCpuSaveState; + SW_SMI_CPU_TRIGGER *SwSmiCpuTrigger; + UINT8 Data; + UINT64 pCommBuff; + UINT32 HighBufferAddress = 0; + UINT32 LowBufferAddress = 0; + UINTN i; + UINTN Cpu = pSmst->CurrentlyExecutingCpu - 1; + + for (i = 0; i < pSmst->NumberOfTableEntries; ++i) { + if (guidcmp(&pSmst->SmmConfigurationTable[i].VendorGuid,&gSwSmiCpuTriggerGuid) == 0) { + break; + } + } + + //If found table, check for the CPU that caused the software Smi. + if (i != pSmst->NumberOfTableEntries) { + SwSmiCpuTrigger = pSmst->SmmConfigurationTable[i].VendorTable; + Cpu = SwSmiCpuTrigger->Cpu; + } + + // + // Found Invalid CPU number, return + // + if(Cpu == (UINTN) -1) { + return; + } + + Data = (UINT8)DispatchContext->SwSmiInputValue; + + pCpuSaveState = pSmst->CpuSaveState; + HighBufferAddress = pCpuSaveState[Cpu].Ia32SaveState.ECX; + LowBufferAddress = pCpuSaveState[Cpu].Ia32SaveState.EBX; + pCommBuff = HighBufferAddress; + pCommBuff = Shl64(pCommBuff, 32); + pCommBuff += LowBufferAddress; + +//TRACE((-1, "Sec SW SMI Flash Hook == 0x%x\n", Data)); + + switch(Data) + { + case SecSMIflash_Load: // 0x1d Send Flash Block to memory + LoadFwImage((FUNC_BLOCK *)pCommBuff); + break; + + case SecSMIflash_GetPolicy: // 0x1e Get Fl Upd Policy + GetFlUpdPolicy((FLASH_POLICY_INFO_BLOCK *)pCommBuff); + break; + + case SecSMIflash_SetFlash: // 0x1f Set Flash method + SetFlUpdMethod((FUNC_FLASH_SESSION_BLOCK *)pCommBuff); + break; + } +} +#endif +//<AMI_PHDR_START> +//---------------------------------------------------------------------- +// Procedure: InSmmFunction +// +// Description: +// +// Input: +// +// Output: +// +// Returns: +// +//---------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS InSmmFunction(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) +{ +#if INSTALL_SECURE_FLASH_SW_SMI_HNDL == 1 + EFI_SMM_SW_DISPATCH_PROTOCOL *pSwDispatch = NULL; + EFI_SMM_SW_DISPATCH_CONTEXT SwContext; + UINTN Index; +#endif +#if FWCAPSULE_RECOVERY_SUPPORT == 1 + EFI_SMM_SX_DISPATCH_CONTEXT SxDispatchContext; + EFI_SMM_SX_DISPATCH_PROTOCOL *SxDispatchProtocol; +#endif + + EFI_HANDLE Handle = NULL; + EFI_HANDLE DummyHandle = NULL; + EFI_STATUS Status; + + UINTN Size = 0; + UINT8 MinSMIPort = SecSMIflash_Load; //0x1d + //UINT8 MinSMIPort = SecSMIflash_GetPolicy; //0x1e; + UINT8 MaxSMIPort = SecSMIflash_SetFlash; //0x1f; + +//PI 1.1 ++ +#if defined(PI_SPECIFICATION_VERSION)&&(PI_SPECIFICATION_VERSION>=0x0001000A) + EFI_SMM_ACCESS2_PROTOCOL *SmmAccess; +#else + EFI_SMM_ACCESS_PROTOCOL *SmmAccess; +#endif + + InitAmiSmmLib( ImageHandle, SystemTable ); + + Status = pBS->LocateProtocol(&gAmiSmmDigitalSignatureProtocolGuid, NULL, &gAmiSig); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR(Status)) return Status; + +// Test if Root Platform Key is available,else - don't install Flash Upd security measures. + gpPubKeyHndl.Blob = NULL; + gpPubKeyHndl.BlobSize = 0; + Status = gAmiSig->GetKey(gAmiSig, &gpPubKeyHndl, &gPRKeyGuid, gpPubKeyHndl.BlobSize, 0); +//TRACE((TRACE_ALWAYS,"GetKey %r (%x, %d bytes)\n",Status, gpPubKeyHndl.Blob,gpPubKeyHndl.BlobSize)); + if (EFI_ERROR(Status) || gpPubKeyHndl.Blob == NULL) { + if(Status == EFI_BUFFER_TOO_SMALL) + return EFI_SUCCESS; + return Status; + } + // + // Get SMRAM information + // +//PI 1.1 ++ +#if defined(PI_SPECIFICATION_VERSION)&&(PI_SPECIFICATION_VERSION>=0x0001000A) + Status = pBS->LocateProtocol (&gEfiSmmAccess2ProtocolGuid, NULL, (VOID **)&SmmAccess); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR(Status)) return Status; +#else + Status = pBS->LocateProtocol(&gEfiSmmAccessProtocolGuid, NULL, &SmmAccess); + ASSERT_EFI_ERROR(Status); + if (EFI_ERROR(Status)) return Status; +#endif + Size = 0; + Status = SmmAccess->GetCapabilities (SmmAccess, &Size, NULL); + ASSERT (Status == EFI_BUFFER_TOO_SMALL); + if (Size==0) return EFI_NOT_FOUND; + Status = pSmst->SmmAllocatePool (EfiRuntimeServicesData,Size,(VOID **)&mSmramRanges); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR(Status)) return Status; + Status = SmmAccess->GetCapabilities (SmmAccess, &Size, mSmramRanges); + if (EFI_ERROR(Status)) return Status; + mSmramRangeCount = Size / sizeof (EFI_SMRAM_DESCRIPTOR); + // + // Allocate scratch buffer to hold entire Signed BIOS image for Secure Capsule and Runtime Flash Updates + // AFU would have to execute a sequence of SW SMI calls to push entire BIOS image to SMM + // + //NEW_BIOS_MEM_ALLOC == 2 AFU will allocate a buffer and provide pointer via SET_FLASH_METHOD API call. + // +#if NEW_BIOS_MEM_ALLOC == 0 + // + // Alternatively the buffer may be reserved within the SMM TSEG memory + // + Status = pSmmBase->SmmAllocatePool(pSmmBase, EfiRuntimeServicesData, gFwCapMaxSize, (void**)&pFwCapsuleLowMem); + +//TRACE((TRACE_ALWAYS,"SecSmiFlash: Alloc 0x%X bytes in SMM, %r\n",gRomFileSize, Status)); +#else +#if NEW_BIOS_MEM_ALLOC == 1 + // + // The buffer allocated in OS reserved memory below 4GB + // +// Status = pST->BootServices->AllocatePool(EfiReservedMemoryType, gRomFileSize, &pFwCapsuleLowMem); + pFwCapsuleLowMem = (UINT32*)0xFFFFFFFF; + Status = pST->BootServices->AllocatePages(AllocateMaxAddress, EfiReservedMemoryType, + EFI_SIZE_TO_PAGES(gFwCapMaxSize), (EFI_PHYSICAL_ADDRESS*)&pFwCapsuleLowMem); +//TRACE((TRACE_ALWAYS,"SecSmiFlash: AllocatePages=%X,(0x%x) %r\n",pFwCapsuleLowMem,gRomFileSize, Status)); +#endif +#endif + ASSERT_EFI_ERROR(Status); + if (EFI_ERROR(Status)) return Status; +#if NEW_BIOS_MEM_ALLOC < 2 + MemSet((void*)pFwCapsuleLowMem, gFwCapMaxSize, 0 ); +#endif + // + // Allocate space to hold a Hash table for all Flash blocks + // + Size = SEC_FLASH_HASH_TBL_SIZE; + Status = pSmmBase->SmmAllocatePool(pSmmBase, EfiRuntimeServicesData, Size, (void**)&gHashTbl); + if (EFI_ERROR(Status)) return Status; + MemSet((void*)gHashTbl, Size, 0xdb ); + +#if FWCAPSULE_RECOVERY_SUPPORT == 0 + FlUpdatePolicy.FlashUpdate &=~FlCapsule; + FlUpdatePolicy.BBUpdate &=~FlCapsule; +#else + // + // Reserve pool in smm runtime memory for capsule's mailbox list + // + Size = 4*sizeof(EFI_CAPSULE_BLOCK_DESCRIPTOR) + sizeof(EFI_CAPSULE_HEADER); // (4*16)+28 + Status = pSmmBase->SmmAllocatePool(pSmmBase, EfiRuntimeServicesData, Size, (void**)&gpEfiCapsuleHdr); +//TRACE((TRACE_ALWAYS,"Mailbox: AllocatePages=%X,(0x%x) %r\n",gpEfiCapsuleHdr,Size, Status)); + if (EFI_ERROR(Status)) return Status; + MemSet((void*)gpEfiCapsuleHdr, Size, 0 ); + + // + // Install callback on S5 Sleep Type SMI. Needed to transition to S3 if Capsule's mailbox ie pending + // Locate the Sx Dispatch Protocol + // + // gEfiSmmSxDispatch2ProtocolGuid + Status = pBS->LocateProtocol (&gEfiSmmSxDispatchProtocolGuid,NULL,&SxDispatchProtocol); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR(Status)) return Status; + // + // Register the callback for S5 entry + // + if (SxDispatchProtocol && SupportUpdateCapsuleReset()) { + SxDispatchContext.Type = SxS5; + SxDispatchContext.Phase = SxEntry; + Status = SxDispatchProtocol->Register (SxDispatchProtocol,SmiS5CapsuleCallback,&SxDispatchContext,&Handle); + ASSERT_EFI_ERROR (Status); + } + if (EFI_ERROR(Status)) goto Done; +#endif +#if RUNTIME_SECURE_UPDATE_FLOW == 1 +/* +AFU For Rom Holes in Runtime/Capsule upd + 1. Read full ROM image to ROM buffer + 2. Merge Rom Hole from input file to ROM buffer + 3. call "LoadImage" for full BIOS + 3. call "SetFlash" with Runtime update (NVRAM block should be unsigned!!!) + 4. calls to upd Rom hole -erase,write should pass +*/ + Status = GetRomLayout(SystemTable, pSmmBase, &RomLayout); +//TRACE((TRACE_ALWAYS,"SecSmiFlash: Get Rom Layout ptr=%X, %r\n",RomLayout, Status)); + // Rom Layout HOB may not be found in Recovery mode and if FW does not include built in FwCapsule Hdr file +// if (EFI_ERROR(Status)) goto Done; + // + // Trap the original Flash Driver API calls to enforce + // Flash Write protection in SMM at the driver API level + // + Status = pBS->LocateProtocol(&gFlashSmmProtocolGuid, NULL, &Flash); +//TRACE((TRACE_ALWAYS,"SecSmiFlash: Flash Protocol Fixup %X->%X\n",Flash->Write,SecureFlashWrite)); + if (EFI_ERROR(Status)) goto Done; + + // preserve org Flash API + pFlashWrite = Flash->Write; + pFlashErase = Flash->Erase; + // replace with local functions + Flash->Erase = SecureFlashErase; + Flash->Write = SecureFlashWrite; + // Calculate the flash mapping start address. This is calculated + // as follows: + // 1. Find the total size of the flash (FLASH_BLOCK_SIZE * NUMBER_OF_BLOCKS) + // 2. Subtract the total flash size from 4GB + Flash4GBMapStart = 0xFFFFFFFF - (FLASH_BLOCK_SIZE * NUMBER_OF_BLOCKS); + Flash4GBMapStart ++; +#endif + // + // Install Secure SMI Flash Protocol + // + SecSmiFlash.pFwCapsule = pFwCapsuleLowMem; + SecSmiFlash.HashTbl = gHashTbl; + SecSmiFlash.RomLayout = RomLayout; +// SecSmiFlash.FSHandle = 0; + Status = pBS->InstallMultipleProtocolInterfaces( + &DummyHandle, + &gSecureSMIFlashProtocolGuid,&SecSmiFlash, + NULL + ); + ASSERT_EFI_ERROR(Status); + if (EFI_ERROR(Status)) return Status; + + // + // Install SW SMI callbacks for 3 SecSMI Flash functions + // !!! do not install if OFBD SecFlash is installed + // +#if INSTALL_SECURE_FLASH_SW_SMI_HNDL == 1 + Status = pBS->LocateProtocol(&gEfiSmmSwDispatchProtocolGuid, NULL, &pSwDispatch); + ASSERT_EFI_ERROR(Status); + if (EFI_ERROR(Status)) return EFI_SUCCESS; + + for(Index=MinSMIPort;Index<=MaxSMIPort;Index++) + { + SwContext.SwSmiInputValue = Index; + Status = pSwDispatch->Register(pSwDispatch, SecSMIFlashSMIHandler, &SwContext, &Handle); + ASSERT_EFI_ERROR(Status); + if (EFI_ERROR(Status)) break; + //If any errors,unregister any registered SwSMI by this driver. + //If error, and driver is unloaded, then a serious problem would exist. + } +#endif +Done: + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------- +// Procedure: SecSMIFlashDriverEntryPoint +// +// Description: Secure SMI Flash driver init +// +// Input: +// +// Output: +// +// Returns: +// +//---------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS SecSMIFlashDriverEntryPoint( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable +) +{ + InitAmiLib(ImageHandle, SystemTable); + return InitSmmHandler(ImageHandle, SystemTable, InSmmFunction, NULL); +} + +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2014, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** diff --git a/Core/EM/SecurityPkg/SecSMIFlash/SecSMIFlash.cif b/Core/EM/SecurityPkg/SecSMIFlash/SecSMIFlash.cif new file mode 100644 index 0000000..5a62525 --- /dev/null +++ b/Core/EM/SecurityPkg/SecSMIFlash/SecSMIFlash.cif @@ -0,0 +1,16 @@ +<component> + name = "Secure SMIFlash" + category = ModulePart + LocalRoot = "CORE\EM\SecurityPkg\SecSMIFlash\" + RefName = "SecSMIFlash" +[files] +"SecSMIFlash.sdl" +"SecSMIFlash.mak" +"SecSMIFlash.dxs" +"SecSMIFlash.c" +"VerifyFwCapsule.c" +[parts] +"SecSMIFlashProtocols" +[dependOn] +"SMIFlash" +<endComponent> diff --git a/Core/EM/SecurityPkg/SecSMIFlash/SecSMIFlash.dxs b/Core/EM/SecurityPkg/SecSMIFlash/SecSMIFlash.dxs new file mode 100644 index 0000000..f28ae6d --- /dev/null +++ b/Core/EM/SecurityPkg/SecSMIFlash/SecSMIFlash.dxs @@ -0,0 +1,67 @@ +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2014, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 6145-F Northbelt Pkwy, Norcross, GA 30071 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** + +//********************************************************************** +// $Header: /Alaska/SOURCE/Modules/SecureFlashPkg/SecureSmiFlash/SecSMIFlash.dxs 4 3/18/14 3:12p Alexp $ +// +// $Revision: 4 $ +// +// $Date: 3/18/14 3:12p $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/SecureFlashPkg/SecureSmiFlash/SecSMIFlash.dxs $ +// +// 4 3/18/14 3:12p Alexp +// update year to 2014 in ftr & hdr +// +// 3 8/10/12 11:42a Alexp +// Removed dependency on Flash Update protocol +// +// +//********************************************************************** +//<AMI_FHDR_START> +// +// Name: SMIFlash_dxs +// +// Description: +// +//<AMI_FHDR_END> +//********************************************************************** + +#include <Protocol/SmiFlash.h> +#include <Protocol/SmmBase.h> +#include <Protocol/SmmSwDispatch.h> +#include <Protocol/AmiDigitalSignature.h> + +DEPENDENCY_START + EFI_SMI_FLASH_GUID AND + EFI_SMM_BASE_PROTOCOL_GUID AND + EFI_SMM_SW_DISPATCH_PROTOCOL_GUID AND + AMI_SMM_DIGITAL_SIGNATURE_PROTOCOL_GUID +DEPENDENCY_END + +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2014, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 6145-F Northbelt Pkwy, Norcross, GA 30071 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** diff --git a/Core/EM/SecurityPkg/SecSMIFlash/SecSMIFlash.mak b/Core/EM/SecurityPkg/SecSMIFlash/SecSMIFlash.mak new file mode 100644 index 0000000..25aae09 --- /dev/null +++ b/Core/EM/SecurityPkg/SecSMIFlash/SecSMIFlash.mak @@ -0,0 +1,108 @@ +#************************************************************************* +#************************************************************************* +#** ** +#** (C)Copyright 1985-2014, American Megatrends, Inc. ** +#** ** +#** All Rights Reserved. ** +#** ** +#** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +#** ** +#** Phone: (770)-246-8600 ** +#** ** +#************************************************************************* +#************************************************************************* + +#************************************************************************// +# $Header: /Alaska/SOURCE/Modules/SecureFlashPkg/SecureSmiFlash/SecSMIFlash.mak 14 3/18/14 3:12p Alexp $ +# +# $Revision: 14 $ +# +# $Date: 3/18/14 3:12p $ +#************************************************************************// +# Revision History +# ---------------- +# $Log: /Alaska/SOURCE/Modules/SecureFlashPkg/SecureSmiFlash/SecSMIFlash.mak $ +# +# 14 3/18/14 3:12p Alexp +# update year to 2014 in ftr & hdr +# +# 13 11/21/12 10:40a Alexp +# do not link CryptoLib with SecSmiFlash. +# +# 12 8/10/12 11:48a Alexp +# Removed build rules of now obsolete SecSmiFlashHooks +# +# 11 5/18/12 5:03p Alexp +# 1. Link Crypto Library with VerifyFwCap in Recovery boot flow.Use Hash +# functions only +# 2. Pass SEC_FLASH_GUID_DEFINES containing unique FwCap Ffs Guid and +# Section guids +# +# 10 12/01/11 5:30p Alexp +# restore build rules. When needed, PRESERVE_LIB eLink can be reused +# +# 9 12/01/11 3:37p Alexp +# Add Build target for SecSmiFlashHooks library. New lib is linked to +# SmiFlash and (or) OFBD SecFlash via PRESERVE_LIB eLink list +# +# 7 11/30/11 8:13p Alexp +# left optional link rules for future usage with Ofbd module +# +# 5 9/20/11 2:20p Alexp +# removed linkage of SecFlashHooks with ReFlash. +# +# 4 8/18/11 4:47p Alexp +# 1. Add Depex rule to launch SecSmiFlash after AimDigitalSig protocol is +# available +# 2. Link SecSMIFlashHooks to ReFlash driver. Needed to preserve +# SecureVars on Recovery style reFlash +# +# 3 8/11/11 5:32p Alexp +# updated header +# +# 2 8/05/11 3:28p Alexp +# add SMM_COMPILE flag to SecSMIFlashHook compile rules +# +#************************************************************************// + +all : SecSMIFlash + +SecSMIFlash : $(BUILD_DIR)\SecSMIFlash.mak SecSMIFlashBin + +$(BUILD_DIR)\SecSMIFlash.mak : $(SEC_SMI_FLASH_DIR)\SecSMIFlash.cif $(SEC_SMI_FLASH_DIR)\$(@B).mak $(BUILD_RULES) + $(CIF2MAK) $(SEC_SMI_FLASH_DIR)\SecSMIFlash.cif $(CIF2MAK_DEFAULTS) + +BUILD_SecSMIFlash_DIR = $(BUILD_DIR)\$(SEC_SMI_FLASH_DIR) + +SecSMIFlash_INCLUDES= \ + /I $(SEC_SMI_FLASH_DIR)\ + /I$(CORE_DIR) + +SecSMIFlash_OBJECTS = \ + $(BUILD_SecSMIFlash_DIR)\SecSMIFlash.obj \ + $(BUILD_SecSMIFlash_DIR)\VerifyFwCapsule.obj + +SecSMIFlashBin : $(AMIDXELIB) $(AMICSPLib) + $(MAKE) /$(MAKEFLAGS) $(BUILD_DEFAULTS)\ + /f $(BUILD_DIR)\SecSMIFlash.mak all\ + GUID=3BF4AF16-AB7C-4b43-898D-AB26AC5DDC6C\ + ENTRY_POINT=SecSMIFlashDriverEntryPoint\ + OBJECTS="$(SecSMIFlash_OBJECTS)" \ + "CFLAGS=$(CFLAGS) $(SEC_FLASH_GUID_DEFINES)" \ + TYPE=RT_DRIVER "EXT_HEADERS=$(BUILD_DIR)\token.h"\ + DEPEX1=$(SEC_SMI_FLASH_DIR)\SecSMIFlash.DXS DEPEX1_TYPE=EFI_SECTION_DXE_DEPEX \ + COMPRESS=1 + +#************************************************************************* +#************************************************************************* +#** ** +#** (C)Copyright 1985-2014, American Megatrends, Inc. ** +#** ** +#** All Rights Reserved. ** +#** ** +#** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +#** ** +#** Phone: (770)-246-8600 ** +#** ** +#************************************************************************* +#************************************************************************* diff --git a/Core/EM/SecurityPkg/SecSMIFlash/SecSMIFlash.sdl b/Core/EM/SecurityPkg/SecSMIFlash/SecSMIFlash.sdl new file mode 100644 index 0000000..f0ad04a --- /dev/null +++ b/Core/EM/SecurityPkg/SecSMIFlash/SecSMIFlash.sdl @@ -0,0 +1,74 @@ +TOKEN + Name = "SecSMIFlash_SUPPORT" + Value = "1" + Help = "Main switch to enable Secured SMIFlash support in Project" + TokenType = Boolean + TargetMAK = Yes + TargetH = Yes + Master = Yes +End + +TOKEN + Name = "INSTALL_SECURE_FLASH_SW_SMI_HNDL" + Value = "0" + Help = "Install SecFlash SW SMI callbacks. Not needed if OFBD Secure Flash is present" + TokenType = Boolean + TargetH = Yes +End + +TOKEN + Name = "NEW_BIOS_MEM_ALLOC" + Value = "1" + Help = "Memory buffer location for new BIOS image.\0-SMM TSEG, 1-ACPI NVS, 2-allocated by AFU" + Range = "0-1-2" + TokenType = Integer + TargetH = Yes +End + +TOKEN + Name = "CSLIB_WARM_RESET_SUPPORTED" + Value = "0" + Help = "1 - Chipset provides SBLib_ResetSystem(EfiResetWarm).\0 - Simulate Warm Reset via S3 & RTC resume." + TokenType = Boolean + TargetMAK = Yes + TargetH = Yes +End + +TOKEN + Name = "SwSmi_LoadFwImage" + Value = "0x1d" + Help = "SW SMI value for Load FW image to SMM RAM" + TokenType = Integer + TargetH = Yes +End + +TOKEN + Name = "SwSmi_GetFlashPolicy" + Value = "0x1e" + Help = "SW SMI value for Get Fl Upd Policy" + TokenType = Integer + TargetH = Yes +End + +TOKEN + Name = "SwSmi_SetFlashMethod" + Value = "0x1f" + Help = "SW SMI value for Set Fl Upd Method" + TokenType = Integer + TargetH = Yes +End + +PATH + Name = "SEC_SMI_FLASH_DIR" +End + +MODULE + Help = "Includes SecSMIFlash.mak to Project" + File = "SecSMIFlash.mak" +End + +ELINK + Name = "$(BUILD_DIR)\SecSMIFlash.ffs" + Parent = "FV_MAIN" + InvokeOrder = AfterParent +End diff --git a/Core/EM/SecurityPkg/SecSMIFlash/VerifyFwCapsule.c b/Core/EM/SecurityPkg/SecSMIFlash/VerifyFwCapsule.c new file mode 100644 index 0000000..b078df2 --- /dev/null +++ b/Core/EM/SecurityPkg/SecSMIFlash/VerifyFwCapsule.c @@ -0,0 +1,790 @@ +//************************************************************************* +//************************************************************************* +//** ** +//** (C)Copyright 1985-2014, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//************************************************************************* +//************************************************************************* + +//********************************************************************** +// $Header: /Alaska/SOURCE/Modules/SecureFlashPkg/SecureSmiFlash/VerifyFwCapsule.c 30 7/03/14 10:15a Alexp $ +// +// $Revision: 30 $ +// +// $Date: 7/03/14 10:15a $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/SecureFlashPkg/SecureSmiFlash/VerifyFwCapsule.c $ +// +// 30 7/03/14 10:15a Alexp +// EIP176297: Fix bug in condition expresison inside For loops. +// +// 29 5/20/14 5:22p Alexp +// Replace a var name gRomFileSize to a more appropriate gFwCapMaxSize +// +// 27 3/20/14 12:31p Alexp +// 1. Don't re-read FwKey. Use gpPubKeyHndl +// 2. CapsuleValidate: sanity check: FwCapHdr RomImageOffset checked +// against max size +// (FWCAPSULE_IMAGE_SIZE-FLASH_SIZE) +// 3. CapsuleValidate: add parameter check pFWCapsuleHdr != NULL +// +// 26 8/22/13 11:34a Alexp +// VerifyFwCertRsa2048Sha256() - Break a loop after RootCert Verify if key +// match is found. Old code would cycle through all certs. +// +// 25 8/12/13 4:31p Alexp +// add check for end of Certificate block marker +// +// 24 7/11/13 3:41p Alexp +// Removed check for FWCAPSULE_MAX_HDR_SIZE. Replaced it with fixed 0x8000 +// value +// +// 23 6/27/13 9:43a Alexp +// fixed range check in ROM_MAP table processing. +// +// 22 6/21/13 11:00a Alexp +// HashFwRomMapImage(): add check for address overflow in UIN32 build mode +// +// 21 6/12/13 3:51p Alexp +// 1. CapsuleValidate() made external function in SecSmiFlash API +// EIP#125800 : Privilege escalation into SMM via Secure SMI Flash SMM +// driver via GetFlUpdPolicy and SetFlUpdMethod - BugID 305294 +// add IsAddressInSmram() checks inside exposed API functions +// 2. VerifyFwCertRsa2048Sha256() - parse multiple chained RootKey +// certificate structures in FwCert header +// +// 20 12/17/12 2:51p Alexp +// fix cppcheck style check finds +// +// 19 11/21/12 10:44a Alexp +// EIP#105015: Implemented handling of Pkcs7# Certificate in Aptio Fw +// Capsule update packages +// Replace direct calls to Hash() infrom CryptoLib with calls to Crypto +// API. Saves ROM space +// +// +// 18 11/20/12 3:30p Alexp +// EIP[104046]: Findings from Security review on Aptio4 Image verification +// Includes the fix for item #10: hardening of RomMap parsing oin +// FwCapsule update +// +// 17 11/13/12 3:23p Alexp +// 1. EIP#106359 : Secure Flash Cross function fail. +// Move FwCapSectionGuid define outside of #if branch +// 2. Calculate offset to RomLayout table within FwCapsHdr instead of +// using hardwired location. Pkcs#7 +// cert will differ in size and offset may change +// 3. Remove dependency on FWSIG_SIGNHDR flag. Use Capsule flags instead. +// +// 16 9/18/12 6:59p Alexp +// Bug: Recovery update was broken for FwCapsule with embedded signature +// and FwSig_hdr token 0. +// Fix: FindCapHdrFFS() change Ffs Hdr size testing +// +// 15 9/06/12 7:28p Alexp +// Add new IGNORE_RUNTIME_UPDATE_IMAGE_REVISION_CHECK flag +// When set, FW Capsule Validate logic will skip image Revision check only +// for Runtime updates +// +// 14 7/26/12 3:26p Alexp +// replaced #if FWSIG_PADDING == 0 with #if FWSIG_SIGNHDR == 1. +// Flag in the FwCap Hdr to switch between PKCS1_5 and PSS padding is +// available only if #if FWSIG_SIGNHDR == 1 +// +// 13 5/21/12 4:55p Alexp +// keep a pointer to FwCaps Hdr withing Capsule image. Streamlines +// creation of Capsule Mailbox. +// +// 12 5/18/12 5:14p Alexp +// 1. Add support for Embedded FwSignature file +// 2. EIP:89687 Replace Hash PPI calls with calls to Crypto lib +// functions. +// Allows to support RomMap tables in FwCaps Hdr with unlimited +// number of +// entries +// 3. VerifyFwVersion. +// a) Moved the call after Rom image signature is verified.; +// b) search $FID struct only in signed FVs with PEI or DXE +// attributes +// +// 11 4/25/12 2:11p Alexp +// Platform FW Key is compared with either Signing or if no match - with +// RootKey certificates +// +// 9 3/09/12 11:16a Alexp +// VerifyFwImage-> fixed logic to process RomMap entries. +// Number of signed elements in RomMap may not exceed max_num_elem +// constant. +// Overall number of elements in th RomMap may not exceed max_num_elem x 2 +// +// 8 2/29/12 4:13p Alexp +// Update format of Capsule signing: +// 1. Entire Cap Hdr and FW_Cert Hdr are included in SigCert Signature +// calculation. Improves Cap image security +// 2. RootKey signs only SignKey buffer and not entire Sign Certificate. +// No need for resigning of RootCert each time SignCert is being created +// +// 7 2/13/12 1:57p Alexp +// GetFidData: Use 1 byte alligned pointer in searching "Section Guid". +// Fixes the issue with RomMap entries that are not 4 byte alligned +// +// 6 12/29/11 4:00p Alexp +// VerifyProjectId(). +// Calculate size of ProjectId string based on SDL Token PROJECT_TAG +// +// 5 11/30/11 8:04p Alexp +// FW Revision searched inside FID structure. Simplified the search +// throughout FW block by 4byte aligned $FID signature only +// +// 4 10/17/11 11:26a Alexp +// Fix misspelled FidSignature name +// +// 3 9/29/11 3:27p Alexp +// Bug fix. EIP#71244: No Rollback support +// +// 2 8/05/11 3:29p Alexp +// add SDL condition to IGNORE_IMAGE_ROLLBACK. Disabled by default +// +// 4 5/16/11 5:54p Alexp +// Use 5 characters for Project Tag comparison (old was 4) +// +// 3 5/10/11 5:09p Alexp +// Hash guids are defined globally +// +// 2 4/13/11 7:15p Alexp +// included first draft of VersionControl code +// +//********************************************************************** +//<AMI_FHDR_START> +//---------------------------------------------------------------------------- +// +// Name: VerifyFwCapsule.c +// +// Description: Verify Aptio FW capsule integrity and performs other security checks +// +//---------------------------------------------------------------------------- +//<AMI_FHDR_END> + +#include <AmiDxeLib.h> +#include <Protocol\SmiFlash.h> +#include <Protocol\SecSmiFlash.h> +#include <Ppi\FwVersion.h> +#include <RomLayout.h> +#include <Ffs.h> +#include "AmiCertificate.h" + +//---------------------------------------------------------------------------- +// Function Externs +extern AMI_DIGITAL_SIGNATURE_PROTOCOL *gAmiSig; +extern UINTN gFwCapMaxSize; // add 4k for capsule's header +extern EFI_GUID gFWCapsuleGuid; +extern EFI_GUID gPRKeyGuid; +extern EFI_GUID gFwCapFfsGuid; +extern EFI_SHA256_HASH *gHashTbl; +extern CRYPT_HANDLE gpPubKeyHndl; +extern UINT8 gHashDB[SHA256_DIGEST_SIZE]; + +BOOLEAN IsAddressInSmram ( + IN EFI_PHYSICAL_ADDRESS Buffer, + IN UINT64 Length +); +//---------------------------------------------------------------------------- +// Local prototypes +EFI_STATUS CapsuleValidate ( + IN OUT UINT8 **pFwCapsule, + IN OUT APTIO_FW_CAPSULE_HEADER **pFWCapsuleHdr +); + +typedef struct { + EFI_FFS_FILE_HEADER FfsHdr; + EFI_COMMON_SECTION_HEADER SecHdr; + EFI_GUID SectionGuid; + UINT8 FwCapHdr[0]; +} AMI_FFS_COMMON_SECTION_HEADER; + +//---------------------------------------------------------------------------- +// Local Variables + +static EFI_GUID FwCapSectionGuid = AMI_FW_CAPSULE_SECTION_GUID; + +//---------------------------------------------------------------------------- +#if IGNORE_RUNTIME_UPDATE_IMAGE_REVISION_CHECK == 0 +//---------------------------------------------------------------------------- +typedef struct _FID_SECTION { + EFI_GUID Guid; + FW_VERSION FwVersion; +} FID_SECTION; + +static EFI_GUID FidSectionGuid = \ + { 0x2EBE0275, 0x6458, 0x4AF9, 0x91, 0xed, 0xD3, 0xF4, 0xED, 0xB1, 0x00, 0xAA }; + +const UINT8 *FidSignature = "$FID"; +//---------------------------------------------------------------------------- +// Function Definitions + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: VerifyProjectId +// +// Description: +// +// Input: +// +// Output: +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +BOOLEAN +VerifyProjectId ( + IN FW_VERSION *FwVersionData +) +{ + char *strProjectId = CONVERT_TO_STRING(PROJECT_TAG); + UINTN Size = sizeof(CONVERT_TO_STRING(PROJECT_TAG)); +/* +CHAR8 BiosTag[9]; //BIOS Tag +EFI_GUID FirmwareGuid; //Firmware GUID +CHAR8 CoreMajorVersion[3]; +CHAR8 CoreMinorVersion[3]; +CHAR8 ProjectMajorVersion[3]; +CHAR8 ProjectMinorVersion[3]; +*/ +// Project ID, Major, Minor rev + TRACE((-1, "OrgBiosTag=%s,NewBiosTag=%s\nPrjMajVer=%02X, NewMajVer=%s\nPrjMinorVer=%02X, NewMinorVer=%s\n", + FwVersionData->BiosTag, strProjectId, + PROJECT_MAJOR_VERSION, FwVersionData->ProjectMajorVersion, + PROJECT_MINOR_VERSION, FwVersionData->ProjectMinorVersion + )); + + if (Size==0 || MemCmp (FwVersionData->BiosTag, strProjectId, Size-1)) return FALSE; +#if IGNORE_IMAGE_ROLLBACK == 0 + if(Atoi(FwVersionData->ProjectMajorVersion) < PROJECT_MAJOR_VERSION) return FALSE; + if(Atoi(FwVersionData->ProjectMinorVersion) < PROJECT_MINOR_VERSION) return FALSE; +#endif + + return TRUE; +} +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: GetFidData +// +// Description: Function to read FFS FID data structure from the given data buffer +// +// Input: OUT FW_VERSION **Fid - pointer to output buffer +// IN VOID *pFV - pointer to data buffer to read from + +// +// Output: EFI_SUCCESS if FID data is retrieved +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +BOOLEAN GetFidData( + IN VOID *pFV, + IN UINT32 Size, + OUT FW_VERSION **FwVersionData +) +{ +// UINT32 Signature; + UINT8 *SearchPointer; + FID_SECTION *Section; + +// Simplified search by $FID signature only. +// SearchPointer = (UINT32 *)((UINT8 *)pFV + sizeof(EFI_GUID)); +// Signature = FidSectionGuid.Data1; + SearchPointer = (UINT8 *)pFV; + + do { +// if(*SearchPointer == Signature) { + Section = (FID_SECTION *)SearchPointer; + if(!guidcmp(&FidSectionGuid, &(Section->Guid)) && + (*((UINT32*)(&Section->FwVersion.FirmwareID[0])) == *(UINT32*)FidSignature)){ + *FwVersionData = &Section->FwVersion; + return TRUE; + } +// } + } while( SearchPointer++ < (UINT8*)((UINT32)pFV+Size)); + + return FALSE; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: VerifyFwRevision +// +// Description: Verify Fw revision compatibility +// NewVer > OldVer, newProjectTAGid = oldProjectTAGid +// +// Input: +// IN OUT UINT8 *pCapsule +// Output: +// EFI_STATUS +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS +VerifyFwRevision ( + IN APTIO_FW_CAPSULE_HEADER *FWCapsuleHdr, + IN UINT8 *RomData +) +{ + ROM_AREA *Area; + EFI_PHYSICAL_ADDRESS FvAddress; + FW_VERSION *FwVersionData; + + Area = (ROM_AREA *)(UINTN)((UINT32)FWCapsuleHdr+FWCapsuleHdr->RomLayoutOffset); + + for (Area; Area->Size != 0; Area++) { + if (!(Area->Attributes & ROM_AREA_FV_SIGNED)) + continue; + // $FID can be in FV with either PEI or DXE + if (!(Area->Attributes & (ROM_AREA_FV_PEI+ROM_AREA_FV_DXE))) + continue; + + FvAddress = (EFI_PHYSICAL_ADDRESS)RomData + (Area->Offset); + if (GetFidData((UINT8*)FvAddress, Area->Size, &FwVersionData)) { + if(VerifyProjectId(FwVersionData)) + return EFI_SUCCESS; + break; + } + } +// At least one FW block must be signed OR no $FID structure found in the new FW image + return EFI_SECURITY_VIOLATION; +} + +#endif // #if IGNORE_RUNTIME_UPDATE_IMAGE_REVISION_CHECK == 0 + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: FindCapHdrFFS +// +// Description: Function to read FW Cap Sig data from Ffs +// +// Input: OUT UINT8 **pFwCapHdr - pointer to output buffer +// IN VOID *pCapsule - pointer to data buffer to read from +// +// Output: EFI_SUCCESS if Capsule Hdr with Signature is retrieved +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS FindCapHdrFFS( + IN VOID *pCapsule, + OUT UINT8 **pFfsData +) +{ + UINT32 Signature; + UINT32 *SearchPointer; + AMI_FFS_COMMON_SECTION_HEADER *FileSection; + APTIO_FW_CAPSULE_HEADER *pFwCapHdr; + + SearchPointer = (UINT32 *)((UINT8 *)pCapsule - sizeof(AMI_FFS_COMMON_SECTION_HEADER) + FLASH_SIZE); + Signature = gFwCapFfsGuid.Data1; + do { + if(*SearchPointer == Signature) { + FileSection = (AMI_FFS_COMMON_SECTION_HEADER *)SearchPointer; + if(!guidcmp(&gFwCapFfsGuid, &(FileSection->FfsHdr.Name)) + && !guidcmp(&FwCapSectionGuid, &(FileSection->SectionGuid)) + ){ + pFwCapHdr = (APTIO_FW_CAPSULE_HEADER*)(FileSection->FwCapHdr); + // just a sanity check - Cap Size must match the Section size + if(((*(UINT32 *)FileSection->FfsHdr.Size) & 0xffffff) >= + pFwCapHdr->CapHdr.HeaderSize + sizeof(AMI_FFS_COMMON_SECTION_HEADER) && + !guidcmp((EFI_GUID*)&pFwCapHdr->CapHdr.CapsuleGuid, &gFWCapsuleGuid) + ){ + *pFfsData = (UINT8*)pFwCapHdr; + return EFI_SUCCESS; + } + } + } + } while(SearchPointer-- != pCapsule); + + return EFI_NOT_FOUND; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: HashFwRomMapImage +// +// Description: The Rom image hash is calculated based on info from the Rom Area map +// +// Input: +// Payload - pointer to a FW Image +// FwCapsuleHdr - pointer to a FW Capsule Hdr +// RomSize - Size of Rom Image +// +// Output: EFI_SUCCESS - capsule processed successfully +// EFI_DEVICE_ERROR - capsule processing failed +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS HashFwRomMapImage ( + IN APTIO_FW_CAPSULE_HEADER *FWCapsuleHdr, + IN UINT8 *Payload, + IN UINTN RomSize, + OUT UINT8 *gHashDB +){ + EFI_STATUS Status = EFI_SUCCESS; + ROM_AREA *RomAreaTbl; + UINTN *Addr; + UINTN *Len; + UINTN i, RomMap_size, max_num_elem, num_elem, max_hash_elem; + + RomAreaTbl = (ROM_AREA *)(UINTN)((UINT32)FWCapsuleHdr+FWCapsuleHdr->RomLayoutOffset); + + RomMap_size = FWCapsuleHdr->RomImageOffset-FWCapsuleHdr->RomLayoutOffset; + max_num_elem = RomMap_size/sizeof(ROM_AREA); +// assume max size of RomMap array = RomMap_size/sizeof(ROM_AREA); +// or better yet ...calculate exact number + num_elem = 0; + for (i=0; i < max_num_elem && RomAreaTbl[i].Size != 0; i++ ) + { + if (RomAreaTbl[i].Attributes & ROM_AREA_FV_SIGNED) + num_elem++; + } + max_num_elem = i; + max_hash_elem = num_elem+2; // add 2 extra entries + Addr = (UINTN*)gHashTbl; + Len = (UINTN*)((UINT8*)gHashTbl + max_hash_elem*sizeof(UINTN)); + + num_elem = 0; + for (i=0; i < max_num_elem && num_elem < max_hash_elem && RomAreaTbl[i].Size != 0; i++) + { + if (!(RomAreaTbl[i].Attributes & ROM_AREA_FV_SIGNED)) + continue; + // sanity check for buffer overruns + if(RomAreaTbl[i].Offset > RomSize || + (UINT64)RomAreaTbl[i].Offset + RomAreaTbl[i].Size > RomSize) + return EFI_SECURITY_VIOLATION; + // RomArea only holds offsets within a payload + Addr[num_elem] = (UINTN)((UINTN)Payload + RomAreaTbl[i].Offset); + Len[num_elem] = RomAreaTbl[i].Size; +//TRACE((-1, "\n Num %d: Offs = %X (%X), len %X\n", num_elem, /*Addr[num_elem]*/RomAreaTbl[i].Offset, (UINT32)*(UINT32*)Addr[num_elem], Len[num_elem])); + + num_elem++; + + } + if(num_elem >= max_hash_elem) return EFI_SECURITY_VIOLATION; +// +// Hash of Capsule Hdr + FW Certificate Hdr +// + if(FWCapsuleHdr->CapHdr.Flags & CAPSULE_FLAGS_CAPHDR_IN_SIGNCERT) { + Addr[num_elem] = (UINTN) FWCapsuleHdr; + Len[num_elem] = (UINTN)&FWCapsuleHdr->FWCert.SignCert.CertData - (UINTN)FWCapsuleHdr; +//TRACE((-1, "\n Num %d: Offs = %X (%X), len %X\n", num_elem, Addr[num_elem], (UINT32)*(UINT32*)Addr[num_elem], Len[num_elem])); + num_elem++; + if(num_elem >= max_hash_elem) return EFI_SECURITY_VIOLATION; + } +// +// Hash of the ROM_MAP table +// + Addr[num_elem] = (UINTN)RomAreaTbl; + Len[num_elem] = (i+1)*sizeof(ROM_AREA); +//TRACE((-1, "\n Num %d: Offs = %X (%X), len %X\n", num_elem, Addr[num_elem], (UINT32)*(UINT32*)Addr[num_elem], Len[num_elem])); + num_elem++; + + Status = gAmiSig->Hash(gAmiSig, &gEfiHashAlgorithmSha256Guid, + num_elem, (const UINT8**)Addr, (const UINTN*)Len, gHashDB ); + +//TRACE((-1, "\nHash the FW Image %r\nNumElems = %d\n", Status, num_elem)); + +//for (i=0; i<16; i++) +// TRACE((-1,"%02X ", (gHashDB[i]) )); + + return Status; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: VerifyFwCertPkcs7 +// +// Description: This code verifies FW Capsule is genuine, +// and performs following checks on the image: +// 1. Signing certificate is signed with trusted Root Platform key +// 2. Integrity check. Image Signature verification +// +// Input: +// Payload - pointer to a FW Image +// FwCapsuleHdr - pointer to a FW Capsule Hdr +// RomSize - Size of Rom Image +// +// Output: EFI_SUCCESS - capsule processed successfully +// EFI_DEVICE_ERROR - capsule processing failed +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS VerifyFwCertPkcs7 ( + IN APTIO_FW_CAPSULE_HEADER *FWCapsuleHdr, + IN UINT8 *Payload, + IN UINTN RomSize +){ + EFI_STATUS Status; + UINT8 *Pkcs7Cert, *pDigest; + UINTN Pkcs7Cert_len, DigestLen; + UINT32 Flags=0; + +// TRACE((-1, "Verify Fw Pkcs7 Cert\n")); +// +// 1. Verify Platform Key algo matches x509 cert +// + if(guidcmp(&gpPubKeyHndl.AlgGuid, &gEfiCertX509Guid)) + return EFI_UNSUPPORTED; + +// 2. Verify Signing Cert Signature +// +// 2.1 The Rom image hash is calculated based on info from the Rom Area map +// + Status = HashFwRomMapImage(FWCapsuleHdr, Payload, RomSize, gHashDB); + if (EFI_ERROR(Status)) return Status; + +// 2.2 Verify Fw Certificate + pDigest = &gHashDB[0]; + DigestLen = SHA256_DIGEST_SIZE; + Pkcs7Cert = (UINT8*)&FWCapsuleHdr->FWCert.SignCert.CertData; + Pkcs7Cert_len = FWCapsuleHdr->FWCert.SignCert.Hdr.Hdr.dwLength-sizeof(WIN_CERTIFICATE_UEFI_GUID_1); + Status = gAmiSig->Pkcs7Verify( gAmiSig, + Pkcs7Cert, Pkcs7Cert_len, // Pkcs7Cert + gpPubKeyHndl.Blob, gpPubKeyHndl.BlobSize, // TrustCert + &pDigest, &DigestLen, // In/OutData + Pkcs7CertValidate, + RELEASE // Flags, mutex + ); + + return Status; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: VerifyFwCertRsa2048Sha256 +// +// Description: This code verifies FW Capsule is genuine, +// and performs following checks on the image: +// 1. Signing certificate is signed with trusted Root Platform key +// 2. Integrity check. Image Signature verification +// +// Input: +// Payload - pointer to a FW Image +// FwCapsuleHdr - pointer to a FW Capsule Hdr +// RomSize - Size of Rom Image +// +// Output: EFI_SUCCESS - capsule processed successfully +// EFI_DEVICE_ERROR - capsule processing failed +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS VerifyFwCertRsa2048Sha256 ( + IN APTIO_FW_CAPSULE_HEADER *FWCapsuleHdr, + IN UINT8 *Payload, + IN UINTN RomSize +){ + EFI_STATUS Status; + CRYPT_HANDLE HashHndl; + CRYPT_HANDLE PubKeyHndl; + UINT8 *pSig; + UINT32 Flags; + UINT8 *Addr; + UINTN Size; + EFI_CERT_BLOCK_RSA_2048_SHA256* pRootCert; + +// Version 010 and later supporting extended flags +// if(FWCapsuleHdr->CapHdr.Flags & CAPSULE_FLAGS_CAPHDR_IN_SIGNCERT) + if(FWCapsuleHdr->CapHdr.HeaderSize == FWCapsuleHdr->RomImageOffset) + { + if(FWCapsuleHdr->CapHdr.Flags & CAPSULE_FLAGS_RSA_PSS_PADDING_SCHEME) + Flags = EFI_CRYPT_RSASSA_PSS; + else + Flags = EFI_CRYPT_RSASSA_PKCS1V15; + } + else + Flags = EFI_CRYPT_RSASSA_PSS; + + HashHndl.AlgGuid = gEfiHashAlgorithmSha256Guid; + HashHndl.BlobSize = SHA256_DIGEST_SIZE; + HashHndl.Blob = gHashDB; + + PubKeyHndl.AlgGuid = gEfiCertRsa2048Guid; + PubKeyHndl.BlobSize = DEFAULT_RSA_KEY_MODULUS_LEN; +// +// 1. Compare Capsule's Sign Cert key with Platform Root Key +// + PubKeyHndl.Blob = (UINT8*)FWCapsuleHdr->FWCert.SignCert.CertData.PublicKey; + Status = gAmiSig->VerifyKey(gAmiSig, &gPRKeyGuid, &PubKeyHndl); + // Skip the RootCert key checking if SignCert Key and PR Key are matching +//TRACE((-1, "Compare SignCert Key == FW Key(%X) : %r\n", (UINT32)*PubKeyHndl.Blob, Status)); + if(EFI_ERROR(Status)) { +// +// 1.1 Compare Platform Root with Capsule's Key from a Root Key store +// + for (pRootCert = &FWCapsuleHdr->FWCert.RootCert; + (UINT8*)pRootCert < + (UINT8*)&FWCapsuleHdr->FWCert+FWCapsuleHdr->FWCert.SignCert.Hdr.Hdr.dwLength && + pRootCert->PublicKey[0]!=0; + pRootCert++) + { + PubKeyHndl.Blob = pRootCert->PublicKey; + Status = gAmiSig->VerifyKey(gAmiSig, &gPRKeyGuid, &PubKeyHndl); +//TRACE((-1, "Compare RootCert Key == FW Key(%X) : %r\n", (UINT32)*PubKeyHndl.Blob, Status)); + if (EFI_ERROR(Status)) continue; +// +// 2. Verify RootCert.Signature +// +// 2.1 Compute FWCert.SignCert.PublicKey Hash + if(FWCapsuleHdr->CapHdr.Flags & CAPSULE_FLAGS_SIGNKEY_IN_ROOTCERT) + { + Addr = (UINT8*)&FWCapsuleHdr->FWCert.SignCert.CertData.PublicKey; + Size = DEFAULT_RSA_KEY_MODULUS_LEN; + } else +// 2.2 Compute FWCert.SignCert Hash + { + Addr = (UINT8*)&FWCapsuleHdr->FWCert.SignCert; + Size = sizeof(AMI_CERTIFICATE_RSA2048_SHA256); + } + + Status = gAmiSig->Hash(gAmiSig, &gEfiHashAlgorithmSha256Guid, 1,&Addr,(const UINTN*)&Size, gHashDB); + if (EFI_ERROR(Status)) break; + + pSig = (void*)pRootCert->Signature; + Status = gAmiSig->Pkcs1Verify(gAmiSig, &PubKeyHndl, &HashHndl, pSig, DEFAULT_RSA_SIG_LEN, Flags); +//TRACE((-1, "Verify Root Cert : %r\n", Status)); + break; + } + } + if (EFI_ERROR(Status)) return EFI_SECURITY_VIOLATION; +// 3. Verify Signing Cert Signature +// +// 3.1 The Rom image hash is calculated based on info from the Rom Area map +// + Status = HashFwRomMapImage(FWCapsuleHdr, Payload, RomSize, gHashDB); + if (EFI_ERROR(Status)) return Status; + + pSig = (void*)FWCapsuleHdr->FWCert.SignCert.CertData.Signature; + PubKeyHndl.Blob = (UINT8*)FWCapsuleHdr->FWCert.SignCert.CertData.PublicKey; + Status = gAmiSig->Pkcs1Verify(gAmiSig, &PubKeyHndl, &HashHndl, pSig, DEFAULT_RSA_SIG_LEN, Flags); + + return Status; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: CapsuleValidate +// +// Description: This code verifies FW Capsule is genuine, +// and performs following checks on the image: +// 1. Re-Play protection. Verifies that new FW image version is newer then the current one +// 2. Signing certificate is signed with trusted Root Platform key +// 3. Integrity check. Image Signature verification +// +// Input: +// IN VOID *pFwCapsule - pointer to a FW Image +// OUT UINT8 *pFwCapsuleHdr - return a pointer to a FW Capsule Hdr(optional if parameter is not NULL) +// +// Output: EFI_SUCCESS - capsule processed successfully +// EFI_SECURITY_VIOLATION - capsule processing failed +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS CapsuleValidate ( + IN OUT UINT8 **pFwCapsule, + IN OUT APTIO_FW_CAPSULE_HEADER **pFWCapsuleHdr +){ + EFI_STATUS Status = EFI_DEVICE_ERROR; + APTIO_FW_CAPSULE_HEADER *FWCapsuleHdr; + UINTN RomSize; + UINT8 *Payload; + + FWCapsuleHdr = (APTIO_FW_CAPSULE_HEADER*)*pFwCapsule; + Payload = (UINT8*)*pFwCapsule; + RomSize = FLASH_SIZE; + +/* + - CapsuleValidate + - Look up Capsule GUID + - Found - + update pFwCapsule ptr to beginning of BIOS ROM data + continue with Image Verify + - Not found at offs 0 - assume Cap Hdr in FFS + Call GetSigFFS + locate FFS by Hole GUID, Sec GUID + if found, update FWCapsuleHdr, + continue with Image Verify +*/ +// proper FW Capsule presence check + +// verify Capsule Mailbox points to FW_CAPSULE hdr + if(!guidcmp((EFI_GUID*)&FWCapsuleHdr->CapHdr.CapsuleGuid, &gFWCapsuleGuid)) + { +// Update pFwCapsule to point to beginning of Bios ROM + Payload = (UINT8*)((UINT32)FWCapsuleHdr + FWCapsuleHdr->RomImageOffset); + RomSize = (FWCapsuleHdr->CapHdr.CapsuleImageSize - FWCapsuleHdr->RomImageOffset); + *pFwCapsule = Payload; + } + else + { +//TRACE((-1, "Looking for embedded Signature...\n")); + if(EFI_ERROR(FindCapHdrFFS(Payload, (UINT8**)&FWCapsuleHdr))) + return EFI_SECURITY_VIOLATION; + } +TRACE((-1, "Found Fw Capsule GUID %g\n\r", &(FWCapsuleHdr->CapHdr.CapsuleGuid))); + +// update return argument with a ptr to FwCapHdr + if(pFWCapsuleHdr) + *pFWCapsuleHdr = FWCapsuleHdr; + +// Aptio FW Capsule only supporting WIN_CERT_TYPE_EFI_GUID + if(FWCapsuleHdr->FWCert.SignCert.Hdr.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) + return EFI_SECURITY_VIOLATION; + +// sanity check for buffer overruns + if((FWCapsuleHdr->CapHdr.CapsuleImageSize > gFwCapMaxSize) || + (FWCapsuleHdr->RomImageOffset > (FWCAPSULE_IMAGE_SIZE-FLASH_SIZE)) || // 16k is a MAX possible FwCap Hdr size + (FWCapsuleHdr->CapHdr.HeaderSize > FWCapsuleHdr->RomImageOffset) || + (FWCapsuleHdr->RomLayoutOffset > FWCapsuleHdr->RomImageOffset) || + (FWCapsuleHdr->FWCert.SignCert.Hdr.Hdr.dwLength + offsetof(APTIO_FW_CAPSULE_HEADER, FWCert) > + FWCapsuleHdr->RomLayoutOffset ) + ) + return EFI_SECURITY_VIOLATION; + + if(!IsAddressInSmram((EFI_PHYSICAL_ADDRESS)gpPubKeyHndl.Blob, gpPubKeyHndl.BlobSize) ) + return EFI_SECURITY_VIOLATION; + TRACE((TRACE_ALWAYS,"gpKey (%x, %x bytes)\n",gpPubKeyHndl.Blob,gpPubKeyHndl.BlobSize)); +// Begin Authentication + if(!guidcmp((EFI_GUID*)&FWCapsuleHdr->FWCert.SignCert.Hdr.CertType, &gEfiCertTypePkcs7Guid)) + Status = VerifyFwCertPkcs7(FWCapsuleHdr, Payload, RomSize); + else + Status = VerifyFwCertRsa2048Sha256(FWCapsuleHdr, Payload, RomSize); + TRACE((-1, "Signature validate %r\n", Status)); + if (EFI_ERROR(Status)) return Status; +// +// Local PEI $FID is linked with CspLib. extern FW_VERSION FwVersionData; +// Find $FID in new Fw FVs. Any found should do for us. Use RomMap from Capsule's Hdr +// compare local BB and Main $Fid BIOS Major/Minor revs with New one. +#if IGNORE_RUNTIME_UPDATE_IMAGE_REVISION_CHECK == 0 + Status = VerifyFwRevision(FWCapsuleHdr, Payload); +//TRACE((-1, "FW Revision test %r\n", Status)); +#endif + +//TRACE((-1, "Capsule Verify %r\n", Status)); + + return Status; +} + +//************************************************************************* +//************************************************************************* +//** ** +//** (C)Copyright 1985-2014, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//************************************************************************* +//************************************************************************* |