1531 lines
48 KiB
C
1531 lines
48 KiB
C
/** @file
|
|
|
|
;******************************************************************************
|
|
;* Copyright (c) 2020 - 2021, Insyde Software Corp. All Rights Reserved.
|
|
;*
|
|
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
|
|
;* transmit, broadcast, present, recite, release, license or otherwise exploit
|
|
;* any part of this publication in any form, by any means, without the prior
|
|
;* written permission of Insyde Software Corporation.
|
|
;*
|
|
;******************************************************************************
|
|
*/
|
|
/** @file
|
|
ME Resiliency init Dxe driver.
|
|
|
|
@copyright
|
|
INTEL CONFIDENTIAL
|
|
Copyright 2020 Intel Corporation.
|
|
|
|
The source code contained or described herein and all documents related to the
|
|
source code ("Material") are owned by Intel Corporation or its suppliers or
|
|
licensors. Title to the Material remains with Intel Corporation or its suppliers
|
|
and licensors. The Material may contain trade secrets and proprietary and
|
|
confidential information of Intel Corporation and its suppliers and licensors,
|
|
and is protected by worldwide copyright and trade secret laws and treaty
|
|
provisions. No part of the Material may be used, copied, reproduced, modified,
|
|
published, uploaded, posted, transmitted, distributed, or disclosed in any way
|
|
without Intel's prior express written permission.
|
|
|
|
No license under any patent, copyright, trade secret or other intellectual
|
|
property right is granted to or conferred upon you by disclosure or delivery
|
|
of the Materials, either expressly, by implication, inducement, estoppel or
|
|
otherwise. Any license under such intellectual property rights must be
|
|
express and approved by Intel in writing.
|
|
|
|
Unless otherwise agreed by Intel in writing, you may not remove or alter
|
|
this notice or any other notice embedded in Materials by Intel or
|
|
Intel's suppliers or licensors in any way.
|
|
|
|
This file contains a 'Sample Driver' and is licensed as such under the terms
|
|
of your license agreement with Intel or your vendor. This file may be modified
|
|
by the user, subject to the additional terms of the license agreement.
|
|
|
|
@par Specification Reference:
|
|
**/
|
|
#include <Library/BaseLib.h>
|
|
#include <Library/BaseMemoryLib.h>
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/PciSegmentLib.h>
|
|
#include <Library/UefiBootServicesTableLib.h>
|
|
#include <Library/UefiRuntimeServicesTableLib.h>
|
|
#include <Protocol/FirmwareManagement.h>
|
|
//[-start-201112-IB16810138-remove]//
|
|
//#include <Protocol/PlatformSpecificResetFilter.h>
|
|
//[-end-201112-IB16810138-remove]//
|
|
|
|
#include <Register/HeciRegs.h>
|
|
#include <Register/MeRegs.h>
|
|
//[-start-201112-IB16810138-remove]//
|
|
//#include <Library/SeamlessRecoverySupportLib.h>
|
|
//#include <PchResetPlatformSpecific.h>
|
|
//[-end-201112-IB16810138-remove]//
|
|
//[-start-201112-IB16810138-add]//
|
|
#include <Library/H2OCpLib.h>
|
|
#include <Library/VariableLib.h>
|
|
//[-end-201112-IB16810138-add]//
|
|
//[-start-201112-IB16810138-add]//
|
|
#include <Library/CapsuleUpdateCriteriaLib.h>
|
|
#include <Library/BaseCryptLib.h>
|
|
#include <Uefi.h>
|
|
#include <Uefi/UefiSpec.h>
|
|
#include <Protocol/SimpleFileSystem.h>
|
|
#include <Protocol/DevicePath.h>
|
|
#include <Library/DevicePathLib.h>
|
|
#include <Guid/FileSystemInfo.h>
|
|
#include <Guid/FileInfo.h>
|
|
#include <Guid/SysFwUpdateProgress.h>
|
|
#include <Library/MemoryAllocationLib.h>
|
|
#include <Library/PrintLib.h>
|
|
#include <SecureFlash.h>
|
|
#include <Library/UefiLib.h>
|
|
|
|
#define MAX_BOOT_OPTIONS 128
|
|
#define SHA256_DIGEST_HASH_SIZE 0x20
|
|
#define EFI_CAPSULE_FILE_PATH L"EFI\\UpdateCapsule"
|
|
#define EFI_CAPSULE_FILE_NAME L"CapsuleUpdateFile"
|
|
|
|
STATIC UINT8 InsydeBiosSignature[] = {'$', '_', 'I', 'F', 'L', 'A', 'S', 'H', '_', 'B', 'I', 'O', 'S', 'I', 'M', 'G'};
|
|
STATIC UINT8 InsydeMeSig[] = {'_', 'M', 'E', '_','I', 'M', 'G', '_'};
|
|
|
|
EFI_STATUS
|
|
GetFwUpdateInfo (
|
|
OUT SYSTEM_FIRMWARE_COMPONENT *Component
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN DataSize;
|
|
SYSTEM_FIRMWARE_COMPONENT TempComponent;
|
|
|
|
|
|
DataSize = sizeof (SYSTEM_FIRMWARE_COMPONENT);
|
|
Status = CommonGetVariable (
|
|
FW_UPDATEINFO_VARIABLE_NAME,
|
|
&gSysFwUpdateProgressGuid,
|
|
&DataSize,
|
|
&TempComponent
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
CopyMem (Component, &TempComponent, sizeof (SYSTEM_FIRMWARE_COMPONENT));
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
SetFwUpdateInfo (
|
|
IN SYSTEM_FIRMWARE_COMPONENT *Component
|
|
)
|
|
{
|
|
return SetVariableToSensitiveVariable (
|
|
FW_UPDATEINFO_VARIABLE_NAME,
|
|
&gSysFwUpdateProgressGuid,
|
|
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
|
|
sizeof (SYSTEM_FIRMWARE_COMPONENT),
|
|
Component
|
|
);
|
|
}
|
|
|
|
VOID
|
|
ClearFwUpdateInfo (
|
|
VOID
|
|
)
|
|
{
|
|
|
|
SetVariableToSensitiveVariable (
|
|
FW_UPDATEINFO_VARIABLE_NAME,
|
|
&gSysFwUpdateProgressGuid,
|
|
0,
|
|
0,
|
|
NULL
|
|
);
|
|
|
|
}
|
|
|
|
/**
|
|
Dump raw data.
|
|
|
|
@param[in] Data raw data
|
|
@param[in] Size raw data size
|
|
|
|
**/
|
|
VOID
|
|
InternalDumpData (
|
|
IN UINT8 *Data8,
|
|
IN UINTN DataSize
|
|
)
|
|
{
|
|
DEBUG_CODE_BEGIN();
|
|
|
|
UINTN Index;
|
|
|
|
for (Index = 0; Index < DataSize; Index++) {
|
|
if (Index % 0x10 == 0) {
|
|
DEBUG ((DEBUG_INFO, "\n%08X:", Index));
|
|
}
|
|
DEBUG ((DEBUG_INFO, " %02X", *Data8++));
|
|
}
|
|
DEBUG ((DEBUG_INFO, "\n"));
|
|
|
|
DEBUG_CODE_END();
|
|
}
|
|
|
|
/**
|
|
Calculate SHA256 Hash
|
|
|
|
@param[in] Data data
|
|
@param[in] Size data size
|
|
@param[out] Digest SHA256 digest
|
|
|
|
**/
|
|
VOID
|
|
CreateSha256Hash (
|
|
IN UINT8 *Data,
|
|
IN UINTN Size,
|
|
OUT UINT8 *Digest
|
|
)
|
|
{
|
|
UINTN CtxSize;
|
|
VOID *HashCtx;
|
|
|
|
CtxSize = Sha256GetContextSize ();
|
|
HashCtx = AllocatePool (CtxSize);
|
|
ASSERT (HashCtx != NULL);
|
|
Sha256Init (HashCtx);
|
|
Sha256Update (HashCtx, Data, Size);
|
|
Sha256Final (HashCtx, Digest);
|
|
InternalDumpData (Digest, 32);
|
|
|
|
FreePool (HashCtx);
|
|
}
|
|
/**
|
|
Check if root file system has capsule image file or not.
|
|
|
|
@param[in] SysRootHandle A pointer to a file handle.
|
|
|
|
@retval TRUE It has the capsule image file.
|
|
@retval FALSE It does not has the capsule image file.
|
|
**/
|
|
STATIC
|
|
BOOLEAN
|
|
HaveCapsuleImageFile (
|
|
IN EFI_FILE_HANDLE SysRootHandle
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_FILE_HANDLE CapsuleHandle;
|
|
UINTN FileInfoSize;
|
|
EFI_FILE_INFO *FileInfo;
|
|
UINTN FileSize;
|
|
BOOLEAN Result;
|
|
|
|
if (SysRootHandle == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
Status = SysRootHandle->Open (
|
|
SysRootHandle,
|
|
&CapsuleHandle,
|
|
EFI_CAPSULE_FILE_PATH,
|
|
EFI_FILE_MODE_READ,
|
|
EFI_FILE_DIRECTORY
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return FALSE;
|
|
}
|
|
|
|
Result = FALSE;
|
|
FileInfo = NULL;
|
|
|
|
FileInfoSize = 0;
|
|
Status = CapsuleHandle->GetInfo (CapsuleHandle, &gEfiFileInfoGuid, &FileInfoSize, NULL);
|
|
if (Status != EFI_BUFFER_TOO_SMALL) {
|
|
goto Exit;
|
|
}
|
|
FileInfo = AllocatePool (FileInfoSize);
|
|
if (FileInfo == NULL) {
|
|
goto Exit;
|
|
}
|
|
Status = CapsuleHandle->GetInfo (CapsuleHandle,&gEfiFileInfoGuid, &FileInfoSize, (VOID *) FileInfo);
|
|
if (EFI_ERROR (Status) || FileInfo->FileSize == 0) {
|
|
goto Exit;
|
|
}
|
|
|
|
FileInfoSize = (UINTN) FileInfo->FileSize;
|
|
FreePool (FileInfo);
|
|
FileInfo = AllocatePool (FileInfoSize);
|
|
if (FileInfo == NULL) {
|
|
goto Exit;
|
|
}
|
|
|
|
while (TRUE) {
|
|
FileSize = FileInfoSize;
|
|
Status = CapsuleHandle->Read (
|
|
CapsuleHandle,
|
|
&FileSize,
|
|
(VOID *) FileInfo
|
|
);
|
|
if (EFI_ERROR (Status) || FileSize == 0) {
|
|
break;
|
|
}
|
|
|
|
if (FileInfo->FileSize > 0 &&
|
|
((FileInfo->Attribute & EFI_FILE_DIRECTORY) != EFI_FILE_DIRECTORY) &&
|
|
StrnCmp (FileInfo->FileName, EFI_CAPSULE_FILE_NAME, sizeof (EFI_CAPSULE_FILE_NAME) / sizeof (CHAR16) - 1) == 0) {
|
|
Result = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
CapsuleHandle->Close (CapsuleHandle);
|
|
if (FileInfo != NULL) {
|
|
FreePool (FileInfo);
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
/**
|
|
Get the offset of the boot loader file path from system partition for the boot
|
|
device path of the current boot option
|
|
|
|
@param[in] BootDevicePath The device path of the boot option
|
|
@param[out] BootFilePathOffset The offset from the boot device path of the boot
|
|
loader file path
|
|
|
|
@retval EFI_SUCCESS The BootFilePathOffset is correctly set
|
|
@return Others Unable to get boot file path offset
|
|
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
GetBootFilePathDevicePathOffset (
|
|
IN EFI_DEVICE_PATH_PROTOCOL *BootDevicePath,
|
|
OUT UINTN *BootFilePathDevicePathOffset
|
|
)
|
|
{
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
|
EFI_STATUS Status;
|
|
|
|
if (BootDevicePath == NULL || BootFilePathDevicePathOffset == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
Status = EFI_NOT_FOUND;
|
|
DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)BootDevicePath;
|
|
while (!IsDevicePathEnd(DevicePath)) {
|
|
if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) &&
|
|
(DevicePathSubType (DevicePath) == MEDIA_FILEPATH_DP)) {
|
|
*BootFilePathDevicePathOffset = (UINTN)((UINT8 *)DevicePath - (UINT8 *)BootDevicePath);
|
|
Status = EFI_SUCCESS;
|
|
break;
|
|
}
|
|
DevicePath = NextDevicePathNode (DevicePath);
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Get the information of system drive which contain capsule image file from all simple file system instances.
|
|
|
|
@param[out] SysRootDevicePath The pointer of system root device path pointer
|
|
@param[out] SysRoorHandle The pointer of EFI_FILE_HANDLE of system drive
|
|
|
|
@retval EFI_SUCCESS The system drive information is correctly get
|
|
@return Others Unable to get system drive information
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
GetSystemRootInfoFromFileSystems (
|
|
OUT EFI_DEVICE_PATH **SysRootDevicePath,
|
|
OUT EFI_FILE_HANDLE *SysRootHandle
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_HANDLE *HandleBuffer;
|
|
UINTN NumberOfHandles;
|
|
UINTN Index;
|
|
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFileSystem;
|
|
EFI_FILE_HANDLE RootHandle;
|
|
EFI_DEVICE_PATH *DevicePath;
|
|
|
|
if (SysRootDevicePath == NULL || SysRootHandle == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Status = gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiSimpleFileSystemProtocolGuid,
|
|
NULL,
|
|
&NumberOfHandles,
|
|
&HandleBuffer
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
for (Index = 0; Index < NumberOfHandles; Index++) {
|
|
Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiSimpleFileSystemProtocolGuid, (VOID **) &SimpleFileSystem);
|
|
if (EFI_ERROR (Status)) {
|
|
continue;
|
|
}
|
|
|
|
Status = SimpleFileSystem->OpenVolume (SimpleFileSystem, &RootHandle);
|
|
if (EFI_ERROR (Status)) {
|
|
continue;
|
|
}
|
|
|
|
Status = gBS->HandleProtocol(HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **) &DevicePath);
|
|
if (EFI_ERROR (Status)) {
|
|
RootHandle->Close (RootHandle);
|
|
continue;
|
|
}
|
|
|
|
*SysRootDevicePath = DevicePath;
|
|
*SysRootHandle = RootHandle;
|
|
break;
|
|
}
|
|
|
|
FreePool (HandleBuffer);
|
|
return (Index < NumberOfHandles) ? EFI_SUCCESS : EFI_NOT_FOUND;
|
|
}
|
|
|
|
/**
|
|
Get the system drive information through the boot loader file path under system partition
|
|
|
|
@param[out] SysRootDevicePath The pointer of system root device path pointer
|
|
@param[out] SysRoorHandle The pointer of EFI_FILE_HANDLE of system drive
|
|
|
|
@retval EFI_SUCCESS The system drive information is correctly get
|
|
@return Others Unable to get system drive information
|
|
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
GetSystemRootInfoFromCurrentBootOption (
|
|
OUT EFI_DEVICE_PATH **SysRootDevicePath,
|
|
OUT EFI_FILE_HANDLE *SysRootHandle
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN TotalBootOptions;
|
|
UINT16 BootOptions[MAX_BOOT_OPTIONS];
|
|
UINTN Size;
|
|
CHAR16 BootOption[] = L"Boot0000";
|
|
UINT8 *BootOptionData;
|
|
CHAR16 *BootOptionDesc;
|
|
EFI_DEVICE_PATH_PROTOCOL *BootDevicePath;
|
|
UINTN BootFilePathDevicePathOffset;
|
|
UINTN CompareSize;
|
|
BOOLEAN Found;
|
|
EFI_HANDLE *HandleBuffer;
|
|
UINTN NumberOfHandles;
|
|
UINTN CurrentOption;
|
|
UINTN Index;
|
|
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFileSystem;
|
|
|
|
if (SysRootDevicePath == NULL || SysRootHandle == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
TotalBootOptions = 0;
|
|
Status = EFI_NOT_FOUND;
|
|
Size = sizeof(UINT16);
|
|
Status = CommonGetVariable (
|
|
L"BootNext",
|
|
&gEfiGlobalVariableGuid,
|
|
&Size,
|
|
&BootOptions[0]
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
TotalBootOptions ++;
|
|
}
|
|
Size = sizeof(UINT16) * (MAX_BOOT_OPTIONS - TotalBootOptions);
|
|
Status = CommonGetVariable (
|
|
L"BootOrder",
|
|
&gEfiGlobalVariableGuid,
|
|
&Size,
|
|
&BootOptions[TotalBootOptions]
|
|
);
|
|
if (EFI_ERROR (Status) && TotalBootOptions == 0) {
|
|
return Status;
|
|
}
|
|
TotalBootOptions += (Size / sizeof(UINT16));
|
|
for (CurrentOption = 0, Found = FALSE, Status = EFI_NOT_FOUND; CurrentOption < TotalBootOptions && !Found; CurrentOption ++) {
|
|
UnicodeSPrint (BootOption, sizeof(BootOption), L"Boot%04x", BootOptions[CurrentOption]);
|
|
BootOptionData = CommonGetVariableData (BootOption, &gEfiGlobalVariableGuid);
|
|
if (BootOptionData == NULL) {
|
|
continue;
|
|
}
|
|
//
|
|
// Get the boot loader file path from the current Boot Option data
|
|
//
|
|
BootOptionDesc = (CHAR16 *)(BootOptionData + sizeof(UINT32) + sizeof(UINT16));
|
|
BootDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)(BootOptionData + sizeof(UINT32) + sizeof(UINT16) + StrSize(BootOptionDesc));
|
|
Status = GetBootFilePathDevicePathOffset (BootDevicePath, &BootFilePathDevicePathOffset);
|
|
if (Status == EFI_SUCCESS) {
|
|
CompareSize = BootFilePathDevicePathOffset;
|
|
} else {
|
|
CompareSize = GetDevicePathSize (BootDevicePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL);
|
|
}
|
|
Status = gBS->LocateHandleBuffer(
|
|
ByProtocol,
|
|
&gEfiSimpleFileSystemProtocolGuid,
|
|
NULL,
|
|
&NumberOfHandles,
|
|
&HandleBuffer
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
FreePool (BootOptionData);
|
|
continue;
|
|
}
|
|
|
|
for (Index = 0; Index < NumberOfHandles; Index++) {
|
|
Status = gBS->HandleProtocol(
|
|
HandleBuffer[Index],
|
|
&gEfiDevicePathProtocolGuid,
|
|
(VOID **)SysRootDevicePath
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
continue;
|
|
}
|
|
if (CompareMem (
|
|
((UINT8 *)*SysRootDevicePath) + GetDevicePathSize (*SysRootDevicePath) - CompareSize - sizeof(EFI_DEVICE_PATH),
|
|
BootDevicePath,
|
|
CompareSize) == 0) {
|
|
Found = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if (Found) {
|
|
Status = gBS->HandleProtocol(
|
|
HandleBuffer[Index],
|
|
&gEfiSimpleFileSystemProtocolGuid,
|
|
(VOID **)&SimpleFileSystem
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
Status = SimpleFileSystem->OpenVolume(SimpleFileSystem, SysRootHandle);
|
|
}
|
|
} else {
|
|
Status = EFI_NOT_FOUND;
|
|
}
|
|
FreePool (HandleBuffer);
|
|
FreePool (BootOptionData);
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Get the information of system drive which contain capsule image file.
|
|
|
|
@param[out] SysRootDevicePath The pointer of system root device path pointer
|
|
@param[out] SysRoorHandle The pointer of EFI_FILE_HANDLE of system drive
|
|
|
|
@retval EFI_SUCCESS The system drive information is correctly get
|
|
@return Others Unable to get system drive information
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
GetSystemRootInfo (
|
|
OUT EFI_DEVICE_PATH **SysRootDevicePath,
|
|
OUT EFI_FILE_HANDLE *SysRootHandle
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
Status = GetSystemRootInfoFromCurrentBootOption (SysRootDevicePath, SysRootHandle);
|
|
if (!EFI_ERROR (Status)) {
|
|
if (HaveCapsuleImageFile (*SysRootHandle)) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
(*SysRootHandle)->Close (*SysRootHandle);
|
|
}
|
|
|
|
return GetSystemRootInfoFromFileSystems (SysRootDevicePath, SysRootHandle);
|
|
}
|
|
|
|
/**
|
|
Write a file to an root file handle.
|
|
|
|
@param[in] SysRoot The system root file handle.
|
|
@param[in] FileName Pointer to file name.
|
|
@param[in] FileBuffer The buffer to be written into file system.
|
|
@param[in] FileSize The size of FileBuffer.
|
|
|
|
@retval EFI_SUCCESS Wrote the file successfully.
|
|
@retval Others Failed to write the file.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
WriteFileToStorage (
|
|
IN EFI_FILE_HANDLE SysRoot,
|
|
IN CHAR16 *FileName,
|
|
IN UINT8 *FileBuffer,
|
|
IN UINTN FileSize,
|
|
IN BOOLEAN IsWriteToDirectory
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_FILE *FileHandle;
|
|
EFI_FILE *DirHandle;
|
|
UINTN WriteSize;
|
|
|
|
DEBUG ((DEBUG_INFO, "WriteFileToStorage - start\n"));
|
|
|
|
if (IsWriteToDirectory){
|
|
//
|
|
// Ensure that efi and updatecapsule directories exist
|
|
//
|
|
Status = SysRoot->Open (SysRoot, &DirHandle, L"\\EFI", EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE, 0);
|
|
if (EFI_ERROR (Status)) {
|
|
Status = SysRoot->Open (SysRoot, &DirHandle, L"\\EFI", EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, EFI_FILE_DIRECTORY);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_INFO, "Unable to create %s directory\n", L"\\EFI"));
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
}
|
|
Status = SysRoot->Open (SysRoot, &DirHandle, EFI_CAPSULE_FILE_DIRECTORY, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE , 0);
|
|
if (EFI_ERROR (Status)) {
|
|
Status = SysRoot->Open (SysRoot, &DirHandle, EFI_CAPSULE_FILE_DIRECTORY, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, EFI_FILE_DIRECTORY);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_INFO, "Unable to create %s directory\n", EFI_CAPSULE_FILE_DIRECTORY));
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
}
|
|
} else {
|
|
Status = SysRoot->Open (SysRoot, &FileHandle, FileName, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, 0);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_INFO, "Cannot open file: %s. Status = %r\n", FileName, Status));
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
if (IsWriteToDirectory) {
|
|
//
|
|
// Open UpdateCapsule file
|
|
//
|
|
Status = DirHandle->Open (DirHandle, &FileHandle, FileName, EFI_FILE_MODE_CREATE | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ, 0);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "Unable to create %s file\n", FileName));
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
}
|
|
|
|
if (FileHandle == NULL) {
|
|
Status = EFI_UNSUPPORTED;
|
|
DEBUG ((DEBUG_ERROR, "Failed to open root dir on partition for writing. Stautus = %r\n", Status));
|
|
return Status;
|
|
}
|
|
|
|
do {
|
|
WriteSize = (FileSize > SIZE_4KB) ? SIZE_4KB : FileSize;
|
|
Status = FileHandle->Write (FileHandle, &WriteSize, FileBuffer);
|
|
if (EFI_ERROR (Status)) {
|
|
break;
|
|
}
|
|
FileSize = FileSize - WriteSize;
|
|
FileBuffer = FileBuffer + WriteSize;
|
|
} while (FileSize > 0);
|
|
|
|
DEBUG ((DEBUG_INFO, "WriteFileToStorage %s %r\n", FileName, Status));
|
|
FileHandle->Close (FileHandle);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Delete a file from root file handle.
|
|
|
|
@param[in] Root The root file handle.
|
|
@param[in] FileName Pointer to file name.
|
|
|
|
@retval EFI_SUCCESS File does not exist or deleted the file successfully.
|
|
@retval Others Failed to delete the file.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
DeleteFileFromSys (
|
|
IN EFI_FILE_HANDLE Root,
|
|
IN CHAR16 *FileName
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_FILE *FileHandle;
|
|
|
|
DEBUG ((DEBUG_INFO, "DeleteFileFromRoot - start\n"));
|
|
|
|
Status = Root->Open (Root, &FileHandle, FileName, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE, 0);
|
|
if (Status == EFI_NOT_FOUND) {
|
|
DEBUG ((DEBUG_INFO, "File %s does not exist. No need to delete\n", FileName));
|
|
return EFI_SUCCESS;
|
|
} else if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "Cannot open file: %s. Status = %r\n", FileName, Status));
|
|
return Status;
|
|
}
|
|
|
|
if (FileHandle == NULL) {
|
|
Status = EFI_UNSUPPORTED;
|
|
DEBUG ((DEBUG_ERROR, "Failed to open root dir - %r\n", Status));
|
|
return Status;
|
|
}
|
|
|
|
Status = FileHandle->Delete (FileHandle);
|
|
DEBUG ((DEBUG_INFO, "DeleteFileFromRoot %s %r\n", FileName, Status));
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Read a file from a root file handle.
|
|
|
|
@param[in] SysRoot The system root file handle.
|
|
@param[in] FileName Pointer to file name.
|
|
@param[in] FileBuffer The buffer read from file system.
|
|
@param[in] FileSize The size of FileBuffer.
|
|
|
|
@retval EFI_SUCCESS Read the file successfully.
|
|
@retval Others Failed to read the file.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
ReadFileFromStorage (
|
|
IN EFI_FILE_HANDLE SysRoot,
|
|
IN CHAR16 *FileName,
|
|
OUT VOID **Buffer,
|
|
OUT UINTN *BufferSize
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_FILE *FileHandle;
|
|
UINTN FileInfoSize;
|
|
EFI_FILE_INFO *FileInfo;
|
|
EFI_GUID FileInfoGuid = EFI_FILE_INFO_ID;
|
|
|
|
DEBUG ((DEBUG_INFO, "ReadFileFromStorage - start\n"));
|
|
|
|
Status = SysRoot->Open (SysRoot, &FileHandle, FileName, EFI_FILE_MODE_READ, 0);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "Open file on root: %s. error - %r\n", FileName, Status));
|
|
return Status;
|
|
}
|
|
|
|
if (FileHandle == NULL) {
|
|
Status = EFI_UNSUPPORTED;
|
|
DEBUG ((DEBUG_ERROR, "Open file on root: %s. error - %r\n", FileName, Status));
|
|
return Status;
|
|
}
|
|
|
|
FileInfoSize = 0;
|
|
FileInfo = NULL;
|
|
|
|
Status = FileHandle->GetInfo (
|
|
FileHandle,
|
|
&FileInfoGuid,
|
|
&FileInfoSize,
|
|
NULL
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
if (Status != EFI_BUFFER_TOO_SMALL) {
|
|
DEBUG ((DEBUG_ERROR, "GetInfo error - %r\n", Status));
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "FileRead\n"));
|
|
FileInfo = AllocatePool (FileInfoSize);
|
|
if (FileInfo == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "GetInfo fail, AllocatePool(Size: %x) error\n", FileInfoSize));
|
|
goto Exit;
|
|
}
|
|
|
|
Status = FileHandle->GetInfo (
|
|
FileHandle,
|
|
&FileInfoGuid,
|
|
&FileInfoSize,
|
|
FileInfo
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "FileRead fail, GetInfo error, Status: %r\n", Status));
|
|
goto Exit;
|
|
}
|
|
|
|
*BufferSize = (UINT32) FileInfo->FileSize;
|
|
if (*BufferSize != 0) {
|
|
*Buffer = AllocateZeroPool (*BufferSize);
|
|
if (*Buffer == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "Read fail, AllocatePool(Size: %x) error\n", FileInfoSize));
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto Exit;
|
|
}
|
|
|
|
Status = FileHandle->Read (
|
|
FileHandle,
|
|
BufferSize,
|
|
*Buffer
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "Read fail, error - %r\n", Status));
|
|
FreePool (*Buffer);
|
|
goto Exit;
|
|
}
|
|
|
|
} else {
|
|
DEBUG ((DEBUG_INFO, "File size is 0, set return Buffer to NULL.\n"));
|
|
*Buffer = NULL;
|
|
}
|
|
|
|
Status = EFI_SUCCESS;
|
|
|
|
Exit:
|
|
if (FileInfo != NULL) {
|
|
FreePool (FileInfo);
|
|
}
|
|
|
|
FileHandle->Close (FileHandle);
|
|
|
|
DEBUG ((DEBUG_INFO, "ReadFileFromStorage %s BufferSize: %x %r\n", FileName, *BufferSize, Status));
|
|
return Status;
|
|
}
|
|
|
|
|
|
EFI_STATUS
|
|
GetBackupMeAsCapsule(
|
|
OUT BOOLEAN *IsMultiple
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_DEVICE_PATH_PROTOCOL *SysRootDevicePath;
|
|
EFI_FILE_HANDLE SysRootHandle;
|
|
UINT8 CapsuleSha256[SHA256_DIGEST_HASH_SIZE];
|
|
UINT8 BackupSha256[SHA256_DIGEST_HASH_SIZE];
|
|
UINTN VariableSize;
|
|
UINT8 *Buffer;
|
|
UINTN BufferSize;
|
|
UINT8 *Ptr;
|
|
UINTN Index;
|
|
|
|
Ptr = NULL;
|
|
Index = 0;
|
|
*IsMultiple = FALSE;
|
|
|
|
DEBUG ((DEBUG_INFO, "GetBackupMeAsCapsule - entry\n"));
|
|
|
|
Status = GetSystemRootInfo (&SysRootDevicePath, &SysRootHandle);
|
|
if (EFI_ERROR (Status) || SysRootHandle == NULL) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
Status = ReadFileFromStorage (SysRootHandle,SYSFW_UPDATE_ME_RECOVERY_CAPSULE_NAME_NEW,(VOID **)&Buffer, &BufferSize);
|
|
if (!EFI_ERROR (Status)) {
|
|
//
|
|
// Delete broken capsule.
|
|
//
|
|
DeleteFileFromSys (SysRootHandle, SYSFW_UPDATE_ME_RECOVERY_CAPSULE_NAME_NEW);
|
|
}
|
|
//
|
|
// Get backup ME.
|
|
//
|
|
Status = ReadFileFromStorage (SysRootHandle,SYSFW_UPDATE_ME_RECOVERY_CAPSULE_NAME,(VOID **)&Buffer, &BufferSize);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "Cannot find Backup ME Capsule image.\n"));
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
//
|
|
// Verify capsule
|
|
//
|
|
ZeroMem (CapsuleSha256, SHA256_DIGEST_HASH_SIZE);
|
|
CreateSha256Hash (Buffer, BufferSize, CapsuleSha256);
|
|
|
|
VariableSize = SHA256_DIGEST_HASH_SIZE;
|
|
ZeroMem (BackupSha256, SHA256_DIGEST_SIZE);
|
|
Status = gRT->GetVariable (
|
|
ME_CAPSULE_DIGEST_VARIABLE_NAME,
|
|
&gSysFwUpdateDigiestGuid,
|
|
NULL,
|
|
&VariableSize,
|
|
&BackupSha256
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "Can't find Me backup digest.\n"));
|
|
return Status;
|
|
}
|
|
|
|
if (CompareMem (CapsuleSha256, BackupSha256, SHA256_DIGEST_HASH_SIZE) == 0) {
|
|
Status = WriteFileToStorage (SysRootHandle, CAPSULE_IMAGE_NAME, (UINT8 *)(UINTN) Buffer, BufferSize, TRUE);
|
|
} else {
|
|
DEBUG ((DEBUG_ERROR, "Me backup image loaded from ESP is corrupted.\n"));
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
Index = 0;
|
|
Ptr = Buffer + Index;
|
|
while (Index < BufferSize) {
|
|
if (CompareMem (Ptr, InsydeBiosSignature, sizeof (InsydeBiosSignature)) == 0) {
|
|
*IsMultiple = TRUE;
|
|
break;
|
|
}
|
|
Index += sizeof(UINT64);
|
|
Ptr = Buffer + Index;
|
|
}
|
|
//
|
|
// Get backup ux
|
|
//
|
|
Status = ReadFileFromStorage (SysRootHandle,SYSFW_UPDATE_WINDOWS_UX_CAPSULE_FILE_NAME, (VOID **)&Buffer, &BufferSize);
|
|
if (EFI_ERROR (Status)) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
Status = WriteFileToStorage (SysRootHandle, UX_IMAGE_NAME, (UINT8 *)(UINTN) Buffer, BufferSize, TRUE);
|
|
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Save current ME/Monolithic Capsule as ME rollback capsule.
|
|
|
|
@param[in] PayloadImage Pointer to ME/Monolithic FMP payload image (FMP image header is stripped off).
|
|
@param[in] PayloadImageSize The size of PayloadImage.
|
|
|
|
@retval EFI_SUCCESS Successfully backed up necessary files on external storage.
|
|
@retval Others Failed to back up necessary files.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
SaveMeCapsuleForRollback (
|
|
IN BOOLEAN IsSecureflash
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT8 *Buffer;
|
|
UINTN Length;
|
|
UINT8 Sha256[SHA256_DIGEST_HASH_SIZE];
|
|
EFI_DEVICE_PATH_PROTOCOL *SysRootDevicePath;
|
|
EFI_FILE_HANDLE SysRootHandle;
|
|
EFI_CAPSULE_HEADER CapsuleHeader;
|
|
UINT8 *NewBuffer;
|
|
UINTN NewLength;
|
|
UINT8 *CurrentBuffer;
|
|
UINTN CurrentLength;
|
|
|
|
Buffer = NULL;
|
|
Length = 0;
|
|
NewBuffer = NULL;
|
|
NewLength = 0;
|
|
CurrentBuffer = NULL;
|
|
CurrentLength = 0;
|
|
|
|
DEBUG ((DEBUG_INFO, "SaveMeCapsuleForRollback - entry\n"));
|
|
|
|
Status = GetSystemRootInfo (&SysRootDevicePath, &SysRootHandle);
|
|
if (EFI_ERROR (Status) || SysRootHandle == NULL) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
|
|
//
|
|
// Get capsule as backup ME.
|
|
//
|
|
Status = ReadFileFromStorage (SysRootHandle, CAPSULE_IMAGE_FULL_PATH,(VOID **)&Buffer, &Length);
|
|
if (EFI_ERROR (Status)) {
|
|
if (IsSecureflash) {
|
|
//
|
|
// Get isflash.bin as backup ME.
|
|
//
|
|
Status = ReadFileFromStorage (SysRootHandle, SECURE_FLASH_IMAGE_PATH,(VOID **)&NewBuffer, &NewLength);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "Cannot find ME image.\n"));
|
|
return Status;
|
|
} else {
|
|
Buffer = NULL;
|
|
//
|
|
// Append EFI_CAPSULE_HEADER
|
|
//
|
|
CopyGuid (&CapsuleHeader.CapsuleGuid, PcdGetPtr (PcdWindowsMeFirmwareCapsuleGuid));
|
|
CapsuleHeader.Flags = 0x50000;
|
|
CapsuleHeader.HeaderSize = 0x1000;
|
|
CapsuleHeader.CapsuleImageSize = (UINT32)NewLength + CapsuleHeader.HeaderSize;
|
|
|
|
Buffer = AllocateZeroPool(CapsuleHeader.CapsuleImageSize);
|
|
CopyMem(Buffer, &CapsuleHeader, sizeof(EFI_CAPSULE_HEADER));
|
|
CopyMem((VOID*)((UINT8*)Buffer + CapsuleHeader.HeaderSize), (VOID*)NewBuffer, NewLength);
|
|
Length = CapsuleHeader.CapsuleImageSize;
|
|
}
|
|
} else {
|
|
DEBUG ((DEBUG_ERROR, "Cannot find ME image.\n"));
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Replace the any existing old recovery capsule with new capsule.
|
|
//
|
|
Status = DeleteFileFromSys (SysRootHandle, SYSFW_UPDATE_ME_RECOVERY_CAPSULE_NAME_NEW);
|
|
if (!EFI_ERROR (Status) || (Status == EFI_NOT_FOUND)) {
|
|
Status = WriteFileToStorage (SysRootHandle, SYSFW_UPDATE_ME_RECOVERY_CAPSULE_NAME_NEW, (UINT8 *)(UINTN) Buffer, Length, FALSE);
|
|
}
|
|
|
|
//
|
|
// Caculate temp digest
|
|
//
|
|
ZeroMem (Sha256, SHA256_DIGEST_HASH_SIZE);
|
|
CreateSha256Hash (Buffer, Length, Sha256);
|
|
Status = SetVariableToSensitiveVariable (
|
|
ME_CAPSULE_DIGEST_TEMP_VARIABLE_NAME,
|
|
&gSysFwUpdateDigiestGuid,
|
|
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
|
|
SHA256_DIGEST_HASH_SIZE,
|
|
Sha256
|
|
);
|
|
|
|
//
|
|
// If system has UX, save UX capsule.
|
|
//
|
|
Status = ReadFileFromStorage (SysRootHandle,UX_IMAGE_FULL_PATH,(VOID **)&Buffer, &Length);
|
|
if (!EFI_ERROR (Status)) {
|
|
Status = WriteFileToStorage (SysRootHandle, SYSFW_UPDATE_WINDOWS_UX_CAPSULE_FILE_NAME, (UINT8 *)(UINTN) Buffer, Length, FALSE);
|
|
} else {
|
|
DEBUG ((DEBUG_INFO, "System don't have UX.\n"));
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Replace MeRecovCap with MeRecovCapNew upon successful capsule update.
|
|
|
|
|
|
@retval EFI_SUCCESS Successfully old recovery capsule with new recovery capsule.
|
|
@retval Others Failed to sync old/new recovery capsules.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
SyncMeRecoveryCapsules (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT8 *Buffer;
|
|
UINTN Length;
|
|
UINT8 Sha256[SHA256_DIGEST_HASH_SIZE];
|
|
UINTN VariableSize;
|
|
EFI_DEVICE_PATH_PROTOCOL *SysRootDevicePath;
|
|
EFI_FILE_HANDLE SysRootHandle;
|
|
SYSTEM_FIRMWARE_COMPONENT Component;
|
|
|
|
Status = EFI_SUCCESS;
|
|
Buffer = NULL;
|
|
Length = 0;
|
|
|
|
DEBUG ((DEBUG_INFO, "SyncMeRecoveryCapsules - entry\n"));
|
|
|
|
Status = GetFwUpdateInfo (&Component);
|
|
if(!EFI_ERROR(Status)) {
|
|
if(Component != UpdatingBios){
|
|
//During flash.
|
|
goto Exit;
|
|
} else {
|
|
// Flash ME done, clear flag.
|
|
ClearFwUpdateInfo ();
|
|
}
|
|
}
|
|
|
|
Status = GetSystemRootInfo (&SysRootDevicePath, &SysRootHandle);
|
|
if (EFI_ERROR (Status) || SysRootHandle == NULL) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
Status = ReadFileFromStorage (SysRootHandle,SYSFW_UPDATE_ME_RECOVERY_CAPSULE_NAME_NEW,(VOID **)&Buffer, &Length);
|
|
if (!EFI_ERROR (Status)) {
|
|
|
|
VariableSize = SHA256_DIGEST_HASH_SIZE;
|
|
ZeroMem (Sha256, SHA256_DIGEST_SIZE);
|
|
Status = gRT->GetVariable (
|
|
ME_CAPSULE_DIGEST_TEMP_VARIABLE_NAME,
|
|
&gSysFwUpdateDigiestGuid,
|
|
NULL,
|
|
&VariableSize,
|
|
&Sha256
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_INFO, "Get me digest fail, Status %r\n", Status));
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// A new ME Recovery capsule exists on storage. Replace old recovery capsule with new capsule.
|
|
//
|
|
Status = DeleteFileFromSys (SysRootHandle, SYSFW_UPDATE_ME_RECOVERY_CAPSULE_NAME);
|
|
if (!EFI_ERROR (Status) || (Status == EFI_NOT_FOUND)) {
|
|
|
|
Status = WriteFileToStorage (SysRootHandle, SYSFW_UPDATE_ME_RECOVERY_CAPSULE_NAME, (UINT8 *) (UINTN) Buffer, Length, FALSE);
|
|
if(EFI_ERROR (Status)){
|
|
DEBUG ((DEBUG_INFO, "Write ME backup fail, Status %r\n", Status));
|
|
goto Exit;
|
|
}
|
|
|
|
Status = SetVariableToSensitiveVariable (
|
|
ME_CAPSULE_DIGEST_VARIABLE_NAME,
|
|
&gSysFwUpdateDigiestGuid,
|
|
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
|
|
SHA256_DIGEST_HASH_SIZE,
|
|
Sha256
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_INFO, "Write me digest fail, Status %r\n", Status));
|
|
goto Exit;
|
|
}
|
|
|
|
Status = DeleteFileFromSys (SysRootHandle, SYSFW_UPDATE_ME_RECOVERY_CAPSULE_NAME_NEW);
|
|
SetVariableToSensitiveVariable (
|
|
ME_CAPSULE_DIGEST_TEMP_VARIABLE_NAME,
|
|
&gSysFwUpdateProgressGuid,
|
|
0,
|
|
0,
|
|
NULL
|
|
);
|
|
|
|
}
|
|
FreePool (Buffer);
|
|
}
|
|
|
|
Exit:
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Search for ME recovery capsule on storage and return TRUE if present.
|
|
|
|
@retval TRUE ME recovery image is present.
|
|
@retval FALSE ME recovery image is not present.
|
|
|
|
**/
|
|
BOOLEAN
|
|
IsMeBackupExistOnStorage (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_DEVICE_PATH_PROTOCOL *SysRootDevicePath;
|
|
EFI_FILE_HANDLE SysRootHandle;
|
|
|
|
Status = GetSystemRootInfo (&SysRootDevicePath, &SysRootHandle);
|
|
if (!EFI_ERROR (Status) || SysRootHandle != NULL) {
|
|
Status = ReadFileFromStorage (SysRootHandle, SYSFW_UPDATE_ME_RECOVERY_CAPSULE_NAME, NULL, NULL);
|
|
}
|
|
return (Status == EFI_SUCCESS);
|
|
}
|
|
//[-end-201112-IB16810138-add]//
|
|
BOOLEAN
|
|
IsCapsuleUpdate(
|
|
VOID
|
|
)
|
|
{
|
|
UINTN Size;
|
|
UINT64 OsIndications;
|
|
SYSTEM_FIRMWARE_COMPONENT Component;
|
|
EFI_STATUS Status;
|
|
|
|
Size = sizeof (UINT64);
|
|
Status = CommonGetVariable (
|
|
L"OsIndications",
|
|
&gEfiGlobalVariableGuid,
|
|
&Size,
|
|
&OsIndications
|
|
);
|
|
|
|
if (!EFI_ERROR (Status) && (OsIndications & EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED)) {
|
|
Status = GetFwUpdateInfo (&Component);
|
|
if ((!EFI_ERROR (Status) && Component == UpdatingMe) || (!EFI_ERROR (Status) && Component == UpdatingTypeMax)) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
BOOLEAN
|
|
IsSecureFlash(
|
|
OUT BOOLEAN *IsMultipleImage
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT8 *Buffer;
|
|
UINTN Length;
|
|
EFI_DEVICE_PATH_PROTOCOL *SysRootDevicePath;
|
|
EFI_FILE_HANDLE SysRootHandle;
|
|
IMAGE_INFO ImageInfo;
|
|
UINTN Size;
|
|
UINTN Index;
|
|
UINT8 *Ptr;
|
|
BOOLEAN FoundMeFlag;
|
|
SYSTEM_FIRMWARE_COMPONENT Component;
|
|
|
|
DEBUG ((DEBUG_INFO, "IsSecureFlash - entry\n"));
|
|
|
|
Buffer = NULL;
|
|
Length = 0;
|
|
Ptr = NULL;
|
|
FoundMeFlag = FALSE;
|
|
|
|
Size = sizeof (IMAGE_INFO);
|
|
Status = CommonGetVariable (
|
|
SECURE_FLASH_INFORMATION_NAME,
|
|
&gSecureFlashInfoGuid,
|
|
&Size,
|
|
&ImageInfo
|
|
);
|
|
|
|
if ((Status == EFI_SUCCESS) && (ImageInfo.FlashMode)) {
|
|
Status = GetSystemRootInfo (&SysRootDevicePath, &SysRootHandle);
|
|
if (EFI_ERROR (Status) || SysRootHandle == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "GetSystemRootInfo fail.\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
Status = GetFwUpdateInfo (&Component);
|
|
if(!EFI_ERROR (Status)) {
|
|
return FALSE;
|
|
} else {
|
|
//
|
|
//First time do secure flash
|
|
//
|
|
Status = ReadFileFromStorage (SysRootHandle, SECURE_FLASH_IMAGE_PATH,(VOID **)&Buffer, &Length);
|
|
if (!EFI_ERROR (Status)) {
|
|
// Find Signature
|
|
if (Buffer != NULL) {
|
|
Index = 0;
|
|
Ptr = Buffer + Index;
|
|
while (Index < Length) {
|
|
if (CompareMem (Ptr, InsydeMeSig, sizeof (InsydeMeSig)) == 0) {
|
|
FoundMeFlag = TRUE;
|
|
break;
|
|
}
|
|
Index += sizeof(UINT64);
|
|
Ptr = Buffer + Index;
|
|
}
|
|
}
|
|
|
|
if(FoundMeFlag) {
|
|
if(Length > PcdGet32 (PcdFlashAreaSize)){
|
|
*IsMultipleImage = TRUE;
|
|
return TRUE;
|
|
} else {
|
|
*IsMultipleImage = FALSE;
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
MeResiliencyCallBack
|
|
|
|
ME Resiliency Feature to determine the CSE Image health and then
|
|
initiate capsule based recovery.
|
|
|
|
@param[in] Event - A pointer to the Event that triggered the callback.
|
|
@param[in] Context - A pointer to private data registered with the callback function.
|
|
**/
|
|
//[-start-201112-IB16810138-modify]//
|
|
VOID
|
|
EFIAPI
|
|
MeUpdateFaultToleranceCallBack (
|
|
//[-end-201112-IB16810138-modify]//
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT8 *Buffer;
|
|
UINTN Length;
|
|
UINT64 HeciBaseAddress;
|
|
HECI_FWS_REGISTER MeFwSts;
|
|
HECI_GS_SHDW_REGISTER MeFwSts2;
|
|
//[-start-201112-IB16810138-remove]//
|
|
// PCH_RESET_DATA ResetData;
|
|
// UINTN ResetDataSize;
|
|
// SYSTEM_FIRMWARE_UPDATE_PROGRESS PreviousProgress;
|
|
//[-end-201112-IB16810138-remove]//
|
|
//[-start-201112-IB16810138-add]//
|
|
UINTN Size;
|
|
UINT64 OsIndications;
|
|
SYSTEM_FIRMWARE_COMPONENT Component;
|
|
BOOLEAN IsMultipleImage;
|
|
//[-end-201112-IB16810138-add]//
|
|
//[-start-201112-IB16810138-modify]//
|
|
DEBUG((DEBUG_INFO, "MeUpdateFaultToleranceCallBack Start\n"));
|
|
//[-end-201112-IB16810138-modify]//
|
|
Status = EFI_SUCCESS;
|
|
Buffer = NULL;
|
|
Length = 0;
|
|
IsMultipleImage = FALSE;
|
|
|
|
HeciBaseAddress = PCI_SEGMENT_LIB_ADDRESS (ME_SEGMENT, ME_BUS, ME_DEVICE_NUMBER, HECI_FUNCTION_NUMBER, 0);
|
|
//
|
|
// Read ME FWS
|
|
//
|
|
MeFwSts.ul = PciSegmentRead32 (HeciBaseAddress + R_ME_HFS);
|
|
DEBUG ((DEBUG_INFO, "MeFwSts = 0x%X!\n", MeFwSts.ul));
|
|
|
|
//
|
|
// Read ME FWS2
|
|
//
|
|
MeFwSts2.ul = PciSegmentRead32 (HeciBaseAddress + R_ME_HFS_2);
|
|
DEBUG ((DEBUG_INFO, "MeFwSts2 = 0x%X!\n", MeFwSts2.ul));
|
|
|
|
if ((MeFwSts.r.CurrentState == ME_STATE_RECOVERY) ||
|
|
(MeFwSts.r.FtBupLdFlr == 1) ||
|
|
(MeFwSts2.r.FwUpdIpu == 1)) {
|
|
DEBUG ((DEBUG_INFO, "ME region is corrupted, initiate ME recovery\n"));
|
|
//[-start-201112-IB16810138-modify]//
|
|
//[-start-201112-IB16810138-add]//
|
|
Status = GetFwUpdateInfo (&Component);
|
|
//[-start-201112-IB16810138-modify]//
|
|
if (EFI_ERROR (Status) && IsMeBackupExistOnStorage ()) {
|
|
//[-end-201112-IB16810138-modify]//
|
|
//[-start-201112-IB16810138-add]//
|
|
Status = GetBackupMeAsCapsule (&IsMultipleImage);
|
|
if (!EFI_ERROR (Status)) {
|
|
//[-end-201112-IB16810138-add]//
|
|
//
|
|
// Set Update Progress variable for resiliency.
|
|
// Clear this variable in ClearFirmwareUpdateProgress() after TriggerCapsuleUpdate()
|
|
//
|
|
// SetUpdateProgress (UpdatingMeResiliency, 0);
|
|
//[-start-201112-IB16810138-add]//
|
|
if (IsMultipleImage) {
|
|
//
|
|
// Set Bios update flag
|
|
//
|
|
Component = UpdatingBios;
|
|
Status = gRT->SetVariable (
|
|
L"FmpCapsuleInfo",
|
|
&gFmpCapsuleInfoGuid,
|
|
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
|
|
sizeof(SYSTEM_FIRMWARE_COMPONENT),
|
|
&Component
|
|
);
|
|
|
|
}
|
|
|
|
Component = UpdatingMe;
|
|
Status = SetVariableToSensitiveVariable (
|
|
FW_UPDATEINFO_VARIABLE_NAME,
|
|
&gSysFwUpdateProgressGuid,
|
|
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
|
|
sizeof(SYSTEM_FIRMWARE_COMPONENT),
|
|
&Component
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "Set FW_UPDATEINFO_VARIABLE_NAME to UpdatingMeResiliency fail.\n"));
|
|
}
|
|
//
|
|
// Trigger capsule update to fix ME
|
|
//
|
|
Size = sizeof(UINT64);
|
|
OsIndications = 0;
|
|
Status = CommonGetVariable (
|
|
L"OsIndications",
|
|
&gEfiGlobalVariableGuid,
|
|
&Size,
|
|
&OsIndications
|
|
);
|
|
if (EFI_ERROR (Status) || (OsIndications & EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED) == 0) {
|
|
OsIndications |= EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED;
|
|
Status = CommonSetVariable (
|
|
L"OsIndications",
|
|
&gEfiGlobalVariableGuid,
|
|
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
|
|
sizeof(UINT64),
|
|
&OsIndications
|
|
);
|
|
//[-end-201112-IB16810138-add]//
|
|
//
|
|
// Issue a global reset to initiate capsule based recovery.
|
|
//
|
|
// ResetDataSize = sizeof (PCH_RESET_DATA);
|
|
// CopyMem (&ResetData.Guid, &gPchGlobalResetGuid, sizeof (EFI_GUID));
|
|
// StrCpyS (ResetData.Description, PCH_RESET_DATA_STRING_MAX_LENGTH, PCH_PLATFORM_SPECIFIC_RESET_STRING);
|
|
|
|
// DEBUG ((DEBUG_INFO, "Issue global reset for capsule based recovery\n"));
|
|
gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
|
|
}
|
|
}
|
|
} else {
|
|
DEBUG ((DEBUG_ERROR, "ME Recovery capsule is not found on storage - skip recovery.\n"));
|
|
}
|
|
} else {
|
|
//
|
|
// Sync ME Recovery Capsules.
|
|
//
|
|
//[-start-201112-IB16810138-add]//
|
|
if (IsCapsuleUpdate ()) {
|
|
Status = SaveMeCapsuleForRollback (FALSE);
|
|
} else if (IsSecureFlash (&IsMultipleImage)) {
|
|
|
|
if (IsMultipleImage) {
|
|
Component = UpdatingTypeMax;
|
|
} else {
|
|
Component = UpdatingMe;
|
|
}
|
|
Status = SetFwUpdateInfo (&Component);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Exit;
|
|
}
|
|
Status = SaveMeCapsuleForRollback (TRUE);
|
|
} else {
|
|
//
|
|
// ME update completed and boot success.
|
|
// Sync ME Recovery Capsules.
|
|
//
|
|
//[-end-201112-IB16810138-add]//
|
|
Status = SyncMeRecoveryCapsules ();
|
|
DEBUG ((DEBUG_INFO, "SyncMeRecoveryCapsules - %r\n", Status));
|
|
}
|
|
}
|
|
//[-end-201112-IB16810138-modify]//
|
|
Exit:
|
|
DEBUG((DEBUG_INFO, "MeResiliencyCallBack End\n"));
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
EFIAPI
|
|
MeUpdateFaultToleranceOnReadyToBootBefore (
|
|
IN EFI_EVENT Event,
|
|
IN H2O_CP_HANDLE Handle
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT8 *Buffer;
|
|
UINTN Length;
|
|
EFI_DEVICE_PATH_PROTOCOL *SysRootDevicePath;
|
|
EFI_FILE_HANDLE SysRootHandle;
|
|
|
|
Status = EFI_SUCCESS;
|
|
Buffer = NULL;
|
|
Length = 0;
|
|
|
|
H2OCpUnregisterHandler (Handle);
|
|
|
|
//
|
|
// The update has been processed before this funtion called.
|
|
// Clear flag at this point.
|
|
//
|
|
ClearFwUpdateInfo ();
|
|
|
|
|
|
Status = GetSystemRootInfo (&SysRootDevicePath, &SysRootHandle);
|
|
if (EFI_ERROR (Status) || SysRootHandle == NULL) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Delete backup temp file.
|
|
//
|
|
Status = ReadFileFromStorage (SysRootHandle,SYSFW_UPDATE_ME_RECOVERY_CAPSULE_NAME_NEW,(VOID **)&Buffer, &Length);
|
|
if (!EFI_ERROR (Status)) {
|
|
DeleteFileFromSys (SysRootHandle, SYSFW_UPDATE_ME_RECOVERY_CAPSULE_NAME_NEW);
|
|
|
|
SetVariableToSensitiveVariable (
|
|
ME_CAPSULE_DIGEST_TEMP_VARIABLE_NAME,
|
|
&gSysFwUpdateProgressGuid,
|
|
0,
|
|
0,
|
|
NULL
|
|
);
|
|
|
|
}
|
|
}
|
|
|
|
/**
|
|
Initialize Resiliency Support for ME.
|
|
|
|
@retval EFI_SUCCESS Resiliency Support is initialized successfully
|
|
@retval EFI_NOT_FOUND Resiliency Support is not initialized successfully
|
|
**/
|
|
//[-start-201112-IB16810138-modify]//
|
|
EFI_STATUS
|
|
EFIAPI
|
|
MeUpdateFaultToleranceEntryPoint (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
//[-end-201112-IB16810138-modify]//
|
|
{
|
|
EFI_STATUS Status;
|
|
//[-start-201112-IB16810138-modify]//
|
|
// EFI_EVENT BeforeEndOfDxeEvent;
|
|
H2O_CP_HANDLE CpHandle;
|
|
|
|
Status = EFI_SUCCESS;
|
|
// BeforeEndOfDxeEvent = NULL;
|
|
//[-start-201112-IB16810138-modify]//
|
|
DEBUG ((DEBUG_INFO, "MeUpdateFaultToleranceEntryPoint Start\n"));
|
|
//[-end-201112-IB16810138-modify]//
|
|
DEBUG ((DEBUG_INFO, "Register an EndOfDxe Callback Function for ME Resiliency Health Check \n"));
|
|
//[-start-201112-IB16810138-remove]//
|
|
// Status = gBS->CreateEventEx (
|
|
// EVT_NOTIFY_SIGNAL,
|
|
// TPL_CALLBACK,
|
|
// MeResiliencyCallBack,
|
|
// NULL,
|
|
// &gPlatformBeforeEndOfDxeEventGroupGuid,
|
|
// &BeforeEndOfDxeEvent
|
|
// );
|
|
// ASSERT_EFI_ERROR (Status);
|
|
// if (EFI_ERROR (Status)) {
|
|
// DEBUG ((DEBUG_ERROR, "Failed to Register an EndOfDxe CallBack function for ME Resiliency, Status: %d\n", Status));
|
|
// }
|
|
//[-end-201112-IB16810138-remove]//
|
|
//[-start-201112-IB16810138-add]//
|
|
if (FeaturePcdGet (PcdH2OBdsCpEndOfDxeBeforeSupported)) {
|
|
//[-start-201112-IB16810138-modify]//
|
|
Status = H2OCpRegisterHandler (
|
|
&gH2OBdsCpEndOfDxeBeforeGuid,
|
|
MeUpdateFaultToleranceCallBack,
|
|
H2O_CP_MEDIUM_HIGH,
|
|
&CpHandle
|
|
);
|
|
//[-end-201112-IB16810138-modify]//
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG_CP ((DEBUG_ERROR, "Checkpoint Register Fail: %g (%r)\n", &gH2OBdsCpEndOfDxeBeforeGuid, Status));
|
|
return Status;
|
|
}
|
|
DEBUG_CP ((DEBUG_INFO, "Checkpoint Registered: %g (%r)\n", &gH2OBdsCpEndOfDxeBeforeGuid, Status));
|
|
}
|
|
//[-end-201112-IB16810138-add]//
|
|
|
|
if (FeaturePcdGet (PcdH2OBdsCpReadyToBootBeforeSupported)) {
|
|
Status = H2OCpRegisterHandler (
|
|
&gH2OBdsCpReadyToBootBeforeGuid,
|
|
MeUpdateFaultToleranceOnReadyToBootBefore,
|
|
H2O_CP_LOW,
|
|
&CpHandle
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG_CP ((DEBUG_ERROR, "Checkpoint Register Fail: %g (%r)\n", &gH2OBdsCpReadyToBootBeforeGuid, Status));
|
|
return Status;
|
|
}
|
|
DEBUG_CP ((DEBUG_INFO, "Checkpoint Registered: %g (%r)\n", &gH2OBdsCpReadyToBootBeforeGuid, Status));
|
|
}
|
|
|
|
//[-end-201112-IB16810138-modify]//
|
|
//[-start-201112-IB16810138-modify]//
|
|
DEBUG ((DEBUG_INFO, "MeUpdateFaultToleranceEntryPoint End\n"));
|
|
//[-end-201112-IB16810138-modify]//
|
|
return Status;
|
|
}
|